Path: blob/master/src/java.desktop/share/classes/sun/java2d/pipe/RegionClipSpanIterator.java
41159 views
/*1* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.java2d.pipe;262728/**29* This class clips a SpanIterator to a Region and outputs the30* resulting spans as another SpanIterator.31*32* Spans are output in the usual y/x order, unless the input span33* iterator doesn't conform to this order, or the iterator's span34* straddle more than one band of the Region used for clipping.35*36* Principle of operation:37*38* The iterator maintains a several cursors onto the RegionIterator39* in order to avoid having to buffer spans from the SpanIterator.40* They are:41* resetState The initial state of the RegionIterator42* lwm Low Water Mark, a running start point for43* processing each band. Usually goes down, but44* can be reset to resetState if a span has a lower45* start coordinate than the previous one.46* row The start of the current band of the RegionIterator47* box The current span of the current row48*49* The main nextSpan() loop implements a coroutine like structure, with50* three producers to get the next span, row and box calling each other51* to iterate through the span iterator and region.52*53* REMIND: Needs a native implementation!54*/55public class RegionClipSpanIterator implements SpanIterator {5657// The inputs to the filter58Region rgn;59SpanIterator spanIter;6061// The cursors that track the progress through the region62RegionIterator resetState;63RegionIterator lwm;64RegionIterator row;65RegionIterator box;6667// The bounds of the current span iterator span68int spanlox, spanhix, spanloy, spanhiy;6970// The extent of the region band marking the low water mark71int lwmloy, lwmhiy;7273// The bounds of the current region box74int rgnlox, rgnloy, rgnhix, rgnhiy;7576// The bounding box of the input Region. Used for click77// rejection of iterator spans78int rgnbndslox, rgnbndsloy, rgnbndshix, rgnbndshiy;7980// The array used to hold coordinates from the region iterator81int[] rgnbox = new int[4];8283// The array used to hold coordinates from the span iterator84int[] spanbox = new int[4];8586// True if the next iterator span should be read on the next87// iteration of the main nextSpan() loop88boolean doNextSpan;8990// True if the next region box should be read on the next91// iteration of the main nextSpan() loop92boolean doNextBox;9394// True if there are no more spans or the Region is empty95boolean done = false;9697/*98* Creates an instance that filters the spans generated by99* spanIter through the region described by rgn.100*/101public RegionClipSpanIterator(Region rgn, SpanIterator spanIter) {102103this.spanIter = spanIter;104105resetState = rgn.getIterator();106lwm = resetState.createCopy();107108if (!lwm.nextYRange(rgnbox)) {109done = true;110return;111}112113rgnloy = lwmloy = rgnbox[1];114rgnhiy = lwmhiy = rgnbox[3];115116rgn.getBounds(rgnbox);117rgnbndslox = rgnbox[0];118rgnbndsloy = rgnbox[1];119rgnbndshix = rgnbox[2];120rgnbndshiy = rgnbox[3];121if (rgnbndslox >= rgnbndshix ||122rgnbndsloy >= rgnbndshiy) {123done = true;124return;125}126127this.rgn = rgn;128129130row = lwm.createCopy();131box = row.createCopy();132doNextSpan = true;133doNextBox = false;134}135136/*137* Gets the bbox of the available path segments, clipped to the138* Region.139*/140public void getPathBox(int[] pathbox) {141int[] rgnbox = new int[4];142rgn.getBounds(rgnbox);143spanIter.getPathBox(pathbox);144145if (pathbox[0] < rgnbox[0]) {146pathbox[0] = rgnbox[0];147}148149if (pathbox[1] < rgnbox[1]) {150pathbox[1] = rgnbox[1];151}152153if (pathbox[2] > rgnbox[2]) {154pathbox[2] = rgnbox[2];155}156157if (pathbox[3] > rgnbox[3]) {158pathbox[3] = rgnbox[3];159}160}161162/*163* Intersects the path box with the given bbox.164* Returned spans are clipped to this region, or discarded165* altogether if they lie outside it.166*/167public void intersectClipBox(int lox, int loy, int hix, int hiy) {168spanIter.intersectClipBox(lox, loy, hix, hiy);169}170171172/*173* Fetches the next span that needs to be operated on.174* If the return value is false then there are no more spans.175*/176public boolean nextSpan(int[] resultbox) {177if (done) {178return false;179}180181int resultlox, resultloy, resulthix, resulthiy;182boolean doNextRow = false;183184// REMIND: Cache the coordinate inst vars used in this loop185// in locals vars.186while (true) {187// We've exhausted the current span so get the next one188if (doNextSpan) {189if (!spanIter.nextSpan(spanbox)) {190done = true;191return false;192} else {193spanlox = spanbox[0];194// Clip out spans that lie outside of the rgn's bounds195if (spanlox >= rgnbndshix) {196continue;197}198199spanloy = spanbox[1];200if (spanloy >= rgnbndshiy) {201continue;202}203204spanhix = spanbox[2];205if (spanhix <= rgnbndslox) {206continue;207}208209spanhiy = spanbox[3];210if (spanhiy <= rgnbndsloy) {211continue;212}213}214// If the span starts higher up than the low-water mark,215// reset the lwm. This can only happen if spans aren't216// returned in strict y/x order, or the first time through.217if (lwmloy > spanloy) {218lwm.copyStateFrom(resetState);219lwm.nextYRange(rgnbox);220lwmloy = rgnbox[1];221lwmhiy = rgnbox[3];222}223// Skip to the first rgn row whose bottom edge is224// below the top of the current span. This will only225// execute >0 times when the current span starts in a226// lower region row than the previous one, or possibly the227// first time through.228while (lwmhiy <= spanloy) {229if (!lwm.nextYRange(rgnbox))230break;231lwmloy = rgnbox[1];232lwmhiy = rgnbox[3];233}234// If the row overlaps the span, process it, otherwise235// fetch another span236if (lwmhiy > spanloy && lwmloy < spanhiy) {237// Update the current row if it's different from the238// new lwm239if (rgnloy != lwmloy) {240row.copyStateFrom(lwm);241rgnloy = lwmloy;242rgnhiy = lwmhiy;243}244box.copyStateFrom(row);245doNextBox = true;246doNextSpan = false;247}248continue;249}250251// The current row's spans are exhausted, do the next one252if (doNextRow) {253// Next time we either do the next span or the next box254doNextRow = false;255// Get the next row256boolean ok = row.nextYRange(rgnbox);257// If there was one, update the bounds258if (ok) {259rgnloy = rgnbox[1];260rgnhiy = rgnbox[3];261}262if (!ok || rgnloy >= spanhiy) {263// If we've exhausted the rows or this one is below the span,264// go onto the next span265doNextSpan = true;266}267else {268// Otherwise get the first box on this row269box.copyStateFrom(row);270doNextBox = true;271}272continue;273}274275// Process the next box in the current row276if (doNextBox) {277boolean ok = box.nextXBand(rgnbox);278if (ok) {279rgnlox = rgnbox[0];280rgnhix = rgnbox[2];281}282if (!ok || rgnlox >= spanhix) {283// If there was no next rgn span or it's beyond the284// source span, go onto the next row or span285doNextBox = false;286if (rgnhiy >= spanhiy) {287// If the current row totally overlaps the span,288// go onto the next span289doNextSpan = true;290} else {291// otherwise go onto the next rgn row292doNextRow = true;293}294} else {295// Otherwise, if the new rgn span overlaps the296// spanbox, no need to get another box297doNextBox = rgnhix <= spanlox;298}299continue;300}301302// Prepare to do the next box either on this call or303// or the subsequent one304doNextBox = true;305306// Clip the current span against the current box307if (spanlox > rgnlox) {308resultlox = spanlox;309}310else {311resultlox = rgnlox;312}313314if (spanloy > rgnloy) {315resultloy = spanloy;316}317else {318resultloy = rgnloy;319}320321if (spanhix < rgnhix) {322resulthix = spanhix;323}324else {325resulthix = rgnhix;326}327328if (spanhiy < rgnhiy) {329resulthiy = spanhiy;330}331else {332resulthiy = rgnhiy;333}334335// If the result is empty, try then next box336// otherwise return the box.337// REMIND: I think by definition it's non-empty338// if we're here. Need to think about this some more.339if (resultlox >= resulthix ||340resultloy >= resulthiy) {341continue;342}343else {344break;345}346}347348resultbox[0] = resultlox;349resultbox[1] = resultloy;350resultbox[2] = resulthix;351resultbox[3] = resulthiy;352return true;353354}355356357/**358* This method tells the iterator that it may skip all spans359* whose Y range is completely above the indicated Y coordinate.360*/361public void skipDownTo(int y) {362spanIter.skipDownTo(y);363}364365/**366* This method returns a native pointer to a function block that367* can be used by a native method to perform the same iteration368* cycle that the above methods provide while avoiding upcalls to369* the Java object.370* The definition of the structure whose pointer is returned by371* this method is defined in:372* <pre>373* src/share/native/sun/java2d/pipe/SpanIterator.h374* </pre>375*/376public long getNativeIterator() {377return 0;378}379}380381382