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