0N/A/*
2362N/A * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage sun.java2d.pipe;
0N/A
0N/Aimport java.awt.geom.PathIterator;
0N/Aimport java.awt.Rectangle;
0N/A
0N/A/**
0N/A * This class clips a SpanIterator to a Region and outputs the
0N/A * resulting spans as another SpanIterator.
0N/A *
0N/A * Spans are output in the usual y/x order, unless the input span
0N/A * iterator doesn't conform to this order, or the iterator's span
0N/A * straddle more than one band of the Region used for clipping.
0N/A *
0N/A * Principle of operation:
0N/A *
0N/A * The iterator maintains a several cursors onto the RegionIterator
0N/A * in order to avoid having to buffer spans from the SpanIterator.
0N/A * They are:
0N/A * resetState The initial state of the RegionIterator
0N/A * lwm Low Water Mark, a running start point for
0N/A * processing each band. Usually goes down, but
0N/A * can be reset to resetState if a span has a lower
0N/A * start coordinate than the previous one.
0N/A * row The start of the current band of the RegionIterator
0N/A * box The current span of the current row
0N/A *
0N/A * The main nextSpan() loop implements a coroutine like structure, with
0N/A * three producers to get the next span, row and box calling each other
0N/A * to iterate through the span iterator and region.
0N/A *
0N/A * REMIND: Needs a native implementation!
0N/A */
0N/Apublic class RegionClipSpanIterator implements SpanIterator {
0N/A
0N/A // The inputs to the filter
0N/A Region rgn;
0N/A SpanIterator spanIter;
0N/A
0N/A // The cursors that track the progress through the region
0N/A RegionIterator resetState;
0N/A RegionIterator lwm;
0N/A RegionIterator row;
0N/A RegionIterator box;
0N/A
0N/A // The bounds of the current span iterator span
0N/A int spanlox, spanhix, spanloy, spanhiy;
0N/A
0N/A // The extent of the region band marking the low water mark
0N/A int lwmloy, lwmhiy;
0N/A
0N/A // The bounds of the current region box
0N/A int rgnlox, rgnloy, rgnhix, rgnhiy;
0N/A
0N/A // The bounding box of the input Region. Used for click
0N/A // rejection of iterator spans
0N/A int rgnbndslox, rgnbndsloy, rgnbndshix, rgnbndshiy;
0N/A
0N/A // The array used to hold coordinates from the region iterator
0N/A int rgnbox[] = new int[4];
0N/A
0N/A // The array used to hold coordinates from the span iterator
0N/A int spanbox[] = new int[4];
0N/A
0N/A // True if the next iterator span should be read on the next
0N/A // iteration of the main nextSpan() loop
0N/A boolean doNextSpan;
0N/A
0N/A // True if the next region box should be read on the next
0N/A // iteration of the main nextSpan() loop
0N/A boolean doNextBox;
0N/A
0N/A // True if there are no more spans or the Region is empty
0N/A boolean done = false;
0N/A
0N/A /*
0N/A * Creates an instance that filters the spans generated by
0N/A * spanIter through the region described by rgn.
0N/A */
0N/A public RegionClipSpanIterator(Region rgn, SpanIterator spanIter) {
0N/A
0N/A this.spanIter = spanIter;
0N/A
0N/A resetState = rgn.getIterator();
0N/A lwm = resetState.createCopy();
0N/A
0N/A if (!lwm.nextYRange(rgnbox)) {
0N/A done = true;
0N/A return;
0N/A }
0N/A
0N/A rgnloy = lwmloy = rgnbox[1];
0N/A rgnhiy = lwmhiy = rgnbox[3];
0N/A
0N/A rgn.getBounds(rgnbox);
0N/A rgnbndslox = rgnbox[0];
0N/A rgnbndsloy = rgnbox[1];
0N/A rgnbndshix = rgnbox[2];
0N/A rgnbndshiy = rgnbox[3];
0N/A if (rgnbndslox >= rgnbndshix ||
0N/A rgnbndsloy >= rgnbndshiy) {
0N/A done = true;
0N/A return;
0N/A }
0N/A
0N/A this.rgn = rgn;
0N/A
0N/A
0N/A row = lwm.createCopy();
0N/A box = row.createCopy();
0N/A doNextSpan = true;
0N/A doNextBox = false;
0N/A }
0N/A
0N/A /*
0N/A * Gets the bbox of the available path segments, clipped to the
0N/A * Region.
0N/A */
0N/A public void getPathBox(int pathbox[]) {
0N/A int[] rgnbox = new int[4];
0N/A rgn.getBounds(rgnbox);
0N/A spanIter.getPathBox(pathbox);
0N/A
0N/A if (pathbox[0] < rgnbox[0]) {
0N/A pathbox[0] = rgnbox[0];
0N/A }
0N/A
0N/A if (pathbox[1] < rgnbox[1]) {
0N/A pathbox[1] = rgnbox[1];
0N/A }
0N/A
0N/A if (pathbox[2] > rgnbox[2]) {
0N/A pathbox[2] = rgnbox[2];
0N/A }
0N/A
0N/A if (pathbox[3] > rgnbox[3]) {
0N/A pathbox[3] = rgnbox[3];
0N/A }
0N/A}
0N/A
0N/A /*
0N/A * Intersects the path box with the given bbox.
0N/A * Returned spans are clipped to this region, or discarded
0N/A * altogether if they lie outside it.
0N/A */
0N/A public void intersectClipBox(int lox, int loy, int hix, int hiy) {
0N/A spanIter.intersectClipBox(lox, loy, hix, hiy);
0N/A }
0N/A
0N/A
0N/A /*
0N/A * Fetches the next span that needs to be operated on.
0N/A * If the return value is false then there are no more spans.
0N/A */
0N/A public boolean nextSpan(int resultbox[]) {
0N/A if (done) {
0N/A return false;
0N/A }
0N/A
0N/A int resultlox, resultloy, resulthix, resulthiy;
0N/A boolean doNextRow = false;
0N/A
0N/A // REMIND: Cache the coordinate inst vars used in this loop
0N/A // in locals vars.
0N/A while (true) {
0N/A // We've exhausted the current span so get the next one
0N/A if (doNextSpan) {
0N/A if (!spanIter.nextSpan(spanbox)) {
0N/A done = true;
0N/A return false;
0N/A } else {
0N/A spanlox = spanbox[0];
0N/A // Clip out spans that lie outside of the rgn's bounds
0N/A if (spanlox >= rgnbndshix) {
0N/A continue;
0N/A }
0N/A
0N/A spanloy = spanbox[1];
0N/A if (spanloy >= rgnbndshiy) {
0N/A continue;
0N/A }
0N/A
0N/A spanhix = spanbox[2];
0N/A if (spanhix <= rgnbndslox) {
0N/A continue;
0N/A }
0N/A
0N/A spanhiy = spanbox[3];
0N/A if (spanhiy <= rgnbndsloy) {
0N/A continue;
0N/A }
0N/A }
0N/A // If the span starts higher up than the low-water mark,
0N/A // reset the lwm. This can only happen if spans aren't
0N/A // returned in strict y/x order, or the first time through.
0N/A if (lwmloy > spanloy) {
0N/A lwm.copyStateFrom(resetState);
0N/A lwm.nextYRange(rgnbox);
0N/A lwmloy = rgnbox[1];
0N/A lwmhiy = rgnbox[3];
0N/A }
0N/A // Skip to the first rgn row whose bottom edge is
0N/A // below the top of the current span. This will only
0N/A // execute >0 times when the current span starts in a
0N/A // lower region row than the previous one, or possibly the
0N/A // first time through.
0N/A while (lwmhiy <= spanloy) {
0N/A if (!lwm.nextYRange(rgnbox))
0N/A break;
0N/A lwmloy = rgnbox[1];
0N/A lwmhiy = rgnbox[3];
0N/A }
0N/A // If the row overlaps the span, process it, otherwise
0N/A // fetch another span
0N/A if (lwmhiy > spanloy && lwmloy < spanhiy) {
0N/A // Update the current row if it's different from the
0N/A // new lwm
0N/A if (rgnloy != lwmloy) {
0N/A row.copyStateFrom(lwm);
0N/A rgnloy = lwmloy;
0N/A rgnhiy = lwmhiy;
0N/A }
0N/A box.copyStateFrom(row);
0N/A doNextBox = true;
0N/A doNextSpan = false;
0N/A }
0N/A continue;
0N/A }
0N/A
0N/A // The current row's spans are exhausted, do the next one
0N/A if (doNextRow) {
0N/A // Next time we either do the next span or the next box
0N/A doNextRow = false;
0N/A // Get the next row
0N/A boolean ok = row.nextYRange(rgnbox);
0N/A // If there was one, update the bounds
0N/A if (ok) {
0N/A rgnloy = rgnbox[1];
0N/A rgnhiy = rgnbox[3];
0N/A }
0N/A if (!ok || rgnloy >= spanhiy) {
0N/A // If we've exhausted the rows or this one is below the span,
0N/A // go onto the next span
0N/A doNextSpan = true;
0N/A }
0N/A else {
0N/A // Otherwise get the first box on this row
0N/A box.copyStateFrom(row);
0N/A doNextBox = true;
0N/A }
0N/A continue;
0N/A }
0N/A
0N/A // Process the next box in the current row
0N/A if (doNextBox) {
0N/A boolean ok = box.nextXBand(rgnbox);
0N/A if (ok) {
0N/A rgnlox = rgnbox[0];
0N/A rgnhix = rgnbox[2];
0N/A }
0N/A if (!ok || rgnlox >= spanhix) {
0N/A // If there was no next rgn span or it's beyond the
0N/A // source span, go onto the next row or span
0N/A doNextBox = false;
0N/A if (rgnhiy >= spanhiy) {
0N/A // If the current row totally overlaps the span,
0N/A // go onto the next span
0N/A doNextSpan = true;
0N/A } else {
0N/A // otherwise go onto the next rgn row
0N/A doNextRow = true;
0N/A }
0N/A } else {
0N/A // Otherwise, if the new rgn span overlaps the
0N/A // spanbox, no need to get another box
0N/A doNextBox = rgnhix <= spanlox;
0N/A }
0N/A continue;
0N/A }
0N/A
0N/A // Prepare to do the next box either on this call or
0N/A // or the subsequent one
0N/A doNextBox = true;
0N/A
0N/A // Clip the current span against the current box
0N/A if (spanlox > rgnlox) {
0N/A resultlox = spanlox;
0N/A }
0N/A else {
0N/A resultlox = rgnlox;
0N/A }
0N/A
0N/A if (spanloy > rgnloy) {
0N/A resultloy = spanloy;
0N/A }
0N/A else {
0N/A resultloy = rgnloy;
0N/A }
0N/A
0N/A if (spanhix < rgnhix) {
0N/A resulthix = spanhix;
0N/A }
0N/A else {
0N/A resulthix = rgnhix;
0N/A }
0N/A
0N/A if (spanhiy < rgnhiy) {
0N/A resulthiy = spanhiy;
0N/A }
0N/A else {
0N/A resulthiy = rgnhiy;
0N/A }
0N/A
0N/A // If the result is empty, try then next box
0N/A // otherwise return the box.
0N/A // REMIND: I think by definition it's non-empty
0N/A // if we're here. Need to think about this some more.
0N/A if (resultlox >= resulthix ||
0N/A resultloy >= resulthiy) {
0N/A continue;
0N/A }
0N/A else {
0N/A break;
0N/A }
0N/A }
0N/A
0N/A resultbox[0] = resultlox;
0N/A resultbox[1] = resultloy;
0N/A resultbox[2] = resulthix;
0N/A resultbox[3] = resulthiy;
0N/A return true;
0N/A
0N/A }
0N/A
0N/A
0N/A /**
0N/A * This method tells the iterator that it may skip all spans
0N/A * whose Y range is completely above the indicated Y coordinate.
0N/A */
0N/A public void skipDownTo(int y) {
0N/A spanIter.skipDownTo(y);
0N/A }
0N/A
0N/A /**
0N/A * This method returns a native pointer to a function block that
0N/A * can be used by a native method to perform the same iteration
0N/A * cycle that the above methods provide while avoiding upcalls to
0N/A * the Java object.
0N/A * The definition of the structure whose pointer is returned by
0N/A * this method is defined in:
0N/A * <pre>
0N/A * src/share/native/sun/java2d/pipe/SpanIterator.h
0N/A * </pre>
0N/A */
0N/A public long getNativeIterator() {
0N/A return 0;
0N/A }
0N/A
0N/A /*
0N/A * Cleans out all internal data structures.
0N/A */
0N/A //public native void dispose();
0N/A
0N/A protected void finalize() {
0N/A //dispose();
0N/A }
0N/A
0N/A}