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(),
524374d266SArmin Le Grand             maVersion(),
534374d266SArmin Le Grand             mbStyleAttributesInitialized(false) // #125258#
54ddde725dSArmin Le Grand         {
554374d266SArmin Le Grand         }
564374d266SArmin Le Grand 
574374d266SArmin Le Grand         // #125258#
584374d266SArmin Le Grand         void SvgSvgNode::initializeStyleAttributes()
594374d266SArmin Le Grand         {
604374d266SArmin Le Grand             if(!mbStyleAttributesInitialized)
61ddde725dSArmin Le Grand             {
624374d266SArmin Le Grand                 // #125258# determine if initial values need to be initialized with hard values
634374d266SArmin Le Grand                 // for the case that this is the outmost SVG statement and it has no parent
644374d266SArmin Le Grand                 // stale (CssStyle for svg may be defined)
654374d266SArmin Le Grand                 bool bSetInitialValues(true);
664374d266SArmin Le Grand 
674374d266SArmin Le Grand                 if(getParent())
684374d266SArmin Le Grand                 {
694374d266SArmin Le Grand                     // #125258# no initial values when it's a SVG element embedded in SVG
704374d266SArmin Le Grand                     bSetInitialValues = false;
714374d266SArmin Le Grand                 }
724374d266SArmin Le Grand 
734374d266SArmin Le Grand                 if(bSetInitialValues)
744374d266SArmin Le Grand                 {
754374d266SArmin Le Grand                     const SvgStyleAttributes* pStyles = getSvgStyleAttributes();
764374d266SArmin Le Grand 
774374d266SArmin Le Grand                     if(pStyles && pStyles->getParentStyle())
784374d266SArmin Le Grand                     {
79*9d01bcdeSArmin Le Grand                         // SVG has a parent style (probably CssStyle), check if fill is set there anywhere
80*9d01bcdeSArmin Le Grand                         // already. If yes, do not set the default fill (black)
81*9d01bcdeSArmin Le Grand                         bool bFillSet(false);
82*9d01bcdeSArmin Le Grand                         const SvgStyleAttributes* pParentStyle = pStyles->getParentStyle();
83*9d01bcdeSArmin Le Grand 
84*9d01bcdeSArmin Le Grand                         while(pParentStyle && !bFillSet)
85*9d01bcdeSArmin Le Grand                         {
86*9d01bcdeSArmin Le Grand                             bFillSet = pParentStyle->isFillSet();
87*9d01bcdeSArmin Le Grand                             pParentStyle = pParentStyle->getParentStyle();
88*9d01bcdeSArmin Le Grand                         }
89*9d01bcdeSArmin Le Grand 
90*9d01bcdeSArmin Le Grand                         if(bFillSet)
91*9d01bcdeSArmin Le Grand                         {
92*9d01bcdeSArmin Le Grand                             // #125258# no initial values when SVG has a parent style at which a fill
93*9d01bcdeSArmin Le Grand                             // is already set
94*9d01bcdeSArmin Le Grand                             bSetInitialValues = false;
95*9d01bcdeSArmin Le Grand                         }
964374d266SArmin Le Grand                     }
974374d266SArmin Le Grand                 }
984374d266SArmin Le Grand 
994374d266SArmin Le Grand                 if(bSetInitialValues)
1004374d266SArmin Le Grand                 {
1014374d266SArmin Le Grand                     // #125258# only set if not yet initialized (SvgSvgNode::parseAttribute is already done,
1024374d266SArmin Le Grand                     // just setting may revert an already set valid value)
1034374d266SArmin Le Grand                     if(!maSvgStyleAttributes.isFillSet())
1044374d266SArmin Le Grand                     {
1054374d266SArmin Le Grand                         // #125258# initial fill is black (see SVG1.1 spec)
1064374d266SArmin Le Grand                         maSvgStyleAttributes.setFill(SvgPaint(basegfx::BColor(0.0, 0.0, 0.0), true, true));
1074374d266SArmin Le Grand                     }
1084374d266SArmin Le Grand                 }
1094374d266SArmin Le Grand 
1104374d266SArmin Le Grand                 mbStyleAttributesInitialized = true;
111ddde725dSArmin Le Grand             }
112ddde725dSArmin Le Grand         }
113ddde725dSArmin Le Grand 
114ddde725dSArmin Le Grand         SvgSvgNode::~SvgSvgNode()
115ddde725dSArmin Le Grand         {
116ddde725dSArmin Le Grand             if(mpViewBox) delete mpViewBox;
117ddde725dSArmin Le Grand         }
118ddde725dSArmin Le Grand 
119ddde725dSArmin Le Grand         const SvgStyleAttributes* SvgSvgNode::getSvgStyleAttributes() const
120ddde725dSArmin Le Grand         {
1214374d266SArmin Le Grand             // #125258# svg node can vahe CssStyles, too, so check for it here
1224374d266SArmin Le Grand             static rtl::OUString aClassStr(rtl::OUString::createFromAscii("svg"));
1234374d266SArmin Le Grand 
1244374d266SArmin Le Grand             return checkForCssStyle(aClassStr, maSvgStyleAttributes);
125ddde725dSArmin Le Grand         }
126ddde725dSArmin Le Grand 
127ddde725dSArmin Le Grand         void SvgSvgNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
128ddde725dSArmin Le Grand         {
129ddde725dSArmin Le Grand             // call parent
130ddde725dSArmin Le Grand             SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
131ddde725dSArmin Le Grand 
132ddde725dSArmin Le Grand             // read style attributes
133ddde725dSArmin Le Grand             maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent);
134ddde725dSArmin Le Grand 
135ddde725dSArmin Le Grand             // parse own
136ddde725dSArmin Le Grand             switch(aSVGToken)
137ddde725dSArmin Le Grand             {
138ddde725dSArmin Le Grand                 case SVGTokenStyle:
139ddde725dSArmin Le Grand                 {
140*9d01bcdeSArmin Le Grand                     readLocalCssStyle(aContent);
141ddde725dSArmin Le Grand                     break;
142ddde725dSArmin Le Grand                 }
143ddde725dSArmin Le Grand                 case SVGTokenViewBox:
144ddde725dSArmin Le Grand                 {
145ddde725dSArmin Le Grand                     const basegfx::B2DRange aRange(readViewBox(aContent, *this));
146ddde725dSArmin Le Grand 
147ddde725dSArmin Le Grand                     if(!aRange.isEmpty())
148ddde725dSArmin Le Grand                     {
149ddde725dSArmin Le Grand                         setViewBox(&aRange);
150ddde725dSArmin Le Grand                     }
151ddde725dSArmin Le Grand                     break;
152ddde725dSArmin Le Grand                 }
153ddde725dSArmin Le Grand                 case SVGTokenPreserveAspectRatio:
154ddde725dSArmin Le Grand                 {
155ddde725dSArmin Le Grand                     setSvgAspectRatio(readSvgAspectRatio(aContent));
156ddde725dSArmin Le Grand                     break;
157ddde725dSArmin Le Grand                 }
158ddde725dSArmin Le Grand                 case SVGTokenX:
159ddde725dSArmin Le Grand                 {
160ddde725dSArmin Le Grand                     SvgNumber aNum;
161ddde725dSArmin Le Grand 
162ddde725dSArmin Le Grand                     if(readSingleNumber(aContent, aNum))
163ddde725dSArmin Le Grand                     {
164ddde725dSArmin Le Grand                         setX(aNum);
165ddde725dSArmin Le Grand                     }
166ddde725dSArmin Le Grand                     break;
167ddde725dSArmin Le Grand                 }
168ddde725dSArmin Le Grand                 case SVGTokenY:
169ddde725dSArmin Le Grand                 {
170ddde725dSArmin Le Grand                     SvgNumber aNum;
171ddde725dSArmin Le Grand 
172ddde725dSArmin Le Grand                     if(readSingleNumber(aContent, aNum))
173ddde725dSArmin Le Grand                     {
174ddde725dSArmin Le Grand                         setY(aNum);
175ddde725dSArmin Le Grand                     }
176ddde725dSArmin Le Grand                     break;
177ddde725dSArmin Le Grand                 }
178ddde725dSArmin Le Grand                 case SVGTokenWidth:
179ddde725dSArmin Le Grand                 {
180ddde725dSArmin Le Grand                     SvgNumber aNum;
181ddde725dSArmin Le Grand 
182ddde725dSArmin Le Grand                     if(readSingleNumber(aContent, aNum))
183ddde725dSArmin Le Grand                     {
184ddde725dSArmin Le Grand                         if(aNum.isPositive())
185ddde725dSArmin Le Grand                         {
186ddde725dSArmin Le Grand                             setWidth(aNum);
187ddde725dSArmin Le Grand                         }
188ddde725dSArmin Le Grand                     }
189ddde725dSArmin Le Grand                     break;
190ddde725dSArmin Le Grand                 }
191ddde725dSArmin Le Grand                 case SVGTokenHeight:
192ddde725dSArmin Le Grand                 {
193ddde725dSArmin Le Grand                     SvgNumber aNum;
194ddde725dSArmin Le Grand 
195ddde725dSArmin Le Grand                     if(readSingleNumber(aContent, aNum))
196ddde725dSArmin Le Grand                     {
197ddde725dSArmin Le Grand                         if(aNum.isPositive())
198ddde725dSArmin Le Grand                         {
199ddde725dSArmin Le Grand                             setHeight(aNum);
200ddde725dSArmin Le Grand                         }
201ddde725dSArmin Le Grand                     }
202ddde725dSArmin Le Grand                     break;
203ddde725dSArmin Le Grand                 }
204ddde725dSArmin Le Grand                 case SVGTokenVersion:
205ddde725dSArmin Le Grand                 {
206ddde725dSArmin Le Grand                     SvgNumber aNum;
207ddde725dSArmin Le Grand 
208ddde725dSArmin Le Grand                     if(readSingleNumber(aContent, aNum))
209ddde725dSArmin Le Grand                     {
210ddde725dSArmin Le Grand                         setVersion(aNum);
211ddde725dSArmin Le Grand                     }
212ddde725dSArmin Le Grand                     break;
213e2bf1e9dSArmin Le Grand                 }
214e2bf1e9dSArmin Le Grand                 default:
215e2bf1e9dSArmin Le Grand                 {
216e2bf1e9dSArmin Le Grand                     break;
217ddde725dSArmin Le Grand                 }
218ddde725dSArmin Le Grand             }
219ddde725dSArmin Le Grand         }
220ddde725dSArmin Le Grand 
2212169cc62SArmin Le Grand         void SvgSvgNode::seekReferenceWidth(double& fWidth, bool& bHasFound) const
2222169cc62SArmin Le Grand         {
2232169cc62SArmin Le Grand             if (!getParent() || bHasFound)
2242169cc62SArmin Le Grand             {
2252169cc62SArmin Le Grand                 return;
2262169cc62SArmin Le Grand             }
2272169cc62SArmin Le Grand             const SvgSvgNode* pParentSvgSvgNode = 0;
2282169cc62SArmin Le Grand             // enclosing svg might have relative width, need to cumulate them till they are
2292169cc62SArmin Le Grand             // resolved somewhere up in the node tree
2302169cc62SArmin Le Grand             double fPercentage(1.0);
2312169cc62SArmin Le Grand             for(const SvgNode* pParent = getParent(); pParent && !bHasFound; pParent = pParent->getParent())
2322169cc62SArmin Le Grand             {
2332169cc62SArmin Le Grand                 // dynamic_cast results Null-pointer for not SvgSvgNode and so skips them in if condition
2342169cc62SArmin Le Grand                 pParentSvgSvgNode = dynamic_cast< const SvgSvgNode* >(pParent);
2352169cc62SArmin Le Grand                 if (pParentSvgSvgNode)
2362169cc62SArmin Le Grand                 {
2372169cc62SArmin Le Grand                     if (pParentSvgSvgNode->getViewBox())
2382169cc62SArmin Le Grand                     {
2392169cc62SArmin Le Grand                         // viewbox values are already in 'user unit'.
2402169cc62SArmin Le Grand                         fWidth = pParentSvgSvgNode->getViewBox()->getWidth() * fPercentage;
2412169cc62SArmin Le Grand                         bHasFound = true;
2422169cc62SArmin Le Grand                     }
2432169cc62SArmin Le Grand                     else
2442169cc62SArmin Le Grand                     {
2452169cc62SArmin Le Grand                         // take absolute value or cummulate percentage
2462169cc62SArmin Le Grand                         if (pParentSvgSvgNode->getWidth().isSet())
2472169cc62SArmin Le Grand                         {
2482169cc62SArmin Le Grand                             if (Unit_percent == pParentSvgSvgNode->getWidth().getUnit())
2492169cc62SArmin Le Grand                             {
2502169cc62SArmin Le Grand                                 fPercentage *= pParentSvgSvgNode->getWidth().getNumber() * 0.01;
2512169cc62SArmin Le Grand                             }
2522169cc62SArmin Le Grand                             else
2532169cc62SArmin Le Grand                             {
2542169cc62SArmin Le Grand                                 fWidth = pParentSvgSvgNode->getWidth().solveNonPercentage(*pParentSvgSvgNode) * fPercentage;
2552169cc62SArmin Le Grand                                 bHasFound = true;
2562169cc62SArmin Le Grand                             }
2572169cc62SArmin Le Grand                         } // not set => width=100% => factor 1, no need for else
2582169cc62SArmin Le Grand                     }
2592169cc62SArmin Le Grand                 }
2602169cc62SArmin Le Grand             }
2612169cc62SArmin Le Grand         }
2622169cc62SArmin Le Grand 
2632169cc62SArmin Le Grand         void SvgSvgNode::seekReferenceHeight(double& fHeight, bool& bHasFound) const
2642169cc62SArmin Le Grand         {
2652169cc62SArmin Le Grand             if (!getParent() || bHasFound)
2662169cc62SArmin Le Grand             {
2672169cc62SArmin Le Grand                 return;
2682169cc62SArmin Le Grand             }
2692169cc62SArmin Le Grand             const SvgSvgNode* pParentSvgSvgNode = 0;
2702169cc62SArmin Le Grand             // enclosing svg might have relative width and height, need to cumulate them till they are
2712169cc62SArmin Le Grand             // resolved somewhere up in the node tree
2722169cc62SArmin Le Grand             double fPercentage(1.0);
2732169cc62SArmin Le Grand             for(const SvgNode* pParent = getParent(); pParent && !bHasFound; pParent = pParent->getParent())
2742169cc62SArmin Le Grand             {
2752169cc62SArmin Le Grand                 // dynamic_cast results Null-pointer for not SvgSvgNode and so skips them in if condition
2762169cc62SArmin Le Grand                 pParentSvgSvgNode = dynamic_cast< const SvgSvgNode* >(pParent);
2772169cc62SArmin Le Grand                 if (pParentSvgSvgNode)
2782169cc62SArmin Le Grand                 {
2792169cc62SArmin Le Grand                     if (pParentSvgSvgNode->getViewBox())
2802169cc62SArmin Le Grand                     {
2812169cc62SArmin Le Grand                         // viewbox values are already in 'user unit'.
2822169cc62SArmin Le Grand                         fHeight = pParentSvgSvgNode->getViewBox()->getHeight() * fPercentage;
2832169cc62SArmin Le Grand                         bHasFound = true;
2842169cc62SArmin Le Grand                     }
2852169cc62SArmin Le Grand                     else
2862169cc62SArmin Le Grand                     {
2872169cc62SArmin Le Grand                         // take absolute value or cummulate percentage
2882169cc62SArmin Le Grand                         if (pParentSvgSvgNode->getHeight().isSet())
2892169cc62SArmin Le Grand                         {
2902169cc62SArmin Le Grand                             if (Unit_percent == pParentSvgSvgNode->getHeight().getUnit())
2912169cc62SArmin Le Grand                             {
2922169cc62SArmin Le Grand                                 fPercentage *= pParentSvgSvgNode->getHeight().getNumber() * 0.01;
2932169cc62SArmin Le Grand                             }
2942169cc62SArmin Le Grand                             else
2952169cc62SArmin Le Grand                             {
2962169cc62SArmin Le Grand                                 fHeight = pParentSvgSvgNode->getHeight().solveNonPercentage(*pParentSvgSvgNode) * fPercentage;
2972169cc62SArmin Le Grand                                 bHasFound = true;
2982169cc62SArmin Le Grand                             }
2992169cc62SArmin Le Grand                         } // not set => height=100% => factor 1, no need for else
3002169cc62SArmin Le Grand                     }
3012169cc62SArmin Le Grand                 }
3022169cc62SArmin Le Grand             }
3032169cc62SArmin Le Grand         }
3042169cc62SArmin Le Grand 
3052169cc62SArmin Le Grand // ToDo: Consider attribute overflow in method decomposeSvgNode
306ddde725dSArmin Le Grand         void SvgSvgNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const
307ddde725dSArmin Le Grand         {
308ddde725dSArmin Le Grand             drawinglayer::primitive2d::Primitive2DSequence aSequence;
309ddde725dSArmin Le Grand 
3104374d266SArmin Le Grand             // #125258# check now if we need to init some style settings locally. Do not do this
3114374d266SArmin Le Grand             // in the constructor, there is not yet informatikon e.g. about existing CssStyles.
3124374d266SArmin Le Grand             // Here all nodes are read and interpreted
3134374d266SArmin Le Grand             const_cast< SvgSvgNode* >(this)->initializeStyleAttributes();
3144374d266SArmin Le Grand 
315ddde725dSArmin Le Grand             // decompose childs
316ddde725dSArmin Le Grand             SvgNode::decomposeSvgNode(aSequence, bReferenced);
317ddde725dSArmin Le Grand 
318ddde725dSArmin Le Grand             if(aSequence.hasElements())
319ddde725dSArmin Le Grand             {
320ddde725dSArmin Le Grand                 if(getParent())
321ddde725dSArmin Le Grand                 {
3222169cc62SArmin Le Grand                     // #122594# if width/height is not given, it's 100% (see 5.1.2 The 'svg' element in SVG1.1 spec).
323bca0eb5dSArmin Le Grand                     // If it is relative, the question is to what. The previous implementatin assumed relative to the
324bca0eb5dSArmin Le Grand                     // local ViewBox which is implied by (4.2 Basic data types):
325bca0eb5dSArmin Le Grand                     //
326bca0eb5dSArmin Le Grand                     // "Note that the non-property <length> definition also allows a percentage unit identifier.
327bca0eb5dSArmin Le Grand                     // The meaning of a percentage length value depends on the attribute for which the percentage
328bca0eb5dSArmin Le Grand                     // length value has been specified. Two common cases are: (a) when a percentage length value
329bca0eb5dSArmin Le Grand                     // represents a percentage of the viewport width or height (refer to the section that discusses
330bca0eb5dSArmin Le Grand                     // units in general), and (b) when a percentage length value represents a percentage of the
331bca0eb5dSArmin Le Grand                     // bounding box width or height on a given object (refer to the section that describes object
332bca0eb5dSArmin Le Grand                     // bounding box units)."
3332169cc62SArmin Le Grand 
3342169cc62SArmin Le Grand                     // Comparisons with commom browsers show, that it's mostly interpreted relative to the viewport
3352169cc62SArmin Le Grand                     // of the parent, and so does the new implementation.
3362169cc62SArmin Le Grand 
3372169cc62SArmin Le Grand                     // Extract known viewport data
3382169cc62SArmin Le Grand                     // bXXXIsAbsolute tracks whether relative values could be resolved to absolute values
3392169cc62SArmin Le Grand 
3402169cc62SArmin Le Grand                     // If width or height is not provided, the default 100% is used, see SVG 1.1 section 5.1.2
3412169cc62SArmin Le Grand                     // value 0.0 here is only to initialize variable
3422169cc62SArmin Le Grand                     bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit());
3432169cc62SArmin Le Grand                     double fW( bWidthIsAbsolute ? getWidth().solveNonPercentage(*this) : 0.0);
3442169cc62SArmin Le Grand 
3452169cc62SArmin Le Grand                     bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit());
3462169cc62SArmin Le Grand                     double fH( bHeightIsAbsolute ? getHeight().solveNonPercentage(*this) : 0.0);
3472169cc62SArmin Le Grand 
3482169cc62SArmin Le Grand                     // If x or y not provided, then default 0.0 is used, see SVG 1.1 Section 5.1.2
3492169cc62SArmin Le Grand                     bool bXIsAbsolute((getX().isSet() && Unit_percent != getX().getUnit()) || !getX().isSet());
3502169cc62SArmin Le Grand                     double fX( bXIsAbsolute && getX().isSet() ? getX().solveNonPercentage(*this) : 0.0);
3512169cc62SArmin Le Grand 
3522169cc62SArmin Le Grand                     bool bYIsAbsolute((getY().isSet() && Unit_percent != getY().getUnit()) || !getY().isSet());
3532169cc62SArmin Le Grand                     double fY( bYIsAbsolute && getY().isSet() ? getY().solveNonPercentage(*this) : 0.0);
3542169cc62SArmin Le Grand 
3552169cc62SArmin Le Grand                     if ( !bXIsAbsolute || !bWidthIsAbsolute)
356bca0eb5dSArmin Le Grand                     {
3572169cc62SArmin Le Grand                         // get width of enclosing svg and resolve percentage in x and width;
3582169cc62SArmin Le Grand                         double fWReference(0.0);
3592169cc62SArmin Le Grand                         bool bHasFoundWidth(false);
3602169cc62SArmin Le Grand                         seekReferenceWidth(fWReference, bHasFoundWidth);
3612169cc62SArmin Le Grand                         if (!bHasFoundWidth)
362bca0eb5dSArmin Le Grand                         {
3632169cc62SArmin Le Grand                             // Even outermost svg has not all information to resolve relative values,
3642169cc62SArmin Le Grand                             // I use content itself as fallback to set missing values for viewport
3652169cc62SArmin Le Grand                             // Any better idea for such ill structures svg documents?
3662169cc62SArmin Le Grand                             const basegfx::B2DRange aChildRange(
3672169cc62SArmin Le Grand                                         drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(
3682169cc62SArmin Le Grand                                             aSequence,
3692169cc62SArmin Le Grand                                         drawinglayer::geometry::ViewInformation2D()));
3702169cc62SArmin Le Grand                             fWReference = aChildRange.getWidth();
371bca0eb5dSArmin Le Grand                         }
3722169cc62SArmin Le Grand                         // referenced values are already in 'user unit'
3732169cc62SArmin Le Grand                         if (!bXIsAbsolute)
374bca0eb5dSArmin Le Grand                         {
3752169cc62SArmin Le Grand                             fX = getX().getNumber() * 0.01 * fWReference;
3762169cc62SArmin Le Grand                         }
3772169cc62SArmin Le Grand                         if (!bWidthIsAbsolute)
3782169cc62SArmin Le Grand                         {
3792169cc62SArmin Le Grand                             fW = (getWidth().isSet() ? getWidth().getNumber() *0.01 : 1.0) * fWReference;
380bca0eb5dSArmin Le Grand                         }
381bca0eb5dSArmin Le Grand                     }
382bca0eb5dSArmin Le Grand 
3832169cc62SArmin Le Grand                     if ( !bYIsAbsolute || !bHeightIsAbsolute)
384bca0eb5dSArmin Le Grand                     {
3852169cc62SArmin Le Grand                         // get height of enclosing svg and resolve percentage in y and height
3862169cc62SArmin Le Grand                         double fHReference(0.0);
3872169cc62SArmin Le Grand                         bool bHasFoundHeight(false);
3882169cc62SArmin Le Grand                         seekReferenceHeight(fHReference, bHasFoundHeight);
3892169cc62SArmin Le Grand                         if (!bHasFoundHeight)
3902169cc62SArmin Le Grand                         {
3912169cc62SArmin Le Grand                             // Even outermost svg has not all information to resolve relative values,
3922169cc62SArmin Le Grand                             // I use content itself as fallback to set missing values for viewport
3932169cc62SArmin Le Grand                             // Any better idea for such ill structures svg documents?
3942169cc62SArmin Le Grand                             const basegfx::B2DRange aChildRange(
3952169cc62SArmin Le Grand                                         drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(
3962169cc62SArmin Le Grand                                             aSequence,
3972169cc62SArmin Le Grand                                         drawinglayer::geometry::ViewInformation2D()));
3982169cc62SArmin Le Grand                             fHReference = aChildRange.getHeight();
3992169cc62SArmin Le Grand                         }
400bca0eb5dSArmin Le Grand 
4012169cc62SArmin Le Grand                         // referenced values are already in 'user unit'
4022169cc62SArmin Le Grand                         if (!bYIsAbsolute)
403bca0eb5dSArmin Le Grand                         {
4042169cc62SArmin Le Grand                             fY = getY().getNumber() * 0.01 * fHReference;
4052169cc62SArmin Le Grand                         }
4062169cc62SArmin Le Grand                         if (!bHeightIsAbsolute)
4072169cc62SArmin Le Grand                         {
4082169cc62SArmin Le Grand                             fH = (getHeight().isSet() ? getHeight().getNumber() *0.01 : 1.0) * fHReference;
409bca0eb5dSArmin Le Grand                         }
410bca0eb5dSArmin Le Grand                     }
411bca0eb5dSArmin Le Grand 
412ddde725dSArmin Le Grand                     if(getViewBox())
413ddde725dSArmin Le Grand                     {
4142169cc62SArmin Le Grand                         // SVG 1.1 defines in section 7.7 that a negative value for width or height
4152169cc62SArmin Le Grand                         // in viewBox is an error and that 0.0 disables rendering
4162169cc62SArmin Le Grand                         if(basegfx::fTools::more(getViewBox()->getWidth(),0.0) && basegfx::fTools::more(getViewBox()->getHeight(),0.0))
417ddde725dSArmin Le Grand                         {
4182169cc62SArmin Le Grand                             // create target range homing x,y, width and height as calculated above
419ddde725dSArmin Le Grand                             const basegfx::B2DRange aTarget(fX, fY, fX + fW, fY + fH);
420ddde725dSArmin Le Grand 
421ddde725dSArmin Le Grand                             if(aTarget.equal(*getViewBox()))
422ddde725dSArmin Le Grand                             {
423ddde725dSArmin Le Grand                                 // no mapping needed, append
424ddde725dSArmin Le Grand                                 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aSequence);
425ddde725dSArmin Le Grand                             }
426ddde725dSArmin Le Grand                             else
427ddde725dSArmin Le Grand                             {
428ddde725dSArmin Le Grand                                 // create mapping
4292169cc62SArmin Le Grand                                 // #i122610 SVG 1.1 defines in section 5.1.2 that if the attribute perserveAspectRatio is not specified,
4302169cc62SArmin Le Grand                                 // then the effect is as if a value of 'xMidYMid meet' were specified.
4312169cc62SArmin Le Grand                                 SvgAspectRatio aRatioDefault(Align_xMidYMid,false,true);
4322169cc62SArmin Le Grand                                 const SvgAspectRatio& rRatio = getSvgAspectRatio().isSet()? getSvgAspectRatio() : aRatioDefault;
4332169cc62SArmin Le Grand 
4342169cc62SArmin Le Grand                                 // let mapping be created from SvgAspectRatio
4352169cc62SArmin Le Grand                                 const basegfx::B2DHomMatrix aEmbeddingTransform(
4362169cc62SArmin Le Grand                                     rRatio.createMapping(aTarget, *getViewBox()));
4372169cc62SArmin Le Grand 
4382169cc62SArmin Le Grand                                 // prepare embedding in transformation
4392169cc62SArmin Le Grand                                 const drawinglayer::primitive2d::Primitive2DReference xRef(
4402169cc62SArmin Le Grand                                     new drawinglayer::primitive2d::TransformPrimitive2D(
4412169cc62SArmin Le Grand                                         aEmbeddingTransform,
4422169cc62SArmin Le Grand                                         aSequence));
443ddde725dSArmin Le Grand 
4442169cc62SArmin Le Grand                                 if(rRatio.isMeetOrSlice())
445ddde725dSArmin Le Grand                                 {
4462169cc62SArmin Le Grand                                     // embed in transformation
4472169cc62SArmin Le Grand                                     drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xRef);
448ddde725dSArmin Le Grand                                 }
449ddde725dSArmin Le Grand                                 else
450ddde725dSArmin Le Grand                                 {
4512169cc62SArmin Le Grand                                     // need to embed in MaskPrimitive2D, too
4522169cc62SArmin Le Grand                                     const drawinglayer::primitive2d::Primitive2DReference xMask(
4532169cc62SArmin Le Grand                                         new drawinglayer::primitive2d::MaskPrimitive2D(
4542169cc62SArmin Le Grand                                             basegfx::B2DPolyPolygon(basegfx::tools::createPolygonFromRect(aTarget)),
4552169cc62SArmin Le Grand                                             drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1)));
456ddde725dSArmin Le Grand 
4572169cc62SArmin Le Grand                                     drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xMask);
458ddde725dSArmin Le Grand                                 }
459ddde725dSArmin Le Grand                             }
460ddde725dSArmin Le Grand                         }
461ddde725dSArmin Le Grand                     }
4622169cc62SArmin Le Grand                     else // no viewBox attribute
463ddde725dSArmin Le Grand                     {
464ddde725dSArmin Le Grand                         // Svg defines that a negative value is an error and that 0.0 disables rendering
465ddde725dSArmin Le Grand                         if(basegfx::fTools::more(fW, 0.0) && basegfx::fTools::more(fH, 0.0))
466ddde725dSArmin Le Grand                         {
467ddde725dSArmin Le Grand                             if(!basegfx::fTools::equalZero(fX) || !basegfx::fTools::equalZero(fY))
468ddde725dSArmin Le Grand                             {
469ddde725dSArmin Le Grand                                 // embed in transform
470ddde725dSArmin Le Grand                                 const drawinglayer::primitive2d::Primitive2DReference xRef(
471ddde725dSArmin Le Grand                                     new drawinglayer::primitive2d::TransformPrimitive2D(
472ddde725dSArmin Le Grand                                         basegfx::tools::createTranslateB2DHomMatrix(fX, fY),
473ddde725dSArmin Le Grand                                         aSequence));
474ddde725dSArmin Le Grand 
475ddde725dSArmin Le Grand                                 aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1);
476ddde725dSArmin Le Grand                             }
477ddde725dSArmin Le Grand 
478ddde725dSArmin Le Grand                             // embed in MaskPrimitive2D to clip
479ddde725dSArmin Le Grand                             const drawinglayer::primitive2d::Primitive2DReference xMask(
480ddde725dSArmin Le Grand                                 new drawinglayer::primitive2d::MaskPrimitive2D(
481ddde725dSArmin Le Grand                                     basegfx::B2DPolyPolygon(
482ddde725dSArmin Le Grand                                         basegfx::tools::createPolygonFromRect(
483ddde725dSArmin Le Grand                                             basegfx::B2DRange(fX, fY, fX + fW, fY + fH))),
484ddde725dSArmin Le Grand                                     aSequence));
485ddde725dSArmin Le Grand 
486ddde725dSArmin Le Grand                             // append
487ddde725dSArmin Le Grand                             drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xMask);
488ddde725dSArmin Le Grand                         }
489ddde725dSArmin Le Grand                     }
490ddde725dSArmin Le Grand                 }
4912169cc62SArmin Le Grand                 else // Outermost SVG element
492ddde725dSArmin Le Grand                 {
4932169cc62SArmin Le Grand                     double fW = 0.0; // effective value depends on viewBox
4942169cc62SArmin Le Grand                     double fH = 0.0;
495ddde725dSArmin Le Grand 
496ddde725dSArmin Le Grand                     // Svg defines that a negative value is an error and that 0.0 disables rendering
4972169cc62SArmin Le Grand                     // isPositive() not usable because it allows 0.0 in contrast to mathematical definition of 'positive'
4982169cc62SArmin Le Grand                     const bool bWidthInvalid(getWidth().isSet() && basegfx::fTools::lessOrEqual(getWidth().getNumber(), 0.0));
4992169cc62SArmin Le Grand                     const bool bHeightInvalid(getHeight().isSet() && basegfx::fTools::lessOrEqual(getHeight().getNumber(), 0.0));
5002169cc62SArmin Le Grand                     if(!bWidthInvalid && !bHeightInvalid)
501ddde725dSArmin Le Grand                     {
5022169cc62SArmin Le Grand                         basegfx::B2DRange aSvgCanvasRange; // effective value depends on viewBox
503ddde725dSArmin Le Grand                         if(getViewBox())
504ddde725dSArmin Le Grand                         {
5052169cc62SArmin Le Grand                             // SVG 1.1 defines in section 7.7 that a negative value for width or height
5062169cc62SArmin Le Grand                             // in viewBox is an error and that 0.0 disables rendering
5072169cc62SArmin Le Grand                             const double fViewBoxWidth = getViewBox()->getWidth();
5082169cc62SArmin Le Grand                             const double fViewBoxHeight = getViewBox()->getHeight();
5092169cc62SArmin Le Grand                             if(basegfx::fTools::more(fViewBoxWidth,0.0) && basegfx::fTools::more(fViewBoxHeight,0.0))
510ddde725dSArmin Le Grand                             {
5112169cc62SArmin Le Grand                                 // The intrinsic aspect ratio of the svg element is given by absolute values of both width and height
5122169cc62SArmin Le Grand                                 // or if one or both of them is relative by the width and height of the viewBox
5132169cc62SArmin Le Grand                                 // see SVG 1.1 section 7.12
5142169cc62SArmin Le Grand                                 const bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit());
5152169cc62SArmin Le Grand                                 const bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit());
5162169cc62SArmin Le Grand                                 if(bWidthIsAbsolute && bHeightIsAbsolute)
517ddde725dSArmin Le Grand                                 {
5182169cc62SArmin Le Grand                                     fW =getWidth().solveNonPercentage(*this);
5192169cc62SArmin Le Grand                                     fH =getHeight().solveNonPercentage(*this);
5202169cc62SArmin Le Grand                                 }
5212169cc62SArmin Le Grand                                 else if (bWidthIsAbsolute)
5222169cc62SArmin Le Grand                                 {
5232169cc62SArmin Le Grand                                     fW = getWidth().solveNonPercentage(*this);
5242169cc62SArmin Le Grand                                     fH = fW * fViewBoxWidth / fViewBoxHeight ;
5252169cc62SArmin Le Grand                                 }
5262169cc62SArmin Le Grand                                 else if (bHeightIsAbsolute)
5272169cc62SArmin Le Grand                                 {
5282169cc62SArmin Le Grand                                     fH = getHeight().solveNonPercentage(*this);
5292169cc62SArmin Le Grand                                     fW = fH * fViewBoxWidth / fViewBoxHeight ;
530ddde725dSArmin Le Grand                                 }
531ddde725dSArmin Le Grand                                 else
532ddde725dSArmin Le Grand                                 {
5332169cc62SArmin Le Grand                                     fW = fViewBoxWidth;
5342169cc62SArmin Le Grand                                     fH = fViewBoxHeight;
535ddde725dSArmin Le Grand                                 }
5362169cc62SArmin Le Grand                                 // SVG 1.1 defines in section 5.1.2 that x,y has no meanig for the outermost SVG element.
5372169cc62SArmin Le Grand                                 aSvgCanvasRange = basegfx::B2DRange(0.0, 0.0, fW, fH);
5382169cc62SArmin Le Grand 
5392169cc62SArmin Le Grand                                 // create mapping
5402169cc62SArmin Le Grand                                 // SVG 1.1 defines in section 5.1.2 that if the attribute perserveAspectRatio is not specified,
5412169cc62SArmin Le Grand                                 // then the effect is as if a value of 'xMidYMid meet' were specified.
5422169cc62SArmin Le Grand                                 SvgAspectRatio aRatioDefault(Align_xMidYMid,false,true);
5432169cc62SArmin Le Grand                                 const SvgAspectRatio& rRatio = getSvgAspectRatio().isSet()? getSvgAspectRatio() : aRatioDefault;
5442169cc62SArmin Le Grand 
5452169cc62SArmin Le Grand                                 basegfx::B2DHomMatrix aViewBoxMapping;
5462169cc62SArmin Le Grand                                 aViewBoxMapping = rRatio.createMapping(aSvgCanvasRange, *getViewBox());
5472169cc62SArmin Le Grand                                 // no need to check ratio here for slice, the outermost Svg will
5482169cc62SArmin Le Grand                                 // be clipped anyways (see below)
549ddde725dSArmin Le Grand 
550ddde725dSArmin Le Grand                                 // scale content to viewBox definitions
551ddde725dSArmin Le Grand                                 const drawinglayer::primitive2d::Primitive2DReference xTransform(
552ddde725dSArmin Le Grand                                     new drawinglayer::primitive2d::TransformPrimitive2D(
553ddde725dSArmin Le Grand                                         aViewBoxMapping,
554ddde725dSArmin Le Grand                                         aSequence));
555ddde725dSArmin Le Grand 
556ddde725dSArmin Le Grand                                 aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xTransform, 1);
557ddde725dSArmin Le Grand                             }
558ddde725dSArmin Le Grand                         }
5592169cc62SArmin Le Grand                         else // no viewbox
5602169cc62SArmin Le Grand                         {
5612169cc62SArmin Le Grand                            // There exists no parent to resolve relative width or height.
5622169cc62SArmin Le Grand                            // Use child size as fallback.
5632169cc62SArmin Le Grand                             const bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit());
5642169cc62SArmin Le Grand                             const bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit());
5652169cc62SArmin Le Grand                             if (bWidthIsAbsolute && bHeightIsAbsolute)
5662169cc62SArmin Le Grand                             {
5672169cc62SArmin Le Grand                                 fW =getWidth().solveNonPercentage(*this);
5682169cc62SArmin Le Grand                                 fH =getHeight().solveNonPercentage(*this);
5692169cc62SArmin Le Grand 
5702169cc62SArmin Le Grand                             }
5712169cc62SArmin Le Grand                             else
5722169cc62SArmin Le Grand                             {
5732169cc62SArmin Le Grand                                 const basegfx::B2DRange aChildRange(
5742169cc62SArmin Le Grand                                     drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(
5752169cc62SArmin Le Grand                                         aSequence,
5762169cc62SArmin Le Grand                                      drawinglayer::geometry::ViewInformation2D()));
5772169cc62SArmin Le Grand                                 const double fChildWidth(aChildRange.getWidth());
5782169cc62SArmin Le Grand                                 const double fChildHeight(aChildRange.getHeight());
5792169cc62SArmin Le Grand                                 fW = bWidthIsAbsolute ? getWidth().solveNonPercentage(*this) : fChildWidth;
5802169cc62SArmin Le Grand                                 fH = bHeightIsAbsolute ? getHeight().solveNonPercentage(*this) : fChildHeight;
5812169cc62SArmin Le Grand                             }
5822169cc62SArmin Le Grand                             // SVG 1.1 defines in section 5.1.2 that x,y has no meanig for the outermost SVG element.
5832169cc62SArmin Le Grand                             aSvgCanvasRange = basegfx::B2DRange(0.0, 0.0, fW, fH);
5842169cc62SArmin Le Grand                         }
585ddde725dSArmin Le Grand 
586ddde725dSArmin Le Grand                         // to be completely correct in Svg sense it is necessary to clip
587ddde725dSArmin Le Grand                         // the whole content to the given canvas. I choose here to do this
588ddde725dSArmin Le Grand                         // initially despite I found various examples of Svg files out there
589ddde725dSArmin Le Grand                         // which have no correct values for this clipping. It's correct
590ddde725dSArmin Le Grand                         // due to the Svg spec.
591ddde725dSArmin Le Grand                         bool bDoCorrectCanvasClipping(true);
592ddde725dSArmin Le Grand 
593ddde725dSArmin Le Grand                         if(bDoCorrectCanvasClipping)
594ddde725dSArmin Le Grand                         {
595ddde725dSArmin Le Grand                             // different from Svg we have the possibility with primitives to get
59641923119SArmin Le Grand                             // a correct bounding box for the geometry. Get it for evtl. taking action
597ddde725dSArmin Le Grand                             const basegfx::B2DRange aContentRange(
598ddde725dSArmin Le Grand                                 drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(
599ddde725dSArmin Le Grand                                     aSequence,
600ddde725dSArmin Le Grand                                     drawinglayer::geometry::ViewInformation2D()));
601ddde725dSArmin Le Grand 
60241923119SArmin Le Grand                             if(aSvgCanvasRange.isInside(aContentRange))
603ddde725dSArmin Le Grand                             {
60441923119SArmin Le Grand                                 // no clip needed, but an invisible HiddenGeometryPrimitive2D
60541923119SArmin Le Grand                                 // to allow getting the full Svg range using the primitive mechanisms.
60641923119SArmin Le Grand                                 // This is needed since e.g. an SdrObject using this as graphic will
60741923119SArmin Le Grand                                 // create a mapping transformation to exactly map the content to it's
60841923119SArmin Le Grand                                 // real life size
60941923119SArmin Le Grand                                 const drawinglayer::primitive2d::Primitive2DReference xLine(
61041923119SArmin Le Grand                                     new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
61141923119SArmin Le Grand                                         basegfx::tools::createPolygonFromRect(
61241923119SArmin Le Grand                                             aSvgCanvasRange),
61341923119SArmin Le Grand                                         basegfx::BColor(0.0, 0.0, 0.0)));
61441923119SArmin Le Grand                                 const drawinglayer::primitive2d::Primitive2DReference xHidden(
61541923119SArmin Le Grand                                     new drawinglayer::primitive2d::HiddenGeometryPrimitive2D(
61641923119SArmin Le Grand                                         drawinglayer::primitive2d::Primitive2DSequence(&xLine, 1)));
61741923119SArmin Le Grand 
61841923119SArmin Le Grand                                 drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(aSequence, xHidden);
61941923119SArmin Le Grand                             }
62041923119SArmin Le Grand                             else if(aSvgCanvasRange.overlaps(aContentRange))
62141923119SArmin Le Grand                             {
62241923119SArmin Le Grand                                 // Clip is necessary. This will make Svg images evtl. smaller
62341923119SArmin Le Grand                                 // than wanted from Svg (the free space which may be around it is
62486e1cf34SPedro Giffuni                                 // conform to the Svg spec), but avoids an expensive and unnecessary
62541923119SArmin Le Grand                                 // clip. Keep the full Svg range here to get the correct mappings
62641923119SArmin Le Grand                                 // to objects using this. Optimizations can be done in the processors
627ddde725dSArmin Le Grand                                 const drawinglayer::primitive2d::Primitive2DReference xMask(
628ddde725dSArmin Le Grand                                     new drawinglayer::primitive2d::MaskPrimitive2D(
629ddde725dSArmin Le Grand                                         basegfx::B2DPolyPolygon(
630ddde725dSArmin Le Grand                                             basegfx::tools::createPolygonFromRect(
631ddde725dSArmin Le Grand                                                 aSvgCanvasRange)),
632ddde725dSArmin Le Grand                                         aSequence));
633ddde725dSArmin Le Grand 
634ddde725dSArmin Le Grand                                 aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xMask, 1);
635ddde725dSArmin Le Grand                             }
63641923119SArmin Le Grand                             else
63741923119SArmin Le Grand                             {
63841923119SArmin Le Grand                                 // not inside, no overlap. Empty Svg
63941923119SArmin Le Grand                                 aSequence.realloc(0);
64041923119SArmin Le Grand                             }
641ddde725dSArmin Le Grand                         }
642ddde725dSArmin Le Grand 
64341923119SArmin Le Grand                         if(aSequence.hasElements())
644ddde725dSArmin Le Grand                         {
645ddde725dSArmin Le Grand                             // embed in transform primitive to scale to 1/100th mm
6462169cc62SArmin Le Grand                             // where 1 inch == 25.4 mm to get from Svg coordinates (px) to
6472169cc62SArmin Le Grand                             // drawinglayer coordinates
6482169cc62SArmin Le Grand                             const double fScaleTo100thmm(25.4 * 100.0 / F_SVG_PIXEL_PER_INCH);
649ddde725dSArmin Le Grand                             const basegfx::B2DHomMatrix aTransform(
650ddde725dSArmin Le Grand                                 basegfx::tools::createScaleB2DHomMatrix(
651ddde725dSArmin Le Grand                                     fScaleTo100thmm,
652ddde725dSArmin Le Grand                                     fScaleTo100thmm));
653ddde725dSArmin Le Grand 
654ddde725dSArmin Le Grand                             const drawinglayer::primitive2d::Primitive2DReference xTransform(
655ddde725dSArmin Le Grand                                 new drawinglayer::primitive2d::TransformPrimitive2D(
656ddde725dSArmin Le Grand                                     aTransform,
657ddde725dSArmin Le Grand                                     aSequence));
658ddde725dSArmin Le Grand 
659ddde725dSArmin Le Grand                             aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xTransform, 1);
660ddde725dSArmin Le Grand 
66141923119SArmin Le Grand                             // append to result
66241923119SArmin Le Grand                             drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aSequence);
66341923119SArmin Le Grand                         }
664ddde725dSArmin Le Grand                     }
665ddde725dSArmin Le Grand                 }
666ddde725dSArmin Le Grand             }
667ddde725dSArmin Le Grand         }
668ddde725dSArmin Le Grand 
669e92bb418SOliver-Rainer Wittmann         const basegfx::B2DRange SvgSvgNode::getCurrentViewPort() const
670ddde725dSArmin Le Grand         {
671ddde725dSArmin Le Grand             if(getViewBox())
672ddde725dSArmin Le Grand             {
673e92bb418SOliver-Rainer Wittmann                 return *(getViewBox());
674ddde725dSArmin Le Grand             }
6752169cc62SArmin Le Grand             else // viewport should be given by x, y, width, and height
676ddde725dSArmin Le Grand             {
6772169cc62SArmin Le Grand                 // Extract known viewport data
6782169cc62SArmin Le Grand                 // bXXXIsAbsolute tracks whether relative values could be resolved to absolute values
6792169cc62SArmin Le Grand                 if (getParent())
6802169cc62SArmin Le Grand                     {
6812169cc62SArmin Le Grand                     // If width or height is not provided, the default 100% is used, see SVG 1.1 section 5.1.2
6822169cc62SArmin Le Grand                     // value 0.0 here is only to initialize variable
6832169cc62SArmin Le Grand                     bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit());
6842169cc62SArmin Le Grand                     double fW( bWidthIsAbsolute ? getWidth().solveNonPercentage(*this) : 0.0);
6852169cc62SArmin Le Grand                     bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit());
6862169cc62SArmin Le Grand                     double fH( bHeightIsAbsolute ? getHeight().solveNonPercentage(*this) : 0.0);
6872169cc62SArmin Le Grand 
6882169cc62SArmin Le Grand                     // If x or y not provided, then default 0.0 is used, see SVG 1.1 Section 5.1.2
6892169cc62SArmin Le Grand                     bool bXIsAbsolute((getX().isSet() && Unit_percent != getX().getUnit()) || !getX().isSet());
6902169cc62SArmin Le Grand                     double fX( bXIsAbsolute && getX().isSet() ? getX().solveNonPercentage(*this) : 0.0);
6912169cc62SArmin Le Grand 
6922169cc62SArmin Le Grand                     bool bYIsAbsolute((getY().isSet() && Unit_percent != getY().getUnit()) || !getY().isSet());
6932169cc62SArmin Le Grand                     double fY( bYIsAbsolute && getY().isSet() ? getY().solveNonPercentage(*this) : 0.0);
6942169cc62SArmin Le Grand 
6952169cc62SArmin Le Grand                     if (bXIsAbsolute && bYIsAbsolute && bWidthIsAbsolute && bHeightIsAbsolute)
6962169cc62SArmin Le Grand                     {
697e92bb418SOliver-Rainer Wittmann                         return basegfx::B2DRange(fX, fY, fX+fW, fY+fH);
6982169cc62SArmin Le Grand                     }
6992169cc62SArmin Le Grand                     else // try to resolve relative values
7002169cc62SArmin Le Grand                     {
7012169cc62SArmin Le Grand                         if (!bXIsAbsolute || !bWidthIsAbsolute)
7022169cc62SArmin Le Grand                         {
7032169cc62SArmin Le Grand                             // get width of enclosing svg and resolve percentage in x and width
7042169cc62SArmin Le Grand                             double fWReference(0.0);
7052169cc62SArmin Le Grand                             bool bHasFoundWidth(false);
7062169cc62SArmin Le Grand                             seekReferenceWidth(fWReference, bHasFoundWidth);
7072169cc62SArmin Le Grand                             // referenced values are already in 'user unit'
7082169cc62SArmin Le Grand                             if (!bXIsAbsolute && bHasFoundWidth)
7092169cc62SArmin Le Grand                             {
7102169cc62SArmin Le Grand                                 fX = getX().getNumber() * 0.01 * fWReference;
7112169cc62SArmin Le Grand                                 bXIsAbsolute = true;
7122169cc62SArmin Le Grand                             }
7132169cc62SArmin Le Grand                             if (!bWidthIsAbsolute && bHasFoundWidth)
7142169cc62SArmin Le Grand                             {
7152169cc62SArmin Le Grand                                 fW = (getWidth().isSet() ? getWidth().getNumber() *0.01 : 1.0) * fWReference;
7162169cc62SArmin Le Grand                                 bWidthIsAbsolute = true;
7172169cc62SArmin Le Grand                             }
7182169cc62SArmin Le Grand                         }
7192169cc62SArmin Le Grand                         if (!bYIsAbsolute || !bHeightIsAbsolute)
7202169cc62SArmin Le Grand                         {
7212169cc62SArmin Le Grand                             // get height of enclosing svg and resolve percentage in y and height
7222169cc62SArmin Le Grand                             double fHReference(0.0);
7232169cc62SArmin Le Grand                             bool bHasFoundHeight(false);
7242169cc62SArmin Le Grand                             seekReferenceHeight(fHReference, bHasFoundHeight);
7252169cc62SArmin Le Grand                             // referenced values are already in 'user unit'
7262169cc62SArmin Le Grand                             if (!bYIsAbsolute && bHasFoundHeight)
7272169cc62SArmin Le Grand                             {
7282169cc62SArmin Le Grand                                 fY = getY().getNumber() * 0.01 * fHReference;
7292169cc62SArmin Le Grand                                 bYIsAbsolute = true;
7302169cc62SArmin Le Grand                             }
7312169cc62SArmin Le Grand                             if (!bHeightIsAbsolute && bHasFoundHeight)
7322169cc62SArmin Le Grand                             {
7332169cc62SArmin Le Grand                                 fH = (getHeight().isSet() ? getHeight().getNumber() *0.01 : 1.0) * fHReference;
7342169cc62SArmin Le Grand                                 bHeightIsAbsolute = true;
7352169cc62SArmin Le Grand                             }
7362169cc62SArmin Le Grand                         }
7372169cc62SArmin Le Grand 
7382169cc62SArmin Le Grand                         if (bXIsAbsolute && bYIsAbsolute && bWidthIsAbsolute && bHeightIsAbsolute)
7392169cc62SArmin Le Grand                         {
740e92bb418SOliver-Rainer Wittmann                             return basegfx::B2DRange(fX, fY, fX+fW, fY+fH);
7412169cc62SArmin Le Grand                         }
7422169cc62SArmin Le Grand                         else // relative values could not be resolved, there exists no fallback
7432169cc62SArmin Le Grand                         {
7442169cc62SArmin Le Grand                             return SvgNode::getCurrentViewPort();
7452169cc62SArmin Le Grand                         }
7462169cc62SArmin Le Grand                     }
7472169cc62SArmin Le Grand                 }
7482169cc62SArmin Le Grand                 else //outermost svg
7492169cc62SArmin Le Grand                 {
7502169cc62SArmin Le Grand                     // If width or height is not provided, the default would be 100%, see SVG 1.1 section 5.1.2
7512169cc62SArmin Le Grand                     // But here it cannot be resolved and no fallback exists.
7522169cc62SArmin Le Grand                     // SVG 1.1 defines in section 5.1.2 that x,y has no meanig for the outermost SVG element.
7532169cc62SArmin Le Grand                     bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit());
7542169cc62SArmin Le Grand                     double fW( bWidthIsAbsolute ? getWidth().solveNonPercentage(*this) : 0.0);
7552169cc62SArmin Le Grand                     bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit());
7562169cc62SArmin Le Grand                     double fH( bHeightIsAbsolute ? getHeight().solveNonPercentage(*this) : 0.0);
7572169cc62SArmin Le Grand                     if (bWidthIsAbsolute && bHeightIsAbsolute)
7582169cc62SArmin Le Grand                     {
759e92bb418SOliver-Rainer Wittmann                         return basegfx::B2DRange(0.0, 0.0, fW, fH);
7602169cc62SArmin Le Grand                     }
7612169cc62SArmin Le Grand                     else // no fallback exists
7622169cc62SArmin Le Grand                     {
7632169cc62SArmin Le Grand                             return SvgNode::getCurrentViewPort();
7642169cc62SArmin Le Grand                     }
7652169cc62SArmin Le Grand                 }
7662169cc62SArmin Le Grand // ToDo: Is it possible to decompose and use the bounding box of the childs, if even the
7672169cc62SArmin Le Grand //       outermost svg has no information to resolve percentage? Is it worth, how expensive is it?
7682169cc62SArmin Le Grand 
769ddde725dSArmin Le Grand             }
770ddde725dSArmin Le Grand         }
771ddde725dSArmin Le Grand 
772ddde725dSArmin Le Grand     } // end of namespace svgreader
773ddde725dSArmin Le Grand } // end of namespace svgio
774ddde725dSArmin Le Grand 
775ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
776ddde725dSArmin Le Grand // eof
777