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/svgtextnode.hxx>
26ddde725dSArmin Le Grand #include <svgio/svgreader/svgcharacternode.hxx>
27ddde725dSArmin Le Grand #include <svgio/svgreader/svgstyleattributes.hxx>
28ddde725dSArmin Le Grand #include <svgio/svgreader/svgtrefnode.hxx>
29ddde725dSArmin Le Grand #include <svgio/svgreader/svgtextpathnode.hxx>
30ddde725dSArmin Le Grand #include <svgio/svgreader/svgtspannode.hxx>
31ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
32ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
33ddde725dSArmin Le Grand 
34ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
35ddde725dSArmin Le Grand 
36ddde725dSArmin Le Grand namespace svgio
37ddde725dSArmin Le Grand {
38ddde725dSArmin Le Grand     namespace svgreader
39ddde725dSArmin Le Grand     {
40ddde725dSArmin Le Grand         SvgTextNode::SvgTextNode(
41ddde725dSArmin Le Grand             SvgDocument& rDocument,
42ddde725dSArmin Le Grand             SvgNode* pParent)
43ddde725dSArmin Le Grand         :   SvgNode(SVGTokenText, rDocument, pParent),
44ddde725dSArmin Le Grand             maSvgStyleAttributes(*this),
45ddde725dSArmin Le Grand             mpaTransform(0),
46ddde725dSArmin Le Grand             maSvgTextPositions()
47ddde725dSArmin Le Grand         {
48ddde725dSArmin Le Grand         }
49ddde725dSArmin Le Grand 
50ddde725dSArmin Le Grand         SvgTextNode::~SvgTextNode()
51ddde725dSArmin Le Grand         {
52ddde725dSArmin Le Grand             if(mpaTransform) delete mpaTransform;
53ddde725dSArmin Le Grand         }
54ddde725dSArmin Le Grand 
55ddde725dSArmin Le Grand         const SvgStyleAttributes* SvgTextNode::getSvgStyleAttributes() const
56ddde725dSArmin Le Grand         {
57ddde725dSArmin Le Grand             static rtl::OUString aClassStr(rtl::OUString::createFromAscii("text"));
58ddde725dSArmin Le Grand             maSvgStyleAttributes.checkForCssStyle(aClassStr);
59ddde725dSArmin Le Grand 
60ddde725dSArmin Le Grand             return &maSvgStyleAttributes;
61ddde725dSArmin Le Grand         }
62ddde725dSArmin Le Grand 
63ddde725dSArmin Le Grand         void SvgTextNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
64ddde725dSArmin Le Grand         {
65ddde725dSArmin Le Grand             // call parent
66ddde725dSArmin Le Grand             SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
67ddde725dSArmin Le Grand 
68ddde725dSArmin Le Grand             // read style attributes
69ddde725dSArmin Le Grand             maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent);
70ddde725dSArmin Le Grand 
71ddde725dSArmin Le Grand             // read text position attributes
72ddde725dSArmin Le Grand             maSvgTextPositions.parseTextPositionAttributes(rTokenName, aSVGToken, aContent);
73ddde725dSArmin Le Grand 
74ddde725dSArmin Le Grand             // parse own
75ddde725dSArmin Le Grand             switch(aSVGToken)
76ddde725dSArmin Le Grand             {
77ddde725dSArmin Le Grand                 case SVGTokenStyle:
78ddde725dSArmin Le Grand                 {
79ddde725dSArmin Le Grand                     maSvgStyleAttributes.readStyle(aContent);
80ddde725dSArmin Le Grand                     break;
81ddde725dSArmin Le Grand                 }
82ddde725dSArmin Le Grand                 case SVGTokenTransform:
83ddde725dSArmin Le Grand                 {
84ddde725dSArmin Le Grand                     const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this));
85ddde725dSArmin Le Grand 
86ddde725dSArmin Le Grand                     if(!aMatrix.isIdentity())
87ddde725dSArmin Le Grand                     {
88ddde725dSArmin Le Grand                         setTransform(&aMatrix);
89ddde725dSArmin Le Grand                     }
90ddde725dSArmin Le Grand                     break;
91ddde725dSArmin Le Grand                 }
92*e2bf1e9dSArmin Le Grand                 default:
93*e2bf1e9dSArmin Le Grand                 {
94*e2bf1e9dSArmin Le Grand                     break;
95*e2bf1e9dSArmin Le Grand                 }
96ddde725dSArmin Le Grand             }
97ddde725dSArmin Le Grand         }
98ddde725dSArmin Le Grand 
99ddde725dSArmin Le Grand         void SvgTextNode::addTextPrimitives(
100ddde725dSArmin Le Grand             const SvgNode& rCandidate,
101ddde725dSArmin Le Grand             drawinglayer::primitive2d::Primitive2DSequence& rTarget,
102ddde725dSArmin Le Grand             drawinglayer::primitive2d::Primitive2DSequence& rSource) const
103ddde725dSArmin Le Grand         {
104ddde725dSArmin Le Grand             if(rSource.hasElements())
105ddde725dSArmin Le Grand             {
106ddde725dSArmin Le Grand                 const SvgStyleAttributes* pAttributes = rCandidate.getSvgStyleAttributes();
107ddde725dSArmin Le Grand 
108ddde725dSArmin Le Grand                 if(pAttributes)
109ddde725dSArmin Le Grand                 {
110ddde725dSArmin Le Grand                     // add text with taking all Fill/Stroke attributes into account
111ddde725dSArmin Le Grand                     pAttributes->add_text(rTarget, rSource);
112ddde725dSArmin Le Grand                 }
113ddde725dSArmin Le Grand                 else
114ddde725dSArmin Le Grand                 {
115ddde725dSArmin Le Grand                     // should not happen, every subnode from SvgTextNode will at least
116ddde725dSArmin Le Grand                     // return the attributes from SvgTextNode. Nonetheless, add text
117ddde725dSArmin Le Grand                     drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, rSource);
118ddde725dSArmin Le Grand                 }
119ddde725dSArmin Le Grand             }
120ddde725dSArmin Le Grand         }
121ddde725dSArmin Le Grand 
122ddde725dSArmin Le Grand         void SvgTextNode::DecomposeChild(const SvgNode& rCandidate, drawinglayer::primitive2d::Primitive2DSequence& rTarget, SvgTextPosition& rSvgTextPosition) const
123ddde725dSArmin Le Grand         {
124ddde725dSArmin Le Grand             switch(rCandidate.getType())
125ddde725dSArmin Le Grand             {
126ddde725dSArmin Le Grand                 case SVGTokenCharacter:
127ddde725dSArmin Le Grand                 {
128ddde725dSArmin Le Grand                     // direct SvgTextPathNode derivates, decompose them
129ddde725dSArmin Le Grand                     const SvgCharacterNode& rSvgCharacterNode = static_cast< const SvgCharacterNode& >(rCandidate);
130ddde725dSArmin Le Grand                     rSvgCharacterNode.decomposeText(rTarget, rSvgTextPosition);
131ddde725dSArmin Le Grand                     break;
132ddde725dSArmin Le Grand                 }
133ddde725dSArmin Le Grand                 case SVGTokenTextPath:
134ddde725dSArmin Le Grand                 {
135ddde725dSArmin Le Grand                     // direct TextPath decompose
136ddde725dSArmin Le Grand                     const SvgTextPathNode& rSvgTextPathNode = static_cast< const SvgTextPathNode& >(rCandidate);
137ddde725dSArmin Le Grand                     const SvgNodeVector& rChildren = rSvgTextPathNode.getChildren();
138ddde725dSArmin Le Grand                     const sal_uInt32 nCount(rChildren.size());
139ddde725dSArmin Le Grand 
140ddde725dSArmin Le Grand                     if(nCount && rSvgTextPathNode.isValid())
141ddde725dSArmin Le Grand                     {
142ddde725dSArmin Le Grand                         // remember original TextStart to later detect hor/ver offsets
143ddde725dSArmin Le Grand                         const basegfx::B2DPoint aTextStart(rSvgTextPosition.getPosition());
144ddde725dSArmin Le Grand                         drawinglayer::primitive2d::Primitive2DSequence aNewTarget;
145ddde725dSArmin Le Grand 
146ddde725dSArmin Le Grand                         // decompose to regular TextPrimitives
147ddde725dSArmin Le Grand                         for(sal_uInt32 a(0); a < nCount; a++)
148ddde725dSArmin Le Grand                         {
149ddde725dSArmin Le Grand                             DecomposeChild(*rChildren[a], aNewTarget, rSvgTextPosition);
150ddde725dSArmin Le Grand                         }
151ddde725dSArmin Le Grand 
152ddde725dSArmin Le Grand                         if(aNewTarget.hasElements())
153ddde725dSArmin Le Grand                         {
154ddde725dSArmin Le Grand                             const drawinglayer::primitive2d::Primitive2DSequence aPathContent(aNewTarget);
155ddde725dSArmin Le Grand                             aNewTarget.realloc(0);
156ddde725dSArmin Le Grand 
157ddde725dSArmin Le Grand                             // dismantle TextPrimitives and map them on curve/path
158ddde725dSArmin Le Grand                             rSvgTextPathNode.decomposePathNode(aPathContent, aNewTarget, aTextStart);
159ddde725dSArmin Le Grand                         }
160ddde725dSArmin Le Grand 
161ddde725dSArmin Le Grand                         if(aNewTarget.hasElements())
162ddde725dSArmin Le Grand                         {
163ddde725dSArmin Le Grand                             addTextPrimitives(rCandidate, rTarget, aNewTarget);
164ddde725dSArmin Le Grand                         }
165ddde725dSArmin Le Grand                     }
166ddde725dSArmin Le Grand 
167ddde725dSArmin Le Grand                     break;
168ddde725dSArmin Le Grand                 }
169ddde725dSArmin Le Grand                 case SVGTokenTspan:
170ddde725dSArmin Le Grand                 {
171ddde725dSArmin Le Grand                     // Tspan may have children, call recursively
172ddde725dSArmin Le Grand                     const SvgTspanNode& rSvgTspanNode = static_cast< const SvgTspanNode& >(rCandidate);
173ddde725dSArmin Le Grand                     const SvgNodeVector& rChildren = rSvgTspanNode.getChildren();
174ddde725dSArmin Le Grand                     const sal_uInt32 nCount(rChildren.size());
175ddde725dSArmin Le Grand 
176ddde725dSArmin Le Grand                     if(nCount)
177ddde725dSArmin Le Grand                     {
178ddde725dSArmin Le Grand                         SvgTextPosition aSvgTextPosition(&rSvgTextPosition, rSvgTspanNode, rSvgTspanNode.getSvgTextPositions());
179ddde725dSArmin Le Grand                         drawinglayer::primitive2d::Primitive2DSequence aNewTarget;
180ddde725dSArmin Le Grand 
181ddde725dSArmin Le Grand                         for(sal_uInt32 a(0); a < nCount; a++)
182ddde725dSArmin Le Grand                         {
183ddde725dSArmin Le Grand                             DecomposeChild(*rChildren[a], aNewTarget, aSvgTextPosition);
184ddde725dSArmin Le Grand                         }
185ddde725dSArmin Le Grand 
186ddde725dSArmin Le Grand                         rSvgTextPosition.setPosition(aSvgTextPosition.getPosition());
187ddde725dSArmin Le Grand 
188ddde725dSArmin Le Grand                         if(aNewTarget.hasElements())
189ddde725dSArmin Le Grand                         {
190ddde725dSArmin Le Grand                             addTextPrimitives(rCandidate, rTarget, aNewTarget);
191ddde725dSArmin Le Grand                         }
192ddde725dSArmin Le Grand                     }
193ddde725dSArmin Le Grand                     break;
194ddde725dSArmin Le Grand                 }
195ddde725dSArmin Le Grand                 case SVGTokenTref:
196ddde725dSArmin Le Grand                 {
197ddde725dSArmin Le Grand                     const SvgTrefNode& rSvgTrefNode = static_cast< const SvgTrefNode& >(rCandidate);
198ddde725dSArmin Le Grand                     const SvgTextNode* pRefText = rSvgTrefNode.getReferencedSvgTextNode();
199ddde725dSArmin Le Grand 
200ddde725dSArmin Le Grand                     if(pRefText)
201ddde725dSArmin Le Grand                     {
202ddde725dSArmin Le Grand                         const SvgNodeVector& rChildren = pRefText->getChildren();
203ddde725dSArmin Le Grand                         const sal_uInt32 nCount(rChildren.size());
204ddde725dSArmin Le Grand                         drawinglayer::primitive2d::Primitive2DSequence aNewTarget;
205ddde725dSArmin Le Grand 
206ddde725dSArmin Le Grand                         if(nCount)
207ddde725dSArmin Le Grand                         {
208ddde725dSArmin Le Grand                             for(sal_uInt32 a(0); a < nCount; a++)
209ddde725dSArmin Le Grand                             {
210ddde725dSArmin Le Grand                                 const SvgNode& rChildCandidate = *rChildren[a];
211ddde725dSArmin Le Grand                                 const_cast< SvgNode& >(rChildCandidate).setAlternativeParent(this);
212ddde725dSArmin Le Grand 
213ddde725dSArmin Le Grand                                 DecomposeChild(rChildCandidate, aNewTarget, rSvgTextPosition);
214ddde725dSArmin Le Grand                                 const_cast< SvgNode& >(rChildCandidate).setAlternativeParent(0);
215ddde725dSArmin Le Grand                             }
216ddde725dSArmin Le Grand 
217ddde725dSArmin Le Grand                             if(aNewTarget.hasElements())
218ddde725dSArmin Le Grand                             {
219ddde725dSArmin Le Grand                                 addTextPrimitives(rCandidate, rTarget, aNewTarget);
220ddde725dSArmin Le Grand                             }
221ddde725dSArmin Le Grand                         }
222ddde725dSArmin Le Grand                     }
223ddde725dSArmin Le Grand 
224ddde725dSArmin Le Grand                     break;
225ddde725dSArmin Le Grand                 }
226ddde725dSArmin Le Grand                 default:
227ddde725dSArmin Le Grand                 {
228ddde725dSArmin Le Grand                     OSL_ENSURE(false, "Unexpected node in text token (!)");
229ddde725dSArmin Le Grand                     break;
230ddde725dSArmin Le Grand                 }
231ddde725dSArmin Le Grand             }
232ddde725dSArmin Le Grand         }
233ddde725dSArmin Le Grand 
234*e2bf1e9dSArmin Le Grand         void SvgTextNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool /*bReferenced`*/) const
235ddde725dSArmin Le Grand         {
236ddde725dSArmin Le Grand             // text has a group of child nodes, allowed are SVGTokenCharacter, SVGTokenTspan,
237ddde725dSArmin Le Grand             // SVGTokenTref and SVGTokenTextPath. These increase a given current text position
238ddde725dSArmin Le Grand             const SvgStyleAttributes* pStyle = getSvgStyleAttributes();
239ddde725dSArmin Le Grand 
240ddde725dSArmin Le Grand             if(pStyle && !getChildren().empty())
241ddde725dSArmin Le Grand             {
242ddde725dSArmin Le Grand                 const double fOpacity(pStyle->getOpacity().getNumber());
243ddde725dSArmin Le Grand 
244ddde725dSArmin Le Grand                 if(fOpacity > 0.0)
245ddde725dSArmin Le Grand                 {
246ddde725dSArmin Le Grand                     SvgTextPosition aSvgTextPosition(0, *this, getSvgTextPositions());
247ddde725dSArmin Le Grand                     drawinglayer::primitive2d::Primitive2DSequence aNewTarget;
248ddde725dSArmin Le Grand                     const SvgNodeVector& rChildren = getChildren();
249ddde725dSArmin Le Grand                     const sal_uInt32 nCount(rChildren.size());
250ddde725dSArmin Le Grand 
251ddde725dSArmin Le Grand                     for(sal_uInt32 a(0); a < nCount; a++)
252ddde725dSArmin Le Grand                     {
253ddde725dSArmin Le Grand                         const SvgNode& rCandidate = *rChildren[a];
254ddde725dSArmin Le Grand 
255ddde725dSArmin Le Grand                         DecomposeChild(rCandidate, aNewTarget, aSvgTextPosition);
256ddde725dSArmin Le Grand                     }
257ddde725dSArmin Le Grand 
258ddde725dSArmin Le Grand                     if(aNewTarget.hasElements())
259ddde725dSArmin Le Grand                     {
260ddde725dSArmin Le Grand                         drawinglayer::primitive2d::Primitive2DSequence aNewTarget2;
261ddde725dSArmin Le Grand 
262ddde725dSArmin Le Grand                         addTextPrimitives(*this, aNewTarget2, aNewTarget);
263ddde725dSArmin Le Grand                         aNewTarget = aNewTarget2;
264ddde725dSArmin Le Grand                     }
265ddde725dSArmin Le Grand 
266ddde725dSArmin Le Grand                     if(aNewTarget.hasElements())
267ddde725dSArmin Le Grand                     {
268ddde725dSArmin Le Grand                         pStyle->add_postProcess(rTarget, aNewTarget, getTransform());
269ddde725dSArmin Le Grand                     }
270ddde725dSArmin Le Grand                 }
271ddde725dSArmin Le Grand             }
272ddde725dSArmin Le Grand         }
273ddde725dSArmin Le Grand     } // end of namespace svgreader
274ddde725dSArmin Le Grand } // end of namespace svgio
275ddde725dSArmin Le Grand 
276ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
277ddde725dSArmin Le Grand // eof
278