1 /* ScanlineCoverage.java -- Manages coverage information for a scanline
2    Copyright (C) 2007 Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 package gnu.java.awt.java2d;
39 
40 /**
41  * Stores and handles the pixel converage for a scanline. The pixel coverage
42  * is stored as sorted list of {@linke Covergage} entries, each of which holds
43  * information about the coverage for the X and Y axis. This is utilized to
44  * compute the actual coverage for each pixel on the scanline and finding
45  * chunks of pixels with equal coverage quickly.
46  */
47 public final class ScanlineCoverage
48 {
49 
50   /**
51    * Iterates over the coverage list and calculates the actual coverage
52    * ranges on a scanline.
53    */
54   public final class Iterator
55   {
56     /**
57      * This instance is reused in the iteration.
58      */
59     private Range range;
60 
61     /**
62      * The pointer to the current item in the iteration.
63      */
64     private Coverage currentItem;
65 
66     /**
67      * The current coverage value.
68      */
69     private int currentCoverage;
70 
71     /**
72      * True when the current pixel coverage has already been handled, false
73      * otherwise.
74      */
75     private boolean handledPixelCoverage;
76 
77     /**
78      * Creates a new CoverageIterator.
79      */
Iterator()80     Iterator()
81     {
82       range = new Range();
83     }
84 
85     /**
86      * Returns the next coverage range on the scanline. The returned object
87      * will always be the same object, but with different values. Keep that
88      * in mind when dealing with this object.
89      *
90      * @return the next coverage range on the scanline
91      */
next()92     public Range next()
93     {
94       // TODO: Lump together the single-pixel coverage and the
95       // between-pixel coverage when the pixel coverage delta is 0.
96       if (handledPixelCoverage == false)
97         {
98           // Handle single pixel coverage.
99           range.setXPos(currentItem.xPos);
100           range.setLength(1);
101           range.setCoverage(currentCoverage + currentItem.pixelCoverage);
102           handledPixelCoverage = true;
103         }
104       else
105         {
106           // Handle pixel span coverage.
107           currentCoverage += currentItem.covDelta;
108           range.setCoverage(currentCoverage);
109           range.setXPos(currentItem.xPos + 1);
110           currentItem = currentItem.next;
111           range.setLength(currentItem.xPos - range.xPos);
112           handledPixelCoverage = false;
113         }
114       return range;
115     }
116 
117     /**
118      * Returns {@ true} when there are more coverage ranges to iterate,
119      * {@ false} otherwise.
120      *
121      * @return {@ true} when there are more coverage ranges to iterate,
122      *         {@ false} otherwise
123      */
hasNext()124     public boolean hasNext()
125     {
126       boolean hasNext;
127       if (currentItem != null && handledPixelCoverage == false)
128         {
129           // We have at least one more coverage item when there's a pixel
130           // coverage piece left.
131           hasNext = true;
132         }
133       else if (currentItem == null || currentItem.next == null
134           || currentItem.next == last)
135         {
136           hasNext = false;
137         }
138       else
139         {
140           hasNext = true;
141         }
142       return hasNext;
143     }
144 
145     /**
146      * Resets this iterator to the start of the list.
147      */
reset()148     void reset()
149     {
150       currentItem = head;
151       currentCoverage = 0;
152       handledPixelCoverage = false;
153     }
154   }
155 
156   /**
157    * A data object that carries information about pixel coverage on a scanline.
158    * The data consists of a starting X position on the scanline, the
159    * length of the range in pixels and the actual coverage value.
160    **/
161   public static final class Range
162   {
163     /**
164      * The X position on the scanline, in pixels.
165      */
166     private int xPos;
167 
168     /**
169      * The length of the range, in pixels.
170      */
171     private int length;
172 
173     /**
174      * The actual coverage. The relation depends on
175      * {@link ScanlineCoverage#maxCoverage}.
176      */
177     private int coverage;
178 
179     /**
180      * Creates a new CoverageRange object.
181      */
Range()182     Range()
183     {
184       // Nothing to do. The values get initialized in the corresponding
185       // setters.
186     }
187 
188     /**
189      * Sets the X start position (left) on the scanline. This value is
190      * considered to be in pixels and device space.
191      *
192      * @param x the x position
193      */
setXPos(int x)194     void setXPos(int x)
195     {
196       xPos = x;
197     }
198 
199     /**
200      * Returns the X start position (left) on the scanline. This value
201      * is considered to be in pixels and device space.
202      *
203      * @return the X position on the scanline
204      */
getXPos()205     public int getXPos()
206     {
207       return xPos;
208     }
209 
210     /**
211      * Sets the length of the pixel range. This is in pixel units.
212      *
213      * @param l the length of the range
214      */
setLength(int l)215     void setLength(int l)
216     {
217       length = l;
218     }
219 
220     /**
221      * Returns the length of the range in pixel units.
222      *
223      * @return the length of the range in pixel units
224      */
getLength()225     public int getLength()
226     {
227       return length;
228     }
229 
230     /**
231      * Returns the first X position after the range.
232      *
233      * @return the first X position after the range
234      */
getXPosEnd()235     public int getXPosEnd()
236     {
237       return xPos + length;
238     }
239 
240     /**
241      * Sets the coverage of the pixel range. The relation of that value
242      * depends on {@link ScanlineCoverage#maxCoverage}.
243      *
244      * @param cov the coverage value for the pixel range
245      */
setCoverage(int cov)246     void setCoverage(int cov)
247     {
248       coverage = cov;
249     }
250 
251     /**
252      * Returns the coverage of the pixel range. The relation of this value
253      * depends on {@link ScanlineCoverage#getMaxCoverage()}.
254      *
255      * @return the coverage of the pixel range
256      */
getCoverage()257     public int getCoverage()
258     {
259       return coverage;
260     }
261 
262     /**
263      * Returns a string representation.
264      */
toString()265     public String toString()
266     {
267       return "Coverage range: xPos=" + xPos + ", length=" + length
268              + ", coverage: " + coverage;
269     }
270   }
271 
272   /**
273    * One bucket in the list.
274    */
275   private static final class Coverage
276   {
277     /**
278      * The X coordinate on the scanline to which this bucket belongs.
279      */
280     int xPos;
281 
282     /**
283      * The coverage delta from the pixel at xPos to xPos + 1.
284      */
285     int covDelta;
286 
287     /**
288      * The delta for the pixel at xPos. This is added to the pixel at xPos,
289      * but not to the following pixel.
290      */
291     int pixelCoverage;
292 
293     /**
294      * Implements a linked list. This points to the next element of the list.
295      */
296     Coverage next;
297 
298     /**
299      * Returns the X coordinate for this entry.
300      *
301      * @return the X coordinate for this entry
302      */
getXPos()303     public int getXPos()
304     {
305       return xPos;
306     }
307 
308     /**
309      * Returns the coverage delta for this entry.
310      *
311      * @return the coverage delta for this entry
312      */
getCoverageDelta()313     public int getCoverageDelta()
314     {
315       return covDelta;
316     }
317 
318     /**
319      * Returns a string representation.
320      *
321      * @return a string representation
322      */
toString()323     public String toString()
324     {
325       return "Coverage: xPos: " + xPos + ", covDelta: " + covDelta;
326     }
327 
328     /**
329      * Returns a string representation of this entry and all the following
330      * in the linked list.
331      *
332      * @return a string representation of this entry and all the following
333      *         in the linked list
334      */
list()335     public String list()
336     {
337       String str = toString();
338       if (next != null)
339         str = str + " --> " + next.list();
340       return str;
341     }
342   }
343 
344   /**
345    * The head of the sorted list of buckets.
346    */
347   private Coverage head;
348 
349   /**
350    * The current bucket. We make use of the fact that the scanline converter
351    * always scans the scanline (and thus this list) from left to right to
352    * quickly find buckets or insertion points.
353    */
354   private Coverage current;
355 
356   /**
357    * The item that is before current in the list.
358    */
359   private Coverage currentPrev;
360 
361   /**
362    * The bucket after the last valid bucket. Unused buckets are not thrown
363    * away and garbage collected. Instead, we keep them at the tail of the list
364    * and reuse them when necessary.
365    */
366   private Coverage last;
367 
368   /**
369    * The last valid entry.
370    */
371   private Coverage lastPrev;
372 
373   /**
374    * The minimum X coordinate of this scanline.
375    */
376   private int minX;
377 
378   /**
379    * The maximum X coordinate of this scanline.
380    */
381   private int maxX;
382 
383   /**
384    * The maximum coverage value.
385    */
386   private int maxCoverage;
387 
388   /**
389    * The iterator over the ranges of this scanline.
390    */
391   private Iterator iterator;
392 
393   /**
394    * Creates a new ScanlineCoverage instance.
395    */
ScanlineCoverage()396   public ScanlineCoverage()
397   {
398     iterator = new Iterator();
399   }
400 
401   /**
402    * Indicates the the next scan of the scanline begins and that the next
403    * request will be at the beginning of this list. This makes searching and
404    * sorting of this list very quick.
405    */
rewind()406   public void rewind()
407   {
408     current = head;
409     currentPrev = null;
410   }
411 
412   /**
413    * Clears the list. This does not throw away the old buckets but only
414    * resets the end-pointer of the list to the first element. All buckets are
415    * then unused and are reused when the list is filled again.
416    */
clear()417   public void clear()
418   {
419     last = head;
420     lastPrev = null;
421     current = head;
422     currentPrev = null;
423     minX = Integer.MAX_VALUE;
424     maxX = Integer.MIN_VALUE;
425   }
426 
427   /**
428    * This adds the specified coverage to the pixel at the specified
429    * X position.
430    *
431    * @param x the X position
432    * @param xc the x coverage
433    * @param yc the y coverage
434    */
add(int x, int xc, int yc)435   public void add(int x, int xc, int yc)
436   {
437     Coverage bucket = findOrInsert(x);
438     bucket.covDelta += xc;
439     bucket.pixelCoverage += yc;
440     minX = Math.min(minX, x);
441     maxX = Math.max(maxX, x);
442   }
443 
444   /**
445    * Returns the maximum coverage value for the scanline.
446    *
447    * @return the maximum coverage value for the scanline
448    */
getMaxCoverage()449   public int getMaxCoverage()
450   {
451     return maxCoverage;
452   }
453 
454   /**
455    * Sets the maximum coverage value for the scanline.
456    *
457    * @param maxCov the maximum coverage value for the scanline
458    */
setMaxCoverage(int maxCov)459   void setMaxCoverage(int maxCov)
460   {
461     maxCoverage = maxCov;
462   }
463 
464   /**
465    * Returns the maximum X coordinate of the current scanline.
466    *
467    * @return the maximum X coordinate of the current scanline
468    */
getMaxX()469   public int getMaxX()
470   {
471     return maxX;
472   }
473 
474   /**
475    * Returns the minimum X coordinate of the current scanline.
476    *
477    * @return the minimum X coordinate of the current scanline
478    */
getMinX()479   public int getMinX()
480   {
481     return minX;
482   }
483 
484   /**
485    * Finds the bucket in the list with the specified X coordinate.
486    * If no such bucket is found, then a new one is fetched (either a cached
487    * bucket from the end of the list or a newly allocated one) inserted at the
488    * correct position and returned.
489    *
490    * @param x the X coordinate
491    *
492    * @return a bucket to hold the coverage data
493    */
findOrInsert(int x)494   private Coverage findOrInsert(int x)
495   {
496     // First search for a matching bucket.
497     if (head == null)
498       {
499         // Special case: the list is still empty.
500         // Testpoint 1.
501         head = new Coverage();
502         head.xPos = x;
503         current = head;
504         currentPrev = null;
505         return head;
506       }
507 
508     // This performs a linear search, starting from the current bucket.
509     // This is reasonably efficient because access to this list is always done
510     // in a linear fashion and we are usually not more then 1 or 2 buckets away
511     // from the one we're looking for.
512     Coverage match = current;
513     Coverage prev = currentPrev;
514     while (match != last && match.xPos < x)
515       {
516         prev = match;
517         match = match.next;
518       }
519 
520     // At this point we have either found an entry with xPos >= x, or reached
521     // the end of the list (match == last || match == null).
522     if (match == null)
523       {
524         // End of the list. No cached items to reuse.
525         // Testpoint 2.
526         match = new Coverage();
527         match.xPos = x;
528         if (prev != null)
529           prev.next = match;
530         current = match;
531         currentPrev = prev;
532         return match;
533       }
534     else if (match == last)
535       {
536         // End of the list. Reuse this item. Expand list.
537         // Testpoint 3.
538         last = match.next;
539         lastPrev = match;
540         match.xPos = x;
541         match.covDelta = 0;
542         match.pixelCoverage = 0;
543         // Keep link to last element or null, indicating the end of the list.
544         current = match;
545         currentPrev = prev;
546         return match;
547       }
548 
549     if (x == match.xPos)
550       {
551         // Special case: We have another coverage entry at the same location
552         // as an already existing entry. Return this.
553         // Testpoint 4.
554         current = match;
555         currentPrev = prev;
556         return match;
557       }
558     else // x <= match.xPos
559       {
560         assert (x <= match.xPos);
561         assert (prev == null ||x > prev.xPos);
562 
563         // Create new entry, or reuse existing one.
564         Coverage cov;
565         if (last != null)
566           {
567             // Testpoint 5.
568             cov = last;
569             last = cov.next;
570             lastPrev.next = last;
571           }
572         else
573           {
574             // Testpoint 6.
575             cov = new Coverage();
576           }
577 
578         cov.xPos = x;
579         cov.covDelta = 0;
580         cov.pixelCoverage = 0;
581 
582         // Insert this item in the list.
583         if (prev != null)
584           {
585             // Testpoint 5 & 6.
586             prev.next = cov;
587             cov.next = match;
588             current = cov;
589             currentPrev = prev;
590           }
591         else
592           {
593             // Testpoint 7.
594             assert (match == head);
595             // Insert at head.
596             head = cov;
597             head.next = match;
598             current = head;
599             currentPrev = null;
600           }
601         return cov;
602       }
603   }
604 
605   /**
606    * (Re-)Starts iterating the coverage values for the scanline.
607    * Use the returned iterator to get the consecutive coverage ranges.
608    *
609    * @return the iterator
610    */
iterate()611   public Iterator iterate()
612   {
613     iterator.reset();
614     return iterator;
615   }
616 
617   /**
618    * Returns {@ true} if this object has no entries for the current scanline,
619    * {@ false} otherwise.
620    *
621    * @return {@ true} if this object has no entries for the current scanline,
622    *         {@ false} otherwise
623    */
isEmpty()624   public boolean isEmpty()
625   {
626     return head == null || head == last
627            || head.next == null || head.next == last;
628   }
629 
630 }
631