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_slideshow.hxx"
26 
27 #include <canvas/debug.hxx>
28 #include <tools/diagnose_ex.h>
29 #include "clippingfunctor.hxx"
30 #include "transitiontools.hxx"
31 
32 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
33 #include <basegfx/polygon/b2dpolygonclipper.hxx>
34 #include <basegfx/polygon/b2dpolygontools.hxx>
35 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
36 #include <basegfx/matrix/b2dhommatrixtools.hxx>
37 
38 namespace slideshow
39 {
40     namespace internal
41     {
42         ClippingFunctor::ClippingFunctor(const ParametricPolyPolygonSharedPtr&   rPolygon,
43                                          const TransitionInfo&                   rTransitionInfo,
44                                          bool                                    bDirectionForward,
45                                          bool                                    bModeIn ) :
46             mpParametricPoly( rPolygon ),
47             maStaticTransformation(),
48             // AW: Not needed
49 			// maBackgroundRect( createUnitRect() ),
50             mbForwardParameterSweep( true ),
51             mbSubtractPolygon( false ),
52             mbScaleIsotrophically( rTransitionInfo.mbScaleIsotrophically ),
53             mbFlip(false)
54         {
55             ENSURE_OR_THROW( rPolygon,
56                               "ClippingFunctor::ClippingFunctor(): Invalid parametric polygon" );
57 
58             // maBackgroundRect serves as the minuent when
59             // subtracting a given clip polygon from the
60             // background. To speed up the clipper algo, avoid
61             // actual intersections of the generated
62             // poly-polygon with the minuent - i.e. choose the
63             // polygon to subtract from sufficiently large.
64 
65             // blow up unit rect to (-1,-1),(2,2)
66             // AW: Not needed, just use range
67 			// ::basegfx::B2DHomMatrix aMatrix;
68             // aMatrix.scale(3.0,3.0);
69             // aMatrix.translate(-1.0,-1.0);
70             // maBackgroundRect.transform( aMatrix );
71 
72             // extract modification info from maTransitionInfo
73             // -----------------------------------------------
74 
75             // perform general transformations _before_ the reverse
76             // mode changes. This allows the Transition table to be
77             // filled more constitently (otherwise, when e.g. rotating
78             // a clip 90 degrees, the REVERSEMETHOD_FLIP_X becomes
79             // REVERSEMETHOD_FLIP_Y instead)
80             if (rTransitionInfo.mnRotationAngle != 0.0 ||
81                 rTransitionInfo.mnScaleX != 1.0 ||
82                 rTransitionInfo.mnScaleY != 1.0)
83             {
84                 maStaticTransformation.translate( -0.5, -0.5 );
85                 // apply further transformations:
86                 if (rTransitionInfo.mnRotationAngle != 0.0)
87                 {
88                     maStaticTransformation.rotate(
89                         basegfx::deg2rad(rTransitionInfo.mnRotationAngle) );
90                 }
91                 if (rTransitionInfo.mnScaleX != 1.0 ||
92                     rTransitionInfo.mnScaleY != 1.0)
93                 {
94                     maStaticTransformation.scale(
95                         rTransitionInfo.mnScaleX,
96                         rTransitionInfo.mnScaleY );
97                 }
98                 maStaticTransformation.translate( 0.5, 0.5 );
99             }
100 
101             if( !bDirectionForward )
102             {
103                 // Client has requested reversed
104                 // direction. Apply TransitionInfo's choice
105                 // for that
106                 switch( rTransitionInfo.meReverseMethod )
107                 {
108                     default:
109                         ENSURE_OR_THROW(
110                             false,
111                             "TransitionFactory::TransitionFactory(): Unexpected reverse method" );
112                         break;
113 
114                     case TransitionInfo::REVERSEMETHOD_IGNORE:
115                         break;
116 
117                     case TransitionInfo::REVERSEMETHOD_INVERT_SWEEP:
118                         mbForwardParameterSweep = !mbForwardParameterSweep;
119                         break;
120 
121                     case TransitionInfo::REVERSEMETHOD_SUBTRACT_POLYGON:
122                         mbSubtractPolygon = !mbSubtractPolygon;
123                         break;
124 
125                     case TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT:
126                         mbForwardParameterSweep = !mbForwardParameterSweep;
127                         mbSubtractPolygon = !mbSubtractPolygon;
128                         break;
129 
130                     case TransitionInfo::REVERSEMETHOD_ROTATE_180:
131                         maStaticTransformation = basegfx::tools::createRotateAroundPoint(0.5, 0.5, M_PI)
132                             * maStaticTransformation;
133                         break;
134 
135                     case TransitionInfo::REVERSEMETHOD_FLIP_X:
136                         maStaticTransformation = basegfx::tools::createScaleTranslateB2DHomMatrix(-1.0, 1.0, 1.0, 0.0)
137                             * maStaticTransformation;
138                         mbFlip = true;
139                         break;
140 
141                     case TransitionInfo::REVERSEMETHOD_FLIP_Y:
142                         maStaticTransformation = basegfx::tools::createScaleTranslateB2DHomMatrix(1.0, -1.0, 0.0, 1.0)
143                             * maStaticTransformation;
144                         mbFlip = true;
145                         break;
146                 }
147             }
148 
149             if( !bModeIn )
150             {
151                 // client has requested 'out' mode. Apply
152                 // TransitionInfo's method of choice
153                 if( rTransitionInfo.mbOutInvertsSweep )
154                     mbForwardParameterSweep = !mbForwardParameterSweep;
155                 else
156                     mbSubtractPolygon = !mbSubtractPolygon;
157             }
158         }
159 
160         ::basegfx::B2DPolyPolygon ClippingFunctor::operator()( double 						nValue,
161                                                                const ::basegfx::B2DSize&	rTargetSize )
162         {
163             // modify clip polygon according to static
164             // transformation plus current shape size
165             ::basegfx::B2DHomMatrix aMatrix( maStaticTransformation );
166 
167             // retrieve current clip polygon
168             ::basegfx::B2DPolyPolygon aClipPoly = (*mpParametricPoly)(
169                 mbForwardParameterSweep ? nValue : 1.0 - nValue );
170 
171             // TODO(Q4): workaround here, better be fixed in cppcanvas
172             if (aClipPoly.count() == 0)
173                 aClipPoly.append( basegfx::B2DPolygon() );
174 
175             if (mbFlip)
176                 aClipPoly.flip();
177 
178             // currently, clipper cannot cope with curves. Subdivide first
179             // AW: Should be no longer necessary; clipping tools are now bezier-safe
180             // if( aClipPoly.areControlPointsUsed() )
181             //    aClipPoly = ::basegfx::tools::adaptiveSubdivideByAngle(aClipPoly);
182 
183 			if( mbSubtractPolygon )
184             {
185                 // subtract given polygon from background
186                 // rect. Do that before any transformations.
187 
188                 // calc maBackgroundRect \ aClipPoly
189                 // =================================
190 
191                 // AW: Simplified
192 		        // use a range with fixed size (-1,-1),(2,2)
193 				const basegfx::B2DRange aBackgroundRange(-1, -1, 2, 2);
194 				const basegfx::B2DRange aClipPolyRange(aClipPoly.getB2DRange());
195 
196 				if(aBackgroundRange.isInside(aClipPolyRange))
197 				{
198                     // combine polygons; make the clip polygon the hole
199 					aClipPoly = ::basegfx::tools::correctOrientations(aClipPoly);
200                     aClipPoly.flip();
201                     aClipPoly.insert(0, basegfx::tools::createPolygonFromRect(aBackgroundRange));
202 				}
203                 else
204                 {
205 					// when not completely inside aBackgroundRange clipping is needed
206                     // substract aClipPoly from aBackgroundRange
207                     const basegfx::B2DPolyPolygon aBackgroundPolyPoly(basegfx::tools::createPolygonFromRect(aBackgroundRange));
208                     aClipPoly = basegfx::tools::solvePolygonOperationDiff(aBackgroundPolyPoly, aClipPoly);
209                 }
210             }
211 
212             // scale polygon up to current shape size
213             if( mbScaleIsotrophically )
214             {
215                 const double nScale( ::std::max( rTargetSize.getX(),
216                                                  rTargetSize.getY() ) );
217                 aMatrix.scale( nScale, nScale );
218                 aMatrix.translate( -(nScale-rTargetSize.getX())/2.0,
219                                    -(nScale-rTargetSize.getY())/2.0 );
220             }
221             else
222             {
223                 aMatrix.scale( rTargetSize.getX(),
224                                rTargetSize.getY() );
225             }
226 
227             // apply cumulative transformation to clip polygon
228             aClipPoly.transform( aMatrix );
229 
230             return aClipPoly;
231         }
232 
233     }
234 }
235