1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 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/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 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 . 18 */ 19 20 #include <drawinglayer/primitive2d/metafileprimitive2d.hxx> 21 #include <wmfemfhelper.hxx> 22 23 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> 24 #include <drawinglayer/primitive2d/transformprimitive2d.hxx> 25 #include <basegfx/polygon/b2dpolygontools.hxx> 26 #include <drawinglayer/primitive2d/maskprimitive2d.hxx> 27 #include <vcl/canvastools.hxx> 28 29 using namespace com::sun::star; 30 31 namespace drawinglayer 32 { 33 namespace primitive2d 34 { create2DDecomposition(Primitive2DContainer & rContainer,const geometry::ViewInformation2D & rViewInformation) const35 void MetafilePrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& rViewInformation) const 36 { 37 // Interpret the Metafile and get the content. There should be only one target, as in the start condition, 38 // but iterating will be the right thing to do when some push/pop is not closed 39 Primitive2DContainer xRetval(wmfemfhelper::interpretMetafile(getMetaFile(), rViewInformation)); 40 41 if(!xRetval.empty()) 42 { 43 // get target size 44 const ::tools::Rectangle aMtfTarget(getMetaFile().GetPrefMapMode().GetOrigin(), getMetaFile().GetPrefSize()); 45 const basegfx::B2DRange aMtfRange(vcl::unotools::b2DRectangleFromRectangle(aMtfTarget)); 46 47 // tdf#113197 get content range and check if we have an overlap with 48 // defined target range (aMtfRange) 49 if (!aMtfRange.isEmpty()) 50 { 51 const basegfx::B2DRange aContentRange(xRetval.getB2DRange(rViewInformation)); 52 53 // also test equal since isInside gives also true for equal 54 if (!aMtfRange.equal(aContentRange) && !aMtfRange.isInside(aContentRange)) 55 { 56 // contentRange is partly larger than aMtfRange (stuff sticks 57 // outside), clipping is needed 58 const drawinglayer::primitive2d::Primitive2DReference xMask( 59 new drawinglayer::primitive2d::MaskPrimitive2D( 60 basegfx::B2DPolyPolygon( 61 basegfx::utils::createPolygonFromRect( 62 aMtfRange)), 63 xRetval)); 64 65 xRetval = drawinglayer::primitive2d::Primitive2DContainer{ xMask }; 66 } 67 } 68 69 // create transformation 70 basegfx::B2DHomMatrix aAdaptedTransform; 71 72 aAdaptedTransform.translate(-aMtfTarget.Left(), -aMtfTarget.Top()); 73 aAdaptedTransform.scale( 74 aMtfTarget.getWidth() ? 1.0 / aMtfTarget.getWidth() : 1.0, 75 aMtfTarget.getHeight() ? 1.0 / aMtfTarget.getHeight() : 1.0); 76 aAdaptedTransform = getTransform() * aAdaptedTransform; 77 78 // embed to target transformation 79 const Primitive2DReference aEmbeddedTransform( 80 new TransformPrimitive2D( 81 aAdaptedTransform, 82 xRetval)); 83 84 xRetval = Primitive2DContainer { aEmbeddedTransform }; 85 } 86 87 rContainer.insert(rContainer.end(), xRetval.begin(), xRetval.end()); 88 } 89 MetafilePrimitive2D(const basegfx::B2DHomMatrix & rMetaFileTransform,const GDIMetaFile & rMetaFile)90 MetafilePrimitive2D::MetafilePrimitive2D( 91 const basegfx::B2DHomMatrix& rMetaFileTransform, 92 const GDIMetaFile& rMetaFile) 93 : BufferedDecompositionPrimitive2D(), 94 maMetaFileTransform(rMetaFileTransform), 95 maMetaFile(rMetaFile) 96 { 97 } 98 operator ==(const BasePrimitive2D & rPrimitive) const99 bool MetafilePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const 100 { 101 if(BufferedDecompositionPrimitive2D::operator==(rPrimitive)) 102 { 103 const MetafilePrimitive2D& rCompare = static_cast<const MetafilePrimitive2D&>(rPrimitive); 104 105 return (getTransform() == rCompare.getTransform() 106 && getMetaFile() == rCompare.getMetaFile()); 107 } 108 109 return false; 110 } 111 getB2DRange(const geometry::ViewInformation2D &) const112 basegfx::B2DRange MetafilePrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const 113 { 114 // use own implementation to quickly answer the getB2DRange question. The 115 // MetafilePrimitive2D assumes that all geometry is inside of the shape. If 116 // this is not the case (i have already seen some wrong Metafiles) it should 117 // be embedded to a MaskPrimitive2D 118 basegfx::B2DRange aRetval(0.0, 0.0, 1.0, 1.0); 119 aRetval.transform(getTransform()); 120 121 return aRetval; 122 } 123 124 // from MetafileAccessor accessMetafile(GDIMetaFile & rTargetMetafile) const125 void MetafilePrimitive2D::accessMetafile(GDIMetaFile& rTargetMetafile) const 126 { 127 rTargetMetafile = maMetaFile; 128 } 129 130 // provide unique ID 131 ImplPrimitive2DIDBlock(MetafilePrimitive2D, PRIMITIVE2D_ID_METAFILEPRIMITIVE2D) 132 133 } // end of namespace primitive2d 134 } // end of namespace drawinglayer 135 136 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 137