392 lines · 12.6 KB · Java
RawDownload
/* * Copyright (c) 1999, 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; import java.awt.geom.PathIterator;import java.awt.Rectangle; /** * This class clips a SpanIterator to a Region and outputs the * resulting spans as another SpanIterator. * * Spans are output in the usual y/x order, unless the input span * iterator doesn't conform to this order, or the iterator's span * straddle more than one band of the Region used for clipping. * * Principle of operation: * * The iterator maintains a several cursors onto the RegionIterator * in order to avoid having to buffer spans from the SpanIterator. * They are: *  resetState    The initial state of the RegionIterator *  lwm             Low Water Mark, a running start point for *                  processing each band. Usually goes down, but *                  can be reset to resetState if a span has a lower *                  start coordinate than the previous one. *  row             The start of the current band of the RegionIterator *  box             The current span of the current row * * The main nextSpan() loop implements a coroutine like structure, with * three producers to get the next span, row and box calling each other * to iterate through the span iterator and region. * * REMIND: Needs a native implementation! */public class RegionClipSpanIterator implements SpanIterator {     // The inputs to the filter    Region rgn;    SpanIterator spanIter;     // The cursors that track the progress through the region    RegionIterator resetState;    RegionIterator lwm;    RegionIterator row;    RegionIterator box;     // The bounds of the current span iterator span    int spanlox, spanhix, spanloy, spanhiy;     // The extent of the region band marking the low water mark    int lwmloy, lwmhiy;     // The bounds of the current region box    int rgnlox, rgnloy, rgnhix, rgnhiy;     // The bounding box of the input Region. Used for click    // rejection of iterator spans    int rgnbndslox, rgnbndsloy, rgnbndshix, rgnbndshiy;     // The array used to hold coordinates from the region iterator    int rgnbox[] = new int[4];     // The array used to hold coordinates from the span iterator    int spanbox[] = new int[4];     // True if the next iterator span should be read on the next    // iteration of the main nextSpan() loop    boolean doNextSpan;     // True if the next region box should be read on the next    // iteration of the main nextSpan() loop    boolean doNextBox;     // True if there are no more spans or the Region is empty    boolean done = false;     /*     * Creates an instance that filters the spans generated by     * spanIter through the region described by rgn.     */    public RegionClipSpanIterator(Region rgn, SpanIterator spanIter) {         this.spanIter = spanIter;         resetState = rgn.getIterator();        lwm = resetState.createCopy();         if (!lwm.nextYRange(rgnbox)) {            done = true;            return;        }         rgnloy = lwmloy = rgnbox[1];        rgnhiy = lwmhiy = rgnbox[3];         rgn.getBounds(rgnbox);        rgnbndslox = rgnbox[0];        rgnbndsloy = rgnbox[1];        rgnbndshix = rgnbox[2];        rgnbndshiy = rgnbox[3];        if (rgnbndslox >= rgnbndshix ||            rgnbndsloy >= rgnbndshiy) {            done = true;            return;        }         this.rgn = rgn;          row = lwm.createCopy();        box = row.createCopy();        doNextSpan = true;        doNextBox = false;    }     /*     * Gets the bbox of the available path segments, clipped to the     * Region.     */    public void getPathBox(int pathbox[]) {        int[] rgnbox = new int[4];        rgn.getBounds(rgnbox);        spanIter.getPathBox(pathbox);         if (pathbox[0] < rgnbox[0]) {            pathbox[0] = rgnbox[0];        }         if (pathbox[1] < rgnbox[1]) {            pathbox[1] = rgnbox[1];        }         if (pathbox[2] > rgnbox[2]) {            pathbox[2] = rgnbox[2];        }         if (pathbox[3] > rgnbox[3]) {            pathbox[3] = rgnbox[3];        }}     /*     * Intersects the path box with the given bbox.     * Returned spans are clipped to this region, or discarded     * altogether if they lie outside it.     */    public void intersectClipBox(int lox, int loy, int hix, int hiy) {        spanIter.intersectClipBox(lox, loy, hix, 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 resultbox[]) {        if (done) {            return false;        }         int resultlox, resultloy, resulthix, resulthiy;        boolean doNextRow = false;         // REMIND: Cache the coordinate inst vars used in this loop        // in locals vars.        while (true) {            // We've exhausted the current span so get the next one            if (doNextSpan) {                if (!spanIter.nextSpan(spanbox)) {                    done = true;                    return false;                } else {                    spanlox = spanbox[0];                    // Clip out spans that lie outside of the rgn's bounds                    if (spanlox >= rgnbndshix) {                        continue;                    }                     spanloy = spanbox[1];                    if (spanloy >= rgnbndshiy) {                        continue;                    }                     spanhix = spanbox[2];                    if (spanhix <= rgnbndslox) {                        continue;                    }                     spanhiy = spanbox[3];                    if (spanhiy <= rgnbndsloy) {                        continue;                    }                }                // If the span starts higher up than the low-water mark,                // reset the lwm. This can only happen if spans aren't                // returned in strict y/x order, or the first time through.                if (lwmloy > spanloy) {                    lwm.copyStateFrom(resetState);                    lwm.nextYRange(rgnbox);                    lwmloy = rgnbox[1];                    lwmhiy = rgnbox[3];                }                // Skip to the first rgn row whose bottom edge is                // below the top of the current span. This will only                // execute >0 times when the current span starts in a                // lower region row than the previous one, or possibly the                // first time through.                while (lwmhiy <= spanloy) {                    if (!lwm.nextYRange(rgnbox))                        break;                    lwmloy = rgnbox[1];                    lwmhiy = rgnbox[3];                }                // If the row overlaps the span, process it, otherwise                // fetch another span                if (lwmhiy > spanloy && lwmloy < spanhiy) {                    // Update the current row if it's different from the                    // new lwm                    if (rgnloy != lwmloy) {                        row.copyStateFrom(lwm);                        rgnloy = lwmloy;                        rgnhiy = lwmhiy;                    }                    box.copyStateFrom(row);                    doNextBox = true;                    doNextSpan = false;                }                continue;            }             // The current row's spans are exhausted, do the next one            if (doNextRow) {                // Next time we either do the next span or the next box                doNextRow = false;                // Get the next row                boolean ok = row.nextYRange(rgnbox);                // If there was one, update the bounds                if (ok) {                    rgnloy = rgnbox[1];                    rgnhiy = rgnbox[3];                }                if (!ok || rgnloy >= spanhiy) {                    // If we've exhausted the rows or this one is below the span,                    // go onto the next span                    doNextSpan = true;                }                else {                    // Otherwise get the first box on this row                    box.copyStateFrom(row);                    doNextBox = true;                }                continue;            }             // Process the next box in the current row            if (doNextBox) {                boolean ok = box.nextXBand(rgnbox);                if (ok) {                    rgnlox = rgnbox[0];                    rgnhix = rgnbox[2];                }                if (!ok || rgnlox >= spanhix) {                    // If there was no next rgn span or it's beyond the                    // source span, go onto the next row or span                    doNextBox = false;                    if (rgnhiy >= spanhiy) {                        // If the current row totally overlaps the span,                        // go onto the next span                        doNextSpan = true;                    } else {                        // otherwise go onto the next rgn row                        doNextRow = true;                    }                } else {                    // Otherwise, if the new rgn span overlaps the                    // spanbox, no need to get another box                    doNextBox = rgnhix <= spanlox;                }                continue;            }             // Prepare to do the next box either on this call or            // or the subsequent one            doNextBox = true;             // Clip the current span against the current box            if (spanlox > rgnlox) {                resultlox = spanlox;            }            else {                resultlox = rgnlox;            }             if (spanloy > rgnloy) {                resultloy = spanloy;            }            else {                resultloy = rgnloy;            }             if (spanhix < rgnhix) {                resulthix = spanhix;            }            else {                resulthix = rgnhix;            }             if (spanhiy < rgnhiy) {                resulthiy = spanhiy;            }            else {                resulthiy = rgnhiy;            }             // If the result is empty, try then next box            // otherwise return the box.            // REMIND: I think by definition it's non-empty            // if we're here. Need to think about this some more.            if (resultlox >= resulthix ||                resultloy >= resulthiy) {                    continue;            }            else {                    break;            }        }         resultbox[0] = resultlox;        resultbox[1] = resultloy;        resultbox[2] = resulthix;        resultbox[3] = resulthiy;        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) {        spanIter.skipDownTo(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.     */    //public native void dispose();     protected void finalize() {        //dispose();    } }