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 <svgio/svgreader/svgtextnode.hxx>
21 #include <svgio/svgreader/svgcharacternode.hxx>
22 #include <svgio/svgreader/svgstyleattributes.hxx>
23 #include <svgio/svgreader/svgtrefnode.hxx>
24 #include <svgio/svgreader/svgtextpathnode.hxx>
25 #include <svgio/svgreader/svgtspannode.hxx>
26 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
27 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
29 //////////////////////////////////////////////////////////////////////////////
35 SvgTextNode::SvgTextNode(
36 SvgDocument
& rDocument
,
38 : SvgNode(SVGTokenText
, rDocument
, pParent
),
39 maSvgStyleAttributes(*this),
45 SvgTextNode::~SvgTextNode()
47 if(mpaTransform
) delete mpaTransform
;
50 const SvgStyleAttributes
* SvgTextNode::getSvgStyleAttributes() const
52 static rtl::OUString
aClassStr(rtl::OUString::createFromAscii("text"));
53 return checkForCssStyle(aClassStr
, maSvgStyleAttributes
);
56 void SvgTextNode::parseAttribute(const OUString
& rTokenName
, SVGToken aSVGToken
, const OUString
& aContent
)
59 SvgNode::parseAttribute(rTokenName
, aSVGToken
, aContent
);
61 // read style attributes
62 maSvgStyleAttributes
.parseStyleAttribute(rTokenName
, aSVGToken
, aContent
);
64 // read text position attributes
65 maSvgTextPositions
.parseTextPositionAttributes(rTokenName
, aSVGToken
, aContent
);
72 maSvgStyleAttributes
.readStyle(aContent
);
75 case SVGTokenTransform
:
77 const basegfx::B2DHomMatrix
aMatrix(readTransform(aContent
, *this));
79 if(!aMatrix
.isIdentity())
81 setTransform(&aMatrix
);
92 void SvgTextNode::addTextPrimitives(
93 const SvgNode
& rCandidate
,
94 drawinglayer::primitive2d::Primitive2DSequence
& rTarget
,
95 drawinglayer::primitive2d::Primitive2DSequence
& rSource
) const
97 if(rSource
.hasElements())
99 const SvgStyleAttributes
* pAttributes
= rCandidate
.getSvgStyleAttributes();
103 // add text with taking all Fill/Stroke attributes into account
104 pAttributes
->add_text(rTarget
, rSource
);
108 // should not happen, every subnode from SvgTextNode will at least
109 // return the attributes from SvgTextNode. Nonetheless, add text
110 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget
, rSource
);
115 void SvgTextNode::DecomposeChild(const SvgNode
& rCandidate
, drawinglayer::primitive2d::Primitive2DSequence
& rTarget
, SvgTextPosition
& rSvgTextPosition
) const
117 switch(rCandidate
.getType())
119 case SVGTokenCharacter
:
121 // direct SvgTextPathNode derivates, decompose them
122 const SvgCharacterNode
& rSvgCharacterNode
= static_cast< const SvgCharacterNode
& >(rCandidate
);
123 rSvgCharacterNode
.decomposeText(rTarget
, rSvgTextPosition
);
126 case SVGTokenTextPath
:
128 // direct TextPath decompose
129 const SvgTextPathNode
& rSvgTextPathNode
= static_cast< const SvgTextPathNode
& >(rCandidate
);
130 const SvgNodeVector
& rChildren
= rSvgTextPathNode
.getChildren();
131 const sal_uInt32
nCount(rChildren
.size());
133 if(nCount
&& rSvgTextPathNode
.isValid())
135 // remember original TextStart to later detect hor/ver offsets
136 const basegfx::B2DPoint
aTextStart(rSvgTextPosition
.getPosition());
137 drawinglayer::primitive2d::Primitive2DSequence aNewTarget
;
139 // decompose to regular TextPrimitives
140 for(sal_uInt32
a(0); a
< nCount
; a
++)
142 DecomposeChild(*rChildren
[a
], aNewTarget
, rSvgTextPosition
);
145 if(aNewTarget
.hasElements())
147 const drawinglayer::primitive2d::Primitive2DSequence
aPathContent(aNewTarget
);
148 aNewTarget
.realloc(0);
150 // dismantle TextPrimitives and map them on curve/path
151 rSvgTextPathNode
.decomposePathNode(aPathContent
, aNewTarget
, aTextStart
);
154 if(aNewTarget
.hasElements())
156 addTextPrimitives(rCandidate
, rTarget
, aNewTarget
);
164 // Tspan may have children, call recursively
165 const SvgTspanNode
& rSvgTspanNode
= static_cast< const SvgTspanNode
& >(rCandidate
);
166 const SvgNodeVector
& rChildren
= rSvgTspanNode
.getChildren();
167 const sal_uInt32
nCount(rChildren
.size());
171 SvgTextPosition
aSvgTextPosition(&rSvgTextPosition
, rSvgTspanNode
, rSvgTspanNode
.getSvgTextPositions());
172 drawinglayer::primitive2d::Primitive2DSequence aNewTarget
;
174 for(sal_uInt32
a(0); a
< nCount
; a
++)
176 DecomposeChild(*rChildren
[a
], aNewTarget
, aSvgTextPosition
);
179 rSvgTextPosition
.setPosition(aSvgTextPosition
.getPosition());
181 if(aNewTarget
.hasElements())
183 addTextPrimitives(rCandidate
, rTarget
, aNewTarget
);
190 const SvgTrefNode
& rSvgTrefNode
= static_cast< const SvgTrefNode
& >(rCandidate
);
191 const SvgTextNode
* pRefText
= rSvgTrefNode
.getReferencedSvgTextNode();
195 const SvgNodeVector
& rChildren
= pRefText
->getChildren();
196 const sal_uInt32
nCount(rChildren
.size());
197 drawinglayer::primitive2d::Primitive2DSequence aNewTarget
;
201 for(sal_uInt32
a(0); a
< nCount
; a
++)
203 const SvgNode
& rChildCandidate
= *rChildren
[a
];
204 const_cast< SvgNode
& >(rChildCandidate
).setAlternativeParent(this);
206 DecomposeChild(rChildCandidate
, aNewTarget
, rSvgTextPosition
);
207 const_cast< SvgNode
& >(rChildCandidate
).setAlternativeParent(0);
210 if(aNewTarget
.hasElements())
212 addTextPrimitives(rCandidate
, rTarget
, aNewTarget
);
221 OSL_ENSURE(false, "Unexpected node in text token (!)");
227 void SvgTextNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence
& rTarget
, bool /*bReferenced`*/) const
229 // text has a group of child nodes, allowed are SVGTokenCharacter, SVGTokenTspan,
230 // SVGTokenTref and SVGTokenTextPath. These increase a given current text position
231 const SvgStyleAttributes
* pStyle
= getSvgStyleAttributes();
233 if(pStyle
&& !getChildren().empty())
235 const double fOpacity(pStyle
->getOpacity().getNumber());
239 SvgTextPosition
aSvgTextPosition(0, *this, getSvgTextPositions());
240 drawinglayer::primitive2d::Primitive2DSequence aNewTarget
;
241 const SvgNodeVector
& rChildren
= getChildren();
242 const sal_uInt32
nCount(rChildren
.size());
244 for(sal_uInt32
a(0); a
< nCount
; a
++)
246 const SvgNode
& rCandidate
= *rChildren
[a
];
248 DecomposeChild(rCandidate
, aNewTarget
, aSvgTextPosition
);
251 if(aNewTarget
.hasElements())
253 drawinglayer::primitive2d::Primitive2DSequence aNewTarget2
;
255 addTextPrimitives(*this, aNewTarget2
, aNewTarget
);
256 aNewTarget
= aNewTarget2
;
259 if(aNewTarget
.hasElements())
261 pStyle
->add_postProcess(rTarget
, aNewTarget
, getTransform());
266 } // end of namespace svgreader
267 } // end of namespace svgio
269 //////////////////////////////////////////////////////////////////////////////
272 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */