1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 // MARKER(update_precomp.py): autogen include statement, do not remove 23 #include "precompiled_drawinglayer.hxx" 24 25 #include <drawinglayer/primitive2d/cropprimitive2d.hxx> 26 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> 27 #include <basegfx/matrix/b2dhommatrix.hxx> 28 #include <basegfx/matrix/b2dhommatrixtools.hxx> 29 #include <drawinglayer/primitive2d/transformprimitive2d.hxx> 30 #include <basegfx/polygon/b2dpolygon.hxx> 31 #include <basegfx/polygon/b2dpolygontools.hxx> 32 #include <drawinglayer/primitive2d/maskprimitive2d.hxx> 33 34 ////////////////////////////////////////////////////////////////////////////// 35 36 using namespace com::sun::star; 37 38 ////////////////////////////////////////////////////////////////////////////// 39 40 namespace drawinglayer 41 { 42 namespace primitive2d 43 { 44 CropPrimitive2D::CropPrimitive2D( 45 const Primitive2DSequence& rChildren, 46 const basegfx::B2DHomMatrix& rTransformation, 47 double fCropLeft, 48 double fCropTop, 49 double fCropRight, 50 double fCropBottom) 51 : GroupPrimitive2D(rChildren), 52 maTransformation(rTransformation), 53 mfCropLeft(fCropLeft), 54 mfCropTop(fCropTop), 55 mfCropRight(fCropRight), 56 mfCropBottom(fCropBottom) 57 { 58 } 59 60 bool CropPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const 61 { 62 if(GroupPrimitive2D::operator==(rPrimitive)) 63 { 64 const CropPrimitive2D& rCompare = static_cast< const CropPrimitive2D& >(rPrimitive); 65 66 return (getTransformation() == rCompare.getTransformation() 67 && getCropLeft() == rCompare.getCropLeft() 68 && getCropTop() == rCompare.getCropTop() 69 && getCropRight() == rCompare.getCropRight() 70 && getCropBottom() == rCompare.getCropBottom()); 71 } 72 73 return false; 74 } 75 76 Primitive2DSequence CropPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const 77 { 78 Primitive2DSequence xRetval; 79 80 if(getChildren().hasElements()) 81 { 82 // decompose to have current translate and scale 83 basegfx::B2DVector aScale, aTranslate; 84 double fRotate, fShearX; 85 86 getTransformation().decompose(aScale, aTranslate, fRotate, fShearX); 87 88 // detect 180 degree rotation, this is the same as mirrored in X and Y, 89 // thus change to mirroring. Prefer mirroring here. Use the equal call 90 // with getSmallValue here, the original which uses rtl::math::approxEqual 91 // is too correct here. Maybe this changes with enhanced precision in aw080 92 // to the better so that this can be reduced to the more precise call again 93 if(basegfx::fTools::equal(fabs(fRotate), F_PI, 0.000000001)) 94 { 95 aScale.setX(aScale.getX() * -1.0); 96 aScale.setY(aScale.getY() * -1.0); 97 fRotate = 0.0; 98 } 99 100 // create target translate and scale 101 const bool bMirroredX(aScale.getX() < 0.0); 102 const bool bMirroredY(aScale.getY() < 0.0); 103 basegfx::B2DVector aTargetScale(aScale); 104 basegfx::B2DVector aTargetTranslate(aTranslate); 105 106 if(bMirroredX) 107 { 108 aTargetTranslate.setX(aTargetTranslate.getX() + getCropRight()); 109 aTargetScale.setX(aTargetScale.getX() - getCropLeft() - getCropRight()); 110 } 111 else 112 { 113 aTargetTranslate.setX(aTargetTranslate.getX() - getCropLeft()); 114 aTargetScale.setX(aTargetScale.getX() + getCropRight() + getCropLeft()); 115 } 116 117 if(bMirroredY) 118 { 119 aTargetTranslate.setY(aTargetTranslate.getY() + getCropBottom()); 120 aTargetScale.setY(aTargetScale.getY() - getCropTop() - getCropBottom()); 121 } 122 else 123 { 124 aTargetTranslate.setY(aTargetTranslate.getY() - getCropTop()); 125 aTargetScale.setY(aTargetScale.getY() + getCropBottom() + getCropTop()); 126 } 127 128 // create ranges to make comparisons 129 const basegfx::B2DRange aCurrent( 130 aTranslate.getX(), aTranslate.getY(), 131 aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY()); 132 const basegfx::B2DRange aCropped( 133 aTargetTranslate.getX(), aTargetTranslate.getY(), 134 aTargetTranslate.getX() + aTargetScale.getX(), aTargetTranslate.getY() + aTargetScale.getY()); 135 136 if(aCropped.isEmpty()) 137 { 138 // nothing to return since cropped content is completely empty 139 } 140 else if(aCurrent.equal(aCropped)) 141 { 142 // no crop, just use content 143 xRetval = getChildren(); 144 } 145 else 146 { 147 // build new combined content transformation 148 basegfx::B2DHomMatrix aNewObjectTransform(getTransformation()); 149 150 // remove content transform by inverting 151 aNewObjectTransform.invert(); 152 153 // add target values and original shear/rotate 154 aNewObjectTransform = basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix( 155 aTargetScale.getX(), 156 aTargetScale.getY(), 157 fShearX, 158 fRotate, 159 aTargetTranslate.getX(), 160 aTargetTranslate.getY()) 161 * aNewObjectTransform; 162 163 // prepare TransformPrimitive2D with xPrimitive 164 const Primitive2DReference xTransformPrimitive( 165 new TransformPrimitive2D( 166 aNewObjectTransform, 167 getChildren())); 168 169 if(aCurrent.isInside(aCropped)) 170 { 171 // crop just shrunk so that its inside content, 172 // no need to use a mask since not really cropped. 173 xRetval = Primitive2DSequence(&xTransformPrimitive, 1); 174 } 175 else 176 { 177 // mask with original object's bounds 178 basegfx::B2DPolyPolygon aMaskPolyPolygon(basegfx::tools::createUnitPolygon()); 179 aMaskPolyPolygon.transform(getTransformation()); 180 181 // create maskPrimitive with aMaskPolyPolygon and aMaskContentVector 182 const Primitive2DReference xMask( 183 new MaskPrimitive2D( 184 aMaskPolyPolygon, 185 Primitive2DSequence(&xTransformPrimitive, 1))); 186 187 xRetval = Primitive2DSequence(&xMask, 1); 188 } 189 } 190 } 191 192 return xRetval; 193 } 194 195 // provide unique ID 196 ImplPrimitrive2DIDBlock(CropPrimitive2D, PRIMITIVE2D_ID_CROPPRIMITIVE2D) 197 198 } // end of namespace primitive2d 199 } // end of namespace drawinglayer 200 201 ////////////////////////////////////////////////////////////////////////////// 202 // eof 203