/* * Copyright (c) 2005, 2006, 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.loops; import java.awt.geom.Path2D;import java.awt.geom.PathIterator;import java.awt.geom.QuadCurve2D;import sun.awt.SunHints;import java.util.*; /* This is the java implementation of the native code from * src/share/native/sun/java2d/loops/ProcessPath.[c,h] * This code is written to be as much similar to the native * as it possible. So, it sometimes does not follow java naming conventions. * * It's important to keep this code synchronized with native one. See more * comments, description and high level scheme of the rendering process in the * ProcessPath.c */ public class ProcessPath { /* Public interfaces and methods for drawing and filling general paths */ public static abstract class DrawHandler { public int xMin; public int yMin; public int xMax; public int yMax; public float xMinf; public float yMinf; public float xMaxf; public float yMaxf; public int strokeControl; public DrawHandler(int xMin, int yMin, int xMax, int yMax, int strokeControl) { setBounds(xMin, yMin, xMax, yMax, strokeControl); } public void setBounds(int xMin, int yMin, int xMax, int yMax) { this.xMin = xMin; this.yMin = yMin; this.xMax = xMax; this.yMax = yMax; /* Setting up fractional clipping box * * We are using following float -> int mapping: * * xi = floor(xf + 0.5) * * So, fractional values that hit the [xmin, xmax) integer interval * will be situated inside the [xmin-0.5, xmax - 0.5) fractional * interval. We are using EPSF constant to provide that upper * boundary is not included. */ xMinf = xMin - 0.5f; yMinf = yMin - 0.5f; xMaxf = xMax - 0.5f - EPSF; yMaxf = yMax - 0.5f - EPSF; } public void setBounds(int xMin, int yMin, int xMax, int yMax, int strokeControl) { this.strokeControl = strokeControl; setBounds(xMin, yMin, xMax, yMax); } public void adjustBounds(int bxMin, int byMin, int bxMax, int byMax) { if (xMin > bxMin) bxMin = xMin; if (xMax < bxMax) bxMax = xMax; if (yMin > byMin) byMin = yMin; if (yMax < byMax) byMax = yMax; setBounds(bxMin, byMin, bxMax, byMax); } public DrawHandler(int xMin, int yMin, int xMax, int yMax) { this(xMin, yMin, xMax, yMax, SunHints.INTVAL_STROKE_DEFAULT); } public abstract void drawLine(int x0, int y0, int x1, int y1); public abstract void drawPixel(int x0, int y0); public abstract void drawScanline(int x0, int x1, int y0); } public interface EndSubPathHandler { public void processEndSubPath(); } public static final int PH_MODE_DRAW_CLIP = 0; public static final int PH_MODE_FILL_CLIP = 1; public static abstract class ProcessHandler implements EndSubPathHandler { DrawHandler dhnd; int clipMode; public ProcessHandler(DrawHandler dhnd, int clipMode) { this.dhnd = dhnd; this.clipMode = clipMode; } public abstract void processFixedLine(int x1, int y1, int x2, int y2, int [] pixelInfo, boolean checkBounds, boolean endSubPath); } public static EndSubPathHandler noopEndSubPathHandler = new EndSubPathHandler() { public void processEndSubPath() { } }; public static boolean fillPath(DrawHandler dhnd, Path2D.Float p2df, int transX, int transY) { FillProcessHandler fhnd = new FillProcessHandler(dhnd); if (!doProcessPath(fhnd, p2df, transX, transY)) { return false; } FillPolygon(fhnd, p2df.getWindingRule()); return true; } public static boolean drawPath(DrawHandler dhnd, EndSubPathHandler endSubPath, Path2D.Float p2df, int transX, int transY) { return doProcessPath(new DrawProcessHandler(dhnd, endSubPath), p2df, transX, transY); } public static boolean drawPath(DrawHandler dhnd, Path2D.Float p2df, int transX, int transY) { return doProcessPath(new DrawProcessHandler(dhnd, noopEndSubPathHandler), p2df, transX, transY); } /* Private implementation of the rendering process */ /* Boundaries used for skipping huge path segments */ private static final float UPPER_BND = Float.MAX_VALUE/4.0f; private static final float LOWER_BND = -UPPER_BND; /* Precision (in bits) used in forward differencing */ private static final int FWD_PREC = 7; /* Precision (in bits) used for the rounding in the midpoint test */ private static final int MDP_PREC = 10; private static final int MDP_MULT = 1 << MDP_PREC; private static final int MDP_HALF_MULT = MDP_MULT >> 1; /* Boundaries used for clipping large path segments (those are inside * [UPPER/LOWER]_BND boundaries) */ private static final int UPPER_OUT_BND = 1 << (30 - MDP_PREC); private static final int LOWER_OUT_BND = -UPPER_OUT_BND; /* Calculation boundaries. They are used for switching to the more slow but * allowing larger input values method of calculation of the initial values * of the scan converted line segments inside the FillPolygon */ private static final float CALC_UBND = 1 << (30 - MDP_PREC); private static final float CALC_LBND = -CALC_UBND; /* Following constants are used for providing open boundaries of the * intervals */ public static final int EPSFX = 1; public static final float EPSF = ((float)EPSFX)/MDP_MULT; /* Bit mask used to separate whole part from the fraction part of the * number */ private static final int MDP_W_MASK = -MDP_MULT; /* Bit mask used to separate fractional part from the whole part of the * number */ private static final int MDP_F_MASK = MDP_MULT - 1; /* * Constants for the forward differencing * of the cubic and quad curves */ /* Maximum size of the cubic curve (calculated as the size of the bounding * box of the control points) which could be rendered without splitting */ private static final int MAX_CUB_SIZE = 256; /* Maximum size of the quad curve (calculated as the size of the bounding * box of the control points) which could be rendered without splitting */ private static final int MAX_QUAD_SIZE = 1024; /* Default power of 2 steps used in the forward differencing. Here DF prefix * stands for DeFault. Constants below are used as initial values for the * adaptive forward differencing algorithm. */ private static final int DF_CUB_STEPS = 3; private static final int DF_QUAD_STEPS = 2; /* Shift of the current point of the curve for preparing to the midpoint * rounding */ private static final int DF_CUB_SHIFT = FWD_PREC + DF_CUB_STEPS*3 - MDP_PREC; private static final int DF_QUAD_SHIFT = FWD_PREC + DF_QUAD_STEPS*2 - MDP_PREC; /* Default amount of steps of the forward differencing */ private static final int DF_CUB_COUNT = (1<<DF_CUB_STEPS); private static final int DF_QUAD_COUNT = (1<<DF_QUAD_STEPS); /* Default boundary constants used to check the necessity of the restepping */ private static final int DF_CUB_DEC_BND = 1<<DF_CUB_STEPS*3 + FWD_PREC + 2; private static final int DF_CUB_INC_BND = 1<<DF_CUB_STEPS*3 + FWD_PREC - 1; private static final int DF_QUAD_DEC_BND = 1<<DF_QUAD_STEPS*2 + FWD_PREC + 2; private static final int DF_QUAD_INC_BND = 1<<DF_QUAD_STEPS*2 + FWD_PREC - 1; /* Multipliers for the coefficients of the polynomial form of the cubic and * quad curves representation */ private static final int CUB_A_SHIFT = FWD_PREC; private static final int CUB_B_SHIFT = (DF_CUB_STEPS + FWD_PREC + 1); private static final int CUB_C_SHIFT = (DF_CUB_STEPS*2 + FWD_PREC); private static final int CUB_A_MDP_MULT = (1<<CUB_A_SHIFT); private static final int CUB_B_MDP_MULT = (1<<CUB_B_SHIFT); private static final int CUB_C_MDP_MULT = (1<<CUB_C_SHIFT); private static final int QUAD_A_SHIFT = FWD_PREC; private static final int QUAD_B_SHIFT = (DF_QUAD_STEPS + FWD_PREC); private static final int QUAD_A_MDP_MULT = (1<<QUAD_A_SHIFT); private static final int QUAD_B_MDP_MULT = (1<<QUAD_B_SHIFT); /* Clipping macros for drawing and filling algorithms */ private static float CLIP(float a1, float b1, float a2, float b2, double t) { return (float)(b1 + (double)(t - a1)*(b2 - b1) / (a2 - a1)); } private static int CLIP(int a1, int b1, int a2, int b2, double t) { return (int)(b1 + (double)(t - a1)*(b2 - b1) / (a2 - a1)); } private static final int CRES_MIN_CLIPPED = 0; private static final int CRES_MAX_CLIPPED = 1; private static final int CRES_NOT_CLIPPED = 3; private static final int CRES_INVISIBLE = 4; private static boolean IS_CLIPPED(int res) { return res == CRES_MIN_CLIPPED || res == CRES_MAX_CLIPPED; } /* This is java implementation of the macro from ProcessGeneralPath.c. * To keep the logic of the java code similar to the native one * array and set of indexes are used to point out the data. */ private static int TESTANDCLIP(float LINE_MIN, float LINE_MAX, float[] c, int a1, int b1, int a2, int b2) { double t; int res = CRES_NOT_CLIPPED; if (c[a1] < (LINE_MIN) || c[a1] > (LINE_MAX)) { if (c[a1] < (LINE_MIN)) { if (c[a2] < (LINE_MIN)) { return CRES_INVISIBLE; }; res = CRES_MIN_CLIPPED; t = (LINE_MIN); } else { if (c[a2] > (LINE_MAX)) { return CRES_INVISIBLE; }; res = CRES_MAX_CLIPPED; t = (LINE_MAX); } c[b1] = CLIP(c[a1], c[b1], c[a2], c[b2], t); c[a1] = (float)t; } return res; } /* Integer version of the method above */ private static int TESTANDCLIP(int LINE_MIN, int LINE_MAX, int[] c, int a1, int b1, int a2, int b2) { double t; int res = CRES_NOT_CLIPPED; if (c[a1] < (LINE_MIN) || c[a1] > (LINE_MAX)) { if (c[a1] < (LINE_MIN)) { if (c[a2] < (LINE_MIN)) { return CRES_INVISIBLE; }; res = CRES_MIN_CLIPPED; t = (LINE_MIN); } else { if (c[a2] > (LINE_MAX)) { return CRES_INVISIBLE; }; res = CRES_MAX_CLIPPED; t = (LINE_MAX); } c[b1] = CLIP(c[a1], c[b1], c[a2], c[b2], t); c[a1] = (int)t; } return res; } /* Following method is used for clipping and clumping filled shapes. * An example of this process is shown on the picture below: * ----+ ----+ * |/ | |/ | * + | + | * /| | I | * / | | I | * | | | ===> I | * \ | | I | * \| | I | * + | + | * |\ | |\ | * | ----+ | ----+ * boundary boundary * * We can only perform clipping in case of right side of the output area * because all segments passed out the right boundary don't influence on the * result of scan conversion algorithm (it correctly handles half open * contours). * * This is java implementation of the macro from ProcessGeneralPath.c. * To keep the logic of the java code similar to the native one * array and set of indexes are used to point out the data. * */ private static int CLIPCLAMP(float LINE_MIN, float LINE_MAX, float[] c, int a1, int b1, int a2, int b2, int a3, int b3) { c[a3] = c[a1]; c[b3] = c[b1]; int res = TESTANDCLIP(LINE_MIN, LINE_MAX, c, a1, b1, a2, b2); if (res == CRES_MIN_CLIPPED) { c[a3] = c[a1]; } else if (res == CRES_MAX_CLIPPED) { c[a3] = c[a1]; res = CRES_MAX_CLIPPED; } else if (res == CRES_INVISIBLE) { if (c[a1] > LINE_MAX) { res = CRES_INVISIBLE; } else { c[a1] = LINE_MIN; c[a2] = LINE_MIN; res = CRES_NOT_CLIPPED; } } return res; } /* Integer version of the method above */ private static int CLIPCLAMP(int LINE_MIN, int LINE_MAX, int[] c, int a1, int b1, int a2, int b2, int a3, int b3) { c[a3] = c[a1]; c[b3] = c[b1]; int res = TESTANDCLIP(LINE_MIN, LINE_MAX, c, a1, b1, a2, b2); if (res == CRES_MIN_CLIPPED) { c[a3] = c[a1]; } else if (res == CRES_MAX_CLIPPED) { c[a3] = c[a1]; res = CRES_MAX_CLIPPED; } else if (res == CRES_INVISIBLE) { if (c[a1] > LINE_MAX) { res = CRES_INVISIBLE; } else { c[a1] = LINE_MIN; c[a2] = LINE_MIN; res = CRES_NOT_CLIPPED; } } return res; } private static class DrawProcessHandler extends ProcessHandler { EndSubPathHandler processESP; public DrawProcessHandler(DrawHandler dhnd, EndSubPathHandler processESP) { super(dhnd, PH_MODE_DRAW_CLIP); this.dhnd = dhnd; this.processESP = processESP; } public void processEndSubPath() { processESP.processEndSubPath(); } void PROCESS_LINE(int fX0, int fY0, int fX1, int fY1, boolean checkBounds, int[] pixelInfo) { int X0 = fX0 >> MDP_PREC; int Y0 = fY0 >> MDP_PREC; int X1 = fX1 >> MDP_PREC; int Y1 = fY1 >> MDP_PREC; /* Handling lines having just one pixel */ if (((X0^X1) | (Y0^Y1)) == 0) { if (checkBounds && (dhnd.yMin > Y0 || dhnd.yMax <= Y0 || dhnd.xMin > X0 || dhnd.xMax <= X0)) return; if (pixelInfo[0] == 0) { pixelInfo[0] = 1; pixelInfo[1] = X0; pixelInfo[2] = Y0; pixelInfo[3] = X0; pixelInfo[4] = Y0; dhnd.drawPixel(X0, Y0); } else if ((X0 != pixelInfo[3] || Y0 != pixelInfo[4]) && (X0 != pixelInfo[1] || Y0 != pixelInfo[2])) { dhnd.drawPixel(X0, Y0); pixelInfo[3] = X0; pixelInfo[4] = Y0; } return; } if (!checkBounds || (dhnd.yMin <= Y0 && dhnd.yMax > Y0 && dhnd.xMin <= X0 && dhnd.xMax > X0)) { /* Switch off first pixel of the line before drawing */ if (pixelInfo[0] == 1 && ((pixelInfo[1] == X0 && pixelInfo[2] == Y0) || (pixelInfo[3] == X0 && pixelInfo[4] == Y0))) { dhnd.drawPixel(X0, Y0); } } dhnd.drawLine(X0, Y0, X1, Y1); if (pixelInfo[0] == 0) { pixelInfo[0] = 1; pixelInfo[1] = X0; pixelInfo[2] = Y0; pixelInfo[3] = X0; pixelInfo[4] = Y0; } /* Switch on last pixel of the line if it was already * drawn during rendering of the previous segments */Lines 1–500 of 2128. Load more
/* * Copyright (c) 2005, 2006, 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.loops; import java.awt.geom.Path2D; import java.awt.geom.PathIterator; import java.awt.geom.QuadCurve2D; import sun.awt.SunHints; import java.util.*; /* This is the java implementation of the native code from * src/share/native/sun/java2d/loops/ProcessPath.[c,h] * This code is written to be as much similar to the native * as it possible. So, it sometimes does not follow java naming conventions. * * It's important to keep this code synchronized with native one. See more * comments, description and high level scheme of the rendering process in the * ProcessPath.c */ public class ProcessPath { /* Public interfaces and methods for drawing and filling general paths */ public static abstract class DrawHandler { public int xMin; public int yMin; public int xMax; public int yMax; public float xMinf; public float yMinf; public float xMaxf; public float yMaxf; public int strokeControl; public DrawHandler(int xMin, int yMin, int xMax, int yMax, int strokeControl) { setBounds(xMin, yMin, xMax, yMax, strokeControl); } public void setBounds(int xMin, int yMin, int xMax, int yMax) { this.xMin = xMin; this.yMin = yMin; this.xMax = xMax; this.yMax = yMax; /* Setting up fractional clipping box * * We are using following float -> int mapping: * * xi = floor(xf + 0.5) * * So, fractional values that hit the [xmin, xmax) integer interval * will be situated inside the [xmin-0.5, xmax - 0.5) fractional * interval. We are using EPSF constant to provide that upper * boundary is not included. */ xMinf = xMin - 0.5f; yMinf = yMin - 0.5f; xMaxf = xMax - 0.5f - EPSF; yMaxf = yMax - 0.5f - EPSF; } public void setBounds(int xMin, int yMin, int xMax, int yMax, int strokeControl) { this.strokeControl = strokeControl; setBounds(xMin, yMin, xMax, yMax); } public void adjustBounds(int bxMin, int byMin, int bxMax, int byMax) { if (xMin > bxMin) bxMin = xMin; if (xMax < bxMax) bxMax = xMax; if (yMin > byMin) byMin = yMin; if (yMax < byMax) byMax = yMax; setBounds(bxMin, byMin, bxMax, byMax); } public DrawHandler(int xMin, int yMin, int xMax, int yMax) { this(xMin, yMin, xMax, yMax, SunHints.INTVAL_STROKE_DEFAULT); } public abstract void drawLine(int x0, int y0, int x1, int y1); public abstract void drawPixel(int x0, int y0); public abstract void drawScanline(int x0, int x1, int y0); } public interface EndSubPathHandler { public void processEndSubPath(); } public static final int PH_MODE_DRAW_CLIP = 0; public static final int PH_MODE_FILL_CLIP = 1; public static abstract class ProcessHandler implements EndSubPathHandler { DrawHandler dhnd; int clipMode; public ProcessHandler(DrawHandler dhnd, int clipMode) { this.dhnd = dhnd; this.clipMode = clipMode; } public abstract void processFixedLine(int x1, int y1, int x2, int y2, int [] pixelInfo, boolean checkBounds, boolean endSubPath); } public static EndSubPathHandler noopEndSubPathHandler = new EndSubPathHandler() { public void processEndSubPath() { } }; public static boolean fillPath(DrawHandler dhnd, Path2D.Float p2df, int transX, int transY) { FillProcessHandler fhnd = new FillProcessHandler(dhnd); if (!doProcessPath(fhnd, p2df, transX, transY)) { return false; } FillPolygon(fhnd, p2df.getWindingRule()); return true; } public static boolean drawPath(DrawHandler dhnd, EndSubPathHandler endSubPath, Path2D.Float p2df, int transX, int transY) { return doProcessPath(new DrawProcessHandler(dhnd, endSubPath), p2df, transX, transY); } public static boolean drawPath(DrawHandler dhnd, Path2D.Float p2df, int transX, int transY) { return doProcessPath(new DrawProcessHandler(dhnd, noopEndSubPathHandler), p2df, transX, transY); } /* Private implementation of the rendering process */ /* Boundaries used for skipping huge path segments */ private static final float UPPER_BND = Float.MAX_VALUE/4.0f; private static final float LOWER_BND = -UPPER_BND; /* Precision (in bits) used in forward differencing */ private static final int FWD_PREC = 7; /* Precision (in bits) used for the rounding in the midpoint test */ private static final int MDP_PREC = 10; private static final int MDP_MULT = 1 << MDP_PREC; private static final int MDP_HALF_MULT = MDP_MULT >> 1; /* Boundaries used for clipping large path segments (those are inside * [UPPER/LOWER]_BND boundaries) */ private static final int UPPER_OUT_BND = 1 << (30 - MDP_PREC); private static final int LOWER_OUT_BND = -UPPER_OUT_BND; /* Calculation boundaries. They are used for switching to the more slow but * allowing larger input values method of calculation of the initial values * of the scan converted line segments inside the FillPolygon */ private static final float CALC_UBND = 1 << (30 - MDP_PREC); private static final float CALC_LBND = -CALC_UBND; /* Following constants are used for providing open boundaries of the * intervals */ public static final int EPSFX = 1; public static final float EPSF = ((float)EPSFX)/MDP_MULT; /* Bit mask used to separate whole part from the fraction part of the * number */ private static final int MDP_W_MASK = -MDP_MULT; /* Bit mask used to separate fractional part from the whole part of the * number */ private static final int MDP_F_MASK = MDP_MULT - 1; /* * Constants for the forward differencing * of the cubic and quad curves */ /* Maximum size of the cubic curve (calculated as the size of the bounding * box of the control points) which could be rendered without splitting */ private static final int MAX_CUB_SIZE = 256; /* Maximum size of the quad curve (calculated as the size of the bounding * box of the control points) which could be rendered without splitting */ private static final int MAX_QUAD_SIZE = 1024; /* Default power of 2 steps used in the forward differencing. Here DF prefix * stands for DeFault. Constants below are used as initial values for the * adaptive forward differencing algorithm. */ private static final int DF_CUB_STEPS = 3; private static final int DF_QUAD_STEPS = 2; /* Shift of the current point of the curve for preparing to the midpoint * rounding */ private static final int DF_CUB_SHIFT = FWD_PREC + DF_CUB_STEPS*3 - MDP_PREC; private static final int DF_QUAD_SHIFT = FWD_PREC + DF_QUAD_STEPS*2 - MDP_PREC; /* Default amount of steps of the forward differencing */ private static final int DF_CUB_COUNT = (1<<DF_CUB_STEPS); private static final int DF_QUAD_COUNT = (1<<DF_QUAD_STEPS); /* Default boundary constants used to check the necessity of the restepping */ private static final int DF_CUB_DEC_BND = 1<<DF_CUB_STEPS*3 + FWD_PREC + 2; private static final int DF_CUB_INC_BND = 1<<DF_CUB_STEPS*3 + FWD_PREC - 1; private static final int DF_QUAD_DEC_BND = 1<<DF_QUAD_STEPS*2 + FWD_PREC + 2; private static final int DF_QUAD_INC_BND = 1<<DF_QUAD_STEPS*2 + FWD_PREC - 1; /* Multipliers for the coefficients of the polynomial form of the cubic and * quad curves representation */ private static final int CUB_A_SHIFT = FWD_PREC; private static final int CUB_B_SHIFT = (DF_CUB_STEPS + FWD_PREC + 1); private static final int CUB_C_SHIFT = (DF_CUB_STEPS*2 + FWD_PREC); private static final int CUB_A_MDP_MULT = (1<<CUB_A_SHIFT); private static final int CUB_B_MDP_MULT = (1<<CUB_B_SHIFT); private static final int CUB_C_MDP_MULT = (1<<CUB_C_SHIFT); private static final int QUAD_A_SHIFT = FWD_PREC; private static final int QUAD_B_SHIFT = (DF_QUAD_STEPS + FWD_PREC); private static final int QUAD_A_MDP_MULT = (1<<QUAD_A_SHIFT); private static final int QUAD_B_MDP_MULT = (1<<QUAD_B_SHIFT); /* Clipping macros for drawing and filling algorithms */ private static float CLIP(float a1, float b1, float a2, float b2, double t) { return (float)(b1 + (double)(t - a1)*(b2 - b1) / (a2 - a1)); } private static int CLIP(int a1, int b1, int a2, int b2, double t) { return (int)(b1 + (double)(t - a1)*(b2 - b1) / (a2 - a1)); } private static final int CRES_MIN_CLIPPED = 0; private static final int CRES_MAX_CLIPPED = 1; private static final int CRES_NOT_CLIPPED = 3; private static final int CRES_INVISIBLE = 4; private static boolean IS_CLIPPED(int res) { return res == CRES_MIN_CLIPPED || res == CRES_MAX_CLIPPED; } /* This is java implementation of the macro from ProcessGeneralPath.c. * To keep the logic of the java code similar to the native one * array and set of indexes are used to point out the data. */ private static int TESTANDCLIP(float LINE_MIN, float LINE_MAX, float[] c, int a1, int b1, int a2, int b2) { double t; int res = CRES_NOT_CLIPPED; if (c[a1] < (LINE_MIN) || c[a1] > (LINE_MAX)) { if (c[a1] < (LINE_MIN)) { if (c[a2] < (LINE_MIN)) { return CRES_INVISIBLE; }; res = CRES_MIN_CLIPPED; t = (LINE_MIN); } else { if (c[a2] > (LINE_MAX)) { return CRES_INVISIBLE; }; res = CRES_MAX_CLIPPED; t = (LINE_MAX); } c[b1] = CLIP(c[a1], c[b1], c[a2], c[b2], t); c[a1] = (float)t; } return res; } /* Integer version of the method above */ private static int TESTANDCLIP(int LINE_MIN, int LINE_MAX, int[] c, int a1, int b1, int a2, int b2) { double t; int res = CRES_NOT_CLIPPED; if (c[a1] < (LINE_MIN) || c[a1] > (LINE_MAX)) { if (c[a1] < (LINE_MIN)) { if (c[a2] < (LINE_MIN)) { return CRES_INVISIBLE; }; res = CRES_MIN_CLIPPED; t = (LINE_MIN); } else { if (c[a2] > (LINE_MAX)) { return CRES_INVISIBLE; }; res = CRES_MAX_CLIPPED; t = (LINE_MAX); } c[b1] = CLIP(c[a1], c[b1], c[a2], c[b2], t); c[a1] = (int)t; } return res; } /* Following method is used for clipping and clumping filled shapes. * An example of this process is shown on the picture below: * ----+ ----+ * |/ | |/ | * + | + | * /| | I | * / | | I | * | | | ===> I | * \ | | I | * \| | I | * + | + | * |\ | |\ | * | ----+ | ----+ * boundary boundary * * We can only perform clipping in case of right side of the output area * because all segments passed out the right boundary don't influence on the * result of scan conversion algorithm (it correctly handles half open * contours). * * This is java implementation of the macro from ProcessGeneralPath.c. * To keep the logic of the java code similar to the native one * array and set of indexes are used to point out the data. * */ private static int CLIPCLAMP(float LINE_MIN, float LINE_MAX, float[] c, int a1, int b1, int a2, int b2, int a3, int b3) { c[a3] = c[a1]; c[b3] = c[b1]; int res = TESTANDCLIP(LINE_MIN, LINE_MAX, c, a1, b1, a2, b2); if (res == CRES_MIN_CLIPPED) { c[a3] = c[a1]; } else if (res == CRES_MAX_CLIPPED) { c[a3] = c[a1]; res = CRES_MAX_CLIPPED; } else if (res == CRES_INVISIBLE) { if (c[a1] > LINE_MAX) { res = CRES_INVISIBLE; } else { c[a1] = LINE_MIN; c[a2] = LINE_MIN; res = CRES_NOT_CLIPPED; } } return res; } /* Integer version of the method above */ private static int CLIPCLAMP(int LINE_MIN, int LINE_MAX, int[] c, int a1, int b1, int a2, int b2, int a3, int b3) { c[a3] = c[a1]; c[b3] = c[b1]; int res = TESTANDCLIP(LINE_MIN, LINE_MAX, c, a1, b1, a2, b2); if (res == CRES_MIN_CLIPPED) { c[a3] = c[a1]; } else if (res == CRES_MAX_CLIPPED) { c[a3] = c[a1]; res = CRES_MAX_CLIPPED; } else if (res == CRES_INVISIBLE) { if (c[a1] > LINE_MAX) { res = CRES_INVISIBLE; } else { c[a1] = LINE_MIN; c[a2] = LINE_MIN; res = CRES_NOT_CLIPPED; } } return res; } private static class DrawProcessHandler extends ProcessHandler { EndSubPathHandler processESP; public DrawProcessHandler(DrawHandler dhnd, EndSubPathHandler processESP) { super(dhnd, PH_MODE_DRAW_CLIP); this.dhnd = dhnd; this.processESP = processESP; } public void processEndSubPath() { processESP.processEndSubPath(); } void PROCESS_LINE(int fX0, int fY0, int fX1, int fY1, boolean checkBounds, int[] pixelInfo) { int X0 = fX0 >> MDP_PREC; int Y0 = fY0 >> MDP_PREC; int X1 = fX1 >> MDP_PREC; int Y1 = fY1 >> MDP_PREC; /* Handling lines having just one pixel */ if (((X0^X1) | (Y0^Y1)) == 0) { if (checkBounds && (dhnd.yMin > Y0 || dhnd.yMax <= Y0 || dhnd.xMin > X0 || dhnd.xMax <= X0)) return; if (pixelInfo[0] == 0) { pixelInfo[0] = 1; pixelInfo[1] = X0; pixelInfo[2] = Y0; pixelInfo[3] = X0; pixelInfo[4] = Y0; dhnd.drawPixel(X0, Y0); } else if ((X0 != pixelInfo[3] || Y0 != pixelInfo[4]) && (X0 != pixelInfo[1] || Y0 != pixelInfo[2])) { dhnd.drawPixel(X0, Y0); pixelInfo[3] = X0; pixelInfo[4] = Y0; } return; } if (!checkBounds || (dhnd.yMin <= Y0 && dhnd.yMax > Y0 && dhnd.xMin <= X0 && dhnd.xMax > X0)) { /* Switch off first pixel of the line before drawing */ if (pixelInfo[0] == 1 && ((pixelInfo[1] == X0 && pixelInfo[2] == Y0) || (pixelInfo[3] == X0 && pixelInfo[4] == Y0))) { dhnd.drawPixel(X0, Y0); } } dhnd.drawLine(X0, Y0, X1, Y1); if (pixelInfo[0] == 0) { pixelInfo[0] = 1; pixelInfo[1] = X0; pixelInfo[2] = Y0; pixelInfo[3] = X0; pixelInfo[4] = Y0; } /* Switch on last pixel of the line if it was already * drawn during rendering of the previous segments */