/* * 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(); } }
/*
* 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();
}
}