mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			631 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			631 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Java
		
	
	
	
/* ScanlineCoverage.java -- Manages coverage information for a scanline
 | 
						|
   Copyright (C) 2007 Free Software Foundation, Inc.
 | 
						|
 | 
						|
This file is part of GNU Classpath.
 | 
						|
 | 
						|
GNU Classpath is free software; you can redistribute it and/or modify
 | 
						|
it under the terms of the GNU General Public License as published by
 | 
						|
the Free Software Foundation; either version 2, or (at your option)
 | 
						|
any later version.
 | 
						|
 | 
						|
GNU Classpath is distributed in the hope that it will be useful, but
 | 
						|
WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
General Public License for more details.
 | 
						|
 | 
						|
You should have received a copy of the GNU General Public License
 | 
						|
along with GNU Classpath; see the file COPYING.  If not, write to the
 | 
						|
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
						|
02110-1301 USA.
 | 
						|
 | 
						|
Linking this library statically or dynamically with other modules is
 | 
						|
making a combined work based on this library.  Thus, the terms and
 | 
						|
conditions of the GNU General Public License cover the whole
 | 
						|
combination.
 | 
						|
 | 
						|
As a special exception, the copyright holders of this library give you
 | 
						|
permission to link this library with independent modules to produce an
 | 
						|
executable, regardless of the license terms of these independent
 | 
						|
modules, and to copy and distribute the resulting executable under
 | 
						|
terms of your choice, provided that you also meet, for each linked
 | 
						|
independent module, the terms and conditions of the license of that
 | 
						|
module.  An independent module is a module which is not derived from
 | 
						|
or based on this library.  If you modify this library, you may extend
 | 
						|
this exception to your version of the library, but you are not
 | 
						|
obligated to do so.  If you do not wish to do so, delete this
 | 
						|
exception statement from your version. */
 | 
						|
 | 
						|
package gnu.java.awt.java2d;
 | 
						|
 | 
						|
/**
 | 
						|
 * Stores and handles the pixel converage for a scanline. The pixel coverage
 | 
						|
 * is stored as sorted list of {@linke Covergage} entries, each of which holds
 | 
						|
 * information about the coverage for the X and Y axis. This is utilized to
 | 
						|
 * compute the actual coverage for each pixel on the scanline and finding
 | 
						|
 * chunks of pixels with equal coverage quickly.
 | 
						|
 */
 | 
						|
