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/svgimagenode.hxx>
26ddde725dSArmin Le Grand #include <svgio/svgreader/svgdocument.hxx>
27ddde725dSArmin Le Grand #include <sax/tools/converter.hxx>
28ddde725dSArmin Le Grand #include <tools/stream.hxx>
29ddde725dSArmin Le Grand #include <vcl/bitmapex.hxx>
30ddde725dSArmin Le Grand #include <svtools/filter.hxx>
31ddde725dSArmin Le Grand #include <basegfx/matrix/b2dhommatrixtools.hxx>
32ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
33ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/groupprimitive2d.hxx>
34ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
35ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
36ddde725dSArmin Le Grand #include <basegfx/polygon/b2dpolygontools.hxx>
37ddde725dSArmin Le Grand #include <basegfx/polygon/b2dpolygon.hxx>
38ddde725dSArmin Le Grand #include <rtl/uri.hxx>
39ddde725dSArmin Le Grand #include <drawinglayer/geometry/viewinformation2d.hxx>
40ddde725dSArmin Le Grand 
41ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
42ddde725dSArmin Le Grand 
43ddde725dSArmin Le Grand namespace svgio
44ddde725dSArmin Le Grand {
45ddde725dSArmin Le Grand     namespace svgreader
46ddde725dSArmin Le Grand     {
47ddde725dSArmin Le Grand         SvgImageNode::SvgImageNode(
48ddde725dSArmin Le Grand             SvgDocument& rDocument,
49ddde725dSArmin Le Grand             SvgNode* pParent)
50ddde725dSArmin Le Grand         :   SvgNode(SVGTokenRect, rDocument, pParent),
51ddde725dSArmin Le Grand             maSvgStyleAttributes(*this),
52ddde725dSArmin Le Grand             maSvgAspectRatio(),
53ddde725dSArmin Le Grand             mpaTransform(0),
54ddde725dSArmin Le Grand             maX(0),
55ddde725dSArmin Le Grand             maY(0),
56ddde725dSArmin Le Grand             maWidth(0),
57ddde725dSArmin Le Grand             maHeight(0),
58ddde725dSArmin Le Grand             maXLink(),
59ddde725dSArmin Le Grand             maUrl(),
60ddde725dSArmin Le Grand             maMimeType(),
61ddde725dSArmin Le Grand             maData()
62ddde725dSArmin Le Grand         {
63ddde725dSArmin Le Grand         }
64ddde725dSArmin Le Grand 
65ddde725dSArmin Le Grand         SvgImageNode::~SvgImageNode()
66ddde725dSArmin Le Grand         {
67ddde725dSArmin Le Grand             if(mpaTransform) delete mpaTransform;
68ddde725dSArmin Le Grand         }
69ddde725dSArmin Le Grand 
70ddde725dSArmin Le Grand         const SvgStyleAttributes* SvgImageNode::getSvgStyleAttributes() const
71ddde725dSArmin Le Grand         {
72ddde725dSArmin Le Grand             static rtl::OUString aClassStr(rtl::OUString::createFromAscii("image"));
73ddde725dSArmin Le Grand             maSvgStyleAttributes.checkForCssStyle(aClassStr);
74ddde725dSArmin Le Grand 
75ddde725dSArmin Le Grand             return &maSvgStyleAttributes;
76ddde725dSArmin Le Grand         }
77ddde725dSArmin Le Grand 
78ddde725dSArmin Le Grand         void SvgImageNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
79ddde725dSArmin Le Grand         {
80ddde725dSArmin Le Grand             // call parent
81ddde725dSArmin Le Grand             SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
82ddde725dSArmin Le Grand 
83ddde725dSArmin Le Grand             // read style attributes
84ddde725dSArmin Le Grand             maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent);
85ddde725dSArmin Le Grand 
86ddde725dSArmin Le Grand             // parse own
87ddde725dSArmin Le Grand             switch(aSVGToken)
88ddde725dSArmin Le Grand             {
89ddde725dSArmin Le Grand                 case SVGTokenStyle:
90ddde725dSArmin Le Grand                 {
91ddde725dSArmin Le Grand                     maSvgStyleAttributes.readStyle(aContent);
92ddde725dSArmin Le Grand                     break;
93ddde725dSArmin Le Grand                 }
94ddde725dSArmin Le Grand                 case SVGTokenPreserveAspectRatio:
95ddde725dSArmin Le Grand                 {
96ddde725dSArmin Le Grand                     setSvgAspectRatio(readSvgAspectRatio(aContent));
97ddde725dSArmin Le Grand                     break;
98ddde725dSArmin Le Grand                 }
99ddde725dSArmin Le Grand                 case SVGTokenTransform:
100ddde725dSArmin Le Grand                 {
101ddde725dSArmin Le Grand                     const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this));
102ddde725dSArmin Le Grand 
103ddde725dSArmin Le Grand                     if(!aMatrix.isIdentity())
104ddde725dSArmin Le Grand                     {
105ddde725dSArmin Le Grand                         setTransform(&aMatrix);
106ddde725dSArmin Le Grand                     }
107ddde725dSArmin Le Grand                     break;
108ddde725dSArmin Le Grand                 }
109ddde725dSArmin Le Grand                 case SVGTokenX:
110ddde725dSArmin Le Grand                 {
111ddde725dSArmin Le Grand                     SvgNumber aNum;
112ddde725dSArmin Le Grand 
113ddde725dSArmin Le Grand                     if(readSingleNumber(aContent, aNum))
114ddde725dSArmin Le Grand                     {
115ddde725dSArmin Le Grand                         setX(aNum);
116ddde725dSArmin Le Grand                     }
117ddde725dSArmin Le Grand                     break;
118ddde725dSArmin Le Grand                 }
119ddde725dSArmin Le Grand                 case SVGTokenY:
120ddde725dSArmin Le Grand                 {
121ddde725dSArmin Le Grand                     SvgNumber aNum;
122ddde725dSArmin Le Grand 
123ddde725dSArmin Le Grand                     if(readSingleNumber(aContent, aNum))
124ddde725dSArmin Le Grand                     {
125ddde725dSArmin Le Grand                         setY(aNum);
126ddde725dSArmin Le Grand                     }
127ddde725dSArmin Le Grand                     break;
128ddde725dSArmin Le Grand                 }
129ddde725dSArmin Le Grand                 case SVGTokenWidth:
130ddde725dSArmin Le Grand                 {
131ddde725dSArmin Le Grand                     SvgNumber aNum;
132ddde725dSArmin Le Grand 
133ddde725dSArmin Le Grand                     if(readSingleNumber(aContent, aNum))
134ddde725dSArmin Le Grand                     {
135ddde725dSArmin Le Grand                         if(aNum.isPositive())
136ddde725dSArmin Le Grand                         {
137ddde725dSArmin Le Grand                             setWidth(aNum);
138ddde725dSArmin Le Grand                         }
139ddde725dSArmin Le Grand                     }
140ddde725dSArmin Le Grand                     break;
141ddde725dSArmin Le Grand                 }
142ddde725dSArmin Le Grand                 case SVGTokenHeight:
143ddde725dSArmin Le Grand                 {
144ddde725dSArmin Le Grand                     SvgNumber aNum;
145ddde725dSArmin Le Grand 
146ddde725dSArmin Le Grand                     if(readSingleNumber(aContent, aNum))
147ddde725dSArmin Le Grand                     {
148ddde725dSArmin Le Grand                         if(aNum.isPositive())
149ddde725dSArmin Le Grand                         {
150ddde725dSArmin Le Grand                             setHeight(aNum);
151ddde725dSArmin Le Grand                         }
152ddde725dSArmin Le Grand                     }
153ddde725dSArmin Le Grand                     break;
154ddde725dSArmin Le Grand                 }
155ddde725dSArmin Le Grand                 case SVGTokenXlinkHref:
156ddde725dSArmin Le Grand                 {
157ddde725dSArmin Le Grand                     const sal_Int32 nLen(aContent.getLength());
158ddde725dSArmin Le Grand 
159ddde725dSArmin Le Grand                     if(nLen)
160ddde725dSArmin Le Grand                     {
161ddde725dSArmin Le Grand                         readImageLink(aContent, maXLink, maUrl, maMimeType, maData);
162ddde725dSArmin Le Grand                     }
163ddde725dSArmin Le Grand                     break;
164ddde725dSArmin Le Grand                 }
165*e2bf1e9dSArmin Le Grand                 default:
166*e2bf1e9dSArmin Le Grand                 {
167*e2bf1e9dSArmin Le Grand                     break;
168*e2bf1e9dSArmin Le Grand                 }
169ddde725dSArmin Le Grand             }
170ddde725dSArmin Le Grand         }
171ddde725dSArmin Le Grand 
172ddde725dSArmin Le Grand         void extractFromGraphic(
173ddde725dSArmin Le Grand             const Graphic& rGraphic,
174ddde725dSArmin Le Grand             drawinglayer::primitive2d::Primitive2DSequence& rEmbedded,
175ddde725dSArmin Le Grand             basegfx::B2DRange& rViewBox,
176ddde725dSArmin Le Grand             BitmapEx& rBitmapEx)
177ddde725dSArmin Le Grand         {
178ddde725dSArmin Le Grand             if(GRAPHIC_BITMAP == rGraphic.GetType())
179ddde725dSArmin Le Grand             {
180ddde725dSArmin Le Grand                 if(rGraphic.getSvgData().get())
181ddde725dSArmin Le Grand                 {
182ddde725dSArmin Le Grand                     // embedded Svg
183ddde725dSArmin Le Grand                     rEmbedded = rGraphic.getSvgData()->getPrimitive2DSequence();
184ddde725dSArmin Le Grand 
185ddde725dSArmin Le Grand                     // fill aViewBox
186ddde725dSArmin Le Grand                     rViewBox = rGraphic.getSvgData()->getRange();
187ddde725dSArmin Le Grand                 }
188ddde725dSArmin Le Grand                 else
189ddde725dSArmin Le Grand                 {
190ddde725dSArmin Le Grand                     // get bitmap
191ddde725dSArmin Le Grand                     rBitmapEx = rGraphic.GetBitmapEx();
192ddde725dSArmin Le Grand                 }
193ddde725dSArmin Le Grand             }
194ddde725dSArmin Le Grand             else
195ddde725dSArmin Le Grand             {
196ddde725dSArmin Le Grand                 // evtl. convert to bitmap
197ddde725dSArmin Le Grand                 rBitmapEx = rGraphic.GetBitmapEx();
198ddde725dSArmin Le Grand             }
199ddde725dSArmin Le Grand         }
200ddde725dSArmin Le Grand 
201*e2bf1e9dSArmin Le Grand         void SvgImageNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool /*bReferenced*/) const
202ddde725dSArmin Le Grand         {
203ddde725dSArmin Le Grand             // get size range and create path
204ddde725dSArmin Le Grand             const SvgStyleAttributes* pStyle = getSvgStyleAttributes();
205ddde725dSArmin Le Grand 
206ddde725dSArmin Le Grand             if(pStyle && getWidth().isSet() && getHeight().isSet())
207ddde725dSArmin Le Grand             {
208ddde725dSArmin Le Grand                 const double fWidth(getWidth().solve(*this, xcoordinate));
209ddde725dSArmin Le Grand                 const double fHeight(getHeight().solve(*this, ycoordinate));
210ddde725dSArmin Le Grand 
211ddde725dSArmin Le Grand                 if(fWidth > 0.0 && fHeight > 0.0)
212ddde725dSArmin Le Grand                 {
213ddde725dSArmin Le Grand                     BitmapEx aBitmapEx;
214ddde725dSArmin Le Grand                     drawinglayer::primitive2d::Primitive2DSequence aNewTarget;
215ddde725dSArmin Le Grand 
216ddde725dSArmin Le Grand                     // prepare Target and ViewBox for evtl. AspectRatio mappings
217ddde725dSArmin Le Grand                     const double fX(getX().isSet() ? getX().solve(*this, xcoordinate) : 0.0);
218ddde725dSArmin Le Grand                     const double fY(getY().isSet() ? getY().solve(*this, ycoordinate) : 0.0);
219ddde725dSArmin Le Grand                     const basegfx::B2DRange aTarget(fX, fY, fX + fWidth, fY + fHeight);
220ddde725dSArmin Le Grand                     basegfx::B2DRange aViewBox(aTarget);
221ddde725dSArmin Le Grand 
222ddde725dSArmin Le Grand                     if(maMimeType.getLength() && maData.getLength())
223ddde725dSArmin Le Grand                     {
224ddde725dSArmin Le Grand                         // use embedded base64 encoded data
225ddde725dSArmin Le Grand                         ::com::sun::star::uno::Sequence< sal_Int8 > aPass;
226ddde725dSArmin Le Grand                         ::sax::Converter::decodeBase64(aPass, maData);
227ddde725dSArmin Le Grand 
228ddde725dSArmin Le Grand                         if(aPass.hasElements())
229ddde725dSArmin Le Grand                         {
230ddde725dSArmin Le Grand                             SvMemoryStream aStream(aPass.getArray(), aPass.getLength(), STREAM_READ);
231ddde725dSArmin Le Grand                             Graphic aGraphic;
232ddde725dSArmin Le Grand 
233ddde725dSArmin Le Grand                             if(GRFILTER_OK == GraphicFilter::GetGraphicFilter()->ImportGraphic(
234ddde725dSArmin Le Grand                                 aGraphic,
235ddde725dSArmin Le Grand                                 String(),
236ddde725dSArmin Le Grand                                 aStream))
237ddde725dSArmin Le Grand                             {
238ddde725dSArmin Le Grand                                 extractFromGraphic(aGraphic, aNewTarget, aViewBox, aBitmapEx);
239ddde725dSArmin Le Grand                             }
240ddde725dSArmin Le Grand                         }
241ddde725dSArmin Le Grand                     }
242ddde725dSArmin Le Grand                     else if(maUrl.getLength())
243ddde725dSArmin Le Grand                     {
244ddde725dSArmin Le Grand                         const rtl::OUString& rPath = getDocument().getAbsolutePath();
245ddde725dSArmin Le Grand                         const rtl::OUString aAbsUrl(rtl::Uri::convertRelToAbs(rPath, maUrl));
246ddde725dSArmin Le Grand 
247ddde725dSArmin Le Grand                         if(aAbsUrl.getLength())
248ddde725dSArmin Le Grand                         {
249ddde725dSArmin Le Grand                             SvFileStream aStream(aAbsUrl, STREAM_STD_READ);
250ddde725dSArmin Le Grand                             Graphic aGraphic;
251ddde725dSArmin Le Grand 
252ddde725dSArmin Le Grand                             if(GRFILTER_OK == GraphicFilter::GetGraphicFilter()->ImportGraphic(
253ddde725dSArmin Le Grand                                 aGraphic,
254ddde725dSArmin Le Grand                                 aAbsUrl,
255ddde725dSArmin Le Grand                                 aStream))
256ddde725dSArmin Le Grand                             {
257ddde725dSArmin Le Grand                                 extractFromGraphic(aGraphic, aNewTarget, aViewBox, aBitmapEx);
258ddde725dSArmin Le Grand                             }
259ddde725dSArmin Le Grand                         }
260ddde725dSArmin Le Grand                     }
261ddde725dSArmin Le Grand                     else if(maXLink.getLength())
262ddde725dSArmin Le Grand                     {
263ddde725dSArmin Le Grand                         const SvgNode* mpXLink = getDocument().findSvgNodeById(maXLink);
264ddde725dSArmin Le Grand 
265ddde725dSArmin Le Grand                         if(mpXLink)
266ddde725dSArmin Le Grand                         {
267ddde725dSArmin Le Grand                             mpXLink->decomposeSvgNode(aNewTarget, true);
268ddde725dSArmin Le Grand 
269ddde725dSArmin Le Grand                             if(aNewTarget.hasElements())
270ddde725dSArmin Le Grand                             {
271ddde725dSArmin Le Grand                                 aViewBox = drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(
272ddde725dSArmin Le Grand                                     aNewTarget,
273ddde725dSArmin Le Grand                                     drawinglayer::geometry::ViewInformation2D());
274ddde725dSArmin Le Grand                             }
275ddde725dSArmin Le Grand                         }
276ddde725dSArmin Le Grand                     }
277ddde725dSArmin Le Grand 
278ddde725dSArmin Le Grand                     if(!aBitmapEx.IsEmpty())
279ddde725dSArmin Le Grand                     {
280ddde725dSArmin Le Grand                         // create content from created bitmap
281ddde725dSArmin Le Grand                         aNewTarget.realloc(1);
282ddde725dSArmin Le Grand                         aNewTarget[0] = new drawinglayer::primitive2d::BitmapPrimitive2D(
283ddde725dSArmin Le Grand                             aBitmapEx,
284ddde725dSArmin Le Grand                             basegfx::B2DHomMatrix());
285ddde725dSArmin Le Grand 
286ddde725dSArmin Le Grand                         // fill aViewBox. No size set yet, use unit size
287ddde725dSArmin Le Grand                         aViewBox = basegfx::B2DRange(0.0, 0.0, 1.0, 1.0);
288ddde725dSArmin Le Grand                     }
289ddde725dSArmin Le Grand 
290ddde725dSArmin Le Grand                     if(aNewTarget.hasElements())
291ddde725dSArmin Le Grand                     {
292ddde725dSArmin Le Grand                         if(aTarget.equal(aViewBox))
293ddde725dSArmin Le Grand                         {
294ddde725dSArmin Le Grand                             // just add to rTarget
295ddde725dSArmin Le Grand                             drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aNewTarget);
296ddde725dSArmin Le Grand                         }
297ddde725dSArmin Le Grand                         else
298ddde725dSArmin Le Grand                         {
299ddde725dSArmin Le Grand                             // create mapping
300ddde725dSArmin Le Grand                             const SvgAspectRatio& rRatio = getSvgAspectRatio();
301ddde725dSArmin Le Grand 
302ddde725dSArmin Le Grand                             if(rRatio.isSet())
303ddde725dSArmin Le Grand                             {
304ddde725dSArmin Le Grand                                 // let mapping be created from SvgAspectRatio
305ddde725dSArmin Le Grand                                 const basegfx::B2DHomMatrix aEmbeddingTransform(rRatio.createMapping(aTarget, aViewBox));
306ddde725dSArmin Le Grand 
307ddde725dSArmin Le Grand                                 if(!aEmbeddingTransform.isIdentity())
308ddde725dSArmin Le Grand                                 {
309ddde725dSArmin Le Grand                                     const drawinglayer::primitive2d::Primitive2DReference xRef(
310ddde725dSArmin Le Grand                                         new drawinglayer::primitive2d::TransformPrimitive2D(
311ddde725dSArmin Le Grand                                             aEmbeddingTransform,
312ddde725dSArmin Le Grand                                             aNewTarget));
313ddde725dSArmin Le Grand 
314ddde725dSArmin Le Grand                                     aNewTarget = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1);
315ddde725dSArmin Le Grand                                 }
316ddde725dSArmin Le Grand 
317ddde725dSArmin Le Grand                                 if(!rRatio.isMeetOrSlice())
318ddde725dSArmin Le Grand                                 {
319ddde725dSArmin Le Grand                                     // need to embed in MaskPrimitive2D to ensure clipping
320ddde725dSArmin Le Grand                                     const drawinglayer::primitive2d::Primitive2DReference xMask(
321ddde725dSArmin Le Grand                                         new drawinglayer::primitive2d::MaskPrimitive2D(
322ddde725dSArmin Le Grand                                             basegfx::B2DPolyPolygon(
323ddde725dSArmin Le Grand                                                 basegfx::tools::createPolygonFromRect(aTarget)),
324ddde725dSArmin Le Grand                                             aNewTarget));
325ddde725dSArmin Le Grand 
326ddde725dSArmin Le Grand                                     aNewTarget = drawinglayer::primitive2d::Primitive2DSequence(&xMask, 1);
327ddde725dSArmin Le Grand                                 }
328ddde725dSArmin Le Grand                             }
329ddde725dSArmin Le Grand                             else
330ddde725dSArmin Le Grand                             {
331ddde725dSArmin Le Grand                                 // choose default mapping
332ddde725dSArmin Le Grand                                 const basegfx::B2DHomMatrix aEmbeddingTransform(rRatio.createLinearMapping(aTarget, aViewBox));
333ddde725dSArmin Le Grand 
334ddde725dSArmin Le Grand                                 if(!aEmbeddingTransform.isIdentity())
335ddde725dSArmin Le Grand                                 {
336ddde725dSArmin Le Grand                                     const drawinglayer::primitive2d::Primitive2DReference xRef(
337ddde725dSArmin Le Grand                                         new drawinglayer::primitive2d::TransformPrimitive2D(
338ddde725dSArmin Le Grand                                             aEmbeddingTransform,
339ddde725dSArmin Le Grand                                             aNewTarget));
340ddde725dSArmin Le Grand 
341ddde725dSArmin Le Grand                                     aNewTarget = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1);
342ddde725dSArmin Le Grand                                 }
343ddde725dSArmin Le Grand                             }
344ddde725dSArmin Le Grand 
345ddde725dSArmin Le Grand                             // embed and add to rTarget, take local extra-transform into account
346ddde725dSArmin Le Grand                             pStyle->add_postProcess(rTarget, aNewTarget, getTransform());
347ddde725dSArmin Le Grand                         }
348ddde725dSArmin Le Grand                     }
349ddde725dSArmin Le Grand                 }
350ddde725dSArmin Le Grand             }
351ddde725dSArmin Le Grand         }
352ddde725dSArmin Le Grand 
353ddde725dSArmin Le Grand     } // end of namespace svgreader
354ddde725dSArmin Le Grand } // end of namespace svgio
355ddde725dSArmin Le Grand 
356ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
357ddde725dSArmin Le Grand // eof
358