Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/classes/sun/java2d/xr/XRDrawLine.java
32288 views
/*1* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.234* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.5*6* This code is free software; you can redistribute it and/or modify it7* under the terms of the GNU General Public License version 2 only, as8* published by the Free Software Foundation. Oracle designates this9* particular file as subject to the "Classpath" exception as provided10* by Oracle in the LICENSE file that accompanied this code.11*12* This code is distributed in the hope that it will be useful, but WITHOUT13* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or14* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License15* version 2 for more details (a copy is included in the LICENSE file that16* accompanied this code).17*18* You should have received a copy of the GNU General Public License version19* 2 along with this work; if not, write to the Free Software Foundation,20* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.21*22* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA23* or visit www.oracle.com if you need additional information or have any24* questions.25*/2627/**28* Bresenham line-drawing implementation decomposing line segments29* into a series of rectangles.30* This is required, because xrender doesn't support line primitives directly.31* The code here is an almost 1:1 port of the existing C-source contained in32* sun/java2d/loop/DrawLine.c and sun/java2d/loop/LoopMacros.h33*/34package sun.java2d.xr;3536public class XRDrawLine {37static final int BIG_MAX = ((1 << 29) - 1);38static final int BIG_MIN = (-(1 << 29));3940static final int OUTCODE_TOP = 1;41static final int OUTCODE_BOTTOM = 2;42static final int OUTCODE_LEFT = 4;43static final int OUTCODE_RIGHT = 8;4445int x1, y1, x2, y2;46int ucX1, ucY1, ucX2, ucY2;4748DirtyRegion region = new DirtyRegion();4950protected void rasterizeLine(GrowableRectArray rectBuffer, int _x1,51int _y1, int _x2, int _y2, int cxmin, int cymin, int cxmax,52int cymax, boolean clip, boolean overflowCheck) {53float diagF;54int error;55int steps;56int errminor, errmajor;57boolean xmajor;58int dx, dy, ax, ay;5960initCoordinates(_x1, _y1, _x2, _y2, overflowCheck);6162dx = x2 - x1;63dy = y2 - y1;64ax = Math.abs(dx);65ay = Math.abs(dy);66xmajor = (ax >= ay);67diagF = ((float) ax) / ay;6869if (clip70&& !clipCoordinates(cxmin, cymin, cxmax, cymax, xmajor, dx, dy,71ax, ay)) {72// whole line was clipped away73return;74}7576region.setDirtyLineRegion(x1, y1, x2, y2);77int xDiff = region.x2 - region.x;78int yDiff = region.y2 - region.y;7980if (xDiff == 0 || yDiff == 0) {81// horizontal / diagonal lines can be represented by a single82// rectangle83rectBuffer.pushRectValues(region.x, region.y, region.x2 - region.x84+ 1, region.y2 - region.y + 1);85return;86}8788// Setup bresenham89if (xmajor) {90errmajor = ay * 2;91errminor = ax * 2;92ax = -ax; /* For clipping adjustment below */93steps = x2 - x1;94} else {95errmajor = ax * 2;96errminor = ay * 2;97ay = -ay; /* For clipping adjustment below */98steps = y2 - y1;99}100101if ((steps = (Math.abs(steps) + 1)) == 0) {102return;103}104105error = -(errminor / 2);106107if (y1 != ucY1) {108int ysteps = y1 - ucY1;109if (ysteps < 0) {110ysteps = -ysteps;111}112error += ysteps * ax * 2;113}114115if (x1 != ucX1) {116int xsteps = x1 - ucX1;117if (xsteps < 0) {118xsteps = -xsteps;119}120error += xsteps * ay * 2;121}122error += errmajor;123errminor -= errmajor;124125int xStep = (dx > 0 ? 1 : -1);126int yStep = (dy > 0 ? 1 : -1);127int orthogonalXStep = xmajor ? xStep : 0;128int orthogonalYStep = !xmajor ? yStep : 0;129130/*131* For lines which proceed in one direction faster, we try to generate132* rectangles instead of points. Otherwise we try to avoid the extra133* work...134*/135if (diagF <= 0.9 || diagF >= 1.1) {136lineToRects(rectBuffer, steps, error, errmajor, errminor, xStep,137yStep, orthogonalXStep, orthogonalYStep);138} else {139lineToPoints(rectBuffer, steps, error, errmajor, errminor, xStep,140yStep, orthogonalXStep, orthogonalYStep);141}142}143144private void lineToPoints(GrowableRectArray rectBuffer, int steps,145int error, int errmajor, int errminor, int xStep, int yStep,146int orthogonalXStep, int orthogonalYStep) {147int x = x1, y = y1;148149do {150rectBuffer.pushRectValues(x, y, 1, 1);151152// "Traditional" Bresenham line drawing153if (error < 0) {154error += errmajor;155x += orthogonalXStep;156y += orthogonalYStep;157} else {158error -= errminor;159x += xStep;160y += yStep;161}162} while (--steps > 0);163}164165private void lineToRects(GrowableRectArray rectBuffer, int steps,166int error, int errmajor, int errminor, int xStep, int yStep,167int orthogonalXStep, int orthogonalYStep) {168int x = x1, y = y1;169int rectX = Integer.MIN_VALUE, rectY = 0;170int rectW = 0, rectH = 0;171172do {173// Combine the resulting rectangles174// for steps performed in a single direction.175if (y == rectY) {176if (x == (rectX + rectW)) {177rectW++;178} else if (x == (rectX - 1)) {179rectX--;180rectW++;181}182} else if (x == rectX) {183if (y == (rectY + rectH)) {184rectH++;185} else if (y == (rectY - 1)) {186rectY--;187rectH++;188}189} else {190// Diagonal step: add the previous rectangle to the list,191// iff it was "real" (= not initialized before the first192// iteration)193if (rectX != Integer.MIN_VALUE) {194rectBuffer.pushRectValues(rectX, rectY, rectW, rectH);195}196rectX = x;197rectY = y;198rectW = rectH = 1;199}200201// "Traditional" Bresenham line drawing202if (error < 0) {203error += errmajor;204x += orthogonalXStep;205y += orthogonalYStep;206} else {207error -= errminor;208x += xStep;209y += yStep;210}211} while (--steps > 0);212213// Add last rectangle which isn't handled by the combination-code214// anymore215rectBuffer.pushRectValues(rectX, rectY, rectW, rectH);216}217218private boolean clipCoordinates(int cxmin, int cymin, int cxmax, int cymax,219boolean xmajor, int dx, int dy, int ax, int ay) {220int outcode1, outcode2;221222outcode1 = outcode(x1, y1, cxmin, cymin, cxmax, cymax);223outcode2 = outcode(x2, y2, cxmin, cymin, cxmax, cymax);224225while ((outcode1 | outcode2) != 0) {226long xsteps = 0, ysteps = 0;227228if ((outcode1 & outcode2) != 0) {229return false;230}231232if (outcode1 != 0) {233if ((outcode1 & (OUTCODE_TOP | OUTCODE_BOTTOM)) != 0) {234if ((outcode1 & OUTCODE_TOP) != 0) {235y1 = cymin;236} else {237y1 = cymax;238}239ysteps = y1 - ucY1;240if (ysteps < 0) {241ysteps = -ysteps;242}243xsteps = 2 * ysteps * ax + ay;244if (xmajor) {245xsteps += ay - ax - 1;246}247xsteps = xsteps / (2 * ay);248if (dx < 0) {249xsteps = -xsteps;250}251x1 = ucX1 + (int) xsteps;252} else if ((outcode1 & (OUTCODE_LEFT | OUTCODE_RIGHT)) != 0) {253if ((outcode1 & OUTCODE_LEFT) != 0) {254x1 = cxmin;255} else {256x1 = cxmax;257}258xsteps = x1 - ucX1;259if (xsteps < 0) {260xsteps = -xsteps;261}262ysteps = 2 * xsteps * ay + ax;263if (!xmajor) {264ysteps += ax - ay - 1;265}266ysteps = ysteps / (2 * ax);267if (dy < 0) {268ysteps = -ysteps;269}270y1 = ucY1 + (int) ysteps;271}272outcode1 = outcode(x1, y1, cxmin, cymin, cxmax, cymax);273} else {274if ((outcode2 & (OUTCODE_TOP | OUTCODE_BOTTOM)) != 0) {275if ((outcode2 & OUTCODE_TOP) != 0) {276y2 = cymin;277} else {278y2 = cymax;279}280ysteps = y2 - ucY2;281if (ysteps < 0) {282ysteps = -ysteps;283}284xsteps = 2 * ysteps * ax + ay;285if (xmajor) {286xsteps += ay - ax;287} else {288xsteps -= 1;289}290xsteps = xsteps / (2 * ay);291if (dx > 0) {292xsteps = -xsteps;293}294x2 = ucX2 + (int) xsteps;295} else if ((outcode2 & (OUTCODE_LEFT | OUTCODE_RIGHT)) != 0) {296if ((outcode2 & OUTCODE_LEFT) != 0) {297x2 = cxmin;298} else {299x2 = cxmax;300}301xsteps = x2 - ucX2;302if (xsteps < 0) {303xsteps = -xsteps;304}305ysteps = 2 * xsteps * ay + ax;306if (xmajor) {307ysteps -= 1;308} else {309ysteps += ax - ay;310}311ysteps = ysteps / (2 * ax);312if (dy > 0) {313ysteps = -ysteps;314}315y2 = ucY2 + (int) ysteps;316}317outcode2 = outcode(x2, y2, cxmin, cymin, cxmax, cymax);318}319}320321return true;322}323324private void initCoordinates(int x1, int y1, int x2, int y2,325boolean checkOverflow) {326/*327* Part of calculating the Bresenham parameters for line stepping328* involves being able to store numbers that are twice the magnitude of329* the biggest absolute difference in coordinates. Since we want the330* stepping parameters to be stored in jints, we then need to avoid any331* absolute differences more than 30 bits. Thus, we need to preprocess332* the coordinates to reduce their range to 30 bits regardless of333* clipping. We need to cut their range back before we do the clipping334* because the Bresenham stepping values need to be calculated based on335* the "unclipped" coordinates.336*337* Thus, first we perform a "pre-clipping" stage to bring the338* coordinates within the 30-bit range and then we proceed to the339* regular clipping procedure, pretending that these were the original340* coordinates all along. Since this operation occurs based on a341* constant "pre-clip" rectangle of +/- 30 bits without any342* consideration for the final clip, the rounding errors that occur here343* will depend only on the line coordinates and be invariant with344* respect to the particular device/user clip rectangles in effect at345* the time. Thus, rendering a given large-range line will be consistent346* under a variety of clipping conditions.347*/348if (checkOverflow349&& (OverflowsBig(x1) || OverflowsBig(y1) || OverflowsBig(x2) || OverflowsBig(y2))) {350/*351* Use doubles to get us into range for "Big" arithmetic.352*353* The math of adjusting an endpoint for clipping can involve an354* intermediate result with twice the number of bits as the original355* coordinate range. Since we want to maintain as much as 30 bits of356* precision in the resulting coordinates, we will get roundoff here357* even using IEEE double-precision arithmetic which cannot carry 60358* bits of mantissa. Since the rounding errors will be consistent359* for a given set of input coordinates the potential roundoff error360* should not affect the consistency of our rendering.361*/362double x1d = x1;363double y1d = y1;364double x2d = x2;365double y2d = y2;366double dxd = x2d - x1d;367double dyd = y2d - y1d;368369if (x1 < BIG_MIN) {370y1d = y1 + (BIG_MIN - x1) * dyd / dxd;371x1d = BIG_MIN;372} else if (x1 > BIG_MAX) {373y1d = y1 - (x1 - BIG_MAX) * dyd / dxd;374x1d = BIG_MAX;375}376/* Use Y1d instead of _y1 for testing now as we may have modified it */377if (y1d < BIG_MIN) {378x1d = x1 + (BIG_MIN - y1) * dxd / dyd;379y1d = BIG_MIN;380} else if (y1d > BIG_MAX) {381x1d = x1 - (y1 - BIG_MAX) * dxd / dyd;382y1d = BIG_MAX;383}384if (x2 < BIG_MIN) {385y2d = y2 + (BIG_MIN - x2) * dyd / dxd;386x2d = BIG_MIN;387} else if (x2 > BIG_MAX) {388y2d = y2 - (x2 - BIG_MAX) * dyd / dxd;389x2d = BIG_MAX;390}391/* Use Y2d instead of _y2 for testing now as we may have modified it */392if (y2d < BIG_MIN) {393x2d = x2 + (BIG_MIN - y2) * dxd / dyd;394y2d = BIG_MIN;395} else if (y2d > BIG_MAX) {396x2d = x2 - (y2 - BIG_MAX) * dxd / dyd;397y2d = BIG_MAX;398}399400x1 = (int) x1d;401y1 = (int) y1d;402x2 = (int) x2d;403y2 = (int) y2d;404}405406this.x1 = ucX1 = x1;407this.y1 = ucY1 = y1;408this.x2 = ucX2 = x2;409this.y2 = ucY2 = y2;410}411412private boolean OverflowsBig(int v) {413return ((v) != (((v) << 2) >> 2));414}415416private int out(int v, int vmin, int vmax, int cmin, int cmax) {417return ((v < vmin) ? cmin : ((v > vmax) ? cmax : 0));418}419420private int outcode(int x, int y, int xmin, int ymin, int xmax, int ymax) {421return out(y, ymin, ymax, OUTCODE_TOP, OUTCODE_BOTTOM)422| out(x, xmin, xmax, OUTCODE_LEFT, OUTCODE_RIGHT);423}424}425426427