1*09dbbe93SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*09dbbe93SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*09dbbe93SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*09dbbe93SAndrew Rist  * distributed with this work for additional information
6*09dbbe93SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*09dbbe93SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*09dbbe93SAndrew Rist  * "License"); you may not use this file except in compliance
9*09dbbe93SAndrew Rist  * with the License.  You may obtain a copy of the License at
10*09dbbe93SAndrew Rist  *
11*09dbbe93SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*09dbbe93SAndrew Rist  *
13*09dbbe93SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*09dbbe93SAndrew Rist  * software distributed under the License is distributed on an
15*09dbbe93SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*09dbbe93SAndrew Rist  * KIND, either express or implied.  See the License for the
17*09dbbe93SAndrew Rist  * specific language governing permissions and limitations
18*09dbbe93SAndrew Rist  * under the License.
19*09dbbe93SAndrew Rist  *
20*09dbbe93SAndrew Rist  *************************************************************/
21*09dbbe93SAndrew Rist 
22*09dbbe93SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_basegfx.hxx"
26cdf0e10cSrcweir #include <basegfx/tools/b2dclipstate.hxx>
27cdf0e10cSrcweir 
28cdf0e10cSrcweir #include <basegfx/range/b2drange.hxx>
29cdf0e10cSrcweir #include <basegfx/range/b2dpolyrange.hxx>
30cdf0e10cSrcweir #include <basegfx/range/b2drangeclipper.hxx>
31cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygon.hxx>
32cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx>
33cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygon.hxx>
34cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygontools.hxx>
35cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
36cdf0e10cSrcweir 
37cdf0e10cSrcweir namespace basegfx
38cdf0e10cSrcweir {
39cdf0e10cSrcweir namespace tools
40cdf0e10cSrcweir {
41cdf0e10cSrcweir     struct ImplB2DClipState
42cdf0e10cSrcweir     {
43cdf0e10cSrcweir     public:
44cdf0e10cSrcweir         enum Operation {UNION, INTERSECT, XOR, SUBTRACT};
45cdf0e10cSrcweir 
ImplB2DClipStatebasegfx::tools::ImplB2DClipState46cdf0e10cSrcweir         ImplB2DClipState() :
47cdf0e10cSrcweir             maPendingPolygons(),
48cdf0e10cSrcweir             maPendingRanges(),
49cdf0e10cSrcweir             maClipPoly(),
50cdf0e10cSrcweir             mePendingOps(UNION)
51cdf0e10cSrcweir         {}
52cdf0e10cSrcweir 
ImplB2DClipStatebasegfx::tools::ImplB2DClipState53cdf0e10cSrcweir         explicit ImplB2DClipState( const B2DRange& rRange ) :
54cdf0e10cSrcweir             maPendingPolygons(),
55cdf0e10cSrcweir             maPendingRanges(),
56cdf0e10cSrcweir             maClipPoly(
57cdf0e10cSrcweir                 tools::createPolygonFromRect(rRange)),
58cdf0e10cSrcweir             mePendingOps(UNION)
59cdf0e10cSrcweir         {}
60cdf0e10cSrcweir 
ImplB2DClipStatebasegfx::tools::ImplB2DClipState61cdf0e10cSrcweir         explicit ImplB2DClipState( const B2DPolygon& rPoly ) :
62cdf0e10cSrcweir             maPendingPolygons(),
63cdf0e10cSrcweir             maPendingRanges(),
64cdf0e10cSrcweir             maClipPoly(rPoly),
65cdf0e10cSrcweir             mePendingOps(UNION)
66cdf0e10cSrcweir         {}
67cdf0e10cSrcweir 
ImplB2DClipStatebasegfx::tools::ImplB2DClipState68cdf0e10cSrcweir         explicit ImplB2DClipState( const B2DPolyPolygon& rPoly ) :
69cdf0e10cSrcweir             maPendingPolygons(),
70cdf0e10cSrcweir             maPendingRanges(),
71cdf0e10cSrcweir             maClipPoly(rPoly),
72cdf0e10cSrcweir             mePendingOps(UNION)
73cdf0e10cSrcweir         {}
74cdf0e10cSrcweir 
isClearedbasegfx::tools::ImplB2DClipState75cdf0e10cSrcweir         bool isCleared() const
76cdf0e10cSrcweir         {
77cdf0e10cSrcweir             return !maClipPoly.count()
78cdf0e10cSrcweir                 && !maPendingPolygons.count()
79cdf0e10cSrcweir                 && !maPendingRanges.count();
80cdf0e10cSrcweir         }
81cdf0e10cSrcweir 
makeClearbasegfx::tools::ImplB2DClipState82cdf0e10cSrcweir         void makeClear()
83cdf0e10cSrcweir         {
84cdf0e10cSrcweir             maPendingPolygons.clear();
85cdf0e10cSrcweir             maPendingRanges.clear();
86cdf0e10cSrcweir             maClipPoly.clear();
87cdf0e10cSrcweir             mePendingOps = UNION;
88cdf0e10cSrcweir         }
89cdf0e10cSrcweir 
isNullClipPolybasegfx::tools::ImplB2DClipState90cdf0e10cSrcweir         bool isNullClipPoly() const
91cdf0e10cSrcweir         {
92cdf0e10cSrcweir             return maClipPoly.count() == 1
93cdf0e10cSrcweir                 && !maClipPoly.getB2DPolygon(0).count();
94cdf0e10cSrcweir         }
95cdf0e10cSrcweir 
isNullbasegfx::tools::ImplB2DClipState96cdf0e10cSrcweir         bool isNull() const
97cdf0e10cSrcweir         {
98cdf0e10cSrcweir             return !maPendingPolygons.count()
99cdf0e10cSrcweir                 && !maPendingRanges.count()
100cdf0e10cSrcweir                 && isNullClipPoly();
101cdf0e10cSrcweir         }
102cdf0e10cSrcweir 
makeNullbasegfx::tools::ImplB2DClipState103cdf0e10cSrcweir         void makeNull()
104cdf0e10cSrcweir         {
105cdf0e10cSrcweir             maPendingPolygons.clear();
106cdf0e10cSrcweir             maPendingRanges.clear();
107cdf0e10cSrcweir             maClipPoly.clear();
108cdf0e10cSrcweir             maClipPoly.append(B2DPolygon());
109cdf0e10cSrcweir             mePendingOps = UNION;
110cdf0e10cSrcweir         }
111cdf0e10cSrcweir 
operator ==basegfx::tools::ImplB2DClipState112cdf0e10cSrcweir         bool operator==(const ImplB2DClipState& rRHS) const
113cdf0e10cSrcweir         {
114cdf0e10cSrcweir             return maPendingPolygons == rRHS.maPendingPolygons
115cdf0e10cSrcweir                 && maPendingRanges == rRHS.maPendingRanges
116cdf0e10cSrcweir                 && maClipPoly == rRHS.maClipPoly
117cdf0e10cSrcweir                 && mePendingOps == rRHS.mePendingOps;
118cdf0e10cSrcweir         }
119cdf0e10cSrcweir 
addRangebasegfx::tools::ImplB2DClipState120cdf0e10cSrcweir         void addRange(const B2DRange& rRange, Operation eOp)
121cdf0e10cSrcweir         {
122cdf0e10cSrcweir             if( rRange.isEmpty() )
123cdf0e10cSrcweir                 return;
124cdf0e10cSrcweir 
125cdf0e10cSrcweir             commitPendingPolygons();
126cdf0e10cSrcweir             if( mePendingOps != eOp )
127cdf0e10cSrcweir                 commitPendingRanges();
128cdf0e10cSrcweir 
129cdf0e10cSrcweir             mePendingOps = eOp;
130cdf0e10cSrcweir             maPendingRanges.appendElement(
131cdf0e10cSrcweir                 rRange,
132cdf0e10cSrcweir                 ORIENTATION_POSITIVE);
133cdf0e10cSrcweir         }
134cdf0e10cSrcweir 
addPolygonbasegfx::tools::ImplB2DClipState135cdf0e10cSrcweir         void addPolygon(B2DPolygon aPoly, Operation eOp)
136cdf0e10cSrcweir         {
137cdf0e10cSrcweir             commitPendingRanges();
138cdf0e10cSrcweir             if( mePendingOps != eOp )
139cdf0e10cSrcweir                 commitPendingPolygons();
140cdf0e10cSrcweir 
141cdf0e10cSrcweir             mePendingOps = eOp;
142cdf0e10cSrcweir             maPendingPolygons.append(aPoly);
143cdf0e10cSrcweir         }
144cdf0e10cSrcweir 
addPolyPolygonbasegfx::tools::ImplB2DClipState145cdf0e10cSrcweir         void addPolyPolygon(B2DPolyPolygon aPoly, Operation eOp)
146cdf0e10cSrcweir         {
147cdf0e10cSrcweir             commitPendingRanges();
148cdf0e10cSrcweir             if( mePendingOps != eOp )
149cdf0e10cSrcweir                 commitPendingPolygons();
150cdf0e10cSrcweir 
151cdf0e10cSrcweir             mePendingOps = eOp;
152cdf0e10cSrcweir             maPendingPolygons.append(aPoly);
153cdf0e10cSrcweir         }
154cdf0e10cSrcweir 
addClipStatebasegfx::tools::ImplB2DClipState155cdf0e10cSrcweir         void addClipState(const ImplB2DClipState& rOther, Operation eOp)
156cdf0e10cSrcweir         {
157cdf0e10cSrcweir             if( rOther.mePendingOps == mePendingOps
158cdf0e10cSrcweir                 && !rOther.maClipPoly.count()
159cdf0e10cSrcweir                 && !rOther.maPendingPolygons.count() )
160cdf0e10cSrcweir             {
161cdf0e10cSrcweir                 maPendingRanges.appendPolyRange( rOther.maPendingRanges );
162cdf0e10cSrcweir             }
163cdf0e10cSrcweir             else
164cdf0e10cSrcweir             {
165cdf0e10cSrcweir                 commitPendingRanges();
166cdf0e10cSrcweir                 commitPendingPolygons();
167cdf0e10cSrcweir                 rOther.commitPendingRanges();
168cdf0e10cSrcweir                 rOther.commitPendingPolygons();
169cdf0e10cSrcweir 
170cdf0e10cSrcweir                 maPendingPolygons = rOther.maClipPoly;
171cdf0e10cSrcweir                 mePendingOps = eOp;
172cdf0e10cSrcweir             }
173cdf0e10cSrcweir         }
174cdf0e10cSrcweir 
unionRangebasegfx::tools::ImplB2DClipState175cdf0e10cSrcweir         void unionRange(const B2DRange& rRange)
176cdf0e10cSrcweir         {
177cdf0e10cSrcweir             if( isCleared() )
178cdf0e10cSrcweir                 return;
179cdf0e10cSrcweir 
180cdf0e10cSrcweir             addRange(rRange,UNION);
181cdf0e10cSrcweir         }
182cdf0e10cSrcweir 
unionPolygonbasegfx::tools::ImplB2DClipState183cdf0e10cSrcweir         void unionPolygon(const B2DPolygon& rPoly)
184cdf0e10cSrcweir         {
185cdf0e10cSrcweir             if( isCleared() )
186cdf0e10cSrcweir                 return;
187cdf0e10cSrcweir 
188cdf0e10cSrcweir             addPolygon(rPoly,UNION);
189cdf0e10cSrcweir         }
190cdf0e10cSrcweir 
unionPolyPolygonbasegfx::tools::ImplB2DClipState191cdf0e10cSrcweir         void unionPolyPolygon(const B2DPolyPolygon& rPolyPoly)
192cdf0e10cSrcweir         {
193cdf0e10cSrcweir             if( isCleared() )
194cdf0e10cSrcweir                 return;
195cdf0e10cSrcweir 
196cdf0e10cSrcweir             addPolyPolygon(rPolyPoly,UNION);
197cdf0e10cSrcweir         }
198cdf0e10cSrcweir 
unionClipStatebasegfx::tools::ImplB2DClipState199cdf0e10cSrcweir         void unionClipState(const ImplB2DClipState& rOther)
200cdf0e10cSrcweir         {
201cdf0e10cSrcweir             if( isCleared() )
202cdf0e10cSrcweir                 return;
203cdf0e10cSrcweir 
204cdf0e10cSrcweir             addClipState(rOther, UNION);
205cdf0e10cSrcweir         }
206cdf0e10cSrcweir 
intersectRangebasegfx::tools::ImplB2DClipState207cdf0e10cSrcweir         void intersectRange(const B2DRange& rRange)
208cdf0e10cSrcweir         {
209cdf0e10cSrcweir             if( isNull() )
210cdf0e10cSrcweir                 return;
211cdf0e10cSrcweir 
212cdf0e10cSrcweir             addRange(rRange,INTERSECT);
213cdf0e10cSrcweir         }
214cdf0e10cSrcweir 
intersectPolygonbasegfx::tools::ImplB2DClipState215cdf0e10cSrcweir         void intersectPolygon(const B2DPolygon& rPoly)
216cdf0e10cSrcweir         {
217cdf0e10cSrcweir             if( isNull() )
218cdf0e10cSrcweir                 return;
219cdf0e10cSrcweir 
220cdf0e10cSrcweir             addPolygon(rPoly,INTERSECT);
221cdf0e10cSrcweir         }
222cdf0e10cSrcweir 
intersectPolyPolygonbasegfx::tools::ImplB2DClipState223cdf0e10cSrcweir         void intersectPolyPolygon(const B2DPolyPolygon& rPolyPoly)
224cdf0e10cSrcweir         {
225cdf0e10cSrcweir             if( isNull() )
226cdf0e10cSrcweir                 return;
227cdf0e10cSrcweir 
228cdf0e10cSrcweir             addPolyPolygon(rPolyPoly,INTERSECT);
229cdf0e10cSrcweir         }
230cdf0e10cSrcweir 
intersectClipStatebasegfx::tools::ImplB2DClipState231cdf0e10cSrcweir         void intersectClipState(const ImplB2DClipState& rOther)
232cdf0e10cSrcweir         {
233cdf0e10cSrcweir             if( isNull() )
234cdf0e10cSrcweir                 return;
235cdf0e10cSrcweir 
236cdf0e10cSrcweir             addClipState(rOther, INTERSECT);
237cdf0e10cSrcweir         }
238cdf0e10cSrcweir 
subtractRangebasegfx::tools::ImplB2DClipState239cdf0e10cSrcweir         void subtractRange(const B2DRange& rRange )
240cdf0e10cSrcweir         {
241cdf0e10cSrcweir             if( isNull() )
242cdf0e10cSrcweir                 return;
243cdf0e10cSrcweir 
244cdf0e10cSrcweir             addRange(rRange,SUBTRACT);
245cdf0e10cSrcweir         }
246cdf0e10cSrcweir 
subtractPolygonbasegfx::tools::ImplB2DClipState247cdf0e10cSrcweir         void subtractPolygon(const B2DPolygon& rPoly)
248cdf0e10cSrcweir         {
249cdf0e10cSrcweir             if( isNull() )
250cdf0e10cSrcweir                 return;
251cdf0e10cSrcweir 
252cdf0e10cSrcweir             addPolygon(rPoly,SUBTRACT);
253cdf0e10cSrcweir         }
254cdf0e10cSrcweir 
subtractPolyPolygonbasegfx::tools::ImplB2DClipState255cdf0e10cSrcweir         void subtractPolyPolygon(const B2DPolyPolygon& rPolyPoly)
256cdf0e10cSrcweir         {
257cdf0e10cSrcweir             if( isNull() )
258cdf0e10cSrcweir                 return;
259cdf0e10cSrcweir 
260cdf0e10cSrcweir             addPolyPolygon(rPolyPoly,SUBTRACT);
261cdf0e10cSrcweir         }
262cdf0e10cSrcweir 
subtractClipStatebasegfx::tools::ImplB2DClipState263cdf0e10cSrcweir         void subtractClipState(const ImplB2DClipState& rOther)
264cdf0e10cSrcweir         {
265cdf0e10cSrcweir             if( isNull() )
266cdf0e10cSrcweir                 return;
267cdf0e10cSrcweir 
268cdf0e10cSrcweir             addClipState(rOther, SUBTRACT);
269cdf0e10cSrcweir         }
270cdf0e10cSrcweir 
xorRangebasegfx::tools::ImplB2DClipState271cdf0e10cSrcweir         void xorRange(const B2DRange& rRange)
272cdf0e10cSrcweir         {
273cdf0e10cSrcweir             addRange(rRange,XOR);
274cdf0e10cSrcweir         }
275cdf0e10cSrcweir 
xorPolygonbasegfx::tools::ImplB2DClipState276cdf0e10cSrcweir         void xorPolygon(const B2DPolygon& rPoly)
277cdf0e10cSrcweir         {
278cdf0e10cSrcweir             addPolygon(rPoly,XOR);
279cdf0e10cSrcweir         }
280cdf0e10cSrcweir 
xorPolyPolygonbasegfx::tools::ImplB2DClipState281cdf0e10cSrcweir         void xorPolyPolygon(const B2DPolyPolygon& rPolyPoly)
282cdf0e10cSrcweir         {
283cdf0e10cSrcweir             addPolyPolygon(rPolyPoly,XOR);
284cdf0e10cSrcweir         }
285cdf0e10cSrcweir 
xorClipStatebasegfx::tools::ImplB2DClipState286cdf0e10cSrcweir         void xorClipState(const ImplB2DClipState& rOther)
287cdf0e10cSrcweir         {
288cdf0e10cSrcweir             addClipState(rOther, XOR);
289cdf0e10cSrcweir         }
290cdf0e10cSrcweir 
getClipPolybasegfx::tools::ImplB2DClipState291cdf0e10cSrcweir         B2DPolyPolygon getClipPoly() const
292cdf0e10cSrcweir         {
293cdf0e10cSrcweir             commitPendingRanges();
294cdf0e10cSrcweir             commitPendingPolygons();
295cdf0e10cSrcweir 
296cdf0e10cSrcweir             return maClipPoly;
297cdf0e10cSrcweir         }
298cdf0e10cSrcweir 
299cdf0e10cSrcweir     private:
commitPendingPolygonsbasegfx::tools::ImplB2DClipState300cdf0e10cSrcweir         void commitPendingPolygons() const
301cdf0e10cSrcweir         {
302cdf0e10cSrcweir             if( !maPendingPolygons.count() )
303cdf0e10cSrcweir                 return;
304cdf0e10cSrcweir 
305cdf0e10cSrcweir             // assumption: maClipPoly has kept polygons prepared for
306cdf0e10cSrcweir             // clipping; i.e. no neutral polygons & correct
307cdf0e10cSrcweir             // orientation
308cdf0e10cSrcweir             maPendingPolygons = tools::prepareForPolygonOperation(maPendingPolygons);
309cdf0e10cSrcweir             const bool bIsEmpty=isNullClipPoly();
310cdf0e10cSrcweir             const bool bIsCleared=!maClipPoly.count();
311cdf0e10cSrcweir             switch(mePendingOps)
312cdf0e10cSrcweir             {
313cdf0e10cSrcweir                 case UNION:
314cdf0e10cSrcweir                     OSL_ASSERT( !bIsCleared );
315cdf0e10cSrcweir 
316cdf0e10cSrcweir                     if( bIsEmpty )
317cdf0e10cSrcweir                         maClipPoly = maPendingPolygons;
318cdf0e10cSrcweir                     else
319cdf0e10cSrcweir                         maClipPoly = tools::solvePolygonOperationOr(
320cdf0e10cSrcweir                             maClipPoly,
321cdf0e10cSrcweir                             maPendingPolygons);
322cdf0e10cSrcweir                     break;
323cdf0e10cSrcweir                 case INTERSECT:
324cdf0e10cSrcweir                     OSL_ASSERT( !bIsEmpty );
325cdf0e10cSrcweir 
326cdf0e10cSrcweir                     if( bIsCleared )
327cdf0e10cSrcweir                         maClipPoly = maPendingPolygons;
328cdf0e10cSrcweir                     else
329cdf0e10cSrcweir                         maClipPoly = tools::solvePolygonOperationAnd(
330cdf0e10cSrcweir                             maClipPoly,
331cdf0e10cSrcweir                             maPendingPolygons);
332cdf0e10cSrcweir                     break;
333cdf0e10cSrcweir                 case XOR:
334cdf0e10cSrcweir                     if( bIsEmpty )
335cdf0e10cSrcweir                         maClipPoly = maPendingPolygons;
336cdf0e10cSrcweir                     else if( bIsCleared )
337cdf0e10cSrcweir                     {
338cdf0e10cSrcweir                         // not representable, strictly speaking,
339cdf0e10cSrcweir                         // using polygons with the common even/odd
340cdf0e10cSrcweir                         // or nonzero winding number fill rule. If
341cdf0e10cSrcweir                         // we'd want to represent it, fill rule
342cdf0e10cSrcweir                         // would need to be "non-negative winding
343cdf0e10cSrcweir                         // number" (and we then would return
344cdf0e10cSrcweir                         // 'holes' here)
345cdf0e10cSrcweir 
346cdf0e10cSrcweir                         // going for an ugly hack meanwhile
347cdf0e10cSrcweir                         maClipPoly = tools::solvePolygonOperationXor(
348cdf0e10cSrcweir                             B2DPolyPolygon(
349cdf0e10cSrcweir                                 tools::createPolygonFromRect(B2DRange(-1E20,-1E20,1E20,1E20))),
350cdf0e10cSrcweir                             maPendingPolygons);
351cdf0e10cSrcweir                     }
352cdf0e10cSrcweir                     else
353cdf0e10cSrcweir                         maClipPoly = tools::solvePolygonOperationXor(
354cdf0e10cSrcweir                             maClipPoly,
355cdf0e10cSrcweir                             maPendingPolygons);
356cdf0e10cSrcweir                     break;
357cdf0e10cSrcweir                 case SUBTRACT:
358cdf0e10cSrcweir                     OSL_ASSERT( !bIsEmpty );
359cdf0e10cSrcweir 
360cdf0e10cSrcweir                     // first union all pending ones, subtract en bloc then
361cdf0e10cSrcweir                     maPendingPolygons = solveCrossovers(maPendingPolygons);
362cdf0e10cSrcweir                     maPendingPolygons = stripNeutralPolygons(maPendingPolygons);
363cdf0e10cSrcweir                     maPendingPolygons = stripDispensablePolygons(maPendingPolygons, false);
364cdf0e10cSrcweir 
365cdf0e10cSrcweir                     if( bIsCleared )
366cdf0e10cSrcweir                     {
367cdf0e10cSrcweir                         // not representable, strictly speaking,
368cdf0e10cSrcweir                         // using polygons with the common even/odd
369cdf0e10cSrcweir                         // or nonzero winding number fill rule. If
370cdf0e10cSrcweir                         // we'd want to represent it, fill rule
371cdf0e10cSrcweir                         // would need to be "non-negative winding
372cdf0e10cSrcweir                         // number" (and we then would return
373cdf0e10cSrcweir                         // 'holes' here)
374cdf0e10cSrcweir 
375cdf0e10cSrcweir                         // going for an ugly hack meanwhile
376cdf0e10cSrcweir                         maClipPoly = tools::solvePolygonOperationDiff(
377cdf0e10cSrcweir                             B2DPolyPolygon(
378cdf0e10cSrcweir                                 tools::createPolygonFromRect(B2DRange(-1E20,-1E20,1E20,1E20))),
379cdf0e10cSrcweir                             maPendingPolygons);
380cdf0e10cSrcweir                     }
381cdf0e10cSrcweir                     else
382cdf0e10cSrcweir                         maClipPoly = tools::solvePolygonOperationDiff(
383cdf0e10cSrcweir                             maClipPoly,
384cdf0e10cSrcweir                             maPendingPolygons);
385cdf0e10cSrcweir                     break;
386cdf0e10cSrcweir             }
387cdf0e10cSrcweir 
388cdf0e10cSrcweir             maPendingPolygons.clear();
389cdf0e10cSrcweir             mePendingOps = UNION;
390cdf0e10cSrcweir         }
391cdf0e10cSrcweir 
commitPendingRangesbasegfx::tools::ImplB2DClipState392cdf0e10cSrcweir         void commitPendingRanges() const
393cdf0e10cSrcweir         {
394cdf0e10cSrcweir             if( !maPendingRanges.count() )
395cdf0e10cSrcweir                 return;
396cdf0e10cSrcweir 
397cdf0e10cSrcweir             // use the specialized range clipper for the win
398cdf0e10cSrcweir             B2DPolyPolygon aCollectedRanges;
399cdf0e10cSrcweir             const bool bIsEmpty=isNullClipPoly();
400cdf0e10cSrcweir             const bool bIsCleared=!maClipPoly.count();
401cdf0e10cSrcweir             switch(mePendingOps)
402cdf0e10cSrcweir             {
403cdf0e10cSrcweir                 case UNION:
404cdf0e10cSrcweir                     OSL_ASSERT( !bIsCleared );
405cdf0e10cSrcweir 
406cdf0e10cSrcweir                     aCollectedRanges = maPendingRanges.solveCrossovers();
407cdf0e10cSrcweir                     aCollectedRanges = stripNeutralPolygons(aCollectedRanges);
408cdf0e10cSrcweir                     aCollectedRanges = stripDispensablePolygons(aCollectedRanges, false);
409cdf0e10cSrcweir                     if( bIsEmpty )
410cdf0e10cSrcweir                         maClipPoly = aCollectedRanges;
411cdf0e10cSrcweir                     else
412cdf0e10cSrcweir                         maClipPoly = tools::solvePolygonOperationOr(
413cdf0e10cSrcweir                             maClipPoly,
414cdf0e10cSrcweir                             aCollectedRanges);
415cdf0e10cSrcweir                     break;
416cdf0e10cSrcweir                 case INTERSECT:
417cdf0e10cSrcweir                     OSL_ASSERT( !bIsEmpty );
418cdf0e10cSrcweir 
419cdf0e10cSrcweir                     aCollectedRanges = maPendingRanges.solveCrossovers();
420cdf0e10cSrcweir                     aCollectedRanges = stripNeutralPolygons(aCollectedRanges);
421cdf0e10cSrcweir                     if( maPendingRanges.count() > 1 )
422cdf0e10cSrcweir                         aCollectedRanges = stripDispensablePolygons(aCollectedRanges, true);
423cdf0e10cSrcweir 
424cdf0e10cSrcweir                     if( bIsCleared )
425cdf0e10cSrcweir                         maClipPoly = aCollectedRanges;
426cdf0e10cSrcweir                     else
427cdf0e10cSrcweir                         maClipPoly = tools::solvePolygonOperationAnd(
428cdf0e10cSrcweir                             maClipPoly,
429cdf0e10cSrcweir                             aCollectedRanges);
430cdf0e10cSrcweir                     break;
431cdf0e10cSrcweir                 case XOR:
432cdf0e10cSrcweir                     aCollectedRanges = maPendingRanges.solveCrossovers();
433cdf0e10cSrcweir                     aCollectedRanges = stripNeutralPolygons(aCollectedRanges);
434cdf0e10cSrcweir                     aCollectedRanges = correctOrientations(aCollectedRanges);
435cdf0e10cSrcweir 
436cdf0e10cSrcweir                     if( bIsEmpty )
437cdf0e10cSrcweir                         maClipPoly = aCollectedRanges;
438cdf0e10cSrcweir                     else if( bIsCleared )
439cdf0e10cSrcweir                     {
440cdf0e10cSrcweir                         // not representable, strictly speaking,
441cdf0e10cSrcweir                         // using polygons with the common even/odd
442cdf0e10cSrcweir                         // or nonzero winding number fill rule. If
443cdf0e10cSrcweir                         // we'd want to represent it, fill rule
444cdf0e10cSrcweir                         // would need to be "non-negative winding
445cdf0e10cSrcweir                         // number" (and we then would return
446cdf0e10cSrcweir                         // 'holes' here)
447cdf0e10cSrcweir 
448cdf0e10cSrcweir                         // going for an ugly hack meanwhile
449cdf0e10cSrcweir                         maClipPoly = tools::solvePolygonOperationXor(
450cdf0e10cSrcweir                             B2DPolyPolygon(
451cdf0e10cSrcweir                                 tools::createPolygonFromRect(B2DRange(-1E20,-1E20,1E20,1E20))),
452cdf0e10cSrcweir                             aCollectedRanges);
453cdf0e10cSrcweir                     }
454cdf0e10cSrcweir                     else
455cdf0e10cSrcweir                         maClipPoly = tools::solvePolygonOperationXor(
456cdf0e10cSrcweir                             maClipPoly,
457cdf0e10cSrcweir                             aCollectedRanges);
458cdf0e10cSrcweir                     break;
459cdf0e10cSrcweir                 case SUBTRACT:
460cdf0e10cSrcweir                     OSL_ASSERT( !bIsEmpty );
461cdf0e10cSrcweir 
462cdf0e10cSrcweir                     // first union all pending ranges, subtract en bloc then
463cdf0e10cSrcweir                     aCollectedRanges = maPendingRanges.solveCrossovers();
464cdf0e10cSrcweir                     aCollectedRanges = stripNeutralPolygons(aCollectedRanges);
465cdf0e10cSrcweir                     aCollectedRanges = stripDispensablePolygons(aCollectedRanges, false);
466cdf0e10cSrcweir 
467cdf0e10cSrcweir                     if( bIsCleared )
468cdf0e10cSrcweir                     {
469cdf0e10cSrcweir                         // not representable, strictly speaking,
470cdf0e10cSrcweir                         // using polygons with the common even/odd
471cdf0e10cSrcweir                         // or nonzero winding number fill rule. If
472cdf0e10cSrcweir                         // we'd want to represent it, fill rule
473cdf0e10cSrcweir                         // would need to be "non-negative winding
474cdf0e10cSrcweir                         // number" (and we then would return
475cdf0e10cSrcweir                         // 'holes' here)
476cdf0e10cSrcweir 
477cdf0e10cSrcweir                         // going for an ugly hack meanwhile
478cdf0e10cSrcweir                         maClipPoly = tools::solvePolygonOperationDiff(
479cdf0e10cSrcweir                             B2DPolyPolygon(
480cdf0e10cSrcweir                                 tools::createPolygonFromRect(B2DRange(-1E20,-1E20,1E20,1E20))),
481cdf0e10cSrcweir                             aCollectedRanges);
482cdf0e10cSrcweir                     }
483cdf0e10cSrcweir                     else
484cdf0e10cSrcweir                         maClipPoly = tools::solvePolygonOperationDiff(
485cdf0e10cSrcweir                             maClipPoly,
486cdf0e10cSrcweir                             aCollectedRanges);
487cdf0e10cSrcweir                     break;
488cdf0e10cSrcweir             }
489cdf0e10cSrcweir 
490cdf0e10cSrcweir             maPendingRanges.clear();
491cdf0e10cSrcweir             mePendingOps = UNION;
492cdf0e10cSrcweir         }
493cdf0e10cSrcweir 
494cdf0e10cSrcweir         mutable B2DPolyPolygon maPendingPolygons;
495cdf0e10cSrcweir         mutable B2DPolyRange   maPendingRanges;
496cdf0e10cSrcweir         mutable B2DPolyPolygon maClipPoly;
497cdf0e10cSrcweir         mutable Operation      mePendingOps;
498cdf0e10cSrcweir     };
499cdf0e10cSrcweir 
B2DClipState()500cdf0e10cSrcweir     B2DClipState::B2DClipState() :
501cdf0e10cSrcweir         mpImpl()
502cdf0e10cSrcweir     {}
503cdf0e10cSrcweir 
~B2DClipState()504cdf0e10cSrcweir     B2DClipState::~B2DClipState()
505cdf0e10cSrcweir     {}
506cdf0e10cSrcweir 
B2DClipState(const B2DClipState & rOrig)507cdf0e10cSrcweir     B2DClipState::B2DClipState( const B2DClipState& rOrig ) :
508cdf0e10cSrcweir         mpImpl(rOrig.mpImpl)
509cdf0e10cSrcweir     {}
510cdf0e10cSrcweir 
B2DClipState(const B2DRange & rRange)511cdf0e10cSrcweir     B2DClipState::B2DClipState( const B2DRange& rRange ) :
512cdf0e10cSrcweir         mpImpl( ImplB2DClipState(rRange) )
513cdf0e10cSrcweir     {}
514cdf0e10cSrcweir 
B2DClipState(const B2DPolygon & rPoly)515cdf0e10cSrcweir     B2DClipState::B2DClipState( const B2DPolygon& rPoly ) :
516cdf0e10cSrcweir         mpImpl( ImplB2DClipState(rPoly) )
517cdf0e10cSrcweir     {}
518cdf0e10cSrcweir 
B2DClipState(const B2DPolyPolygon & rPolyPoly)519cdf0e10cSrcweir     B2DClipState::B2DClipState( const B2DPolyPolygon& rPolyPoly ) :
520cdf0e10cSrcweir         mpImpl( ImplB2DClipState(rPolyPoly) )
521cdf0e10cSrcweir     {}
522cdf0e10cSrcweir 
operator =(const B2DClipState & rRHS)523cdf0e10cSrcweir     B2DClipState& B2DClipState::operator=( const B2DClipState& rRHS )
524cdf0e10cSrcweir     {
525cdf0e10cSrcweir         mpImpl = rRHS.mpImpl;
526cdf0e10cSrcweir         return *this;
527cdf0e10cSrcweir     }
528cdf0e10cSrcweir 
makeUnique()529cdf0e10cSrcweir     void B2DClipState::makeUnique()
530cdf0e10cSrcweir     {
531cdf0e10cSrcweir         mpImpl.make_unique();
532cdf0e10cSrcweir     }
533cdf0e10cSrcweir 
makeNull()534cdf0e10cSrcweir     void B2DClipState::makeNull()
535cdf0e10cSrcweir     {
536cdf0e10cSrcweir         mpImpl->makeNull();
537cdf0e10cSrcweir     }
538cdf0e10cSrcweir 
isNull() const539cdf0e10cSrcweir     bool B2DClipState::isNull() const
540cdf0e10cSrcweir     {
541cdf0e10cSrcweir         return mpImpl->isNull();
542cdf0e10cSrcweir     }
543cdf0e10cSrcweir 
makeClear()544cdf0e10cSrcweir     void B2DClipState::makeClear()
545cdf0e10cSrcweir     {
546cdf0e10cSrcweir         mpImpl->makeClear();
547cdf0e10cSrcweir     }
548cdf0e10cSrcweir 
isCleared() const549cdf0e10cSrcweir     bool B2DClipState::isCleared() const
550cdf0e10cSrcweir     {
551cdf0e10cSrcweir         return mpImpl->isCleared();
552cdf0e10cSrcweir     }
553cdf0e10cSrcweir 
operator ==(const B2DClipState & rRHS) const554cdf0e10cSrcweir     bool B2DClipState::operator==(const B2DClipState& rRHS) const
555cdf0e10cSrcweir     {
556cdf0e10cSrcweir         if(mpImpl.same_object(rRHS.mpImpl))
557cdf0e10cSrcweir             return true;
558cdf0e10cSrcweir 
559cdf0e10cSrcweir         return ((*mpImpl) == (*rRHS.mpImpl));
560cdf0e10cSrcweir     }
561cdf0e10cSrcweir 
operator !=(const B2DClipState & rRHS) const562cdf0e10cSrcweir     bool B2DClipState::operator!=(const B2DClipState& rRHS) const
563cdf0e10cSrcweir     {
564cdf0e10cSrcweir         return !(*this == rRHS);
565cdf0e10cSrcweir     }
566cdf0e10cSrcweir 
unionRange(const B2DRange & rRange)567cdf0e10cSrcweir     void B2DClipState::unionRange(const B2DRange& rRange)
568cdf0e10cSrcweir     {
569cdf0e10cSrcweir         mpImpl->unionRange(rRange);
570cdf0e10cSrcweir     }
571cdf0e10cSrcweir 
unionPolygon(const B2DPolygon & rPoly)572cdf0e10cSrcweir     void B2DClipState::unionPolygon(const B2DPolygon& rPoly)
573cdf0e10cSrcweir     {
574cdf0e10cSrcweir         mpImpl->unionPolygon(rPoly);
575cdf0e10cSrcweir     }
576cdf0e10cSrcweir 
unionPolyPolygon(const B2DPolyPolygon & rPolyPoly)577cdf0e10cSrcweir     void B2DClipState::unionPolyPolygon(const B2DPolyPolygon& rPolyPoly)
578cdf0e10cSrcweir     {
579cdf0e10cSrcweir         mpImpl->unionPolyPolygon(rPolyPoly);
580cdf0e10cSrcweir     }
581cdf0e10cSrcweir 
unionClipState(const B2DClipState & rState)582cdf0e10cSrcweir     void B2DClipState::unionClipState(const B2DClipState& rState)
583cdf0e10cSrcweir     {
584cdf0e10cSrcweir         mpImpl->unionClipState(*rState.mpImpl);
585cdf0e10cSrcweir     }
586cdf0e10cSrcweir 
intersectRange(const B2DRange & rRange)587cdf0e10cSrcweir     void B2DClipState::intersectRange(const B2DRange& rRange)
588cdf0e10cSrcweir     {
589cdf0e10cSrcweir         mpImpl->intersectRange(rRange);
590cdf0e10cSrcweir     }
591cdf0e10cSrcweir 
intersectPolygon(const B2DPolygon & rPoly)592cdf0e10cSrcweir     void B2DClipState::intersectPolygon(const B2DPolygon& rPoly)
593cdf0e10cSrcweir     {
594cdf0e10cSrcweir         mpImpl->intersectPolygon(rPoly);
595cdf0e10cSrcweir     }
596cdf0e10cSrcweir 
intersectPolyPolygon(const B2DPolyPolygon & rPolyPoly)597cdf0e10cSrcweir     void B2DClipState::intersectPolyPolygon(const B2DPolyPolygon& rPolyPoly)
598cdf0e10cSrcweir     {
599cdf0e10cSrcweir         mpImpl->intersectPolyPolygon(rPolyPoly);
600cdf0e10cSrcweir     }
601cdf0e10cSrcweir 
intersectClipState(const B2DClipState & rState)602cdf0e10cSrcweir     void B2DClipState::intersectClipState(const B2DClipState& rState)
603cdf0e10cSrcweir     {
604cdf0e10cSrcweir         mpImpl->intersectClipState(*rState.mpImpl);
605cdf0e10cSrcweir     }
606cdf0e10cSrcweir 
subtractRange(const B2DRange & rRange)607cdf0e10cSrcweir     void B2DClipState::subtractRange(const B2DRange& rRange)
608cdf0e10cSrcweir     {
609cdf0e10cSrcweir         mpImpl->subtractRange(rRange);
610cdf0e10cSrcweir     }
611cdf0e10cSrcweir 
subtractPolygon(const B2DPolygon & rPoly)612cdf0e10cSrcweir     void B2DClipState::subtractPolygon(const B2DPolygon& rPoly)
613cdf0e10cSrcweir     {
614cdf0e10cSrcweir         mpImpl->subtractPolygon(rPoly);
615cdf0e10cSrcweir     }
616cdf0e10cSrcweir 
subtractPolyPolygon(const B2DPolyPolygon & rPolyPoly)617cdf0e10cSrcweir     void B2DClipState::subtractPolyPolygon(const B2DPolyPolygon& rPolyPoly)
618cdf0e10cSrcweir     {
619cdf0e10cSrcweir         mpImpl->subtractPolyPolygon(rPolyPoly);
620cdf0e10cSrcweir     }
621cdf0e10cSrcweir 
subtractClipState(const B2DClipState & rState)622cdf0e10cSrcweir     void B2DClipState::subtractClipState(const B2DClipState& rState)
623cdf0e10cSrcweir     {
624cdf0e10cSrcweir         mpImpl->subtractClipState(*rState.mpImpl);
625cdf0e10cSrcweir     }
626cdf0e10cSrcweir 
xorRange(const B2DRange & rRange)627cdf0e10cSrcweir     void B2DClipState::xorRange(const B2DRange& rRange)
628cdf0e10cSrcweir     {
629cdf0e10cSrcweir         mpImpl->xorRange(rRange);
630cdf0e10cSrcweir     }
631cdf0e10cSrcweir 
xorPolygon(const B2DPolygon & rPoly)632cdf0e10cSrcweir     void B2DClipState::xorPolygon(const B2DPolygon& rPoly)
633cdf0e10cSrcweir     {
634cdf0e10cSrcweir         mpImpl->xorPolygon(rPoly);
635cdf0e10cSrcweir     }
636cdf0e10cSrcweir 
xorPolyPolygon(const B2DPolyPolygon & rPolyPoly)637cdf0e10cSrcweir     void B2DClipState::xorPolyPolygon(const B2DPolyPolygon& rPolyPoly)
638cdf0e10cSrcweir     {
639cdf0e10cSrcweir         mpImpl->xorPolyPolygon(rPolyPoly);
640cdf0e10cSrcweir     }
641cdf0e10cSrcweir 
xorClipState(const B2DClipState & rState)642cdf0e10cSrcweir     void B2DClipState::xorClipState(const B2DClipState& rState)
643cdf0e10cSrcweir     {
644cdf0e10cSrcweir         mpImpl->xorClipState(*rState.mpImpl);
645cdf0e10cSrcweir     }
646cdf0e10cSrcweir 
getClipPoly() const647cdf0e10cSrcweir     B2DPolyPolygon B2DClipState::getClipPoly() const
648cdf0e10cSrcweir     {
649cdf0e10cSrcweir         return mpImpl->getClipPoly();
650cdf0e10cSrcweir     }
651cdf0e10cSrcweir 
652cdf0e10cSrcweir } // end of namespace tools
653cdf0e10cSrcweir } // end of namespace basegfx
654cdf0e10cSrcweir 
655cdf0e10cSrcweir // eof
656