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/svgimagenode.hxx>
21 #include <svgio/svgreader/svgdocument.hxx>
22 #include <sax/tools/converter.hxx>
23 #include <tools/stream.hxx>
24 #include <vcl/bitmapex.hxx>
25 #include <vcl/graphicfilter.hxx>
26 #include <basegfx/matrix/b2dhommatrixtools.hxx>
27 #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
28 #include <drawinglayer/primitive2d/groupprimitive2d.hxx>
29 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
30 #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
31 #include <basegfx/polygon/b2dpolygontools.hxx>
32 #include <basegfx/polygon/b2dpolygon.hxx>
33 #include <rtl/uri.hxx>
34 #include <drawinglayer/geometry/viewinformation2d.hxx>
36 //////////////////////////////////////////////////////////////////////////////
42 SvgImageNode::SvgImageNode(
43 SvgDocument
& rDocument
,
45 : SvgNode(SVGTokenRect
, rDocument
, pParent
),
46 maSvgStyleAttributes(*this),
60 SvgImageNode::~SvgImageNode()
62 if(mpaTransform
) delete mpaTransform
;
65 const SvgStyleAttributes
* SvgImageNode::getSvgStyleAttributes() const
67 static rtl::OUString
aClassStr(rtl::OUString::createFromAscii("image"));
68 return checkForCssStyle(aClassStr
, maSvgStyleAttributes
);
71 void SvgImageNode::parseAttribute(const OUString
& rTokenName
, SVGToken aSVGToken
, const OUString
& aContent
)
74 SvgNode::parseAttribute(rTokenName
, aSVGToken
, aContent
);
76 // read style attributes
77 maSvgStyleAttributes
.parseStyleAttribute(rTokenName
, aSVGToken
, aContent
);
84 maSvgStyleAttributes
.readStyle(aContent
);
87 case SVGTokenPreserveAspectRatio
:
89 setSvgAspectRatio(readSvgAspectRatio(aContent
));
92 case SVGTokenTransform
:
94 const basegfx::B2DHomMatrix
aMatrix(readTransform(aContent
, *this));
96 if(!aMatrix
.isIdentity())
98 setTransform(&aMatrix
);
106 if(readSingleNumber(aContent
, aNum
))
116 if(readSingleNumber(aContent
, aNum
))
126 if(readSingleNumber(aContent
, aNum
))
128 if(aNum
.isPositive())
139 if(readSingleNumber(aContent
, aNum
))
141 if(aNum
.isPositive())
148 case SVGTokenXlinkHref
:
150 const sal_Int32
nLen(aContent
.getLength());
154 readImageLink(aContent
, maXLink
, maUrl
, maMimeType
, maData
);
165 void extractFromGraphic(
166 const Graphic
& rGraphic
,
167 drawinglayer::primitive2d::Primitive2DSequence
& rEmbedded
,
168 basegfx::B2DRange
& rViewBox
,
171 if(GRAPHIC_BITMAP
== rGraphic
.GetType())
173 if(rGraphic
.getSvgData().get())
176 rEmbedded
= rGraphic
.getSvgData()->getPrimitive2DSequence();
179 rViewBox
= rGraphic
.getSvgData()->getRange();
184 rBitmapEx
= rGraphic
.GetBitmapEx();
189 // evtl. convert to bitmap
190 rBitmapEx
= rGraphic
.GetBitmapEx();
194 void SvgImageNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence
& rTarget
, bool /*bReferenced*/) const
196 // get size range and create path
197 const SvgStyleAttributes
* pStyle
= getSvgStyleAttributes();
199 if(pStyle
&& getWidth().isSet() && getHeight().isSet())
201 const double fWidth(getWidth().solve(*this, xcoordinate
));
202 const double fHeight(getHeight().solve(*this, ycoordinate
));
204 if(fWidth
> 0.0 && fHeight
> 0.0)
207 drawinglayer::primitive2d::Primitive2DSequence aNewTarget
;
209 // prepare Target and ViewBox for evtl. AspectRatio mappings
210 const double fX(getX().isSet() ? getX().solve(*this, xcoordinate
) : 0.0);
211 const double fY(getY().isSet() ? getY().solve(*this, ycoordinate
) : 0.0);
212 const basegfx::B2DRange
aTarget(fX
, fY
, fX
+ fWidth
, fY
+ fHeight
);
213 basegfx::B2DRange
aViewBox(aTarget
);
215 if(maMimeType
.getLength() && maData
.getLength())
217 // use embedded base64 encoded data
218 ::com::sun::star::uno::Sequence
< sal_Int8
> aPass
;
219 ::sax::Converter::decodeBase64(aPass
, maData
);
221 if(aPass
.hasElements())
223 SvMemoryStream
aStream(aPass
.getArray(), aPass
.getLength(), STREAM_READ
);
226 if(GRFILTER_OK
== GraphicFilter::GetGraphicFilter().ImportGraphic(
231 extractFromGraphic(aGraphic
, aNewTarget
, aViewBox
, aBitmapEx
);
235 else if(maUrl
.getLength())
237 const OUString
& rPath
= getDocument().getAbsolutePath();
238 const OUString
aAbsUrl(rtl::Uri::convertRelToAbs(rPath
, maUrl
));
240 if(aAbsUrl
.getLength())
242 SvFileStream
aStream(aAbsUrl
, STREAM_STD_READ
);
245 if(GRFILTER_OK
== GraphicFilter::GetGraphicFilter().ImportGraphic(
250 extractFromGraphic(aGraphic
, aNewTarget
, aViewBox
, aBitmapEx
);
254 else if(maXLink
.getLength())
256 const SvgNode
* mpXLink
= getDocument().findSvgNodeById(maXLink
);
260 mpXLink
->decomposeSvgNode(aNewTarget
, true);
262 if(aNewTarget
.hasElements())
264 aViewBox
= drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(
266 drawinglayer::geometry::ViewInformation2D());
271 if(!aBitmapEx
.IsEmpty())
273 // create content from created bitmap
274 aNewTarget
.realloc(1);
275 aNewTarget
[0] = new drawinglayer::primitive2d::BitmapPrimitive2D(
277 basegfx::B2DHomMatrix());
279 // fill aViewBox. No size set yet, use unit size
280 aViewBox
= basegfx::B2DRange(0.0, 0.0, 1.0, 1.0);
283 if(aNewTarget
.hasElements())
285 if(aTarget
.equal(aViewBox
))
287 // just add to rTarget
288 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget
, aNewTarget
);
293 const SvgAspectRatio
& rRatio
= getSvgAspectRatio();
297 // let mapping be created from SvgAspectRatio
298 const basegfx::B2DHomMatrix
aEmbeddingTransform(rRatio
.createMapping(aTarget
, aViewBox
));
300 if(!aEmbeddingTransform
.isIdentity())
302 const drawinglayer::primitive2d::Primitive2DReference
xRef(
303 new drawinglayer::primitive2d::TransformPrimitive2D(
307 aNewTarget
= drawinglayer::primitive2d::Primitive2DSequence(&xRef
, 1);
310 if(!rRatio
.isMeetOrSlice())
312 // need to embed in MaskPrimitive2D to ensure clipping
313 const drawinglayer::primitive2d::Primitive2DReference
xMask(
314 new drawinglayer::primitive2d::MaskPrimitive2D(
315 basegfx::B2DPolyPolygon(
316 basegfx::tools::createPolygonFromRect(aTarget
)),
319 aNewTarget
= drawinglayer::primitive2d::Primitive2DSequence(&xMask
, 1);
324 // choose default mapping
325 const basegfx::B2DHomMatrix
aEmbeddingTransform(rRatio
.createLinearMapping(aTarget
, aViewBox
));
327 if(!aEmbeddingTransform
.isIdentity())
329 const drawinglayer::primitive2d::Primitive2DReference
xRef(
330 new drawinglayer::primitive2d::TransformPrimitive2D(
334 aNewTarget
= drawinglayer::primitive2d::Primitive2DSequence(&xRef
, 1);
338 // embed and add to rTarget, take local extra-transform into account
339 pStyle
->add_postProcess(rTarget
, aNewTarget
, getTransform());
346 } // end of namespace svgreader
347 } // end of namespace svgio
349 //////////////////////////////////////////////////////////////////////////////
352 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */