1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <basegfx/polygon/b2dpolypolygontools.hxx>
21 #include <svgio/svgreader/svgdocument.hxx>
22 #include <svgio/svgreader/svgnode.hxx>
23 #include <svgio/svgreader/svgstyleattributes.hxx>
24 #include <drawinglayer/primitive2d/objectinfoprimitive2d.hxx>
25 #include <tools/urlobj.hxx>
27 //////////////////////////////////////////////////////////////////////////////
33 const SvgStyleAttributes
* SvgNode::getSvgStyleAttributes() const
38 const SvgStyleAttributes
* SvgNode::checkForCssStyle(const rtl::OUString
& rClassStr
, const SvgStyleAttributes
& rOriginal
) const
40 if(maCssStyleVector
.empty()) // #120435# Evaluate for CSS styles only once, this cannot change
42 const SvgDocument
& rDocument
= getDocument();
44 if(rDocument
.hasSvgStyleAttributesById())
48 // find all referenced CSS styles, a list of entries is allowed
49 const rtl::OUString
* pClassList
= getClass();
50 const sal_Int32
nLen(pClassList
->getLength());
52 const SvgStyleAttributes
* pNew
= 0;
54 skip_char(*pClassList
, sal_Unicode(' '), nPos
, nLen
);
58 rtl::OUStringBuffer aTokenValue
;
60 copyToLimiter(*pClassList
, sal_Unicode(' '), nPos
, aTokenValue
, nLen
);
61 skip_char(*pClassList
, sal_Unicode(' '), nPos
, nLen
);
63 rtl::OUString
aId(rtl::OUString::createFromAscii("."));
64 const rtl::OUString
aOUTokenValue(aTokenValue
.makeStringAndClear());
66 // look for CSS style common to token
67 aId
= aId
+ aOUTokenValue
;
68 pNew
= rDocument
.findSvgStyleAttributesById(aId
);
70 if(!pNew
&& rClassStr
.getLength())
72 // look for CSS style common to class.token
73 aId
= rClassStr
+ aId
;
75 pNew
= rDocument
.findSvgStyleAttributesById(aId
);
80 const_cast< SvgNode
* >(this)->maCssStyleVector
.push_back(pNew
);
85 if(maCssStyleVector
.empty() && getId())
87 // if none found, search for CSS style equal to Id
88 const SvgStyleAttributes
* pNew
= rDocument
.findSvgStyleAttributesById(*getId());
92 const_cast< SvgNode
* >(this)->maCssStyleVector
.push_back(pNew
);
96 if(maCssStyleVector
.empty() && rClassStr
.getLength())
98 // if none found, search for CSS style equal to class type
99 const SvgStyleAttributes
* pNew
= rDocument
.findSvgStyleAttributesById(rClassStr
);
103 const_cast< SvgNode
* >(this)->maCssStyleVector
.push_back(pNew
);
109 if(!maCssStyleVector
.empty())
111 // #i123510# if CSS styles were found, create a linked list with rOriginal as parent
112 // and all CSS styles as linked children, so that the style attribute has
113 // priority over the CSS style. If there is no style attribute this means that
114 // no values are set at rOriginal, thus it is still correct to have that order.
115 // Repeated style requests should only be issued from sub-Text nodes and I'm not
116 // sure if in-between text nodes may build other chains (should not happen). But
117 // it's only a re-chaining with pointers (cheap), so allow to do it every time.
118 SvgStyleAttributes
* pCurrent
= const_cast< SvgStyleAttributes
* >(&rOriginal
);
119 pCurrent
->setCssStyleParent(0);
121 for(sal_uInt32
a(0); a
< maCssStyleVector
.size(); a
++)
123 SvgStyleAttributes
* pNext
= const_cast< SvgStyleAttributes
* >(maCssStyleVector
[a
]);
125 pCurrent
->setCssStyleParent(pNext
);
127 pCurrent
->setCssStyleParent(0);
136 SvgDocument
& rDocument
,
139 mrDocument(rDocument
),
141 mpAlternativeParent(0),
145 maXmlSpace(XmlSpace_notset
),
148 OSL_ENSURE(SVGTokenUnknown
!= maType
, "SvgNode with unknown type created (!)");
152 pParent
->maChildren
.push_back(this);
157 if(SVGTokenSvg
!= getType())
159 OSL_ENSURE(false, "No parent for this node (!)");
167 while(maChildren
.size())
169 delete maChildren
[maChildren
.size() - 1];
170 maChildren
.pop_back();
173 if(mpId
) delete mpId
;
174 if(mpClass
) delete mpClass
;
177 void SvgNode::parseAttributes(const com::sun::star::uno::Reference
< com::sun::star::xml::sax::XAttributeList
>& xAttribs
)
179 const sal_uInt32
nAttributes(xAttribs
->getLength());
181 for(sal_uInt32
a(0); a
< nAttributes
; a
++)
183 const OUString
aTokenName(xAttribs
->getNameByIndex(a
));
185 parseAttribute(aTokenName
, StrToSVGToken(aTokenName
), xAttribs
->getValueByIndex(a
));
189 void SvgNode::parseAttribute(const OUString
& /*rTokenName*/, SVGToken aSVGToken
, const OUString
& aContent
)
195 if(aContent
.getLength())
203 if(aContent
.getLength())
209 case SVGTokenXmlSpace
:
211 if(aContent
.getLength())
213 static OUString
aStrDefault(OUString::createFromAscii("default"));
214 static OUString
aStrPreserve(OUString::createFromAscii("preserve"));
216 if(aContent
.match(aStrDefault
))
218 setXmlSpace(XmlSpace_default
);
220 else if(aContent
.match(aStrPreserve
))
222 setXmlSpace(XmlSpace_preserve
);
234 void SvgNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence
& rTarget
, bool bReferenced
) const
238 if(SVGTokenDefs
== getType() ||
239 SVGTokenSymbol
== getType() ||
240 SVGTokenClipPathNode
== getType() ||
241 SVGTokenMask
== getType() ||
242 SVGTokenMarker
== getType() ||
243 SVGTokenPattern
== getType())
245 // do not decompose defs or symbol nodes (these hold only style-like
246 // objects which may be used by referencing them) except when doing
247 // so controlled referenced
249 // also do not decompose ClipPaths and Masks. These should be embedded
250 // in a defs node (which gets not decomposed by itself), but you never
253 // also not directly used are Markers and Patterns, only indirecty used
259 const SvgNodeVector
& rChildren
= getChildren();
261 if(!rChildren
.empty())
263 const sal_uInt32
nCount(rChildren
.size());
265 for(sal_uInt32
a(0); a
< nCount
; a
++)
267 SvgNode
* pCandidate
= rChildren
[a
];
271 drawinglayer::primitive2d::Primitive2DSequence aNewTarget
;
273 pCandidate
->decomposeSvgNode(aNewTarget
, bReferenced
);
275 if(aNewTarget
.hasElements())
277 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget
, aNewTarget
);
282 OSL_ENSURE(false, "Null-Pointer in child node list (!)");
286 if(rTarget
.hasElements())
288 const SvgStyleAttributes
* pStyles
= getSvgStyleAttributes();
292 // check if we have Title or Desc
293 const OUString
& rTitle
= pStyles
->getTitle();
294 const OUString
& rDesc
= pStyles
->getDesc();
296 if(rTitle
.getLength() || rDesc
.getLength())
298 // default object name is empty
299 OUString aObjectName
;
301 // use path as object name when outmost element
302 if(SVGTokenSvg
== getType())
304 aObjectName
= getDocument().getAbsolutePath();
306 if(aObjectName
.getLength())
308 INetURLObject
aURL(aObjectName
);
310 aObjectName
= aURL
.getName(
311 INetURLObject::LAST_SEGMENT
,
313 INetURLObject::DECODE_WITH_CHARSET
);
317 // pack in ObjectInfoPrimitive2D group
318 const drawinglayer::primitive2d::Primitive2DReference
xRef(
319 new drawinglayer::primitive2d::ObjectInfoPrimitive2D(
325 rTarget
= drawinglayer::primitive2d::Primitive2DSequence(&xRef
, 1);
332 const basegfx::B2DRange
* SvgNode::getCurrentViewPort() const
336 return getParent()->getCurrentViewPort();
344 double SvgNode::getCurrentFontSizeInherited() const
348 return getParent()->getCurrentFontSize();
356 double SvgNode::getCurrentFontSize() const
358 if(getSvgStyleAttributes())
359 return getSvgStyleAttributes()->getFontSize().solve(*this, xcoordinate
);
361 return getCurrentFontSizeInherited();
364 double SvgNode::getCurrentXHeightInherited() const
368 return getParent()->getCurrentXHeight();
376 double SvgNode::getCurrentXHeight() const
378 if(getSvgStyleAttributes())
379 // for XHeight, use FontSize currently
380 return getSvgStyleAttributes()->getFontSize().solve(*this, ycoordinate
);
382 return getCurrentXHeightInherited();
385 void SvgNode::setId(const OUString
* pfId
)
389 mrDocument
.removeSvgNodeFromMapper(*mpId
);
396 mpId
= new OUString(*pfId
);
397 mrDocument
.addSvgNodeToMapper(*mpId
, *this);
401 void SvgNode::setClass(const OUString
* pfClass
)
405 mrDocument
.removeSvgNodeFromMapper(*mpClass
);
412 mpClass
= new OUString(*pfClass
);
413 mrDocument
.addSvgNodeToMapper(*mpClass
, *this);
417 XmlSpace
SvgNode::getXmlSpace() const
419 if(maXmlSpace
!= XmlSpace_notset
)
426 return getParent()->getXmlSpace();
429 // default is XmlSpace_default
430 return XmlSpace_default
;
433 } // end of namespace svgreader
434 } // end of namespace svgio
436 //////////////////////////////////////////////////////////////////////////////
439 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */