public class

RegionSpanIterator

extends Object
implements SpanIterator
/*
 * Copyright (c) 1999, 2002, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code 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
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package sun.java2d.pipe;

/**
 * This class implements the ShapeIterator interface for a Region.
 * This is useful as the source iterator of a device clip region
 * (in its native guise), and also as the result of clipping a
 * Region to a rectangle.
 */
public class RegionSpanIterator implements SpanIterator {
    // The RegionIterator that we use to do the work
    RegionIterator ri;

    // Clipping bounds
    int lox, loy, hix, hiy;

    // Current Y band limits
    int curloy, curhiy;

    // Are we done?
    boolean done = false;

    // Is the associated Region rectangular?
    boolean isrect;

/*
    REMIND: For native implementation
    long pData;     // Private storage of rect info

    static {
        initIDs();
    }

    public static native void initIDs();
*/

    /**
     * Constructs an instance based on the given Region
     */
    public RegionSpanIterator(Region r) {
        int[] bounds = new int[4];

        r.getBounds(bounds);
        lox = bounds[0];
        loy = bounds[1];
        hix = bounds[2];
        hiy = bounds[3];
        isrect = r.isRectangular();

        ri = r.getIterator();
    }

    /**
     * Gets the bbox of the available region spans.
     */
    public void getPathBox(int pathbox[]) {
        pathbox[0] = lox;
        pathbox[1] = loy;
        pathbox[2] = hix;
        pathbox[3] = hiy;
    }

    /**
     * Intersect the box used for clipping the output spans with the
     * given box.
     */
    public void intersectClipBox(int clox, int cloy, int chix, int chiy) {
        if (clox > lox) {
            lox = clox;
        }
        if (cloy > loy) {
            loy = cloy;
        }
        if (chix < hix) {
            hix = chix;
        }
        if (chiy < hiy) {
            hiy = chiy;
        }
        done = lox >= hix || loy >= hiy;
    }

    /**
     * Fetches the next span that needs to be operated on.
     * If the return value is false then there are no more spans.
     */
    public boolean nextSpan(int spanbox[]) {

        // Quick test for end conditions
        if (done) {
            return false;
        }

        // If the Region is rectangular, we store our bounds (possibly
        // clipped via intersectClipBox()) in spanbox and return true
        // so that the caller will process the single span.  We set done
        // to true to ensure that this will be the last span processed.
        if (isrect) {
            getPathBox(spanbox);
            done = true;
            return true;
        }

        // Local cache of current span's bounds
        int curlox, curhix;
        int curloy = this.curloy;
        int curhiy = this.curhiy;

        while (true) {
            if (!ri.nextXBand(spanbox)) {
                if (!ri.nextYRange(spanbox)) {
                    done = true;
                    return false;
                }
                // Update the current y band and clip it
                curloy = spanbox[1];
                curhiy = spanbox[3];
                if (curloy < loy) {
                    curloy = loy;
                }
                if (curhiy > hiy) {
                    curhiy = hiy;
                }
                // Check for moving below the clip rect
                if (curloy >= hiy) {
                    done = true;
                    return false;
                }
                continue;
            }
            // Clip the x box
            curlox = spanbox[0];
            curhix = spanbox[2];
            if (curlox < lox) {
                curlox = lox;
            }
            if (curhix > hix) {
                curhix = hix;
            }
            // If it's non- box, we're done
            if (curlox < curhix && curloy < curhiy) {
                break;
            }
        }

        // Update the result and the store y range
        spanbox[0] = curlox;
        spanbox[1] = this.curloy = curloy;
        spanbox[2] = curhix;
        spanbox[3] = this.curhiy = curhiy;
        return true;
    }

    /**
     * This method tells the iterator that it may skip all spans
     * whose Y range is completely above the indicated Y coordinate.
     */
    public void skipDownTo(int y) {
        loy = y;
    }

    /**
     * This method returns a native pointer to a function block that
     * can be used by a native method to perform the same iteration
     * cycle that the above methods provide while avoiding upcalls to
     * the Java object.
     * The definition of the structure whose pointer is returned by
     * this method is defined in:
     * <pre>
     *     src/share/native/sun/java2d/pipe/SpanIterator.h
     * </pre>
     */
    public long getNativeIterator() {
        return 0;
    }

    /*
     * Cleans out all internal data structures.
     * REMIND: Native implementation
    public native void dispose();

    protected void finalize() {
        dispose();
    }
     */
}