blob: c9f03c5b2f9a0b95f3d1d24b70c46191200d440c [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1999 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.java2d.pipe;
27
28import java.awt.geom.PathIterator;
29import java.awt.Rectangle;
30
31/**
32 * This class clips a SpanIterator to a Region and outputs the
33 * resulting spans as another SpanIterator.
34 *
35 * Spans are output in the usual y/x order, unless the input span
36 * iterator doesn't conform to this order, or the iterator's span
37 * straddle more than one band of the Region used for clipping.
38 *
39 * Principle of operation:
40 *
41 * The iterator maintains a several cursors onto the RegionIterator
42 * in order to avoid having to buffer spans from the SpanIterator.
43 * They are:
44 * resetState The initial state of the RegionIterator
45 * lwm Low Water Mark, a running start point for
46 * processing each band. Usually goes down, but
47 * can be reset to resetState if a span has a lower
48 * start coordinate than the previous one.
49 * row The start of the current band of the RegionIterator
50 * box The current span of the current row
51 *
52 * The main nextSpan() loop implements a coroutine like structure, with
53 * three producers to get the next span, row and box calling each other
54 * to iterate through the span iterator and region.
55 *
56 * REMIND: Needs a native implementation!
57 */
58public class RegionClipSpanIterator implements SpanIterator {
59
60 // The inputs to the filter
61 Region rgn;
62 SpanIterator spanIter;
63
64 // The cursors that track the progress through the region
65 RegionIterator resetState;
66 RegionIterator lwm;
67 RegionIterator row;
68 RegionIterator box;
69
70 // The bounds of the current span iterator span
71 int spanlox, spanhix, spanloy, spanhiy;
72
73 // The extent of the region band marking the low water mark
74 int lwmloy, lwmhiy;
75
76 // The bounds of the current region box
77 int rgnlox, rgnloy, rgnhix, rgnhiy;
78
79 // The bounding box of the input Region. Used for click
80 // rejection of iterator spans
81 int rgnbndslox, rgnbndsloy, rgnbndshix, rgnbndshiy;
82
83 // The array used to hold coordinates from the region iterator
84 int rgnbox[] = new int[4];
85
86 // The array used to hold coordinates from the span iterator
87 int spanbox[] = new int[4];
88
89 // True if the next iterator span should be read on the next
90 // iteration of the main nextSpan() loop
91 boolean doNextSpan;
92
93 // True if the next region box should be read on the next
94 // iteration of the main nextSpan() loop
95 boolean doNextBox;
96
97 // True if there are no more spans or the Region is empty
98 boolean done = false;
99
100 /*
101 * Creates an instance that filters the spans generated by
102 * spanIter through the region described by rgn.
103 */
104 public RegionClipSpanIterator(Region rgn, SpanIterator spanIter) {
105
106 this.spanIter = spanIter;
107
108 resetState = rgn.getIterator();
109 lwm = resetState.createCopy();
110
111 if (!lwm.nextYRange(rgnbox)) {
112 done = true;
113 return;
114 }
115
116 rgnloy = lwmloy = rgnbox[1];
117 rgnhiy = lwmhiy = rgnbox[3];
118
119 rgn.getBounds(rgnbox);
120 rgnbndslox = rgnbox[0];
121 rgnbndsloy = rgnbox[1];
122 rgnbndshix = rgnbox[2];
123 rgnbndshiy = rgnbox[3];
124 if (rgnbndslox >= rgnbndshix ||
125 rgnbndsloy >= rgnbndshiy) {
126 done = true;
127 return;
128 }
129
130 this.rgn = rgn;
131
132
133 row = lwm.createCopy();
134 box = row.createCopy();
135 doNextSpan = true;
136 doNextBox = false;
137 }
138
139 /*
140 * Gets the bbox of the available path segments, clipped to the
141 * Region.
142 */
143 public void getPathBox(int pathbox[]) {
144 int[] rgnbox = new int[4];
145 rgn.getBounds(rgnbox);
146 spanIter.getPathBox(pathbox);
147
148 if (pathbox[0] < rgnbox[0]) {
149 pathbox[0] = rgnbox[0];
150 }
151
152 if (pathbox[1] < rgnbox[1]) {
153 pathbox[1] = rgnbox[1];
154 }
155
156 if (pathbox[2] > rgnbox[2]) {
157 pathbox[2] = rgnbox[2];
158 }
159
160 if (pathbox[3] > rgnbox[3]) {
161 pathbox[3] = rgnbox[3];
162 }
163}
164
165 /*
166 * Intersects the path box with the given bbox.
167 * Returned spans are clipped to this region, or discarded
168 * altogether if they lie outside it.
169 */
170 public void intersectClipBox(int lox, int loy, int hix, int hiy) {
171 spanIter.intersectClipBox(lox, loy, hix, hiy);
172 }
173
174
175 /*
176 * Fetches the next span that needs to be operated on.
177 * If the return value is false then there are no more spans.
178 */
179 public boolean nextSpan(int resultbox[]) {
180 if (done) {
181 return false;
182 }
183
184 int resultlox, resultloy, resulthix, resulthiy;
185 boolean doNextRow = false;
186
187 // REMIND: Cache the coordinate inst vars used in this loop
188 // in locals vars.
189 while (true) {
190 // We've exhausted the current span so get the next one
191 if (doNextSpan) {
192 if (!spanIter.nextSpan(spanbox)) {
193 done = true;
194 return false;
195 } else {
196 spanlox = spanbox[0];
197 // Clip out spans that lie outside of the rgn's bounds
198 if (spanlox >= rgnbndshix) {
199 continue;
200 }
201
202 spanloy = spanbox[1];
203 if (spanloy >= rgnbndshiy) {
204 continue;
205 }
206
207 spanhix = spanbox[2];
208 if (spanhix <= rgnbndslox) {
209 continue;
210 }
211
212 spanhiy = spanbox[3];
213 if (spanhiy <= rgnbndsloy) {
214 continue;
215 }
216 }
217 // If the span starts higher up than the low-water mark,
218 // reset the lwm. This can only happen if spans aren't
219 // returned in strict y/x order, or the first time through.
220 if (lwmloy > spanloy) {
221 lwm.copyStateFrom(resetState);
222 lwm.nextYRange(rgnbox);
223 lwmloy = rgnbox[1];
224 lwmhiy = rgnbox[3];
225 }
226 // Skip to the first rgn row whose bottom edge is
227 // below the top of the current span. This will only
228 // execute >0 times when the current span starts in a
229 // lower region row than the previous one, or possibly the
230 // first time through.
231 while (lwmhiy <= spanloy) {
232 if (!lwm.nextYRange(rgnbox))
233 break;
234 lwmloy = rgnbox[1];
235 lwmhiy = rgnbox[3];
236 }
237 // If the row overlaps the span, process it, otherwise
238 // fetch another span
239 if (lwmhiy > spanloy && lwmloy < spanhiy) {
240 // Update the current row if it's different from the
241 // new lwm
242 if (rgnloy != lwmloy) {
243 row.copyStateFrom(lwm);
244 rgnloy = lwmloy;
245 rgnhiy = lwmhiy;
246 }
247 box.copyStateFrom(row);
248 doNextBox = true;
249 doNextSpan = false;
250 }
251 continue;
252 }
253
254 // The current row's spans are exhausted, do the next one
255 if (doNextRow) {
256 // Next time we either do the next span or the next box
257 doNextRow = false;
258 // Get the next row
259 boolean ok = row.nextYRange(rgnbox);
260 // If there was one, update the bounds
261 if (ok) {
262 rgnloy = rgnbox[1];
263 rgnhiy = rgnbox[3];
264 }
265 if (!ok || rgnloy >= spanhiy) {
266 // If we've exhausted the rows or this one is below the span,
267 // go onto the next span
268 doNextSpan = true;
269 }
270 else {
271 // Otherwise get the first box on this row
272 box.copyStateFrom(row);
273 doNextBox = true;
274 }
275 continue;
276 }
277
278 // Process the next box in the current row
279 if (doNextBox) {
280 boolean ok = box.nextXBand(rgnbox);
281 if (ok) {
282 rgnlox = rgnbox[0];
283 rgnhix = rgnbox[2];
284 }
285 if (!ok || rgnlox >= spanhix) {
286 // If there was no next rgn span or it's beyond the
287 // source span, go onto the next row or span
288 doNextBox = false;
289 if (rgnhiy >= spanhiy) {
290 // If the current row totally overlaps the span,
291 // go onto the next span
292 doNextSpan = true;
293 } else {
294 // otherwise go onto the next rgn row
295 doNextRow = true;
296 }
297 } else {
298 // Otherwise, if the new rgn span overlaps the
299 // spanbox, no need to get another box
300 doNextBox = rgnhix <= spanlox;
301 }
302 continue;
303 }
304
305 // Prepare to do the next box either on this call or
306 // or the subsequent one
307 doNextBox = true;
308
309 // Clip the current span against the current box
310 if (spanlox > rgnlox) {
311 resultlox = spanlox;
312 }
313 else {
314 resultlox = rgnlox;
315 }
316
317 if (spanloy > rgnloy) {
318 resultloy = spanloy;
319 }
320 else {
321 resultloy = rgnloy;
322 }
323
324 if (spanhix < rgnhix) {
325 resulthix = spanhix;
326 }
327 else {
328 resulthix = rgnhix;
329 }
330
331 if (spanhiy < rgnhiy) {
332 resulthiy = spanhiy;
333 }
334 else {
335 resulthiy = rgnhiy;
336 }
337
338 // If the result is empty, try then next box
339 // otherwise return the box.
340 // REMIND: I think by definition it's non-empty
341 // if we're here. Need to think about this some more.
342 if (resultlox >= resulthix ||
343 resultloy >= resulthiy) {
344 continue;
345 }
346 else {
347 break;
348 }
349 }
350
351 resultbox[0] = resultlox;
352 resultbox[1] = resultloy;
353 resultbox[2] = resulthix;
354 resultbox[3] = resulthiy;
355 return true;
356
357 }
358
359
360 /**
361 * This method tells the iterator that it may skip all spans
362 * whose Y range is completely above the indicated Y coordinate.
363 */
364 public void skipDownTo(int y) {
365 spanIter.skipDownTo(y);
366 }
367
368 /**
369 * This method returns a native pointer to a function block that
370 * can be used by a native method to perform the same iteration
371 * cycle that the above methods provide while avoiding upcalls to
372 * the Java object.
373 * The definition of the structure whose pointer is returned by
374 * this method is defined in:
375 * <pre>
376 * src/share/native/sun/java2d/pipe/SpanIterator.h
377 * </pre>
378 */
379 public long getNativeIterator() {
380 return 0;
381 }
382
383 /*
384 * Cleans out all internal data structures.
385 */
386 //public native void dispose();
387
388 protected void finalize() {
389 //dispose();
390 }
391
392}