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                 // get original object scale in unit coordinates (no mirroring)
83                 const basegfx::B2DVector aObjectScale(basegfx::absolute(getTransformation() * basegfx::B2DVector(1.0, 1.0)));
84 
85                 // we handle cropping, so when no width or no height, content will be empty,
86                 // so only do something when we have a width and a height
87                 if(!aObjectScale.equalZero())
88                 {
89                     // calculate crop distances in unit coordinates. They are already combined with CropScaleFactor, thus
90                     // are relative only to object scale
91                     const double fBackScaleX(basegfx::fTools::equalZero(aObjectScale.getX()) ? 1.0 : 1.0 / fabs(aObjectScale.getX()));
92                     const double fBackScaleY(basegfx::fTools::equalZero(aObjectScale.getY()) ? 1.0 : 1.0 / fabs(aObjectScale.getY()));
93                     const double fLeft(getCropLeft() * fBackScaleX);
94                     const double fTop(getCropTop() * fBackScaleY);
95                     const double fRight(getCropRight() * fBackScaleX);
96                     const double fBottom(getCropBottom() * fBackScaleY);
97 
98                     // calc new unit range for comparisons; the original range is the unit range
99                     const basegfx::B2DRange aUnitRange(0.0, 0.0, 1.0, 1.0);
100                     const basegfx::B2DRange aNewRange(
101                         -fLeft,
102                         -fTop,
103                         1.0 + fRight,
104                         1.0 + fBottom);
105 
106                     // if we have no overlap the crop has removed everything, so we do only
107                     // have to create content if this is not the case
108                     if(aNewRange.overlaps(aUnitRange))
109                     {
110                         // create new transform; first take out old transform to get
111                         // to unit coordinates by inverting. Inverting should be flawless
112                         // since we already cheched that object size is not zero in X or Y
113                         basegfx::B2DHomMatrix aNewTransform(getTransformation());
114 
115                         aNewTransform.invert();
116 
117                         // apply crop enlargement in unit coordinates
118                         aNewTransform = basegfx::tools::createScaleTranslateB2DHomMatrix(
119                             aNewRange.getRange(),
120                             aNewRange.getMinimum()) * aNewTransform;
121 
122                         // apply original transformation. Since we have manipulated the crop
123                         // in unit coordinates we do not need to care about mirroring or
124                         // a corrected point for eventual shear or rotation, this all comes for
125                         // free
126                         aNewTransform = getTransformation() * aNewTransform;
127 
128                         // prepare TransformPrimitive2D with xPrimitive
129                         const Primitive2DReference xTransformPrimitive(
130                             new TransformPrimitive2D(
131                                 aNewTransform,
132                                 getChildren()));
133 
134                         if(aUnitRange.isInside(aNewRange))
135                         {
136                             // the new range is completely inside the old range (unit range),
137                             // so no masking is needed
138                             xRetval = Primitive2DSequence(&xTransformPrimitive, 1);
139                         }
140                         else
141                         {
142                             // mask with original object's bounds
143                             basegfx::B2DPolyPolygon aMaskPolyPolygon(basegfx::tools::createUnitPolygon());
144                             aMaskPolyPolygon.transform(getTransformation());
145 
146                             // create maskPrimitive with aMaskPolyPolygon and aMaskContentVector
147                             const Primitive2DReference xMask(
148                                 new MaskPrimitive2D(
149                                     aMaskPolyPolygon,
150                                     Primitive2DSequence(&xTransformPrimitive, 1)));
151 
152                             xRetval = Primitive2DSequence(&xMask, 1);
153                         }
154                     }
155                 }
156             }
157 
158             return xRetval;
159         }
160 
161         // provide unique ID
162         ImplPrimitrive2DIDBlock(CropPrimitive2D, PRIMITIVE2D_ID_CROPPRIMITIVE2D)
163 
164     } // end of namespace primitive2d
165 } // end of namespace drawinglayer
166 
167 //////////////////////////////////////////////////////////////////////////////
168 // eof
169