/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_svgio.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include ////////////////////////////////////////////////////////////////////////////// namespace svgio { namespace svgreader { SvgImageNode::SvgImageNode( SvgDocument& rDocument, SvgNode* pParent) : SvgNode(SVGTokenRect, rDocument, pParent), maSvgStyleAttributes(*this), maSvgAspectRatio(), mpaTransform(0), maX(0), maY(0), maWidth(0), maHeight(0), maXLink(), maUrl(), maMimeType(), maData() { } SvgImageNode::~SvgImageNode() { if(mpaTransform) delete mpaTransform; } const SvgStyleAttributes* SvgImageNode::getSvgStyleAttributes() const { static rtl::OUString aClassStr(rtl::OUString::createFromAscii("image")); return checkForCssStyle(aClassStr, maSvgStyleAttributes); } void SvgImageNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent) { // call parent SvgNode::parseAttribute(rTokenName, aSVGToken, aContent); // read style attributes maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent, false); // parse own switch(aSVGToken) { case SVGTokenStyle: { readLocalCssStyle(aContent); break; } case SVGTokenPreserveAspectRatio: { setSvgAspectRatio(readSvgAspectRatio(aContent)); break; } case SVGTokenTransform: { const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this)); if(!aMatrix.isIdentity()) { setTransform(&aMatrix); } break; } case SVGTokenX: { SvgNumber aNum; if(readSingleNumber(aContent, aNum)) { setX(aNum); } break; } case SVGTokenY: { SvgNumber aNum; if(readSingleNumber(aContent, aNum)) { setY(aNum); } break; } case SVGTokenWidth: { SvgNumber aNum; if(readSingleNumber(aContent, aNum)) { if(aNum.isPositive()) { setWidth(aNum); } } break; } case SVGTokenHeight: { SvgNumber aNum; if(readSingleNumber(aContent, aNum)) { if(aNum.isPositive()) { setHeight(aNum); } } break; } case SVGTokenXlinkHref: { const sal_Int32 nLen(aContent.getLength()); if(nLen) { readImageLink(aContent, maXLink, maUrl, maMimeType, maData); } break; } default: { break; } } } void extractFromGraphic( const Graphic& rGraphic, drawinglayer::primitive2d::Primitive2DSequence& rEmbedded, basegfx::B2DRange& rViewBox, BitmapEx& rBitmapEx) { if(GRAPHIC_BITMAP == rGraphic.GetType()) { if(rGraphic.getSvgData().get()) { // embedded Svg rEmbedded = rGraphic.getSvgData()->getPrimitive2DSequence(); // fill aViewBox rViewBox = rGraphic.getSvgData()->getRange(); } else { // get bitmap rBitmapEx = rGraphic.GetBitmapEx(); } } else { // evtl. convert to bitmap rBitmapEx = rGraphic.GetBitmapEx(); } } void SvgImageNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool /*bReferenced*/) const { // get size range and create path const SvgStyleAttributes* pStyle = getSvgStyleAttributes(); if(pStyle && getWidth().isSet() && getHeight().isSet()) { const double fWidth(getWidth().solve(*this, xcoordinate)); const double fHeight(getHeight().solve(*this, ycoordinate)); if(fWidth > 0.0 && fHeight > 0.0) { BitmapEx aBitmapEx; drawinglayer::primitive2d::Primitive2DSequence aNewTarget; // prepare Target and ViewBox for evtl. AspectRatio mappings const double fX(getX().isSet() ? getX().solve(*this, xcoordinate) : 0.0); const double fY(getY().isSet() ? getY().solve(*this, ycoordinate) : 0.0); const basegfx::B2DRange aTarget(fX, fY, fX + fWidth, fY + fHeight); basegfx::B2DRange aViewBox(aTarget); if(maMimeType.getLength() && maData.getLength()) { // use embedded base64 encoded data ::com::sun::star::uno::Sequence< sal_Int8 > aPass; ::sax::Converter::decodeBase64(aPass, maData); if(aPass.hasElements()) { SvMemoryStream aStream(aPass.getArray(), aPass.getLength(), STREAM_READ); Graphic aGraphic; if(GRFILTER_OK == GraphicFilter::GetGraphicFilter()->ImportGraphic( aGraphic, String(), aStream)) { extractFromGraphic(aGraphic, aNewTarget, aViewBox, aBitmapEx); } } } else if(maUrl.getLength()) { const rtl::OUString& rPath = getDocument().getAbsolutePath(); if(rPath.getLength()) { const rtl::OUString aAbsUrl(rtl::Uri::convertRelToAbs(rPath, maUrl)); if(aAbsUrl.getLength()) { SvFileStream aStream(aAbsUrl, STREAM_STD_READ); Graphic aGraphic; if(GRFILTER_OK == GraphicFilter::GetGraphicFilter()->ImportGraphic( aGraphic, aAbsUrl, aStream)) { extractFromGraphic(aGraphic, aNewTarget, aViewBox, aBitmapEx); } } } else { // #123042# detect missing path and assert - content will be missing. The // absolute path to itself needs to be set to correctly import linked // content in a SVG file OSL_ENSURE(false, "SVG graphic with internal links is interpreted, but local AbsolutePath is not set: linked content will be missing (!)"); } } else if(maXLink.getLength()) { const SvgNode* mpXLink = getDocument().findSvgNodeById(maXLink); if(mpXLink && Display_none != mpXLink->getDisplay()) { mpXLink->decomposeSvgNode(aNewTarget, true); if(aNewTarget.hasElements()) { aViewBox = drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence( aNewTarget, drawinglayer::geometry::ViewInformation2D()); } } } if(!aBitmapEx.IsEmpty()) { // create content from created bitmap aNewTarget.realloc(1); aNewTarget[0] = new drawinglayer::primitive2d::BitmapPrimitive2D( aBitmapEx, basegfx::B2DHomMatrix()); // fill aViewBox. No size set yet, use unit size aViewBox = basegfx::B2DRange(0.0, 0.0, 1.0, 1.0); } if(aNewTarget.hasElements()) { if(aTarget.equal(aViewBox)) { // just add to rTarget drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aNewTarget); } else { // create mapping const SvgAspectRatio& rRatio = getSvgAspectRatio(); if(rRatio.isSet()) { // let mapping be created from SvgAspectRatio const basegfx::B2DHomMatrix aEmbeddingTransform(rRatio.createMapping(aTarget, aViewBox)); if(!aEmbeddingTransform.isIdentity()) { const drawinglayer::primitive2d::Primitive2DReference xRef( new drawinglayer::primitive2d::TransformPrimitive2D( aEmbeddingTransform, aNewTarget)); aNewTarget = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1); } if(!rRatio.isMeetOrSlice()) { // need to embed in MaskPrimitive2D to ensure clipping const drawinglayer::primitive2d::Primitive2DReference xMask( new drawinglayer::primitive2d::MaskPrimitive2D( basegfx::B2DPolyPolygon( basegfx::tools::createPolygonFromRect(aTarget)), aNewTarget)); aNewTarget = drawinglayer::primitive2d::Primitive2DSequence(&xMask, 1); } } else { // choose default mapping const basegfx::B2DHomMatrix aEmbeddingTransform(rRatio.createLinearMapping(aTarget, aViewBox)); if(!aEmbeddingTransform.isIdentity()) { const drawinglayer::primitive2d::Primitive2DReference xRef( new drawinglayer::primitive2d::TransformPrimitive2D( aEmbeddingTransform, aNewTarget)); aNewTarget = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1); } } // embed and add to rTarget, take local extra-transform into account pStyle->add_postProcess(rTarget, aNewTarget, getTransform()); } } } } } } // end of namespace svgreader } // end of namespace svgio ////////////////////////////////////////////////////////////////////////////// // eof