public final class ScanlineCoverage
 | 
						|
{
 | 
						|
 | 
						|
  /**
 | 
						|
   * Iterates over the coverage list and calculates the actual coverage
 | 
						|
   * ranges on a scanline.
 | 
						|
   */
 | 
						|
  public final class Iterator
 | 
						|
  {
 | 
						|
    /**
 | 
						|
     * This instance is reused in the iteration.
 | 
						|
     */
 | 
						|
    private Range range;
 | 
						|
 | 
						|
    /**
 | 
						|
     * The pointer to the current item in the iteration.
 | 
						|
     */
 | 
						|
    private Coverage currentItem;
 | 
						|
 | 
						|
    /**
 | 
						|
     * The current coverage value.
 | 
						|
     */
 | 
						|
    private int currentCoverage;
 | 
						|
 | 
						|
    /**
 | 
						|
     * True when the current pixel coverage has already been handled, false
 | 
						|
     * otherwise.
 | 
						|
     */
 | 
						|
    private boolean handledPixelCoverage;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Creates a new CoverageIterator.
 | 
						|
     */
 | 
						|
    Iterator()
 | 
						|
    {
 | 
						|
      range = new Range();
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the next coverage range on the scanline. The returned object
 | 
						|
     * will always be the same object, but with different values. Keep that
 | 
						|
     * in mind when dealing with this object.
 | 
						|
     *
 | 
						|
     * @return the next coverage range on the scanline
 | 
						|
     */
 | 
						|
    public Range next()
 | 
						|
    {
 | 
						|
      // TODO: Lump together the single-pixel coverage and the
 | 
						|
      // between-pixel coverage when the pixel coverage delta is 0.
 | 
						|
      if (handledPixelCoverage == false)
 | 
						|
        {
 | 
						|
          // Handle single pixel coverage.
 | 
						|
          range.setXPos(currentItem.xPos);
 | 
						|
          range.setLength(1);
 | 
						|
          range.setCoverage(currentCoverage + currentItem.pixelCoverage);
 | 
						|
          handledPixelCoverage = true;
 | 
						|
        }
 | 
						|
      else
 | 
						|
        {
 | 
						|
          // Handle pixel span coverage.
 | 
						|
          currentCoverage += currentItem.covDelta;
 | 
						|
          range.setCoverage(currentCoverage);
 | 
						|
          range.setXPos(currentItem.xPos + 1);
 | 
						|
          currentItem = currentItem.next;
 | 
						|
          range.setLength(currentItem.xPos - range.xPos);
 | 
						|
          handledPixelCoverage = false;
 | 
						|
        }
 | 
						|
      return range;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns {@ true} when there are more coverage ranges to iterate,
 | 
						|
     * {@ false} otherwise.
 | 
						|
     *
 | 
						|
     * @return {@ true} when there are more coverage ranges to iterate,
 | 
						|
     *         {@ false} otherwise
 | 
						|
     */
 | 
						|
    public boolean hasNext()
 | 
						|
    {
 | 
						|
      boolean hasNext;
 | 
						|
      if (currentItem != null && handledPixelCoverage == false)
 | 
						|
        {
 | 
						|
          // We have at least one more coverage item when there's a pixel
 | 
						|
          // coverage piece left.
 | 
						|
          hasNext = true;
 | 
						|
        }
 | 
						|
      else if (currentItem == null || currentItem.next == null
 | 
						|
          || currentItem.next == last)
 | 
						|
        {
 | 
						|
          hasNext = false;
 | 
						|
        }
 | 
						|
      else
 | 
						|
        {
 | 
						|
          hasNext = true;
 | 
						|
        }
 | 
						|
      return hasNext;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Resets this iterator to the start of the list.
 | 
						|
     */
 | 
						|
    void reset()
 | 
						|
    {
 | 
						|
      currentItem = head;
 | 
						|
      currentCoverage = 0;
 | 
						|
      handledPixelCoverage = false;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * A data object that carries information about pixel coverage on a scanline.
 | 
						|
   * The data consists of a starting X position on the scanline, the
 | 
						|
   * length of the range in pixels and the actual coverage value.
 | 
						|
   **/
 | 
						|
  public static final class Range
 | 
						|
  {
 | 
						|
    /**
 | 
						|
     * The X position on the scanline, in pixels.
 | 
						|
     */
 | 
						|
    private int xPos;
 | 
						|
 | 
						|
    /**
 | 
						|
     * The length of the range, in pixels.
 | 
						|
     */
 | 
						|
    private int length;
 | 
						|
 | 
						|
    /**
 | 
						|
     * The actual coverage. The relation depends on
 | 
						|
     * {@link ScanlineCoverage#maxCoverage}.
 | 
						|
     */
 | 
						|
    private int coverage;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Creates a new CoverageRange object.
 | 
						|
     */
 | 
						|
    Range()
 | 
						|
    {
 | 
						|
      // Nothing to do. The values get initialized in the corresponding
 | 
						|
      // setters.
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Sets the X start position (left) on the scanline. This value is
 | 
						|
     * considered to be in pixels and device space.
 | 
						|
     *
 | 
						|
     * @param x the x position
 | 
						|
     */
 | 
						|
    void setXPos(int x)
 | 
						|
    {
 | 
						|
      xPos = x;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the X start position (left) on the scanline. This value
 | 
						|
     * is considered to be in pixels and device space.
 | 
						|
     *
 | 
						|
     * @return the X position on the scanline
 | 
						|
     */
 | 
						|
    public int getXPos()
 | 
						|
    {
 | 
						|
      return xPos;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Sets the length of the pixel range. This is in pixel units.
 | 
						|
     *
 | 
						|
     * @param l the length of the range
 | 
						|
     */
 | 
						|
    void setLength(int l)
 | 
						|
    {
 | 
						|
      length = l;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the length of the range in pixel units.
 | 
						|
     *
 | 
						|
     * @return the length of the range in pixel units
 | 
						|
     */
 | 
						|
    public int getLength()
 | 
						|
    {
 | 
						|
      return length;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the first X position after the range.
 | 
						|
     *
 | 
						|
     * @return the first X position after the range
 | 
						|
     */
 | 
						|
    public int getXPosEnd()
 | 
						|
    {
 | 
						|
      return xPos + length;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Sets the coverage of the pixel range. The relation of that value
 | 
						|
     * depends on {@link ScanlineCoverage#maxCoverage}.
 | 
						|
     *
 | 
						|
     * @param cov the coverage value for the pixel range
 | 
						|
     */
 | 
						|
    void setCoverage(int cov)
 | 
						|
    {
 | 
						|
      coverage = cov;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the coverage of the pixel range. The relation of this value
 | 
						|
     * depends on {@link ScanlineCoverage#getMaxCoverage()}.
 | 
						|
     *
 | 
						|
     * @return the coverage of the pixel range
 | 
						|
     */
 | 
						|
    public int getCoverage()
 | 
						|
    {
 | 
						|
      return coverage;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns a string representation.
 | 
						|
     */
 | 
						|
    public String toString()
 | 
						|
    {
 | 
						|
      return "Coverage range: xPos=" + xPos + ", length=" + length
 | 
						|
             + ", coverage: " + coverage;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * One bucket in the list.
 | 
						|
   */
 | 
						|
  private static final class Coverage
 | 
						|
  {
 | 
						|
    /**
 | 
						|
     * The X coordinate on the scanline to which this bucket belongs.
 | 
						|
     */
 | 
						|
    int xPos;
 | 
						|
 | 
						|
    /**
 | 
						|
     * The coverage delta from the pixel at xPos to xPos + 1.
 | 
						|
     */
 | 
						|
    int covDelta;
 | 
						|
 | 
						|
    /**
 | 
						|
     * The delta for the pixel at xPos. This is added to the pixel at xPos,
 | 
						|
     * but not to the following pixel.
 | 
						|
     */
 | 
						|
    int pixelCoverage;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Implements a linked list. This points to the next element of the list.
 | 
						|
     */
 | 
						|
    Coverage next;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the X coordinate for this entry.
 | 
						|
     *
 | 
						|
     * @return the X coordinate for this entry
 | 
						|
     */
 | 
						|
    public int getXPos()
 | 
						|
    {
 | 
						|
      return xPos;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the coverage delta for this entry.
 | 
						|
     *
 | 
						|
     * @return the coverage delta for this entry
 | 
						|
     */
 | 
						|
    public int getCoverageDelta()
 | 
						|
    {
 | 
						|
      return covDelta;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns a string representation.
 | 
						|
     *
 | 
						|
     * @return a string representation
 | 
						|
     */
 | 
						|
    public String toString()
 | 
						|
    {
 | 
						|
      return "Coverage: xPos: " + xPos + ", covDelta: " + covDelta;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns a string representation of this entry and all the following
 | 
						|
     * in the linked list.
 | 
						|
     *
 | 
						|
     * @return a string representation of this entry and all the following
 | 
						|
     *         in the linked list
 | 
						|
     */
 | 
						|
    public String list()
 | 
						|
    {
 | 
						|
      String str = toString();
 | 
						|
      if (next != null)
 | 
						|
        str = str + " --> " + next.list();
 | 
						|
      return str;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * The head of the sorted list of buckets.
 | 
						|
   */
 | 
						|
  private Coverage head;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The current bucket. We make use of the fact that the scanline converter
 | 
						|
   * always scans the scanline (and thus this list) from left to right to
 | 
						|
   * quickly find buckets or insertion points.
 | 
						|
   */
 | 
						|
  private Coverage current;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The item that is before current in the list.
 | 
						|
   */
 | 
						|
  private Coverage currentPrev;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The bucket after the last valid bucket. Unused buckets are not thrown
 | 
						|
   * away and garbage collected. Instead, we keep them at the tail of the list
 | 
						|
   * and reuse them when necessary.
 | 
						|
   */
 | 
						|
  private Coverage last;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The last valid entry.
 | 
						|
   */
 | 
						|
  private Coverage lastPrev;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The minimum X coordinate of this scanline.
 | 
						|
   */
 | 
						|
  private int minX;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The maximum X coordinate of this scanline.
 | 
						|
   */
 | 
						|
  private int maxX;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The maximum coverage value.
 | 
						|
   */
 | 
						|
  private int maxCoverage;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The iterator over the ranges of this scanline.
 | 
						|
   */
 | 
						|
  private Iterator iterator;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Creates a new ScanlineCoverage instance.
 | 
						|
   */
 | 
						|
  public ScanlineCoverage()
 | 
						|
  {
 | 
						|
    iterator = new Iterator();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Indicates the the next scan of the scanline begins and that the next
 | 
						|
   * request will be at the beginning of this list. This makes searching and
 | 
						|
   * sorting of this list very quick.
 | 
						|
   */
 | 
						|
  public void rewind()
 | 
						|
  {
 | 
						|
    current = head;
 | 
						|
    currentPrev = null;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Clears the list. This does not throw away the old buckets but only
 | 
						|
   * resets the end-pointer of the list to the first element. All buckets are
 | 
						|
   * then unused and are reused when the list is filled again.
 | 
						|
   */
 | 
						|
  public void clear()
 | 
						|
  {
 | 
						|
    last = head;
 | 
						|
    lastPrev = null;
 | 
						|
    current = head;
 | 
						|
    currentPrev = null;
 | 
						|
    minX = Integer.MAX_VALUE;
 | 
						|
    maxX = Integer.MIN_VALUE;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * This adds the specified coverage to the pixel at the specified
 | 
						|
   * X position.
 | 
						|
   *
 | 
						|
   * @param x the X position
 | 
						|
   * @param xc the x coverage
 | 
						|
   * @param yc the y coverage
 | 
						|
   */
 | 
						|
  public void add(int x, int xc, int yc)
 | 
						|
  {
 | 
						|
    Coverage bucket = findOrInsert(x);
 | 
						|
    bucket.covDelta += xc;
 | 
						|
    bucket.pixelCoverage += yc;
 | 
						|
    minX = Math.min(minX, x);
 | 
						|
    maxX = Math.max(maxX, x);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the maximum coverage value for the scanline.
 | 
						|
   *
 | 
						|
   * @return the maximum coverage value for the scanline
 | 
						|
   */
 | 
						|
  public int getMaxCoverage()
 | 
						|
  {
 | 
						|
    return maxCoverage;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Sets the maximum coverage value for the scanline.
 | 
						|
   *
 | 
						|
   * @param maxCov the maximum coverage value for the scanline
 | 
						|
   */
 | 
						|
  void setMaxCoverage(int maxCov)
 | 
						|
  {
 | 
						|
    maxCoverage = maxCov;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the maximum X coordinate of the current scanline.
 | 
						|
   *
 | 
						|
   * @return the maximum X coordinate of the current scanline
 | 
						|
   */
 | 
						|
  public int getMaxX()
 | 
						|
  {
 | 
						|
    return maxX;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the minimum X coordinate of the current scanline.
 | 
						|
   *
 | 
						|
   * @return the minimum X coordinate of the current scanline
 | 
						|
   */
 | 
						|
  public int getMinX()
 | 
						|
  {
 | 
						|
    return minX;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Finds the bucket in the list with the specified X coordinate.
 | 
						|
   * If no such bucket is found, then a new one is fetched (either a cached
 | 
						|
   * bucket from the end of the list or a newly allocated one) inserted at the
 | 
						|
   * correct position and returned.
 | 
						|
   *
 | 
						|
   * @param x the X coordinate
 | 
						|
   *
 | 
						|
   * @return a bucket to hold the coverage data
 | 
						|
   */
 | 
						|
  private Coverage findOrInsert(int x)
 | 
						|
  {
 | 
						|
    // First search for a matching bucket.
 | 
						|
    if (head == null)
 | 
						|
      {
 | 
						|
        // Special case: the list is still empty.
 | 
						|
        // Testpoint 1.
 | 
						|
        head = new Coverage();
 | 
						|
        head.xPos = x;
 | 
						|
        current = head;
 | 
						|
        currentPrev = null;
 | 
						|
        return head;
 | 
						|
      }
 | 
						|
 | 
						|
    // This performs a linear search, starting from the current bucket.
 | 
						|
    // This is reasonably efficient because access to this list is always done
 | 
						|
    // in a linear fashion and we are usually not more then 1 or 2 buckets away
 | 
						|
    // from the one we're looking for.
 | 
						|
    Coverage match = current;
 | 
						|
    Coverage prev = currentPrev;
 | 
						|
    while (match != last && match.xPos < x)
 | 
						|
      {
 | 
						|
        prev = match;
 | 
						|
        match = match.next;
 | 
						|
      }
 | 
						|
 | 
						|
    // At this point we have either found an entry with xPos >= x, or reached
 | 
						|
    // the end of the list (match == last || match == null).
 | 
						|
    if (match == null)
 | 
						|
      {
 | 
						|
        // End of the list. No cached items to reuse.
 | 
						|
        // Testpoint 2.
 | 
						|
        match = new Coverage();
 | 
						|
        match.xPos = x;
 | 
						|
        if (prev != null)
 | 
						|
          prev.next = match;
 | 
						|
        current = match;
 | 
						|
        currentPrev = prev;
 | 
						|
        return match;
 | 
						|
      }
 | 
						|
    else if (match == last)
 | 
						|
      {
 | 
						|
        // End of the list. Reuse this item. Expand list.
 | 
						|
        // Testpoint 3.
 | 
						|
        last = match.next;
 | 
						|
        lastPrev = match;
 | 
						|
        match.xPos = x;
 | 
						|
        match.covDelta = 0;
 | 
						|
        match.pixelCoverage = 0;
 | 
						|
        // Keep link to last element or null, indicating the end of the list.
 | 
						|
        current = match;
 | 
						|
        currentPrev = prev;
 | 
						|
        return match;
 | 
						|
      }
 | 
						|
 | 
						|
    if (x == match.xPos)
 | 
						|
      {
 | 
						|
        // Special case: We have another coverage entry at the same location
 | 
						|
        // as an already existing entry. Return this.
 | 
						|
        // Testpoint 4.
 | 
						|
        current = match;
 | 
						|
        currentPrev = prev;
 | 
						|
        return match;
 | 
						|
      }
 | 
						|
    else // x <= match.xPos
 | 
						|
      {
 | 
						|
        assert (x <= match.xPos);
 | 
						|
        assert (prev == null ||x > prev.xPos);
 | 
						|
 | 
						|
        // Create new entry, or reuse existing one.
 | 
						|
        Coverage cov;
 | 
						|
        if (last != null)
 | 
						|
          {
 | 
						|
            // Testpoint 5.
 | 
						|
            cov = last;
 | 
						|
            last = cov.next;
 | 
						|
            lastPrev.next = last;
 | 
						|
          }
 | 
						|
        else
 | 
						|
          {
 | 
						|
            // Testpoint 6.
 | 
						|
            cov = new Coverage();
 | 
						|
          }
 | 
						|
 | 
						|
        cov.xPos = x;
 | 
						|
        cov.covDelta = 0;
 | 
						|
        cov.pixelCoverage = 0;
 | 
						|
 | 
						|
        // Insert this item in the list.
 | 
						|
        if (prev != null)
 | 
						|
          {
 | 
						|
            // Testpoint 5 & 6.
 | 
						|
            prev.next = cov;
 | 
						|
            cov.next = match;
 | 
						|
            current = cov;
 | 
						|
            currentPrev = prev;
 | 
						|
          }
 | 
						|
        else
 | 
						|
          {
 | 
						|
            // Testpoint 7.
 | 
						|
            assert (match == head);
 | 
						|
            // Insert at head.
 | 
						|
            head = cov;
 | 
						|
            head.next = match;
 | 
						|
            current = head;
 | 
						|
            currentPrev = null;
 | 
						|
          }
 | 
						|
        return cov;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * (Re-)Starts iterating the coverage values for the scanline.
 | 
						|
   * Use the returned iterator to get the consecutive coverage ranges.
 | 
						|
   *
 | 
						|
   * @return the iterator
 | 
						|
   */
 | 
						|
  public Iterator iterate()
 | 
						|
  {
 | 
						|
    iterator.reset();
 | 
						|
    return iterator;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns {@ true} if this object has no entries for the current scanline,
 | 
						|
   * {@ false} otherwise.
 | 
						|
   *
 | 
						|
   * @return {@ true} if this object has no entries for the current scanline,
 | 
						|
   *         {@ false} otherwise
 | 
						|
   */
 | 
						|
  public boolean isEmpty()
 | 
						|
  {
 | 
						|
    return head == null || head == last
 | 
						|
           || head.next == null || head.next == last;
 | 
						|
  }
 | 
						|
 | 
						|
}
 |