1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <drawinglayer/primitive2d/cropprimitive2d.hxx>
21 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
22 #include <basegfx/matrix/b2dhommatrix.hxx>
23 #include <basegfx/matrix/b2dhommatrixtools.hxx>
24 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
25 #include <basegfx/polygon/b2dpolygon.hxx>
26 #include <basegfx/polygon/b2dpolygontools.hxx>
27 #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
29 //////////////////////////////////////////////////////////////////////////////
31 using namespace com::sun::star
;
33 //////////////////////////////////////////////////////////////////////////////
35 namespace drawinglayer
39 CropPrimitive2D::CropPrimitive2D(
40 const Primitive2DSequence
& rChildren
,
41 const basegfx::B2DHomMatrix
& rTransformation
,
46 : GroupPrimitive2D(rChildren
),
47 maTransformation(rTransformation
),
48 mfCropLeft(fCropLeft
),
50 mfCropRight(fCropRight
),
51 mfCropBottom(fCropBottom
)
55 bool CropPrimitive2D::operator==(const BasePrimitive2D
& rPrimitive
) const
57 if(GroupPrimitive2D::operator==(rPrimitive
))
59 const CropPrimitive2D
& rCompare
= static_cast< const CropPrimitive2D
& >(rPrimitive
);
61 return (getTransformation() == rCompare
.getTransformation()
62 && getCropLeft() == rCompare
.getCropLeft()
63 && getCropTop() == rCompare
.getCropTop()
64 && getCropRight() == rCompare
.getCropRight()
65 && getCropBottom() == rCompare
.getCropBottom());
71 Primitive2DSequence
CropPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D
& /*rViewInformation*/) const
73 Primitive2DSequence xRetval
;
75 if(getChildren().hasElements())
77 // decompose to have current translate and scale
78 basegfx::B2DVector aScale
, aTranslate
;
79 double fRotate
, fShearX
;
81 getTransformation().decompose(aScale
, aTranslate
, fRotate
, fShearX
);
83 // detect 180 degree rotation, this is the same as mirrored in X and Y,
84 // thus change to mirroring. Prefer mirroring here. Use the equal call
85 // with getSmallValue here, the original which uses rtl::math::approxEqual
86 // is too correct here. Maybe this changes with enhanced precision in aw080
87 // to the better so that this can be reduced to the more precise call again
88 if(basegfx::fTools::equal(fRotate
, F_PI
, 0.000000001))
90 aScale
.setX(aScale
.getX() * -1.0);
91 aScale
.setY(aScale
.getY() * -1.0);
95 // create target translate and scale
96 const bool bMirroredX(aScale
.getX() < 0.0);
97 const bool bMirroredY(aScale
.getY() < 0.0);
98 basegfx::B2DVector
aTargetScale(aScale
);
99 basegfx::B2DVector
aTargetTranslate(aTranslate
);
103 aTargetTranslate
.setX(aTargetTranslate
.getX() + getCropRight());
104 aTargetScale
.setX(aTargetScale
.getX() - getCropLeft() - getCropRight());
108 aTargetTranslate
.setX(aTargetTranslate
.getX() - getCropLeft());
109 aTargetScale
.setX(aTargetScale
.getX() + getCropRight() + getCropLeft());
114 aTargetTranslate
.setY(aTargetTranslate
.getY() + getCropBottom());
115 aTargetScale
.setY(aTargetScale
.getY() - getCropTop() - getCropBottom());
119 aTargetTranslate
.setY(aTargetTranslate
.getY() - getCropTop());
120 aTargetScale
.setY(aTargetScale
.getY() + getCropBottom() + getCropTop());
123 // create ranges to make comparisons
124 const basegfx::B2DRange
aCurrent(
125 aTranslate
.getX(), aTranslate
.getY(),
126 aTranslate
.getX() + aScale
.getX(), aTranslate
.getY() + aScale
.getY());
127 const basegfx::B2DRange
aCropped(
128 aTargetTranslate
.getX(), aTargetTranslate
.getY(),
129 aTargetTranslate
.getX() + aTargetScale
.getX(), aTargetTranslate
.getY() + aTargetScale
.getY());
131 if(aCropped
.isEmpty())
133 // nothing to return since cropped content is completely empty
135 else if(aCurrent
.equal(aCropped
))
137 // no crop, just use content
138 xRetval
= getChildren();
142 // build new combined content transformation
143 basegfx::B2DHomMatrix
aNewObjectTransform(getTransformation());
145 // remove content transform by inverting
146 aNewObjectTransform
.invert();
148 // add target values and original shear/rotate
149 aNewObjectTransform
= basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
154 aTargetTranslate
.getX(),
155 aTargetTranslate
.getY())
156 * aNewObjectTransform
;
158 // prepare TransformPrimitive2D with xPrimitive
159 const Primitive2DReference
xTransformPrimitive(
160 new TransformPrimitive2D(
164 if(aCurrent
.isInside(aCropped
))
166 // crop just shrunk so that its inside content,
167 // no need to use a mask since not really cropped.
168 xRetval
= Primitive2DSequence(&xTransformPrimitive
, 1);
172 // mask with original object's bounds
173 basegfx::B2DPolyPolygon
aMaskPolyPolygon(basegfx::tools::createUnitPolygon());
174 aMaskPolyPolygon
.transform(getTransformation());
176 // create maskPrimitive with aMaskPolyPolygon and aMaskContentVector
177 const Primitive2DReference
xMask(
180 Primitive2DSequence(&xTransformPrimitive
, 1)));
182 xRetval
= Primitive2DSequence(&xMask
, 1);
191 ImplPrimitive2DIDBlock(CropPrimitive2D
, PRIMITIVE2D_ID_CROPPRIMITIVE2D
)
193 } // end of namespace primitive2d
194 } // end of namespace drawinglayer
196 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */