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 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_drawinglayer.hxx"
26 
27 #include <drawinglayer/primitive2d/cropprimitive2d.hxx>
28 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
29 #include <basegfx/matrix/b2dhommatrix.hxx>
30 #include <basegfx/matrix/b2dhommatrixtools.hxx>
31 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
32 #include <basegfx/polygon/b2dpolygon.hxx>
33 #include <basegfx/polygon/b2dpolygontools.hxx>
34 #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
35 
36 //////////////////////////////////////////////////////////////////////////////
37 
38 using namespace com::sun::star;
39 
40 //////////////////////////////////////////////////////////////////////////////
41 
42 namespace drawinglayer
43 {
44     namespace primitive2d
45     {
CropPrimitive2D(const Primitive2DSequence & rChildren,const basegfx::B2DHomMatrix & rTransformation,double fCropLeft,double fCropTop,double fCropRight,double fCropBottom)46         CropPrimitive2D::CropPrimitive2D(
47             const Primitive2DSequence& rChildren,
48             const basegfx::B2DHomMatrix& rTransformation,
49             double fCropLeft,
50             double fCropTop,
51             double fCropRight,
52             double fCropBottom)
53         :   GroupPrimitive2D(rChildren),
54             maTransformation(rTransformation),
55             mfCropLeft(fCropLeft),
56             mfCropTop(fCropTop),
57             mfCropRight(fCropRight),
58             mfCropBottom(fCropBottom)
59         {
60         }
61 
operator ==(const BasePrimitive2D & rPrimitive) const62         bool CropPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
63         {
64             if(GroupPrimitive2D::operator==(rPrimitive))
65             {
66                 const CropPrimitive2D& rCompare = static_cast< const CropPrimitive2D& >(rPrimitive);
67 
68                 return (getTransformation() == rCompare.getTransformation()
69                     && getCropLeft() == rCompare.getCropLeft()
70                     && getCropTop() == rCompare.getCropTop()
71                     && getCropRight() == rCompare.getCropRight()
72                     && getCropBottom() == rCompare.getCropBottom());
73             }
74 
75             return false;
76         }
77 
get2DDecomposition(const geometry::ViewInformation2D &) const78         Primitive2DSequence CropPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
79         {
80             Primitive2DSequence xRetval;
81 
82             if(getChildren().hasElements())
83             {
84                 // get original object scale in unit coordinates (no mirroring)
85                 const basegfx::B2DVector aObjectScale(basegfx::absolute(getTransformation() * basegfx::B2DVector(1.0, 1.0)));
86 
87                 // we handle cropping, so when no width or no height, content will be empty,
88                 // so only do something when we have a width and a height
89                 if(!aObjectScale.equalZero())
90                 {
91                     // calculate crop distances in unit coordinates. They are already combined with CropScaleFactor, thus
92                     // are relative only to object scale
93                     const double fBackScaleX(basegfx::fTools::equalZero(aObjectScale.getX()) ? 1.0 : 1.0 / fabs(aObjectScale.getX()));
94                     const double fBackScaleY(basegfx::fTools::equalZero(aObjectScale.getY()) ? 1.0 : 1.0 / fabs(aObjectScale.getY()));
95                     const double fLeft(getCropLeft() * fBackScaleX);
96                     const double fTop(getCropTop() * fBackScaleY);
97                     const double fRight(getCropRight() * fBackScaleX);
98                     const double fBottom(getCropBottom() * fBackScaleY);
99 
100                     // calculate new unit range for comparisons; the original range is the unit range
101                     const basegfx::B2DRange aUnitRange(0.0, 0.0, 1.0, 1.0);
102                     const basegfx::B2DRange aNewRange(
103                         -fLeft,
104                         -fTop,
105                         1.0 + fRight,
106                         1.0 + fBottom);
107 
108                     // if we have no overlap the crop has removed everything, so we do only
109                     // have to create content if this is not the case
110                     if(aNewRange.overlaps(aUnitRange))
111                     {
112                         // create new transform; first take out old transform to get
113                         // to unit coordinates by inverting. Inverting should be flawless
114                         // since we already checked that object size is not zero in X or Y
115                         basegfx::B2DHomMatrix aNewTransform(getTransformation());
116 
117                         aNewTransform.invert();
118 
119                         // apply crop enlargement in unit coordinates
120                         aNewTransform = basegfx::tools::createScaleTranslateB2DHomMatrix(
121                             aNewRange.getRange(),
122                             aNewRange.getMinimum()) * aNewTransform;
123 
124                         // apply original transformation. Since we have manipulated the crop
125                         // in unit coordinates we do not need to care about mirroring or
126                         // a corrected point for eventual shear or rotation, this all comes for
127                         // free
128                         aNewTransform = getTransformation() * aNewTransform;
129 
130                         // prepare TransformPrimitive2D with xPrimitive
131                         const Primitive2DReference xTransformPrimitive(
132                             new TransformPrimitive2D(
133                                 aNewTransform,
134                                 getChildren()));
135 
136                         if(aUnitRange.isInside(aNewRange))
137                         {
138                             // the new range is completely inside the old range (unit range),
139                             // so no masking is needed
140                             xRetval = Primitive2DSequence(&xTransformPrimitive, 1);
141                         }
142                         else
143                         {
144                             // mask with original object's bounds
145                             basegfx::B2DPolyPolygon aMaskPolyPolygon(basegfx::tools::createUnitPolygon());
146                             aMaskPolyPolygon.transform(getTransformation());
147 
148                             // create maskPrimitive with aMaskPolyPolygon and aMaskContentVector
149                             const Primitive2DReference xMask(
150                                 new MaskPrimitive2D(
151                                     aMaskPolyPolygon,
152                                     Primitive2DSequence(&xTransformPrimitive, 1)));
153 
154                             xRetval = Primitive2DSequence(&xMask, 1);
155                         }
156                     }
157                 }
158             }
159 
160             return xRetval;
161         }
162 
163         // provide unique ID
164         ImplPrimitrive2DIDBlock(CropPrimitive2D, PRIMITIVE2D_ID_CROPPRIMITIVE2D)
165 
166     } // end of namespace primitive2d
167 } // end of namespace drawinglayer
168 
169 /* vim: set noet sw=4 ts=4: */
170