1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir  *
3*cdf0e10cSrcweir  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*cdf0e10cSrcweir  *
5*cdf0e10cSrcweir  * Copyright 2000, 2010 Oracle and/or its affiliates.
6*cdf0e10cSrcweir  *
7*cdf0e10cSrcweir  * OpenOffice.org - a multi-platform office productivity suite
8*cdf0e10cSrcweir  *
9*cdf0e10cSrcweir  * This file is part of OpenOffice.org.
10*cdf0e10cSrcweir  *
11*cdf0e10cSrcweir  * OpenOffice.org is free software: you can redistribute it and/or modify
12*cdf0e10cSrcweir  * it under the terms of the GNU Lesser General Public License version 3
13*cdf0e10cSrcweir  * only, as published by the Free Software Foundation.
14*cdf0e10cSrcweir  *
15*cdf0e10cSrcweir  * OpenOffice.org is distributed in the hope that it will be useful,
16*cdf0e10cSrcweir  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*cdf0e10cSrcweir  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*cdf0e10cSrcweir  * GNU Lesser General Public License version 3 for more details
19*cdf0e10cSrcweir  * (a copy is included in the LICENSE file that accompanied this code).
20*cdf0e10cSrcweir  *
21*cdf0e10cSrcweir  * You should have received a copy of the GNU Lesser General Public License
22*cdf0e10cSrcweir  * version 3 along with OpenOffice.org.  If not, see
23*cdf0e10cSrcweir  * <http://www.openoffice.org/license.html>
24*cdf0e10cSrcweir  * for a copy of the LGPLv3 License.
25*cdf0e10cSrcweir  *
26*cdf0e10cSrcweir  ************************************************************************/
27*cdf0e10cSrcweir 
28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
29*cdf0e10cSrcweir #include "precompiled_slideshow.hxx"
30*cdf0e10cSrcweir 
31*cdf0e10cSrcweir #include <canvas/debug.hxx>
32*cdf0e10cSrcweir #include <tools/diagnose_ex.h>
33*cdf0e10cSrcweir #include "clippingfunctor.hxx"
34*cdf0e10cSrcweir #include "transitiontools.hxx"
35*cdf0e10cSrcweir 
36*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
37*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygonclipper.hxx>
38*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx>
39*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
40*cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrixtools.hxx>
41*cdf0e10cSrcweir 
42*cdf0e10cSrcweir namespace slideshow
43*cdf0e10cSrcweir {
44*cdf0e10cSrcweir     namespace internal
45*cdf0e10cSrcweir     {
46*cdf0e10cSrcweir         ClippingFunctor::ClippingFunctor(const ParametricPolyPolygonSharedPtr&   rPolygon,
47*cdf0e10cSrcweir                                          const TransitionInfo&                   rTransitionInfo,
48*cdf0e10cSrcweir                                          bool                                    bDirectionForward,
49*cdf0e10cSrcweir                                          bool                                    bModeIn ) :
50*cdf0e10cSrcweir             mpParametricPoly( rPolygon ),
51*cdf0e10cSrcweir             maStaticTransformation(),
52*cdf0e10cSrcweir             // AW: Not needed
53*cdf0e10cSrcweir 			// maBackgroundRect( createUnitRect() ),
54*cdf0e10cSrcweir             mbForwardParameterSweep( true ),
55*cdf0e10cSrcweir             mbSubtractPolygon( false ),
56*cdf0e10cSrcweir             mbScaleIsotrophically( rTransitionInfo.mbScaleIsotrophically ),
57*cdf0e10cSrcweir             mbFlip(false)
58*cdf0e10cSrcweir         {
59*cdf0e10cSrcweir             ENSURE_OR_THROW( rPolygon,
60*cdf0e10cSrcweir                               "ClippingFunctor::ClippingFunctor(): Invalid parametric polygon" );
61*cdf0e10cSrcweir 
62*cdf0e10cSrcweir             // maBackgroundRect serves as the minuent when
63*cdf0e10cSrcweir             // subtracting a given clip polygon from the
64*cdf0e10cSrcweir             // background. To speed up the clipper algo, avoid
65*cdf0e10cSrcweir             // actual intersections of the generated
66*cdf0e10cSrcweir             // poly-polygon with the minuent - i.e. choose the
67*cdf0e10cSrcweir             // polygon to subtract from sufficiently large.
68*cdf0e10cSrcweir 
69*cdf0e10cSrcweir             // blow up unit rect to (-1,-1),(2,2)
70*cdf0e10cSrcweir             // AW: Not needed, just use range
71*cdf0e10cSrcweir 			// ::basegfx::B2DHomMatrix aMatrix;
72*cdf0e10cSrcweir             // aMatrix.scale(3.0,3.0);
73*cdf0e10cSrcweir             // aMatrix.translate(-1.0,-1.0);
74*cdf0e10cSrcweir             // maBackgroundRect.transform( aMatrix );
75*cdf0e10cSrcweir 
76*cdf0e10cSrcweir             // extract modification info from maTransitionInfo
77*cdf0e10cSrcweir             // -----------------------------------------------
78*cdf0e10cSrcweir 
79*cdf0e10cSrcweir             // perform general transformations _before_ the reverse
80*cdf0e10cSrcweir             // mode changes. This allows the Transition table to be
81*cdf0e10cSrcweir             // filled more constitently (otherwise, when e.g. rotating
82*cdf0e10cSrcweir             // a clip 90 degrees, the REVERSEMETHOD_FLIP_X becomes
83*cdf0e10cSrcweir             // REVERSEMETHOD_FLIP_Y instead)
84*cdf0e10cSrcweir             if (rTransitionInfo.mnRotationAngle != 0.0 ||
85*cdf0e10cSrcweir                 rTransitionInfo.mnScaleX != 1.0 ||
86*cdf0e10cSrcweir                 rTransitionInfo.mnScaleY != 1.0)
87*cdf0e10cSrcweir             {
88*cdf0e10cSrcweir                 maStaticTransformation.translate( -0.5, -0.5 );
89*cdf0e10cSrcweir                 // apply further transformations:
90*cdf0e10cSrcweir                 if (rTransitionInfo.mnRotationAngle != 0.0)
91*cdf0e10cSrcweir                 {
92*cdf0e10cSrcweir                     maStaticTransformation.rotate(
93*cdf0e10cSrcweir                         basegfx::deg2rad(rTransitionInfo.mnRotationAngle) );
94*cdf0e10cSrcweir                 }
95*cdf0e10cSrcweir                 if (rTransitionInfo.mnScaleX != 1.0 ||
96*cdf0e10cSrcweir                     rTransitionInfo.mnScaleY != 1.0)
97*cdf0e10cSrcweir                 {
98*cdf0e10cSrcweir                     maStaticTransformation.scale(
99*cdf0e10cSrcweir                         rTransitionInfo.mnScaleX,
100*cdf0e10cSrcweir                         rTransitionInfo.mnScaleY );
101*cdf0e10cSrcweir                 }
102*cdf0e10cSrcweir                 maStaticTransformation.translate( 0.5, 0.5 );
103*cdf0e10cSrcweir             }
104*cdf0e10cSrcweir 
105*cdf0e10cSrcweir             if( !bDirectionForward )
106*cdf0e10cSrcweir             {
107*cdf0e10cSrcweir                 // Client has requested reversed
108*cdf0e10cSrcweir                 // direction. Apply TransitionInfo's choice
109*cdf0e10cSrcweir                 // for that
110*cdf0e10cSrcweir                 switch( rTransitionInfo.meReverseMethod )
111*cdf0e10cSrcweir                 {
112*cdf0e10cSrcweir                     default:
113*cdf0e10cSrcweir                         ENSURE_OR_THROW(
114*cdf0e10cSrcweir                             false,
115*cdf0e10cSrcweir                             "TransitionFactory::TransitionFactory(): Unexpected reverse method" );
116*cdf0e10cSrcweir                         break;
117*cdf0e10cSrcweir 
118*cdf0e10cSrcweir                     case TransitionInfo::REVERSEMETHOD_IGNORE:
119*cdf0e10cSrcweir                         break;
120*cdf0e10cSrcweir 
121*cdf0e10cSrcweir                     case TransitionInfo::REVERSEMETHOD_INVERT_SWEEP:
122*cdf0e10cSrcweir                         mbForwardParameterSweep = !mbForwardParameterSweep;
123*cdf0e10cSrcweir                         break;
124*cdf0e10cSrcweir 
125*cdf0e10cSrcweir                     case TransitionInfo::REVERSEMETHOD_SUBTRACT_POLYGON:
126*cdf0e10cSrcweir                         mbSubtractPolygon = !mbSubtractPolygon;
127*cdf0e10cSrcweir                         break;
128*cdf0e10cSrcweir 
129*cdf0e10cSrcweir                     case TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT:
130*cdf0e10cSrcweir                         mbForwardParameterSweep = !mbForwardParameterSweep;
131*cdf0e10cSrcweir                         mbSubtractPolygon = !mbSubtractPolygon;
132*cdf0e10cSrcweir                         break;
133*cdf0e10cSrcweir 
134*cdf0e10cSrcweir                     case TransitionInfo::REVERSEMETHOD_ROTATE_180:
135*cdf0e10cSrcweir                         maStaticTransformation = basegfx::tools::createRotateAroundPoint(0.5, 0.5, M_PI)
136*cdf0e10cSrcweir                             * maStaticTransformation;
137*cdf0e10cSrcweir                         break;
138*cdf0e10cSrcweir 
139*cdf0e10cSrcweir                     case TransitionInfo::REVERSEMETHOD_FLIP_X:
140*cdf0e10cSrcweir                         maStaticTransformation = basegfx::tools::createScaleTranslateB2DHomMatrix(-1.0, 1.0, 1.0, 0.0)
141*cdf0e10cSrcweir                             * maStaticTransformation;
142*cdf0e10cSrcweir                         mbFlip = true;
143*cdf0e10cSrcweir                         break;
144*cdf0e10cSrcweir 
145*cdf0e10cSrcweir                     case TransitionInfo::REVERSEMETHOD_FLIP_Y:
146*cdf0e10cSrcweir                         maStaticTransformation = basegfx::tools::createScaleTranslateB2DHomMatrix(1.0, -1.0, 0.0, 1.0)
147*cdf0e10cSrcweir                             * maStaticTransformation;
148*cdf0e10cSrcweir                         mbFlip = true;
149*cdf0e10cSrcweir                         break;
150*cdf0e10cSrcweir                 }
151*cdf0e10cSrcweir             }
152*cdf0e10cSrcweir 
153*cdf0e10cSrcweir             if( !bModeIn )
154*cdf0e10cSrcweir             {
155*cdf0e10cSrcweir                 // client has requested 'out' mode. Apply
156*cdf0e10cSrcweir                 // TransitionInfo's method of choice
157*cdf0e10cSrcweir                 if( rTransitionInfo.mbOutInvertsSweep )
158*cdf0e10cSrcweir                     mbForwardParameterSweep = !mbForwardParameterSweep;
159*cdf0e10cSrcweir                 else
160*cdf0e10cSrcweir                     mbSubtractPolygon = !mbSubtractPolygon;
161*cdf0e10cSrcweir             }
162*cdf0e10cSrcweir         }
163*cdf0e10cSrcweir 
164*cdf0e10cSrcweir         ::basegfx::B2DPolyPolygon ClippingFunctor::operator()( double 						nValue,
165*cdf0e10cSrcweir                                                                const ::basegfx::B2DSize&	rTargetSize )
166*cdf0e10cSrcweir         {
167*cdf0e10cSrcweir             // modify clip polygon according to static
168*cdf0e10cSrcweir             // transformation plus current shape size
169*cdf0e10cSrcweir             ::basegfx::B2DHomMatrix aMatrix( maStaticTransformation );
170*cdf0e10cSrcweir 
171*cdf0e10cSrcweir             // retrieve current clip polygon
172*cdf0e10cSrcweir             ::basegfx::B2DPolyPolygon aClipPoly = (*mpParametricPoly)(
173*cdf0e10cSrcweir                 mbForwardParameterSweep ? nValue : 1.0 - nValue );
174*cdf0e10cSrcweir 
175*cdf0e10cSrcweir             // TODO(Q4): workaround here, better be fixed in cppcanvas
176*cdf0e10cSrcweir             if (aClipPoly.count() == 0)
177*cdf0e10cSrcweir                 aClipPoly.append( basegfx::B2DPolygon() );
178*cdf0e10cSrcweir 
179*cdf0e10cSrcweir             if (mbFlip)
180*cdf0e10cSrcweir                 aClipPoly.flip();
181*cdf0e10cSrcweir 
182*cdf0e10cSrcweir             // currently, clipper cannot cope with curves. Subdivide first
183*cdf0e10cSrcweir             // AW: Should be no longer necessary; clipping tools are now bezier-safe
184*cdf0e10cSrcweir             // if( aClipPoly.areControlPointsUsed() )
185*cdf0e10cSrcweir             //    aClipPoly = ::basegfx::tools::adaptiveSubdivideByAngle(aClipPoly);
186*cdf0e10cSrcweir 
187*cdf0e10cSrcweir 			if( mbSubtractPolygon )
188*cdf0e10cSrcweir             {
189*cdf0e10cSrcweir                 // subtract given polygon from background
190*cdf0e10cSrcweir                 // rect. Do that before any transformations.
191*cdf0e10cSrcweir 
192*cdf0e10cSrcweir                 // calc maBackgroundRect \ aClipPoly
193*cdf0e10cSrcweir                 // =================================
194*cdf0e10cSrcweir 
195*cdf0e10cSrcweir                 // AW: Simplified
196*cdf0e10cSrcweir 		        // use a range with fixed size (-1,-1),(2,2)
197*cdf0e10cSrcweir 				const basegfx::B2DRange aBackgroundRange(-1, -1, 2, 2);
198*cdf0e10cSrcweir 				const basegfx::B2DRange aClipPolyRange(aClipPoly.getB2DRange());
199*cdf0e10cSrcweir 
200*cdf0e10cSrcweir 				if(aBackgroundRange.isInside(aClipPolyRange))
201*cdf0e10cSrcweir 				{
202*cdf0e10cSrcweir                     // combine polygons; make the clip polygon the hole
203*cdf0e10cSrcweir 					aClipPoly = ::basegfx::tools::correctOrientations(aClipPoly);
204*cdf0e10cSrcweir                     aClipPoly.flip();
205*cdf0e10cSrcweir                     aClipPoly.insert(0, basegfx::tools::createPolygonFromRect(aBackgroundRange));
206*cdf0e10cSrcweir 				}
207*cdf0e10cSrcweir                 else
208*cdf0e10cSrcweir                 {
209*cdf0e10cSrcweir 					// when not completely inside aBackgroundRange clipping is needed
210*cdf0e10cSrcweir                     // substract aClipPoly from aBackgroundRange
211*cdf0e10cSrcweir                     const basegfx::B2DPolyPolygon aBackgroundPolyPoly(basegfx::tools::createPolygonFromRect(aBackgroundRange));
212*cdf0e10cSrcweir                     aClipPoly = basegfx::tools::solvePolygonOperationDiff(aBackgroundPolyPoly, aClipPoly);
213*cdf0e10cSrcweir                 }
214*cdf0e10cSrcweir             }
215*cdf0e10cSrcweir 
216*cdf0e10cSrcweir             // scale polygon up to current shape size
217*cdf0e10cSrcweir             if( mbScaleIsotrophically )
218*cdf0e10cSrcweir             {
219*cdf0e10cSrcweir                 const double nScale( ::std::max( rTargetSize.getX(),
220*cdf0e10cSrcweir                                                  rTargetSize.getY() ) );
221*cdf0e10cSrcweir                 aMatrix.scale( nScale, nScale );
222*cdf0e10cSrcweir                 aMatrix.translate( -(nScale-rTargetSize.getX())/2.0,
223*cdf0e10cSrcweir                                    -(nScale-rTargetSize.getY())/2.0 );
224*cdf0e10cSrcweir             }
225*cdf0e10cSrcweir             else
226*cdf0e10cSrcweir             {
227*cdf0e10cSrcweir                 aMatrix.scale( rTargetSize.getX(),
228*cdf0e10cSrcweir                                rTargetSize.getY() );
229*cdf0e10cSrcweir             }
230*cdf0e10cSrcweir 
231*cdf0e10cSrcweir             // apply cumulative transformation to clip polygon
232*cdf0e10cSrcweir             aClipPoly.transform( aMatrix );
233*cdf0e10cSrcweir 
234*cdf0e10cSrcweir             return aClipPoly;
235*cdf0e10cSrcweir         }
236*cdf0e10cSrcweir 
237*cdf0e10cSrcweir     }
238*cdf0e10cSrcweir }
239