2128 lines · 78.3 KB · Java
RawDownload
/* * 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.