Path: blob/master/src/java.desktop/share/native/libawt/java2d/loops/DrawLine.c
41159 views
/*1* Copyright (c) 2000, 2001, 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*/2425#include "GraphicsPrimitiveMgr.h"2627#include "LineUtils.h"2829#include "sun_java2d_loops_DrawLine.h"3031#define OUTCODE_TOP 132#define OUTCODE_BOTTOM 233#define OUTCODE_LEFT 434#define OUTCODE_RIGHT 83536static void37RefineBounds(SurfaceDataBounds *bounds, jint x1, jint y1, jint x2, jint y2)38{39jint min, max;40if (x1 < x2) {41min = x1;42max = x2;43} else {44min = x2;45max = x1;46}47max++;48if (max <= min) {49/* integer overflow */50max--;51}52if (bounds->x1 < min) bounds->x1 = min;53if (bounds->x2 > max) bounds->x2 = max;54if (y1 < y2) {55min = y1;56max = y2;57} else {58min = y2;59max = y1;60}61max++;62if (max <= min) {63/* integer overflow */64max--;65}66if (bounds->y1 < min) bounds->y1 = min;67if (bounds->y2 > max) bounds->y2 = max;68}6970#define _out(v, vmin, vmax, cmin, cmax) \71((v < vmin) ? cmin : ((v > vmax) ? cmax : 0))7273#define outcode(x, y, xmin, ymin, xmax, ymax) \74(_out(y, ymin, ymax, OUTCODE_TOP, OUTCODE_BOTTOM) | \75_out(x, xmin, xmax, OUTCODE_LEFT, OUTCODE_RIGHT))7677/*78* "Small" math here will be done if the coordinates are less79* than 15 bits in range (-16384 => 16383). This could be80* expanded to 16 bits if we rearrange some of the math in81* the normal version of SetupBresenham.82* "Big" math here will be done with coordinates with 30 bits83* of total range - 2 bits less than a jint holds.84* Intermediate calculations for "Big" coordinates will be85* done using jlong variables.86*/87#define OverflowsSmall(v) ((v) != (((v) << 17) >> 17))88#define OverflowsBig(v) ((v) != (((v) << 2) >> 2))89#define BIG_MAX ((1 << 29) - 1)90#define BIG_MIN (-(1 << 29))9192#define SETUP_BRESENHAM(CALC_TYPE, ORIGX1, ORIGY1, ORIGX2, ORIGY2, SHORTEN) \93do { \94jint X1 = ORIGX1, Y1 = ORIGY1, X2 = ORIGX2, Y2 = ORIGY2; \95jint dx, dy, ax, ay; \96jint cxmin, cymin, cxmax, cymax; \97jint outcode1, outcode2; \98jboolean xmajor; \99jint errminor, errmajor; \100jint error; \101jint steps; \102\103dx = X2 - X1; \104dy = Y2 - Y1; \105ax = (dx < 0) ? -dx : dx; \106ay = (dy < 0) ? -dy : dy; \107\108cxmin = pBounds->x1; \109cymin = pBounds->y1; \110cxmax = pBounds->x2 - 1; \111cymax = pBounds->y2 - 1; \112xmajor = (ax >= ay); \113\114outcode1 = outcode(X1, Y1, cxmin, cymin, cxmax, cymax); \115outcode2 = outcode(X2, Y2, cxmin, cymin, cxmax, cymax); \116while ((outcode1 | outcode2) != 0) { \117CALC_TYPE xsteps, ysteps; \118if ((outcode1 & outcode2) != 0) { \119return JNI_FALSE; \120} \121if (outcode1 != 0) { \122if (outcode1 & (OUTCODE_TOP | OUTCODE_BOTTOM)) { \123if (outcode1 & OUTCODE_TOP) { \124Y1 = cymin; \125} else { \126Y1 = cymax; \127} \128ysteps = Y1 - ORIGY1; \129if (ysteps < 0) { \130ysteps = -ysteps; \131} \132xsteps = 2 * ysteps * ax + ay; \133if (xmajor) { \134xsteps += ay - ax - 1; \135} \136xsteps = xsteps / (2 * ay); \137if (dx < 0) { \138xsteps = -xsteps; \139} \140X1 = ORIGX1 + (jint) xsteps; \141} else if (outcode1 & (OUTCODE_LEFT | OUTCODE_RIGHT)) { \142if (outcode1 & OUTCODE_LEFT) { \143X1 = cxmin; \144} else { \145X1 = cxmax; \146} \147xsteps = X1 - ORIGX1; \148if (xsteps < 0) { \149xsteps = -xsteps; \150} \151ysteps = 2 * xsteps * ay + ax; \152if (!xmajor) { \153ysteps += ax - ay - 1; \154} \155ysteps = ysteps / (2 * ax); \156if (dy < 0) { \157ysteps = -ysteps; \158} \159Y1 = ORIGY1 + (jint) ysteps; \160} \161outcode1 = outcode(X1, Y1, cxmin, cymin, cxmax, cymax); \162} else { \163if (outcode2 & (OUTCODE_TOP | OUTCODE_BOTTOM)) { \164if (outcode2 & OUTCODE_TOP) { \165Y2 = cymin; \166} else { \167Y2 = cymax; \168} \169ysteps = Y2 - ORIGY2; \170if (ysteps < 0) { \171ysteps = -ysteps; \172} \173xsteps = 2 * ysteps * ax + ay; \174if (xmajor) { \175xsteps += ay - ax; \176} else { \177xsteps -= 1; \178} \179xsteps = xsteps / (2 * ay); \180if (dx > 0) { \181xsteps = -xsteps; \182} \183X2 = ORIGX2 + (jint) xsteps; \184} else if (outcode2 & (OUTCODE_LEFT | OUTCODE_RIGHT)) { \185if (outcode2 & OUTCODE_LEFT) { \186X2 = cxmin; \187} else { \188X2 = cxmax; \189} \190xsteps = X2 - ORIGX2; \191if (xsteps < 0) { \192xsteps = -xsteps; \193} \194ysteps = 2 * xsteps * ay + ax; \195if (xmajor) { \196ysteps -= 1; \197} else { \198ysteps += ax - ay; \199} \200ysteps = ysteps / (2 * ax); \201if (dy > 0) { \202ysteps = -ysteps; \203} \204Y2 = ORIGY2 + (jint) ysteps; \205} \206outcode2 = outcode(X2, Y2, cxmin, cymin, cxmax, cymax); \207} \208} \209*pStartX = X1; \210*pStartY = Y1; \211\212if (xmajor) { \213errmajor = ay * 2; \214errminor = ax * 2; \215*pBumpMajorMask = (dx < 0) ? BUMP_NEG_PIXEL : BUMP_POS_PIXEL; \216*pBumpMinorMask = (dy < 0) ? BUMP_NEG_SCAN : BUMP_POS_SCAN; \217ax = -ax; /* For clipping adjustment below */ \218steps = X2 - X1; \219if (X2 != ORIGX2) { \220SHORTEN = 0; \221} \222} else { \223errmajor = ax * 2; \224errminor = ay * 2; \225*pBumpMajorMask = (dy < 0) ? BUMP_NEG_SCAN : BUMP_POS_SCAN; \226*pBumpMinorMask = (dx < 0) ? BUMP_NEG_PIXEL : BUMP_POS_PIXEL; \227ay = -ay; /* For clipping adjustment below */ \228steps = Y2 - Y1; \229if (Y2 != ORIGY2) { \230SHORTEN = 0; \231} \232} \233if ((steps = ((steps >= 0) ? steps : -steps) + 1 - SHORTEN) == 0) { \234return JNI_FALSE; \235} \236error = - (errminor / 2); \237if (Y1 != ORIGY1) { \238jint ysteps = Y1 - ORIGY1; \239if (ysteps < 0) { \240ysteps = -ysteps; \241} \242error += ysteps * ax * 2; \243} \244if (X1 != ORIGX1) { \245jint xsteps = X1 - ORIGX1; \246if (xsteps < 0) { \247xsteps = -xsteps; \248} \249error += xsteps * ay * 2; \250} \251error += errmajor; \252errminor -= errmajor; \253\254*pSteps = steps; \255*pError = error; \256*pErrMajor = errmajor; \257*pErrMinor = errminor; \258} while (0)259260static jboolean261LineUtils_SetupBresenhamBig(jint _x1, jint _y1, jint _x2, jint _y2,262jint shorten,263SurfaceDataBounds *pBounds,264jint *pStartX, jint *pStartY,265jint *pSteps, jint *pError,266jint *pErrMajor, jint *pBumpMajorMask,267jint *pErrMinor, jint *pBumpMinorMask)268{269/*270* Part of calculating the Bresenham parameters for line stepping271* involves being able to store numbers that are twice the magnitude272* of the biggest absolute difference in coordinates. Since we273* want the stepping parameters to be stored in jints, we then need274* to avoid any absolute differences more than 30 bits. Thus, we275* need to preprocess the coordinates to reduce their range to 30276* bits regardless of clipping. We need to cut their range back277* before we do the clipping because the Bresenham stepping values278* need to be calculated based on the "unclipped" coordinates.279*280* Thus, first we perform a "pre-clipping" stage to bring the281* coordinates within the 30-bit range and then we proceed to the282* regular clipping procedure, pretending that these were the283* original coordinates all along. Since this operation occurs284* based on a constant "pre-clip" rectangle of +/- 30 bits without285* any consideration for the final clip, the rounding errors that286* occur here will depend only on the line coordinates and be287* invariant with respect to the particular device/user clip288* rectangles in effect at the time. Thus, rendering a given289* large-range line will be consistent under a variety of290* clipping conditions.291*/292if (OverflowsBig(_x1) || OverflowsBig(_y1) ||293OverflowsBig(_x2) || OverflowsBig(_y2))294{295/*296* Use doubles to get us into range for "Big" arithmetic.297*298* The math of adjusting an endpoint for clipping can involve299* an intermediate result with twice the number of bits as the300* original coordinate range. Since we want to maintain as301* much as 30 bits of precision in the resulting coordinates,302* we will get roundoff here even using IEEE double-precision303* arithmetic which cannot carry 60 bits of mantissa. Since304* the rounding errors will be consistent for a given set305* of input coordinates the potential roundoff error should306* not affect the consistency of our rendering.307*/308double X1d = _x1;309double Y1d = _y1;310double X2d = _x2;311double Y2d = _y2;312double DXd = X2d - X1d;313double DYd = Y2d - Y1d;314if (_x1 < BIG_MIN) {315Y1d = _y1 + (BIG_MIN - _x1) * DYd / DXd;316X1d = BIG_MIN;317} else if (_x1 > BIG_MAX) {318Y1d = _y1 - (_x1 - BIG_MAX) * DYd / DXd;319X1d = BIG_MAX;320}321/* Use Y1d instead of _y1 for testing now as we may have modified it */322if (Y1d < BIG_MIN) {323X1d = _x1 + (BIG_MIN - _y1) * DXd / DYd;324Y1d = BIG_MIN;325} else if (Y1d > BIG_MAX) {326X1d = _x1 - (_y1 - BIG_MAX) * DXd / DYd;327Y1d = BIG_MAX;328}329if (_x2 < BIG_MIN) {330Y2d = _y2 + (BIG_MIN - _x2) * DYd / DXd;331X2d = BIG_MIN;332} else if (_x2 > BIG_MAX) {333Y2d = _y2 - (_x2 - BIG_MAX) * DYd / DXd;334X2d = BIG_MAX;335}336/* Use Y2d instead of _y2 for testing now as we may have modified it */337if (Y2d < BIG_MIN) {338X2d = _x2 + (BIG_MIN - _y2) * DXd / DYd;339Y2d = BIG_MIN;340} else if (Y2d > BIG_MAX) {341X2d = _x2 - (_y2 - BIG_MAX) * DXd / DYd;342Y2d = BIG_MAX;343}344_x1 = (int) X1d;345_y1 = (int) Y1d;346_x2 = (int) X2d;347_y2 = (int) Y2d;348}349350SETUP_BRESENHAM(jlong, _x1, _y1, _x2, _y2, shorten);351352return JNI_TRUE;353}354355jboolean356LineUtils_SetupBresenham(jint _x1, jint _y1, jint _x2, jint _y2,357jint shorten,358SurfaceDataBounds *pBounds,359jint *pStartX, jint *pStartY,360jint *pSteps, jint *pError,361jint *pErrMajor, jint *pBumpMajorMask,362jint *pErrMinor, jint *pBumpMinorMask)363{364if (OverflowsSmall(_x1) || OverflowsSmall(_y1) ||365OverflowsSmall(_x2) || OverflowsSmall(_y2))366{367return LineUtils_SetupBresenhamBig(_x1, _y1, _x2, _y2, shorten,368pBounds,369pStartX, pStartY,370pSteps, pError,371pErrMajor, pBumpMajorMask,372pErrMinor, pBumpMinorMask);373}374375SETUP_BRESENHAM(jint, _x1, _y1, _x2, _y2, shorten);376377return JNI_TRUE;378}379380/*381* Class: sun_java2d_loops_DrawLine382* Method: DrawLine383* Signature: (Lsun/java2d/SunGraphics2D;Lsun/java2d/SurfaceData;IIII)V384*/385JNIEXPORT void JNICALL386Java_sun_java2d_loops_DrawLine_DrawLine387(JNIEnv *env, jobject self,388jobject sg2d, jobject sData,389jint x1, jint y1, jint x2, jint y2)390{391SurfaceDataOps *sdOps;392SurfaceDataRasInfo rasInfo;393NativePrimitive *pPrim;394CompositeInfo compInfo;395jint pixel = GrPrim_Sg2dGetPixel(env, sg2d);396397pPrim = GetNativePrim(env, self);398if (pPrim == NULL) {399return;400}401if (pPrim->pCompType->getCompInfo != NULL) {402GrPrim_Sg2dGetCompInfo(env, sg2d, pPrim, &compInfo);403}404405sdOps = SurfaceData_GetOps(env, sData);406if (sdOps == 0) {407return;408}409410GrPrim_Sg2dGetClip(env, sg2d, &rasInfo.bounds);411412RefineBounds(&rasInfo.bounds, x1, y1, x2, y2);413414if (sdOps->Lock(env, sdOps, &rasInfo, pPrim->dstflags) != SD_SUCCESS) {415return;416}417418if (rasInfo.bounds.x2 > rasInfo.bounds.x1 &&419rasInfo.bounds.y2 > rasInfo.bounds.y1)420{421sdOps->GetRasInfo(env, sdOps, &rasInfo);422if (rasInfo.rasBase) {423LineUtils_ProcessLine(&rasInfo, pixel,424pPrim->funcs.drawline, pPrim, &compInfo,425x1, y1, x2, y2, 0);426}427SurfaceData_InvokeRelease(env, sdOps, &rasInfo);428}429SurfaceData_InvokeUnlock(env, sdOps, &rasInfo);430}431432433