Path: blob/master/src/java.desktop/share/native/libawt/java2d/loops/DrawParallelogram.c
41159 views
/*1* Copyright (c) 2008, 2010, 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 "math.h"26#include "GraphicsPrimitiveMgr.h"27#include "LineUtils.h"28#include "Trace.h"29#include "ParallelogramUtils.h"3031#include "sun_java2d_loops_DrawParallelogram.h"3233#define HANDLE_PGRAM_EDGE(X1, Y1, X2, Y2, \34pRasInfo, pixel, pPrim, pFunc, pCompInfo) \35do { \36jint ix1 = (jint) floor(X1); \37jint ix2 = (jint) floor(X2); \38jint iy1 = (jint) floor(Y1); \39jint iy2 = (jint) floor(Y2); \40LineUtils_ProcessLine(pRasInfo, pixel, \41pFunc, pPrim, pCompInfo, \42ix1, iy1, ix2, iy2, JNI_TRUE); \43} while (0)4445typedef struct {46jdouble x0;47jdouble y0;48jdouble y1;49jdouble slope;50jlong dx;51jint ystart;52jint yend;53} EdgeInfo;5455#define STORE_EDGE(pEDGE, X0, Y0, Y1, SLOPE, DELTAX) \56do { \57(pEDGE)->x0 = (X0); \58(pEDGE)->y0 = (Y0); \59(pEDGE)->y1 = (Y1); \60(pEDGE)->slope = (SLOPE); \61(pEDGE)->dx = (DELTAX); \62(pEDGE)->ystart = (jint) floor((Y0) + 0.5); \63(pEDGE)->yend = (jint) floor((Y1) + 0.5); \64} while (0)6566#define STORE_PGRAM(pLTEDGE, pRTEDGE, \67X0, Y0, dX1, dY1, dX2, dY2, \68SLOPE1, SLOPE2, DELTAX1, DELTAX2) \69do { \70STORE_EDGE((pLTEDGE)+0, \71(X0), (Y0), (Y0) + (dY1), \72(SLOPE1), (DELTAX1)); \73STORE_EDGE((pRTEDGE)+0, \74(X0), (Y0), (Y0) + (dY2), \75(SLOPE2), (DELTAX2)); \76STORE_EDGE((pLTEDGE)+1, \77(X0) + (dX1), (Y0) + (dY1), (Y0) + (dY1) + (dY2), \78(SLOPE2), (DELTAX2)); \79STORE_EDGE((pRTEDGE)+1, \80(X0) + (dX2), (Y0) + (dY2), (Y0) + (dY1) + (dY2), \81(SLOPE1), (DELTAX1)); \82} while (0)8384/*85* Class: sun_java2d_loops_DrawParallelogram86* Method: DrawParallelogram87* Signature: (Lsun/java2d/SunGraphics2D;Lsun/java2d/SurfaceData;DDDDDDDD)V88*/89JNIEXPORT void JNICALL90Java_sun_java2d_loops_DrawParallelogram_DrawParallelogram91(JNIEnv *env, jobject self,92jobject sg2d, jobject sData,93jdouble x0, jdouble y0,94jdouble dx1, jdouble dy1,95jdouble dx2, jdouble dy2,96jdouble lw1, jdouble lw2)97{98SurfaceDataOps *sdOps;99SurfaceDataRasInfo rasInfo;100NativePrimitive *pPrim;101CompositeInfo compInfo;102jint pixel;103EdgeInfo edges[8];104EdgeInfo *active[4];105jint ix1, iy1, ix2, iy2;106jdouble ldx1, ldy1, ldx2, ldy2;107jdouble ox0, oy0;108109/*110* Sort parallelogram by y values, ensure that each delta vector111* has a non-negative y delta.112*/113SORT_PGRAM(x0, y0, dx1, dy1, dx2, dy2,114v = lw1; lw1 = lw2; lw2 = v;);115116// dx,dy for line width in the "1" and "2" directions.117ldx1 = dx1 * lw1;118ldy1 = dy1 * lw1;119ldx2 = dx2 * lw2;120ldy2 = dy2 * lw2;121122// calculate origin of the outer parallelogram123ox0 = x0 - (ldx1 + ldx2) / 2.0;124oy0 = y0 - (ldy1 + ldy2) / 2.0;125126PGRAM_MIN_MAX(ix1, ix2, ox0, dx1+ldx1, dx2+ldx2, JNI_FALSE);127iy1 = (jint) floor(oy0 + 0.5);128iy2 = (jint) floor(oy0 + dy1 + ldy1 + dy2 + ldy2 + 0.5);129130pPrim = GetNativePrim(env, self);131if (pPrim == NULL) {132return;133}134pixel = GrPrim_Sg2dGetPixel(env, sg2d);135if (pPrim->pCompType->getCompInfo != NULL) {136GrPrim_Sg2dGetCompInfo(env, sg2d, pPrim, &compInfo);137}138139sdOps = SurfaceData_GetOps(env, sData);140if (sdOps == NULL) {141return;142}143144GrPrim_Sg2dGetClip(env, sg2d, &rasInfo.bounds);145SurfaceData_IntersectBoundsXYXY(&rasInfo.bounds, ix1, iy1, ix2, iy2);146if (rasInfo.bounds.y2 <= rasInfo.bounds.y1 ||147rasInfo.bounds.x2 <= rasInfo.bounds.x1)148{149return;150}151152if (sdOps->Lock(env, sdOps, &rasInfo, pPrim->dstflags) != SD_SUCCESS) {153return;154}155156ix1 = rasInfo.bounds.x1;157iy1 = rasInfo.bounds.y1;158ix2 = rasInfo.bounds.x2;159iy2 = rasInfo.bounds.y2;160if (ix2 > ix1 && iy2 > iy1) {161sdOps->GetRasInfo(env, sdOps, &rasInfo);162if (rasInfo.rasBase) {163jdouble lslope, rslope;164jlong ldx, rdx;165jint loy, hiy, numedges;166FillParallelogramFunc *pFill =167pPrim->funcs.drawparallelogram->fillpgram;168169lslope = (dy1 == 0) ? 0 : dx1 / dy1;170rslope = (dy2 == 0) ? 0 : dx2 / dy2;171ldx = DblToLong(lslope);172rdx = DblToLong(rslope);173174// Only need to generate 4 quads if the interior still175// has a hole in it (i.e. if the line width ratios were176// both less than 1.0)177if (lw1 < 1.0 && lw2 < 1.0) {178// If the line widths are both less than a pixel wide179// then we can use a drawline function instead for even180// more performance.181lw1 = sqrt(ldx1*ldx1 + ldy1*ldy1);182lw2 = sqrt(ldx2*ldx2 + ldy2*ldy2);183if (lw1 <= 1.0001 && lw2 <= 1.0001) {184jdouble x3, y3;185DrawLineFunc *pLine =186pPrim->funcs.drawparallelogram->drawline;187188x3 = (dx1 += x0);189y3 = (dy1 += y0);190x3 += dx2;191y3 += dy2;192dx2 += x0;193dy2 += y0;194195HANDLE_PGRAM_EDGE( x0, y0, dx1, dy1,196&rasInfo, pixel, pPrim, pLine, &compInfo);197HANDLE_PGRAM_EDGE(dx1, dy1, x3, y3,198&rasInfo, pixel, pPrim, pLine, &compInfo);199HANDLE_PGRAM_EDGE( x3, y3, dx2, dy2,200&rasInfo, pixel, pPrim, pLine, &compInfo);201HANDLE_PGRAM_EDGE(dx2, dy2, x0, y0,202&rasInfo, pixel, pPrim, pLine, &compInfo);203SurfaceData_InvokeRelease(env, sdOps, &rasInfo);204SurfaceData_InvokeUnlock(env, sdOps, &rasInfo);205return;206}207208// To simplify the edge management below we presort the209// inner and outer edges so that they are globally sorted210// from left to right. If you scan across the array of211// edges for a given Y range then the edges you encounter212// will be sorted in X as well.213// If AB are left top and bottom edges of outer parallelogram,214// and CD are the right pair of edges, and abcd are the215// corresponding inner parallelogram edges then we want them216// sorted as ABabcdCD to ensure this horizontal ordering.217// Conceptually it is like 2 pairs of nested parentheses.218STORE_PGRAM(edges + 2, edges + 4,219ox0 + ldx1 + ldx2, oy0 + ldy1 + ldy2,220dx1 - ldx1, dy1 - ldy1,221dx2 - ldx2, dy2 - ldy2,222lslope, rslope, ldx, rdx);223numedges = 8;224} else {225// The line width ratios were large enough to consume226// the entire hole in the middle of the parallelogram227// so we can just issue one large quad for the outer228// parallelogram.229numedges = 4;230}231232// The outer parallelogram always goes in the first two233// and last two entries in the array so we either have234// ABabcdCD ordering for 8 edges or ABCD ordering for 4235// edges. See comment above where we store the inner236// parallelogram for a more complete description.237STORE_PGRAM(edges + 0, edges + numedges-2,238ox0, oy0,239dx1 + ldx1, dy1 + ldy1,240dx2 + ldx2, dy2 + ldy2,241lslope, rslope, ldx, rdx);242243loy = edges[0].ystart;244if (loy < iy1) loy = iy1;245while (loy < iy2) {246jint numactive = 0;247jint cur;248249hiy = iy2;250// Maintaining a sorted edge list is probably overkill for251// 4 or 8 edges. The indices chosen above for storing the252// inner and outer left and right edges already guarantee253// left to right ordering so we just need to scan for edges254// that overlap the current Y range (and also determine the255// maximum Y value for which the range is valid).256for (cur = 0; cur < numedges; cur++) {257EdgeInfo *pEdge = &edges[cur];258jint yend = pEdge->yend;259if (loy < yend) {260// This edge is still in play, have we reached it yet?261jint ystart = pEdge->ystart;262if (loy < ystart) {263// This edge is not active (yet)264// Stop before we get to the top of it265if (hiy > ystart) hiy = ystart;266} else {267// This edge is active, store it268active[numactive++] = pEdge;269// And stop when we get to the bottom of it270if (hiy > yend) hiy = yend;271}272}273}274#ifdef DEBUG275if ((numactive & 1) != 0) {276J2dTraceLn1(J2D_TRACE_ERROR,277"DrawParallelogram: "278"ODD NUMBER OF PGRAM EDGES (%d)!!",279numactive);280}281#endif282for (cur = 0; cur < numactive; cur += 2) {283EdgeInfo *pLeft = active[cur+0];284EdgeInfo *pRight = active[cur+1];285jlong lx = PGRAM_INIT_X(loy,286pLeft->x0, pLeft->y0,287pLeft->slope);288jlong rx = PGRAM_INIT_X(loy,289pRight->x0, pRight->y0,290pRight->slope);291(*pFill)(&rasInfo,292ix1, loy, ix2, hiy,293lx, pLeft->dx,294rx, pRight->dx,295pixel, pPrim, &compInfo);296}297loy = hiy;298}299}300SurfaceData_InvokeRelease(env, sdOps, &rasInfo);301}302SurfaceData_InvokeUnlock(env, sdOps, &rasInfo);303}304305306