Source Code Cross Referenced for ProcessPath.java in  » 6.0-JDK-Modules-sun » java2d » sun » java2d » loops » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules sun » java2d » sun.java2d.loops 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 2005-2006 Sun Microsystems, Inc.  All Rights Reserved.
0003:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004:         *
0005:         * This code is free software; you can redistribute it and/or modify it
0006:         * under the terms of the GNU General Public License version 2 only, as
0007:         * published by the Free Software Foundation.  Sun designates this
0008:         * particular file as subject to the "Classpath" exception as provided
0009:         * by Sun in the LICENSE file that accompanied this code.
0010:         *
0011:         * This code is distributed in the hope that it will be useful, but WITHOUT
0012:         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013:         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
0014:         * version 2 for more details (a copy is included in the LICENSE file that
0015:         * accompanied this code).
0016:         *
0017:         * You should have received a copy of the GNU General Public License version
0018:         * 2 along with this work; if not, write to the Free Software Foundation,
0019:         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020:         *
0021:         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022:         * CA 95054 USA or visit www.sun.com if you need additional information or
0023:         * have any questions.
0024:         */
0025:
0026:        package sun.java2d.loops;
0027:
0028:        import java.awt.geom.Path2D;
0029:        import java.awt.geom.PathIterator;
0030:        import java.awt.geom.QuadCurve2D;
0031:        import sun.awt.SunHints;
0032:        import java.util.*;
0033:
0034:        /* This is the java implementation of the native code from 
0035:         * src/share/native/sun/java2d/loops/ProcessPath.[c,h]
0036:         * This code is written to be as much similar to the native 
0037:         * as it possible. So, it sometimes does not follow java naming conventions.
0038:         *
0039:         * It's important to keep this code synchronized with native one.  See more
0040:         * comments, description and high level scheme of the rendering process in the 
0041:         * ProcessPath.c
0042:         */
0043:
0044:        public class ProcessPath {
0045:
0046:            /* Public interfaces and methods for drawing and filling general paths */
0047:
0048:            public static abstract class DrawHandler {
0049:                public int xMin;
0050:                public int yMin;
0051:                public int xMax;
0052:                public int yMax;
0053:                public float xMinf;
0054:                public float yMinf;
0055:                public float xMaxf;
0056:                public float yMaxf;
0057:
0058:                public int strokeControl;
0059:
0060:                public DrawHandler(int xMin, int yMin, int xMax, int yMax,
0061:                        int strokeControl) {
0062:                    setBounds(xMin, yMin, xMax, yMax, strokeControl);
0063:                }
0064:
0065:                public void setBounds(int xMin, int yMin, int xMax, int yMax) {
0066:                    this .xMin = xMin;
0067:                    this .yMin = yMin;
0068:                    this .xMax = xMax;
0069:                    this .yMax = yMax;
0070:
0071:                    /*                Setting up fractional clipping box
0072:                     *                  
0073:                     * We are using following float -> int mapping: 
0074:                     *
0075:                     *      xi = floor(xf + 0.5) 
0076:                     *
0077:                     * So, fractional values that hit the [xmin, xmax) integer interval
0078:                     * will be situated inside the [xmin-0.5, xmax - 0.5) fractional 
0079:                     * interval. We are using EPSF constant to provide that upper 
0080:                     * boundary is not included.
0081:                     */
0082:                    xMinf = xMin - 0.5f;
0083:                    yMinf = yMin - 0.5f;
0084:                    xMaxf = xMax - 0.5f - EPSF;
0085:                    yMaxf = yMax - 0.5f - EPSF;
0086:                }
0087:
0088:                public void setBounds(int xMin, int yMin, int xMax, int yMax,
0089:                        int strokeControl) {
0090:                    this .strokeControl = strokeControl;
0091:                    setBounds(xMin, yMin, xMax, yMax);
0092:                }
0093:
0094:                public void adjustBounds(int bxMin, int byMin, int bxMax,
0095:                        int byMax) {
0096:                    if (xMin > bxMin)
0097:                        bxMin = xMin;
0098:                    if (xMax < bxMax)
0099:                        bxMax = xMax;
0100:                    if (yMin > byMin)
0101:                        byMin = yMin;
0102:                    if (yMax < byMax)
0103:                        byMax = yMax;
0104:                    setBounds(bxMin, byMin, bxMax, byMax);
0105:                }
0106:
0107:                public DrawHandler(int xMin, int yMin, int xMax, int yMax) {
0108:                    this (xMin, yMin, xMax, yMax, SunHints.INTVAL_STROKE_DEFAULT);
0109:                }
0110:
0111:                public abstract void drawLine(int x0, int y0, int x1, int y1);
0112:
0113:                public abstract void drawPixel(int x0, int y0);
0114:
0115:                public abstract void drawScanline(int x0, int x1, int y0);
0116:            }
0117:
0118:            public interface EndSubPathHandler {
0119:                public void processEndSubPath();
0120:            }
0121:
0122:            public static final int PH_MODE_DRAW_CLIP = 0;
0123:            public static final int PH_MODE_FILL_CLIP = 1;
0124:
0125:            public static abstract class ProcessHandler implements 
0126:                    EndSubPathHandler {
0127:                DrawHandler dhnd;
0128:                int clipMode;
0129:
0130:                public ProcessHandler(DrawHandler dhnd, int clipMode) {
0131:                    this .dhnd = dhnd;
0132:                    this .clipMode = clipMode;
0133:                }
0134:
0135:                public abstract void processFixedLine(int x1, int y1, int x2,
0136:                        int y2, int[] pixelInfo, boolean checkBounds,
0137:                        boolean endSubPath);
0138:            }
0139:
0140:            public static EndSubPathHandler noopEndSubPathHandler = new EndSubPathHandler() {
0141:                public void processEndSubPath() {
0142:                }
0143:            };
0144:
0145:            public static boolean fillPath(DrawHandler dhnd, Path2D.Float p2df,
0146:                    int transX, int transY) {
0147:                FillProcessHandler fhnd = new FillProcessHandler(dhnd);
0148:                if (!doProcessPath(fhnd, p2df, transX, transY)) {
0149:                    return false;
0150:                }
0151:                FillPolygon(fhnd, p2df.getWindingRule());
0152:                return true;
0153:            }
0154:
0155:            public static boolean drawPath(DrawHandler dhnd,
0156:                    EndSubPathHandler endSubPath, Path2D.Float p2df,
0157:                    int transX, int transY) {
0158:                return doProcessPath(new DrawProcessHandler(dhnd, endSubPath),
0159:                        p2df, transX, transY);
0160:            }
0161:
0162:            public static boolean drawPath(DrawHandler dhnd, Path2D.Float p2df,
0163:                    int transX, int transY) {
0164:                return doProcessPath(new DrawProcessHandler(dhnd,
0165:                        noopEndSubPathHandler), p2df, transX, transY);
0166:            }
0167:
0168:            /* Private implementation of the rendering process */
0169:
0170:            /* Boundaries used for skipping huge path segments */
0171:            private static final float UPPER_BND = Float.MAX_VALUE / 4.0f;
0172:            private static final float LOWER_BND = -UPPER_BND;
0173:
0174:            /* Precision (in bits) used in forward differencing */
0175:            private static final int FWD_PREC = 7;
0176:
0177:            /* Precision (in bits) used for the rounding in the midpoint test */
0178:            private static final int MDP_PREC = 10;
0179:
0180:            private static final int MDP_MULT = 1 << MDP_PREC;
0181:            private static final int MDP_HALF_MULT = MDP_MULT >> 1;
0182:
0183:            /* Boundaries used for clipping large path segments (those are inside 
0184:             * [UPPER/LOWER]_BND boundaries) 
0185:             */
0186:            private static final int UPPER_OUT_BND = 1 << (30 - MDP_PREC);
0187:            private static final int LOWER_OUT_BND = -UPPER_OUT_BND;
0188:
0189:            /* Calculation boundaries. They are used for switching to the more slow but 
0190:             * allowing larger input values method of calculation of the initial values
0191:             * of the scan converted line segments inside the FillPolygon
0192:             */
0193:            private static final float CALC_UBND = 1 << (30 - MDP_PREC);
0194:            private static final float CALC_LBND = -CALC_UBND;
0195:
0196:            /* Following constants are used for providing open boundaries of the 
0197:             * intervals
0198:             */
0199:            public static final int EPSFX = 1;
0200:            public static final float EPSF = ((float) EPSFX) / MDP_MULT;
0201:
0202:            /* Bit mask used to separate whole part from the fraction part of the
0203:             * number
0204:             */
0205:            private static final int MDP_W_MASK = -MDP_MULT;
0206:
0207:            /* Bit mask used to separate fractional part from the whole part of the
0208:             * number
0209:             */
0210:            private static final int MDP_F_MASK = MDP_MULT - 1;
0211:
0212:            /*
0213:             *                  Constants for the forward differencing 
0214:             *                      of the cubic and quad curves
0215:             */
0216:
0217:            /* Maximum size of the cubic curve (calculated as the size of the bounding
0218:             * box of the control points) which could be rendered without splitting
0219:             */
0220:            private static final int MAX_CUB_SIZE = 256;
0221:
0222:            /* Maximum size of the quad curve (calculated as the size of the bounding
0223:             * box of the control points) which could be rendered without splitting
0224:             */
0225:            private static final int MAX_QUAD_SIZE = 1024;
0226:
0227:            /* Default power of 2 steps used in the forward differencing. Here DF prefix
0228:             * stands for DeFault. Constants below are used as initial values for the
0229:             * adaptive forward differencing algorithm.
0230:             */
0231:            private static final int DF_CUB_STEPS = 3;
0232:            private static final int DF_QUAD_STEPS = 2;
0233:
0234:            /* Shift of the current point of the curve for preparing to the midpoint
0235:             * rounding 
0236:             */
0237:            private static final int DF_CUB_SHIFT = FWD_PREC + DF_CUB_STEPS * 3
0238:                    - MDP_PREC;
0239:            private static final int DF_QUAD_SHIFT = FWD_PREC + DF_QUAD_STEPS
0240:                    * 2 - MDP_PREC;
0241:
0242:            /* Default amount of steps of the forward differencing */
0243:            private static final int DF_CUB_COUNT = (1 << DF_CUB_STEPS);
0244:            private static final int DF_QUAD_COUNT = (1 << DF_QUAD_STEPS);
0245:
0246:            /* Default boundary constants used to check the necessity of the restepping
0247:             */
0248:            private static final int DF_CUB_DEC_BND = 1 << DF_CUB_STEPS * 3
0249:                    + FWD_PREC + 2;
0250:            private static final int DF_CUB_INC_BND = 1 << DF_CUB_STEPS * 3
0251:                    + FWD_PREC - 1;
0252:            private static final int DF_QUAD_DEC_BND = 1 << DF_QUAD_STEPS * 2
0253:                    + FWD_PREC + 2;
0254:            private static final int DF_QUAD_INC_BND = 1 << DF_QUAD_STEPS * 2
0255:                    + FWD_PREC - 1;
0256:
0257:            /* Multipliers for the coefficients of the polynomial form of the cubic and
0258:             * quad curves representation
0259:             */
0260:            private static final int CUB_A_SHIFT = FWD_PREC;
0261:            private static final int CUB_B_SHIFT = (DF_CUB_STEPS + FWD_PREC + 1);
0262:            private static final int CUB_C_SHIFT = (DF_CUB_STEPS * 2 + FWD_PREC);
0263:
0264:            private static final int CUB_A_MDP_MULT = (1 << CUB_A_SHIFT);
0265:            private static final int CUB_B_MDP_MULT = (1 << CUB_B_SHIFT);
0266:            private static final int CUB_C_MDP_MULT = (1 << CUB_C_SHIFT);
0267:
0268:            private static final int QUAD_A_SHIFT = FWD_PREC;
0269:            private static final int QUAD_B_SHIFT = (DF_QUAD_STEPS + FWD_PREC);
0270:
0271:            private static final int QUAD_A_MDP_MULT = (1 << QUAD_A_SHIFT);
0272:            private static final int QUAD_B_MDP_MULT = (1 << QUAD_B_SHIFT);
0273:
0274:            /* Clipping macros for drawing and filling algorithms */
0275:            private static float CLIP(float a1, float b1, float a2, float b2,
0276:                    double t) {
0277:                return (float) (b1 + (double) (t - a1) * (b2 - b1) / (a2 - a1));
0278:            }
0279:
0280:            private static int CLIP(int a1, int b1, int a2, int b2, double t) {
0281:                return (int) (b1 + (double) (t - a1) * (b2 - b1) / (a2 - a1));
0282:            }
0283:
0284:            private static final int CRES_MIN_CLIPPED = 0;
0285:            private static final int CRES_MAX_CLIPPED = 1;
0286:            private static final int CRES_NOT_CLIPPED = 3;
0287:            private static final int CRES_INVISIBLE = 4;
0288:
0289:            private static boolean IS_CLIPPED(int res) {
0290:                return res == CRES_MIN_CLIPPED || res == CRES_MAX_CLIPPED;
0291:            }
0292:
0293:            /* This is java implementation of the macro from ProcessGeneralPath.c.
0294:             * To keep the logic of the java code similar to the native one 
0295:             * array and set of indexes are used to point out the data.
0296:             */
0297:            private static int TESTANDCLIP(float LINE_MIN, float LINE_MAX,
0298:                    float[] c, int a1, int b1, int a2, int b2) {
0299:                double t;
0300:                int res = CRES_NOT_CLIPPED;
0301:                if (c[a1] < (LINE_MIN) || c[a1] > (LINE_MAX)) {
0302:                    if (c[a1] < (LINE_MIN)) {
0303:                        if (c[a2] < (LINE_MIN)) {
0304:                            return CRES_INVISIBLE;
0305:                        }
0306:                        ;
0307:                        res = CRES_MIN_CLIPPED;
0308:                        t = (LINE_MIN);
0309:                    } else {
0310:                        if (c[a2] > (LINE_MAX)) {
0311:                            return CRES_INVISIBLE;
0312:                        }
0313:                        ;
0314:                        res = CRES_MAX_CLIPPED;
0315:                        t = (LINE_MAX);
0316:                    }
0317:                    c[b1] = CLIP(c[a1], c[b1], c[a2], c[b2], t);
0318:                    c[a1] = (float) t;
0319:                }
0320:                return res;
0321:            }
0322:
0323:            /* Integer version of the method above */
0324:            private static int TESTANDCLIP(int LINE_MIN, int LINE_MAX, int[] c,
0325:                    int a1, int b1, int a2, int b2) {
0326:                double t;
0327:                int res = CRES_NOT_CLIPPED;
0328:                if (c[a1] < (LINE_MIN) || c[a1] > (LINE_MAX)) {
0329:                    if (c[a1] < (LINE_MIN)) {
0330:                        if (c[a2] < (LINE_MIN)) {
0331:                            return CRES_INVISIBLE;
0332:                        }
0333:                        ;
0334:                        res = CRES_MIN_CLIPPED;
0335:                        t = (LINE_MIN);
0336:                    } else {
0337:                        if (c[a2] > (LINE_MAX)) {
0338:                            return CRES_INVISIBLE;
0339:                        }
0340:                        ;
0341:                        res = CRES_MAX_CLIPPED;
0342:                        t = (LINE_MAX);
0343:                    }
0344:                    c[b1] = CLIP(c[a1], c[b1], c[a2], c[b2], t);
0345:                    c[a1] = (int) t;
0346:                }
0347:                return res;
0348:            }
0349:
0350:            /* Following method is used for clipping and clumping filled shapes. 
0351:             * An example of this process is shown on the picture below: 
0352:             *                      ----+          ----+
0353:             *                    |/    |        |/    |
0354:             *                    +     |        +     |
0355:             *                   /|     |        I     |
0356:             *                  / |     |        I     |
0357:             *                  | |     |  ===>  I     |
0358:             *                  \ |     |        I     |
0359:             *                   \|     |        I     |
0360:             *                    +     |        +     |
0361:             *                    |\    |        |\    |
0362:             *                    | ----+        | ----+
0363:             *                 boundary       boundary
0364:             *
0365:             * We can only perform clipping in case of right side of the output area
0366:             * because all segments passed out the right boundary don't influence on the
0367:             * result of scan conversion algorithm (it correctly handles half open
0368:             * contours).
0369:             *
0370:             * This is java implementation of the macro from ProcessGeneralPath.c.
0371:             * To keep the logic of the java code similar to the native one  
0372:             * array and set of indexes are used to point out the data.
0373:             * 
0374:             */
0375:            private static int CLIPCLAMP(float LINE_MIN, float LINE_MAX,
0376:                    float[] c, int a1, int b1, int a2, int b2, int a3, int b3) {
0377:                c[a3] = c[a1];
0378:                c[b3] = c[b1];
0379:                int res = TESTANDCLIP(LINE_MIN, LINE_MAX, c, a1, b1, a2, b2);
0380:                if (res == CRES_MIN_CLIPPED) {
0381:                    c[a3] = c[a1];
0382:                } else if (res == CRES_MAX_CLIPPED) {
0383:                    c[a3] = c[a1];
0384:                    res = CRES_MAX_CLIPPED;
0385:                } else if (res == CRES_INVISIBLE) {
0386:                    if (c[a1] > LINE_MAX) {
0387:                        res = CRES_INVISIBLE;
0388:                    } else {
0389:                        c[a1] = LINE_MIN;
0390:                        c[a2] = LINE_MIN;
0391:                        res = CRES_NOT_CLIPPED;
0392:                    }
0393:                }
0394:                return res;
0395:            }
0396:
0397:            /* Integer version of the method above */
0398:            private static int CLIPCLAMP(int LINE_MIN, int LINE_MAX, int[] c,
0399:                    int a1, int b1, int a2, int b2, int a3, int b3) {
0400:                c[a3] = c[a1];
0401:                c[b3] = c[b1];
0402:                int res = TESTANDCLIP(LINE_MIN, LINE_MAX, c, a1, b1, a2, b2);
0403:                if (res == CRES_MIN_CLIPPED) {
0404:                    c[a3] = c[a1];
0405:                } else if (res == CRES_MAX_CLIPPED) {
0406:                    c[a3] = c[a1];
0407:                    res = CRES_MAX_CLIPPED;
0408:                } else if (res == CRES_INVISIBLE) {
0409:                    if (c[a1] > LINE_MAX) {
0410:                        res = CRES_INVISIBLE;
0411:                    } else {
0412:                        c[a1] = LINE_MIN;
0413:                        c[a2] = LINE_MIN;
0414:                        res = CRES_NOT_CLIPPED;
0415:                    }
0416:                }
0417:                return res;
0418:            }
0419:
0420:            private static class DrawProcessHandler extends ProcessHandler {
0421:
0422:                EndSubPathHandler processESP;
0423:
0424:                public DrawProcessHandler(DrawHandler dhnd,
0425:                        EndSubPathHandler processESP) {
0426:                    super (dhnd, PH_MODE_DRAW_CLIP);
0427:                    this .dhnd = dhnd;
0428:                    this .processESP = processESP;
0429:                }
0430:
0431:                public void processEndSubPath() {
0432:                    processESP.processEndSubPath();
0433:                }
0434:
0435:                void PROCESS_LINE(int fX0, int fY0, int fX1, int fY1,
0436:                        boolean checkBounds, int[] pixelInfo) {
0437:                    int X0 = fX0 >> MDP_PREC;
0438:                    int Y0 = fY0 >> MDP_PREC;
0439:                    int X1 = fX1 >> MDP_PREC;
0440:                    int Y1 = fY1 >> MDP_PREC;
0441:
0442:                    /* Handling lines having just one pixel */
0443:                    if (((X0 ^ X1) | (Y0 ^ Y1)) == 0) {
0444:                        if (checkBounds
0445:                                && (dhnd.yMin > Y0 || dhnd.yMax <= Y0
0446:                                        || dhnd.xMin > X0 || dhnd.xMax <= X0))
0447:                            return;
0448:
0449:                        if (pixelInfo[0] == 0) {
0450:                            pixelInfo[0] = 1;
0451:                            pixelInfo[1] = X0;
0452:                            pixelInfo[2] = Y0;
0453:                            pixelInfo[3] = X0;
0454:                            pixelInfo[4] = Y0;
0455:                            dhnd.drawPixel(X0, Y0);
0456:                        } else if ((X0 != pixelInfo[3] || Y0 != pixelInfo[4])
0457:                                && (X0 != pixelInfo[1] || Y0 != pixelInfo[2])) {
0458:                            dhnd.drawPixel(X0, Y0);
0459:                            pixelInfo[3] = X0;
0460:                            pixelInfo[4] = Y0;
0461:                        }
0462:                        return;
0463:                    }
0464:
0465:                    if (!checkBounds
0466:                            || (dhnd.yMin <= Y0 && dhnd.yMax > Y0
0467:                                    && dhnd.xMin <= X0 && dhnd.xMax > X0)) {
0468:                        /* Switch off first pixel of the line before drawing */
0469:                        if (pixelInfo[0] == 1
0470:                                && ((pixelInfo[1] == X0 && pixelInfo[2] == Y0) || (pixelInfo[3] == X0 && pixelInfo[4] == Y0))) {
0471:                            dhnd.drawPixel(X0, Y0);
0472:                        }
0473:                    }
0474:
0475:                    dhnd.drawLine(X0, Y0, X1, Y1);
0476:
0477:                    if (pixelInfo[0] == 0) {
0478:                        pixelInfo[0] = 1;
0479:                        pixelInfo[1] = X0;
0480:                        pixelInfo[2] = Y0;
0481:                        pixelInfo[3] = X0;
0482:                        pixelInfo[4] = Y0;
0483:                    }
0484:
0485:                    /* Switch on last pixel of the line if it was already
0486:                     * drawn during rendering of the previous segments
0487:                     */
0488:                    if ((pixelInfo[1] == X1 && pixelInfo[2] == Y1)
0489:                            || (pixelInfo[3] == X1 && pixelInfo[4] == Y1)) {
0490:                        if (checkBounds
0491:                                && (dhnd.yMin > Y1 || dhnd.yMax <= Y1
0492:                                        || dhnd.xMin > X1 || dhnd.xMax <= X1)) {
0493:                            return;
0494:                        }
0495:
0496:                        dhnd.drawPixel(X1, Y1);
0497:                    }
0498:                    pixelInfo[3] = X1;
0499:                    pixelInfo[4] = Y1;
0500:                }
0501:
0502:                void PROCESS_POINT(int fX, int fY, boolean checkBounds,
0503:                        int[] pixelInfo) {
0504:                    int _X = fX >> MDP_PREC;
0505:                    int _Y = fY >> MDP_PREC;
0506:                    if (checkBounds
0507:                            && (dhnd.yMin > _Y || dhnd.yMax <= _Y
0508:                                    || dhnd.xMin > _X || dhnd.xMax <= _X))
0509:                        return;
0510:                    /*
0511:                     *  (_X,_Y) should be inside boundaries
0512:                     *
0513:                     *  assert(dhnd.yMin <= _Y &&
0514:                     *         dhnd.yMax >  _Y &&
0515:                     *         dhnd.xMin <= _X &&
0516:                     *         dhnd.xMax >  _X);
0517:                     *
0518:                     */
0519:                    if (pixelInfo[0] == 0) {
0520:                        pixelInfo[0] = 1;
0521:                        pixelInfo[1] = _X;
0522:                        pixelInfo[2] = _Y;
0523:                        pixelInfo[3] = _X;
0524:                        pixelInfo[4] = _Y;
0525:                        dhnd.drawPixel(_X, _Y);
0526:                    } else if ((_X != pixelInfo[3] || _Y != pixelInfo[4])
0527:                            && (_X != pixelInfo[1] || _Y != pixelInfo[2])) {
0528:                        dhnd.drawPixel(_X, _Y);
0529:                        pixelInfo[3] = _X;
0530:                        pixelInfo[4] = _Y;
0531:                    }
0532:                }
0533:
0534:                /*                  Drawing line with subpixel endpoints
0535:                 *
0536:                 * (x1, y1), (x2, y2) -  fixed point coordinates of the endpoints
0537:                 *                       with MDP_PREC bits for the fractional part
0538:                 *
0539:                 * pixelInfo          -  structure which keeps drawing info for avoiding
0540:                 *                       multiple drawing at the same position on the
0541:                 *                       screen (required for the XOR mode of drawing)
0542:                 *
0543:                 *                          pixelInfo[0]   - state of the drawing
0544:                 *                                           0 - no pixel drawn between
0545:                 *                                           moveTo/close of the path
0546:                 *                                           1 - there are drawn pixels
0547:                 *                         
0548:                 *                          pixelInfo[1,2] - first pixel of the path
0549:                 *                                           between moveTo/close of the
0550:                 *                                           path
0551:                 *                         
0552:                 *                          pixelInfo[3,4] - last drawn pixel between
0553:                 *                                           moveTo/close of the path
0554:                 *                         
0555:                 * checkBounds        - flag showing necessity of checking the clip
0556:                 *
0557:                 */
0558:                public void processFixedLine(int x1, int y1, int x2, int y2,
0559:                        int[] pixelInfo, boolean checkBounds, boolean endSubPath) {
0560:
0561:                    /* Checking if line is inside a (X,Y),(X+MDP_MULT,Y+MDP_MULT) box */
0562:                    int c = ((x1 ^ x2) | (y1 ^ y2));
0563:                    int rx1, ry1, rx2, ry2;
0564:                    if ((c & MDP_W_MASK) == 0) {
0565:                        /* Checking for the segments with integer coordinates having
0566:                         * the same start and end points
0567:                         */
0568:                        if (c == 0) {
0569:                            PROCESS_POINT(x1 + MDP_HALF_MULT, y1
0570:                                    + MDP_HALF_MULT, checkBounds, pixelInfo);
0571:                        }
0572:                        return;
0573:                    }
0574:
0575:                    if (x1 == x2 || y1 == y2) {
0576:                        rx1 = x1 + MDP_HALF_MULT;
0577:                        rx2 = x2 + MDP_HALF_MULT;
0578:                        ry1 = y1 + MDP_HALF_MULT;
0579:                        ry2 = y2 + MDP_HALF_MULT;
0580:                    } else {
0581:                        /* Neither dx nor dy can be zero because of the check above */
0582:                        int dx = x2 - x1;
0583:                        int dy = y2 - y1;
0584:
0585:                        /* Floor of x1, y1, x2, y2 */
0586:                        int fx1 = x1 & MDP_W_MASK;
0587:                        int fy1 = y1 & MDP_W_MASK;
0588:                        int fx2 = x2 & MDP_W_MASK;
0589:                        int fy2 = y2 & MDP_W_MASK;
0590:
0591:                        /* Processing first endpoint */
0592:                        if (fx1 == x1 || fy1 == y1) {
0593:                            /* Adding MDP_HALF_MULT to the [xy]1 if f[xy]1 == [xy]1 
0594:                             * will not affect the result 
0595:                             */
0596:                            rx1 = x1 + MDP_HALF_MULT;
0597:                            ry1 = y1 + MDP_HALF_MULT;
0598:                        } else {
0599:                            /* Boundary at the direction from (x1,y1) to (x2,y2) */
0600:                            int bx1 = (x1 < x2) ? fx1 + MDP_MULT : fx1;
0601:                            int by1 = (y1 < y2) ? fy1 + MDP_MULT : fy1;
0602:
0603:                            /* intersection with column bx1 */
0604:                            int cross = y1 + ((bx1 - x1) * dy) / dx;
0605:                            if (cross >= fy1 && cross <= fy1 + MDP_MULT) {
0606:                                rx1 = bx1;
0607:                                ry1 = cross + MDP_HALF_MULT;
0608:                            } else {
0609:                                /* intersection with row by1 */
0610:                                cross = x1 + ((by1 - y1) * dx) / dy;
0611:                                rx1 = cross + MDP_HALF_MULT;
0612:                                ry1 = by1;
0613:                            }
0614:                        }
0615:
0616:                        /* Processing second endpoint */
0617:                        if (fx2 == x2 || fy2 == y2) {
0618:                            /* Adding MDP_HALF_MULT to the [xy]2 if f[xy]2 == [xy]2 
0619:                             * will not affect the result 
0620:                             */
0621:                            rx2 = x2 + MDP_HALF_MULT;
0622:                            ry2 = y2 + MDP_HALF_MULT;
0623:                        } else {
0624:                            /* Boundary at the direction from (x2,y2) to (x1,y1) */
0625:                            int bx2 = (x1 > x2) ? fx2 + MDP_MULT : fx2;
0626:                            int by2 = (y1 > y2) ? fy2 + MDP_MULT : fy2;
0627:
0628:                            /* intersection with column bx2 */
0629:                            int cross = y2 + ((bx2 - x2) * dy) / dx;
0630:                            if (cross >= fy2 && cross <= fy2 + MDP_MULT) {
0631:                                rx2 = bx2;
0632:                                ry2 = cross + MDP_HALF_MULT;
0633:                            } else {
0634:                                /* intersection with row by2 */
0635:                                cross = x2 + ((by2 - y2) * dx) / dy;
0636:                                rx2 = cross + MDP_HALF_MULT;
0637:                                ry2 = by2;
0638:                            }
0639:                        }
0640:                    }
0641:                    PROCESS_LINE(rx1, ry1, rx2, ry2, checkBounds, pixelInfo);
0642:                }
0643:            }
0644:
0645:            /* Performing drawing of the monotonic in X and Y quadratic curves with
0646:             * sizes less than MAX_QUAD_SIZE by using forward differencing method of
0647:             * calculation. See comments to the DrawMonotonicQuad in the 
0648:             * ProcessGeneralPath.c
0649:             */
0650:            private static void DrawMonotonicQuad(ProcessHandler hnd,
0651:                    float[] coords, boolean checkBounds, int[] pixelInfo) {
0652:
0653:                int x0 = (int) (coords[0] * MDP_MULT);
0654:                int y0 = (int) (coords[1] * MDP_MULT);
0655:
0656:                int xe = (int) (coords[4] * MDP_MULT);
0657:                int ye = (int) (coords[5] * MDP_MULT);
0658:
0659:                /* Extracting fractional part of coordinates of first control point */
0660:                int px = (x0 & (~MDP_W_MASK)) << DF_QUAD_SHIFT;
0661:                int py = (y0 & (~MDP_W_MASK)) << DF_QUAD_SHIFT;
0662:
0663:                /* Setting default amount of steps */
0664:                int count = DF_QUAD_COUNT;
0665:
0666:                /* Setting default shift for preparing to the midpoint rounding */
0667:                int shift = DF_QUAD_SHIFT;
0668:
0669:                int ax = (int) ((coords[0] - 2 * coords[2] + coords[4]) * QUAD_A_MDP_MULT);
0670:                int ay = (int) ((coords[1] - 2 * coords[3] + coords[5]) * QUAD_A_MDP_MULT);
0671:
0672:                int bx = (int) ((-2 * coords[0] + 2 * coords[2]) * QUAD_B_MDP_MULT);
0673:                int by = (int) ((-2 * coords[1] + 2 * coords[3]) * QUAD_B_MDP_MULT);
0674:
0675:                int ddpx = 2 * ax;
0676:                int ddpy = 2 * ay;
0677:
0678:                int dpx = ax + bx;
0679:                int dpy = ay + by;
0680:
0681:                int x1, y1;
0682:
0683:                int x2 = x0;
0684:                int y2 = y0;
0685:
0686:                int maxDD = Math.max(Math.abs(ddpx), Math.abs(ddpy));
0687:
0688:                int dx = xe - x0;
0689:                int dy = ye - y0;
0690:
0691:                int x0w = x0 & MDP_W_MASK;
0692:                int y0w = y0 & MDP_W_MASK;
0693:
0694:                /* Perform decreasing step in 2 times if slope of the first forward
0695:                 * difference changes too quickly (more than a pixel per step in X or Y
0696:                 * direction).  We can perform adjusting of the step size before the
0697:                 * rendering loop because the curvature of the quad curve remains the
0698:                 * same along all the curve 
0699:                 */
0700:                while (maxDD > DF_QUAD_DEC_BND) {
0701:                    dpx = (dpx << 1) - ax;
0702:                    dpy = (dpy << 1) - ay;
0703:                    count <<= 1;
0704:                    maxDD >>= 2;
0705:                    px <<= 2;
0706:                    py <<= 2;
0707:                    shift += 2;
0708:                }
0709:
0710:                while (count-- > 1) {
0711:                    px += dpx;
0712:                    py += dpy;
0713:
0714:                    dpx += ddpx;
0715:                    dpy += ddpy;
0716:
0717:                    x1 = x2;
0718:                    y1 = y2;
0719:
0720:                    x2 = x0w + (px >> shift);
0721:                    y2 = y0w + (py >> shift);
0722:
0723:                    /* Checking that we are not running out of the endpoint and bounding
0724:                     * violating coordinate.  The check is pretty simple because the
0725:                     * curve passed to the DrawCubic already splitted into the
0726:                     * monotonic in X and Y pieces
0727:                     */
0728:
0729:                    /* Bounding x2 by xe */
0730:                    if (((xe - x2) ^ dx) < 0) {
0731:                        x2 = xe;
0732:                    }
0733:
0734:                    /* Bounding y2 by ye */
0735:                    if (((ye - y2) ^ dy) < 0) {
0736:                        y2 = ye;
0737:                    }
0738:
0739:                    hnd.processFixedLine(x1, y1, x2, y2, pixelInfo,
0740:                            checkBounds, false);
0741:                }
0742:
0743:                /* We are performing one step less than necessary and use actual
0744:                 * (xe,ye) endpoint of the curve instead of calculated. This prevent us
0745:                 * from running above the curve endpoint due to the accumulated errors
0746:                 * during the iterations.  
0747:                 */
0748:
0749:                hnd.processFixedLine(x2, y2, xe, ye, pixelInfo, checkBounds,
0750:                        false);
0751:            }
0752:
0753:            /*
0754:             * Checking size of the quad curves and split them if necessary.
0755:             * Calling DrawMonotonicQuad for the curves of the appropriate size.
0756:             * Note: coords array could be changed
0757:             */
0758:            private static void ProcessMonotonicQuad(ProcessHandler hnd,
0759:                    float[] coords, int[] pixelInfo) {
0760:
0761:                float[] coords1 = new float[6];
0762:                float tx, ty;
0763:                float xMin, yMin, xMax, yMax;
0764:
0765:                xMin = xMax = coords[0];
0766:                yMin = yMax = coords[1];
0767:                for (int i = 2; i < 6; i += 2) {
0768:                    xMin = (xMin > coords[i]) ? coords[i] : xMin;
0769:                    xMax = (xMax < coords[i]) ? coords[i] : xMax;
0770:                    yMin = (yMin > coords[i + 1]) ? coords[i + 1] : yMin;
0771:                    yMax = (yMax < coords[i + 1]) ? coords[i + 1] : yMax;
0772:                }
0773:
0774:                if (hnd.clipMode == PH_MODE_DRAW_CLIP) {
0775:
0776:                    /* In case of drawing we could just skip curves which are
0777:                     * completely out of bounds 
0778:                     */
0779:                    if (hnd.dhnd.xMaxf < xMin || hnd.dhnd.xMinf > xMax
0780:                            || hnd.dhnd.yMaxf < yMin || hnd.dhnd.yMinf > yMax) {
0781:                        return;
0782:                    }
0783:                } else {
0784:
0785:                    /* In case of filling we could skip curves which are above,
0786:                     * below and behind the right boundary of the visible area
0787:                     */
0788:
0789:                    if (hnd.dhnd.yMaxf < yMin || hnd.dhnd.yMinf > yMax
0790:                            || hnd.dhnd.xMaxf < xMin) {
0791:                        return;
0792:                    }
0793:
0794:                    /* We could clamp x coordinates to the corresponding boundary 
0795:                     * if the curve is completely behind the left one
0796:                     */
0797:
0798:                    if (hnd.dhnd.xMinf > xMax) {
0799:                        coords[0] = coords[2] = coords[4] = hnd.dhnd.xMinf;
0800:                    }
0801:                }
0802:
0803:                if (xMax - xMin > MAX_QUAD_SIZE || yMax - yMin > MAX_QUAD_SIZE) {
0804:                    coords1[4] = coords[4];
0805:                    coords1[5] = coords[5];
0806:                    coords1[2] = (coords[2] + coords[4]) / 2.0f;
0807:                    coords1[3] = (coords[3] + coords[5]) / 2.0f;
0808:                    coords[2] = (coords[0] + coords[2]) / 2.0f;
0809:                    coords[3] = (coords[1] + coords[3]) / 2.0f;
0810:                    coords[4] = coords1[0] = (coords[2] + coords1[2]) / 2.0f;
0811:                    coords[5] = coords1[1] = (coords[3] + coords1[3]) / 2.0f;
0812:
0813:                    ProcessMonotonicQuad(hnd, coords, pixelInfo);
0814:
0815:                    ProcessMonotonicQuad(hnd, coords1, pixelInfo);
0816:                } else {
0817:                    DrawMonotonicQuad(hnd, coords,
0818:                            /* Set checkBounds parameter if curve intersects
0819:                             * boundary of the visible area. We know that the
0820:                             * curve is visible, so the check is pretty
0821:                             * simple
0822:                             */
0823:                            hnd.dhnd.xMinf >= xMin || hnd.dhnd.xMaxf <= xMax
0824:                                    || hnd.dhnd.yMinf >= yMin
0825:                                    || hnd.dhnd.yMaxf <= yMax, pixelInfo);
0826:                }
0827:            }
0828:
0829:            /*
0830:             * Split quadratic curve into monotonic in X and Y parts. Calling
0831:             * ProcessMonotonicQuad for each monotonic piece of the curve.
0832:             * Note: coords array could be changed
0833:             */
0834:            private static void ProcessQuad(ProcessHandler hnd, float[] coords,
0835:                    int[] pixelInfo) {
0836:                /* Temporary array for holding parameters corresponding to the extreme
0837:                 * in X and Y points
0838:                 */
0839:                double params[] = new double[2];
0840:                int cnt = 0;
0841:                double param;
0842:
0843:                /* Simple check for monotonicity in X before searching for the extreme
0844:                 * points of the X(t) function. We first check if the curve is
0845:                 * monotonic in X by seeing if all of the X coordinates are strongly
0846:                 * ordered. 
0847:                 */
0848:                if ((coords[0] > coords[2] || coords[2] > coords[4])
0849:                        && (coords[0] < coords[2] || coords[2] < coords[4])) {
0850:                    /* Searching for extreme points of the X(t) function  by solving
0851:                     * dX(t)  
0852:                     * ----  = 0 equation
0853:                     *  dt
0854:                     */
0855:                    double ax = coords[0] - 2 * coords[2] + coords[4];
0856:                    if (ax != 0) {
0857:                        /* Calculating root of the following equation
0858:                         * ax*t + bx = 0
0859:                         */
0860:                        double bx = coords[0] - coords[2];
0861:
0862:                        param = bx / ax;
0863:                        if (param < 1.0 && param > 0.0) {
0864:                            params[cnt++] = param;
0865:                        }
0866:                    }
0867:                }
0868:
0869:                /* Simple check for monotonicity in Y before searching for the extreme
0870:                 * points of the Y(t) function. We first check if the curve is
0871:                 * monotonic in Y by seeing if all of the Y coordinates are strongly
0872:                 * ordered. 
0873:                 */
0874:                if ((coords[1] > coords[3] || coords[3] > coords[5])
0875:                        && (coords[1] < coords[3] || coords[3] < coords[5])) {
0876:                    /* Searching for extreme points of the Y(t) function by solving
0877:                     * dY(t)
0878:                     * ----- = 0 equation
0879:                     *  dt
0880:                     */
0881:                    double ay = coords[1] - 2 * coords[3] + coords[5];
0882:
0883:                    if (ay != 0) {
0884:                        /* Calculating root of the following equation
0885:                         * ay*t + by = 0
0886:                         */
0887:                        double by = coords[1] - coords[3];
0888:
0889:                        param = by / ay;
0890:                        if (param < 1.0 && param > 0.0) {
0891:                            if (cnt > 0) {
0892:                                /* Inserting parameter only if it differs from
0893:                                 * already stored
0894:                                 */
0895:                                if (params[0] > param) {
0896:                                    params[cnt++] = params[0];
0897:                                    params[0] = param;
0898:                                } else if (params[0] < param) {
0899:                                    params[cnt++] = param;
0900:                                }
0901:                            } else {
0902:                                params[cnt++] = param;
0903:                            }
0904:                        }
0905:                    }
0906:                }
0907:
0908:                /* Processing obtained monotonic parts */
0909:                switch (cnt) {
0910:                case 0:
0911:                    break;
0912:                case 1:
0913:                    ProcessFirstMonotonicPartOfQuad(hnd, coords, pixelInfo,
0914:                            (float) params[0]);
0915:                    break;
0916:                case 2:
0917:                    ProcessFirstMonotonicPartOfQuad(hnd, coords, pixelInfo,
0918:                            (float) params[0]);
0919:                    param = params[1] - params[0];
0920:                    if (param > 0) {
0921:                        ProcessFirstMonotonicPartOfQuad(hnd, coords, pixelInfo,
0922:                        /* Scale parameter to match with
0923:                         * rest of the curve 
0924:                         */
0925:                        (float) (param / (1.0 - params[0])));
0926:                    }
0927:                    break;
0928:                }
0929:
0930:                ProcessMonotonicQuad(hnd, coords, pixelInfo);
0931:            }
0932:
0933:            /*
0934:             * Bite the piece of the quadratic curve from start point till the point
0935:             * corresponding to the specified parameter then call ProcessQuad for the
0936:             * bitten part. 
0937:             * Note: coords array will be changed
0938:             */
0939:            private static void ProcessFirstMonotonicPartOfQuad(
0940:                    ProcessHandler hnd, float[] coords, int[] pixelInfo, float t) {
0941:                float[] coords1 = new float[6];
0942:
0943:                coords1[0] = coords[0];
0944:                coords1[1] = coords[1];
0945:                coords1[2] = coords[0] + t * (coords[2] - coords[0]);
0946:                coords1[3] = coords[1] + t * (coords[3] - coords[1]);
0947:                coords[2] = coords[2] + t * (coords[4] - coords[2]);
0948:                coords[3] = coords[3] + t * (coords[5] - coords[3]);
0949:                coords[0] = coords1[4] = coords1[2] + t
0950:                        * (coords[2] - coords1[2]);
0951:                coords[1] = coords1[5] = coords1[3] + t
0952:                        * (coords[3] - coords1[3]);
0953:
0954:                ProcessMonotonicQuad(hnd, coords1, pixelInfo);
0955:            }
0956:
0957:            /* Performing drawing of the monotonic in X and Y cubic curves with sizes
0958:             * less than MAX_CUB_SIZE by using forward differencing method of
0959:             * calculation.  See comments to the DrawMonotonicCubic in the 
0960:             * ProcessGeneralPath.c
0961:             */
0962:            private static void DrawMonotonicCubic(ProcessHandler hnd,
0963:                    float[] coords, boolean checkBounds, int[] pixelInfo) {
0964:                int x0 = (int) (coords[0] * MDP_MULT);
0965:                int y0 = (int) (coords[1] * MDP_MULT);
0966:
0967:                int xe = (int) (coords[6] * MDP_MULT);
0968:                int ye = (int) (coords[7] * MDP_MULT);
0969:
0970:                /* Extracting fractional part of coordinates of first control point */
0971:                int px = (x0 & (~MDP_W_MASK)) << DF_CUB_SHIFT;
0972:                int py = (y0 & (~MDP_W_MASK)) << DF_CUB_SHIFT;
0973:
0974:                /* Setting default boundary values for checking first and second forward
0975:                 * difference for the necessity of the restepping. See comments to the
0976:                 * boundary values in ProcessQuad for more info.
0977:                 */
0978:                int incStepBnd = DF_CUB_INC_BND;
0979:                int decStepBnd = DF_CUB_DEC_BND;
0980:
0981:                /* Setting default amount of steps */
0982:                int count = DF_CUB_COUNT;
0983:
0984:                /* Setting default shift for preparing to the midpoint rounding */
0985:                int shift = DF_CUB_SHIFT;
0986:
0987:                int ax = (int) ((-coords[0] + 3 * coords[2] - 3 * coords[4] + coords[6]) * CUB_A_MDP_MULT);
0988:                int ay = (int) ((-coords[1] + 3 * coords[3] - 3 * coords[5] + coords[7]) * CUB_A_MDP_MULT);
0989:
0990:                int bx = (int) ((3 * coords[0] - 6 * coords[2] + 3 * coords[4]) * CUB_B_MDP_MULT);
0991:                int by = (int) ((3 * coords[1] - 6 * coords[3] + 3 * coords[5]) * CUB_B_MDP_MULT);
0992:
0993:                int cx = (int) ((-3 * coords[0] + 3 * coords[2]) * (CUB_C_MDP_MULT));
0994:                int cy = (int) ((-3 * coords[1] + 3 * coords[3]) * (CUB_C_MDP_MULT));
0995:
0996:                int dddpx = 6 * ax;
0997:                int dddpy = 6 * ay;
0998:
0999:                int ddpx = dddpx + bx;
1000:                int ddpy = dddpy + by;
1001:
1002:                int dpx = ax + (bx >> 1) + cx;
1003:                int dpy = ay + (by >> 1) + cy;
1004:
1005:                int x1, y1;
1006:
1007:                int x2 = x0;
1008:                int y2 = y0;
1009:
1010:                /* Calculating whole part of the first point of the curve */
1011:                int x0w = x0 & MDP_W_MASK;
1012:                int y0w = y0 & MDP_W_MASK;
1013:
1014:                int dx = xe - x0;
1015:                int dy = ye - y0;
1016:
1017:                while (count > 0) {
1018:                    /* Perform decreasing step in 2 times if necessary */
1019:                    while (Math.abs(ddpx) > decStepBnd
1020:                            || Math.abs(ddpy) > decStepBnd) {
1021:                        ddpx = (ddpx << 1) - dddpx;
1022:                        ddpy = (ddpy << 1) - dddpy;
1023:                        dpx = (dpx << 2) - (ddpx >> 1);
1024:                        dpy = (dpy << 2) - (ddpy >> 1);
1025:                        count <<= 1;
1026:                        decStepBnd <<= 3;
1027:                        incStepBnd <<= 3;
1028:                        px <<= 3;
1029:                        py <<= 3;
1030:                        shift += 3;
1031:                    }
1032:
1033:                    /* Perform increasing step in 2 times if necessary.
1034:                     * Note: we could do it only in even steps
1035:                     */
1036:
1037:                    while ((count & 1) == 0 && shift > DF_CUB_SHIFT
1038:                            && Math.abs(dpx) <= incStepBnd
1039:                            && Math.abs(dpy) <= incStepBnd) {
1040:                        dpx = (dpx >> 2) + (ddpx >> 3);
1041:                        dpy = (dpy >> 2) + (ddpy >> 3);
1042:                        ddpx = (ddpx + dddpx) >> 1;
1043:                        ddpy = (ddpy + dddpy) >> 1;
1044:                        count >>= 1;
1045:                        decStepBnd >>= 3;
1046:                        incStepBnd >>= 3;
1047:                        px >>= 3;
1048:                        py >>= 3;
1049:                        shift -= 3;
1050:                    }
1051:
1052:                    count--;
1053:
1054:                    /* Performing one step less than necessary and use actual (xe,ye) 
1055:                     * curve's endpoint instead of calculated. This prevent us from 
1056:                     * running above the curve endpoint due to the accumulated errors 
1057:                     * during the iterations.
1058:                     */
1059:                    if (count > 0) {
1060:                        px += dpx;
1061:                        py += dpy;
1062:
1063:                        dpx += ddpx;
1064:                        dpy += ddpy;
1065:                        ddpx += dddpx;
1066:                        ddpy += dddpy;
1067:
1068:                        x1 = x2;
1069:                        y1 = y2;
1070:
1071:                        x2 = x0w + (px >> shift);
1072:                        y2 = y0w + (py >> shift);
1073:
1074:                        /* Checking that we are not running out of the endpoint and
1075:                         * bounding violating coordinate.  The check is pretty simple
1076:                         * because the curve passed to the DrawCubic already splitted
1077:                         * into the monotonic in X and Y pieces
1078:                         */
1079:
1080:                        /* Bounding x2 by xe */
1081:                        if (((xe - x2) ^ dx) < 0) {
1082:                            x2 = xe;
1083:                        }
1084:
1085:                        /* Bounding y2 by ye */
1086:                        if (((ye - y2) ^ dy) < 0) {
1087:                            y2 = ye;
1088:                        }
1089:
1090:                        hnd.processFixedLine(x1, y1, x2, y2, pixelInfo,
1091:                                checkBounds, false);
1092:                    } else {
1093:                        hnd.processFixedLine(x2, y2, xe, ye, pixelInfo,
1094:                                checkBounds, false);
1095:                    }
1096:                }
1097:            }
1098:
1099:            /*
1100:             * Checking size of the cubic curves and split them if necessary.
1101:             * Calling DrawMonotonicCubic for the curves of the appropriate size.
1102:             * Note: coords array could be changed
1103:             */
1104:            private static void ProcessMonotonicCubic(ProcessHandler hnd,
1105:                    float[] coords, int[] pixelInfo) {
1106:
1107:                float[] coords1 = new float[8];
1108:                float tx, ty;
1109:                float xMin, xMax;
1110:                float yMin, yMax;
1111:
1112:                xMin = xMax = coords[0];
1113:                yMin = yMax = coords[1];
1114:
1115:                for (int i = 2; i < 8; i += 2) {
1116:                    xMin = (xMin > coords[i]) ? coords[i] : xMin;
1117:                    xMax = (xMax < coords[i]) ? coords[i] : xMax;
1118:                    yMin = (yMin > coords[i + 1]) ? coords[i + 1] : yMin;
1119:                    yMax = (yMax < coords[i + 1]) ? coords[i + 1] : yMax;
1120:                }
1121:
1122:                if (hnd.clipMode == PH_MODE_DRAW_CLIP) {
1123:                    /* In case of drawing we could just skip curves which are
1124:                     * completely out of bounds 
1125:                     */
1126:                    if (hnd.dhnd.xMaxf < xMin || hnd.dhnd.xMinf > xMax
1127:                            || hnd.dhnd.yMaxf < yMin || hnd.dhnd.yMinf > yMax) {
1128:                        return;
1129:                    }
1130:                } else {
1131:
1132:                    /* In case of filling we could skip curves which are above,
1133:                     * below and behind the right boundary of the visible area
1134:                     */
1135:
1136:                    if (hnd.dhnd.yMaxf < yMin || hnd.dhnd.yMinf > yMax
1137:                            || hnd.dhnd.xMaxf < xMin) {
1138:                        return;
1139:                    }
1140:
1141:                    /* We could clamp x coordinates to the corresponding boundary 
1142:                     * if the curve is completely behind the left one
1143:                     */
1144:
1145:                    if (hnd.dhnd.xMinf > xMax) {
1146:                        coords[0] = coords[2] = coords[4] = coords[6] = hnd.dhnd.xMinf;
1147:                    }
1148:                }
1149:
1150:                if (xMax - xMin > MAX_CUB_SIZE || yMax - yMin > MAX_CUB_SIZE) {
1151:                    coords1[6] = coords[6];
1152:                    coords1[7] = coords[7];
1153:                    coords1[4] = (coords[4] + coords[6]) / 2.0f;
1154:                    coords1[5] = (coords[5] + coords[7]) / 2.0f;
1155:                    tx = (coords[2] + coords[4]) / 2.0f;
1156:                    ty = (coords[3] + coords[5]) / 2.0f;
1157:                    coords1[2] = (tx + coords1[4]) / 2.0f;
1158:                    coords1[3] = (ty + coords1[5]) / 2.0f;
1159:                    coords[2] = (coords[0] + coords[2]) / 2.0f;
1160:                    coords[3] = (coords[1] + coords[3]) / 2.0f;
1161:                    coords[4] = (coords[2] + tx) / 2.0f;
1162:                    coords[5] = (coords[3] + ty) / 2.0f;
1163:                    coords[6] = coords1[0] = (coords[4] + coords1[2]) / 2.0f;
1164:                    coords[7] = coords1[1] = (coords[5] + coords1[3]) / 2.0f;
1165:
1166:                    ProcessMonotonicCubic(hnd, coords, pixelInfo);
1167:
1168:                    ProcessMonotonicCubic(hnd, coords1, pixelInfo);
1169:                } else {
1170:                    DrawMonotonicCubic(hnd, coords,
1171:                    /* Set checkBounds parameter if curve intersects
1172:                     * boundary of the visible area. We know that
1173:                     * the curve is visible, so the check is pretty
1174:                     * simple
1175:                     */
1176:                    hnd.dhnd.xMinf > xMin || hnd.dhnd.xMaxf < xMax
1177:                            || hnd.dhnd.yMinf > yMin || hnd.dhnd.yMaxf < yMax,
1178:                            pixelInfo);
1179:                }
1180:            }
1181:
1182:            /*
1183:             * Split cubic curve into monotonic in X and Y parts. Calling
1184:             * ProcessMonotonicCubic for each monotonic piece of the curve.
1185:             *
1186:             * Note: coords array could be changed
1187:             */
1188:            private static void ProcessCubic(ProcessHandler hnd,
1189:                    float[] coords, int[] pixelInfo) {
1190:                /* Temporary array for holding parameters corresponding to the extreme
1191:                 * in X and Y points
1192:                 */
1193:                double params[] = new double[4];
1194:                double eqn[] = new double[3];
1195:                double res[] = new double[2];
1196:                int cnt = 0;
1197:
1198:                /* Simple check for monotonicity in X before searching for the extreme
1199:                 * points of the X(t) function. We first check if the curve is
1200:                 * monotonic in X by seeing if all of the X coordinates are strongly
1201:                 * ordered. 
1202:                 */
1203:                if ((coords[0] > coords[2] || coords[2] > coords[4] || coords[4] > coords[6])
1204:                        && (coords[0] < coords[2] || coords[2] < coords[4] || coords[4] < coords[6])) {
1205:                    /* Searching for extreme points of the X(t) function  by solving
1206:                     * dX(t)  
1207:                     * ----  = 0 equation
1208:                     *  dt
1209:                     */
1210:                    eqn[2] = -coords[0] + 3 * coords[2] - 3 * coords[4]
1211:                            + coords[6];
1212:                    eqn[1] = 2 * (coords[0] - 2 * coords[2] + coords[4]);
1213:                    eqn[0] = -coords[0] + coords[2];
1214:
1215:                    int nr = QuadCurve2D.solveQuadratic(eqn, res);
1216:
1217:                    /* Following code also correctly works in degenerate case of 
1218:                     * the quadratic equation (nr = -1) because we do not need
1219:                     * splitting in this case.
1220:                     */
1221:                    for (int i = 0; i < nr; i++) {
1222:                        if (res[i] > 0 && res[i] < 1) {
1223:                            params[cnt++] = res[i];
1224:                        }
1225:                    }
1226:                }
1227:
1228:                /* Simple check for monotonicity in Y before searching for the extreme
1229:                 * points of the Y(t) function. We first check if the curve is
1230:                 * monotonic in Y by seeing if all of the Y coordinates are strongly
1231:                 * ordered. 
1232:                 */
1233:                if ((coords[1] > coords[3] || coords[3] > coords[5] || coords[5] > coords[7])
1234:                        && (coords[1] < coords[3] || coords[3] < coords[5] || coords[5] < coords[7])) {
1235:                    /* Searching for extreme points of the Y(t) function by solving
1236:                     * dY(t)
1237:                     * ----- = 0 equation
1238:                     *  dt
1239:                     */
1240:                    eqn[2] = -coords[1] + 3 * coords[3] - 3 * coords[5]
1241:                            + coords[7];
1242:                    eqn[1] = 2 * (coords[1] - 2 * coords[3] + coords[5]);
1243:                    eqn[0] = -coords[1] + coords[3];
1244:
1245:                    int nr = QuadCurve2D.solveQuadratic(eqn, res);
1246:
1247:                    /* Following code also correctly works in degenerate case of 
1248:                     * the quadratic equation (nr = -1) because we do not need
1249:                     * splitting in this case.
1250:                     */
1251:                    for (int i = 0; i < nr; i++) {
1252:                        if (res[i] > 0 && res[i] < 1) {
1253:                            params[cnt++] = res[i];
1254:                        }
1255:                    }
1256:                }
1257:
1258:                if (cnt > 0) {
1259:                    /* Sorting parameter values corresponding to the extreme points 
1260:                     * of the curve
1261:                     */
1262:                    Arrays.sort(params, 0, cnt);
1263:
1264:                    /* Processing obtained monotonic parts */
1265:                    ProcessFirstMonotonicPartOfCubic(hnd, coords, pixelInfo,
1266:                            (float) params[0]);
1267:                    for (int i = 1; i < cnt; i++) {
1268:                        double param = params[i] - params[i - 1];
1269:                        if (param > 0) {
1270:                            ProcessFirstMonotonicPartOfCubic(hnd, coords,
1271:                                    pixelInfo,
1272:                                    /* Scale parameter to match with rest of the curve */
1273:                                    (float) (param / (1.0 - params[i - 1])));
1274:                        }
1275:                    }
1276:                }
1277:
1278:                ProcessMonotonicCubic(hnd, coords, pixelInfo);
1279:            }
1280:
1281:            /*
1282:             * Bite the piece of the cubic curve from start point till the point 
1283:             * corresponding to the specified parameter then call ProcessCubic for the 
1284:             * bitten part. 
1285:             * Note: coords array will be changed
1286:             */
1287:            private static void ProcessFirstMonotonicPartOfCubic(
1288:                    ProcessHandler hnd, float[] coords, int[] pixelInfo, float t) {
1289:                float[] coords1 = new float[8];
1290:                float tx, ty;
1291:
1292:                coords1[0] = coords[0];
1293:                coords1[1] = coords[1];
1294:                tx = coords[2] + t * (coords[4] - coords[2]);
1295:                ty = coords[3] + t * (coords[5] - coords[3]);
1296:                coords1[2] = coords[0] + t * (coords[2] - coords[0]);
1297:                coords1[3] = coords[1] + t * (coords[3] - coords[1]);
1298:                coords1[4] = coords1[2] + t * (tx - coords1[2]);
1299:                coords1[5] = coords1[3] + t * (ty - coords1[3]);
1300:                coords[4] = coords[4] + t * (coords[6] - coords[4]);
1301:                coords[5] = coords[5] + t * (coords[7] - coords[5]);
1302:                coords[2] = tx + t * (coords[4] - tx);
1303:                coords[3] = ty + t * (coords[5] - ty);
1304:                coords[0] = coords1[6] = coords1[4] + t
1305:                        * (coords[2] - coords1[4]);
1306:                coords[1] = coords1[7] = coords1[5] + t
1307:                        * (coords[3] - coords1[5]);
1308:
1309:                ProcessMonotonicCubic(hnd, coords1, pixelInfo);
1310:            }
1311:
1312:            /* Note:
1313:             * For more easy reading of the code below each java version of the macros
1314:             * from the ProcessPath.c preceded by the commented origin call
1315:             * containing verbose names of the parameters
1316:             */
1317:            private static void ProcessLine(ProcessHandler hnd, float x1,
1318:                    float y1, float x2, float y2, int[] pixelInfo) {
1319:                float xMin, yMin, xMax, yMax;
1320:                int X1, Y1, X2, Y2, X3, Y3, res;
1321:                boolean clipped = false;
1322:                float x3, y3;
1323:                float c[] = new float[] { x1, y1, x2, y2, 0, 0 };
1324:
1325:                boolean lastClipped;
1326:
1327:                xMin = hnd.dhnd.xMinf;
1328:                yMin = hnd.dhnd.yMinf;
1329:                xMax = hnd.dhnd.xMaxf;
1330:                yMax = hnd.dhnd.yMaxf;
1331:
1332:                // 
1333:                // TESTANDCLIP(yMin, yMax, y1, x1, y2, x2, res);
1334:                // 
1335:                res = TESTANDCLIP(yMin, yMax, c, 1, 0, 3, 2);
1336:                if (res == CRES_INVISIBLE)
1337:                    return;
1338:                clipped = IS_CLIPPED(res);
1339:                // 
1340:                // TESTANDCLIP(yMin, yMax, y2, x2, y1, x1, res);
1341:                // 
1342:                res = TESTANDCLIP(yMin, yMax, c, 3, 2, 1, 0);
1343:                if (res == CRES_INVISIBLE)
1344:                    return;
1345:                lastClipped = IS_CLIPPED(res);
1346:                clipped = clipped || lastClipped;
1347:
1348:                if (hnd.clipMode == PH_MODE_DRAW_CLIP) {
1349:                    // 
1350:                    // TESTANDCLIP(xMin, xMax, x1, y1, x2, y2, res);
1351:                    // 
1352:                    res = TESTANDCLIP(xMin, xMax, c, 0, 1, 2, 3);
1353:                    if (res == CRES_INVISIBLE)
1354:                        return;
1355:                    clipped = clipped || IS_CLIPPED(res);
1356:                    //
1357:                    // TESTANDCLIP(xMin, xMax, x2, y2, x1, y1, res);
1358:                    // 
1359:                    res = TESTANDCLIP(xMin, xMax, c, 2, 3, 0, 1);
1360:                    if (res == CRES_INVISIBLE)
1361:                        return;
1362:                    lastClipped = lastClipped || IS_CLIPPED(res);
1363:                    clipped = clipped || lastClipped;
1364:                    X1 = (int) (c[0] * MDP_MULT);
1365:                    Y1 = (int) (c[1] * MDP_MULT);
1366:                    X2 = (int) (c[2] * MDP_MULT);
1367:                    Y2 = (int) (c[3] * MDP_MULT);
1368:
1369:                    hnd.processFixedLine(X1, Y1, X2, Y2, pixelInfo, clipped, /* enable boundary checking in
1370:                                                                case of clipping to avoid
1371:                                                                entering out of bounds which
1372:                                                                could happens during rounding
1373:                     */
1374:                    lastClipped /* Notify pProcessFixedLine
1375:                                                                   that
1376:                                                                   this is the end of the 
1377:                                                                   subpath (because of exiting 
1378:                                                                   out of boundaries)
1379:                     */
1380:                    );
1381:                } else {
1382:                    /* Clamping starting from first vertex of the the processed
1383:                     * segment
1384:                     * 
1385:                     * CLIPCLAMP(xMin, xMax, x1, y1, x2, y2, x3, y3, res);
1386:                     */
1387:                    res = CLIPCLAMP(xMin, xMax, c, 0, 1, 2, 3, 4, 5);
1388:                    X1 = (int) (c[0] * MDP_MULT);
1389:                    Y1 = (int) (c[1] * MDP_MULT);
1390:
1391:                    /* Clamping only by left boundary */
1392:                    if (res == CRES_MIN_CLIPPED) {
1393:                        X3 = (int) (c[4] * MDP_MULT);
1394:                        Y3 = (int) (c[5] * MDP_MULT);
1395:                        hnd.processFixedLine(X3, Y3, X1, Y1, pixelInfo, false,
1396:                                lastClipped);
1397:
1398:                    } else if (res == CRES_INVISIBLE) {
1399:                        return;
1400:                    }
1401:
1402:                    /* Clamping starting from last vertex of the the processed
1403:                     * segment
1404:                     * 
1405:                     * CLIPCLAMP(xMin, xMax, x2, y2, x1, y1, x3, y3, res);
1406:                     */
1407:                    res = CLIPCLAMP(xMin, xMax, c, 2, 3, 0, 1, 4, 5);
1408:
1409:                    /* Checking if there was a clip by right boundary */
1410:                    lastClipped = lastClipped || (res == CRES_MAX_CLIPPED);
1411:
1412:                    X2 = (int) (c[2] * MDP_MULT);
1413:                    Y2 = (int) (c[3] * MDP_MULT);
1414:                    hnd.processFixedLine(X1, Y1, X2, Y2, pixelInfo, false,
1415:                            lastClipped);
1416:
1417:                    /* Clamping only by left boundary */
1418:                    if (res == CRES_MIN_CLIPPED) {
1419:                        X3 = (int) (c[4] * MDP_MULT);
1420:                        Y3 = (int) (c[5] * MDP_MULT);
1421:                        hnd.processFixedLine(X2, Y2, X3, Y3, pixelInfo, false,
1422:                                lastClipped);
1423:                    }
1424:                }
1425:            }
1426:
1427:            private static boolean doProcessPath(ProcessHandler hnd,
1428:                    Path2D.Float p2df, float transXf, float transYf) {
1429:                float coords[] = new float[8];
1430:                float tCoords[] = new float[8];
1431:                float closeCoord[] = new float[] { 0.0f, 0.0f };
1432:                float firstCoord[] = new float[2];
1433:                int pixelInfo[] = new int[5];
1434:                boolean subpathStarted = false;
1435:                boolean skip = false;
1436:                float lastX, lastY;
1437:                pixelInfo[0] = 0;
1438:
1439:                /* Adjusting boundaries to the capabilities of the 
1440:                 * ProcessPath code
1441:                 */
1442:                hnd.dhnd.adjustBounds(LOWER_OUT_BND, LOWER_OUT_BND,
1443:                        UPPER_OUT_BND, UPPER_OUT_BND);
1444:
1445:                /* Adding support of the KEY_STROKE_CONTROL rendering hint.
1446:                 * Now we are supporting two modes: "pixels at centers" and 
1447:                 * "pixels at corners".
1448:                 * First one is disabled by default but could be enabled by setting
1449:                 * VALUE_STROKE_PURE to the rendering hint. It means that pixel at the
1450:                 * screen (x,y) has (x + 0.5, y + 0.5) float coordinates.
1451:                 * 
1452:                 * Second one is enabled by default and means straightforward mapping
1453:                 * (x,y) --> (x,y)
1454:                 */
1455:                if (hnd.dhnd.strokeControl == SunHints.INTVAL_STROKE_PURE) {
1456:                    closeCoord[0] = -0.5f;
1457:                    closeCoord[1] = -0.5f;
1458:                    transXf -= 0.5;
1459:                    transYf -= 0.5;
1460:                }
1461:
1462:                PathIterator pi = p2df.getPathIterator(null);
1463:
1464:                while (!pi.isDone()) {
1465:                    switch (pi.currentSegment(coords)) {
1466:                    case PathIterator.SEG_MOVETO:
1467:                        /* Performing closing of the unclosed segments */
1468:                        if (subpathStarted && !skip) {
1469:                            if (hnd.clipMode == PH_MODE_FILL_CLIP) {
1470:                                if (tCoords[0] != closeCoord[0]
1471:                                        || tCoords[1] != closeCoord[1]) {
1472:                                    ProcessLine(hnd, tCoords[0], tCoords[1],
1473:                                            closeCoord[0], closeCoord[1],
1474:                                            pixelInfo);
1475:
1476:                                    /* Storing last path's point for using in
1477:                                     * following segments without initial moveTo
1478:                                     */
1479:                                    tCoords[0] = closeCoord[0];
1480:                                    tCoords[1] = closeCoord[1];
1481:                                }
1482:                            }
1483:                            hnd.processEndSubPath();
1484:                        }
1485:
1486:                        tCoords[0] = coords[0] + transXf;
1487:                        tCoords[1] = coords[1] + transYf;
1488:
1489:                        /* Checking SEG_MOVETO coordinates if they are out of the
1490:                         * [LOWER_BND, UPPER_BND] range.  This check also handles
1491:                         * NaN and Infinity values. Skipping next path segment in
1492:                         * case of invalid data.
1493:                         */
1494:
1495:                        if (tCoords[0] < UPPER_BND && tCoords[0] > LOWER_BND
1496:                                && tCoords[1] < UPPER_BND
1497:                                && tCoords[1] > LOWER_BND) {
1498:                            subpathStarted = true;
1499:                            skip = false;
1500:                            closeCoord[0] = tCoords[0];
1501:                            closeCoord[1] = tCoords[1];
1502:                        } else {
1503:                            skip = true;
1504:                        }
1505:                        pixelInfo[0] = 0;
1506:                        break;
1507:                    case PathIterator.SEG_LINETO:
1508:                        lastX = tCoords[2] = coords[0] + transXf;
1509:                        lastY = tCoords[3] = coords[1] + transYf;
1510:
1511:                        /* Checking SEG_LINETO coordinates if they are out of the
1512:                         * [LOWER_BND, UPPER_BND] range.  This check also handles
1513:                         * NaN and Infinity values. Ignoring current path segment
1514:                         * in case  of invalid data. If segment is skipped its
1515:                         * endpoint (if valid) is used to begin new subpath.
1516:                         */
1517:
1518:                        if (lastX < UPPER_BND && lastX > LOWER_BND
1519:                                && lastY < UPPER_BND && lastY > LOWER_BND) {
1520:                            if (skip) {
1521:                                tCoords[0] = closeCoord[0] = lastX;
1522:                                tCoords[1] = closeCoord[1] = lastY;
1523:                                subpathStarted = true;
1524:                                skip = false;
1525:                            } else {
1526:                                ProcessLine(hnd, tCoords[0], tCoords[1],
1527:                                        tCoords[2], tCoords[3], pixelInfo);
1528:                                tCoords[0] = lastX;
1529:                                tCoords[1] = lastY;
1530:                            }
1531:                        }
1532:                        break;
1533:                    case PathIterator.SEG_QUADTO:
1534:                        tCoords[2] = coords[0] + transXf;
1535:                        tCoords[3] = coords[1] + transYf;
1536:                        lastX = tCoords[4] = coords[2] + transXf;
1537:                        lastY = tCoords[5] = coords[3] + transYf;
1538:
1539:                        /* Checking SEG_QUADTO coordinates if they are out of the
1540:                         * [LOWER_BND, UPPER_BND] range.  This check also handles
1541:                         * NaN and Infinity values. Ignoring current path segment
1542:                         * in case  of invalid endpoints's data.  Equivalent to
1543:                         * the SEG_LINETO if endpoint coordinates are valid but
1544:                         * there are invalid data among other coordinates
1545:                         */
1546:
1547:                        if (lastX < UPPER_BND && lastX > LOWER_BND
1548:                                && lastY < UPPER_BND && lastY > LOWER_BND) {
1549:                            if (skip) {
1550:                                tCoords[0] = closeCoord[0] = lastX;
1551:                                tCoords[1] = closeCoord[1] = lastY;
1552:                                subpathStarted = true;
1553:                                skip = false;
1554:                            } else {
1555:                                if (tCoords[2] < UPPER_BND
1556:                                        && tCoords[2] > LOWER_BND
1557:                                        && tCoords[3] < UPPER_BND
1558:                                        && tCoords[3] > LOWER_BND) {
1559:                                    ProcessQuad(hnd, tCoords, pixelInfo);
1560:                                } else {
1561:                                    ProcessLine(hnd, tCoords[0], tCoords[1],
1562:                                            tCoords[4], tCoords[5], pixelInfo);
1563:                                }
1564:                                tCoords[0] = lastX;
1565:                                tCoords[1] = lastY;
1566:                            }
1567:                        }
1568:                        break;
1569:                    case PathIterator.SEG_CUBICTO:
1570:                        tCoords[2] = coords[0] + transXf;
1571:                        tCoords[3] = coords[1] + transYf;
1572:                        tCoords[4] = coords[2] + transXf;
1573:                        tCoords[5] = coords[3] + transYf;
1574:                        lastX = tCoords[6] = coords[4] + transXf;
1575:                        lastY = tCoords[7] = coords[5] + transYf;
1576:
1577:                        /* Checking SEG_CUBICTO coordinates if they are out of the
1578:                         * [LOWER_BND, UPPER_BND] range.  This check also handles
1579:                         * NaN and Infinity values. Ignoring current path segment
1580:                         * in case  of invalid endpoints's data.  Equivalent to
1581:                         * the SEG_LINETO if endpoint coordinates are valid but
1582:                         * there are invalid data among other coordinates
1583:                         */
1584:
1585:                        if (lastX < UPPER_BND && lastX > LOWER_BND
1586:                                && lastY < UPPER_BND && lastY > LOWER_BND) {
1587:                            if (skip) {
1588:                                tCoords[0] = closeCoord[0] = tCoords[6];
1589:                                tCoords[1] = closeCoord[1] = tCoords[7];
1590:                                subpathStarted = true;
1591:                                skip = false;
1592:                            } else {
1593:                                if (tCoords[2] < UPPER_BND
1594:                                        && tCoords[2] > LOWER_BND
1595:                                        && tCoords[3] < UPPER_BND
1596:                                        && tCoords[3] > LOWER_BND
1597:                                        && tCoords[4] < UPPER_BND
1598:                                        && tCoords[4] > LOWER_BND
1599:                                        && tCoords[5] < UPPER_BND
1600:                                        && tCoords[5] > LOWER_BND) {
1601:                                    ProcessCubic(hnd, tCoords, pixelInfo);
1602:                                } else {
1603:                                    ProcessLine(hnd, tCoords[0], tCoords[1],
1604:                                            tCoords[6], tCoords[7], pixelInfo);
1605:                                }
1606:                                tCoords[0] = lastX;
1607:                                tCoords[1] = lastY;
1608:                            }
1609:                        }
1610:                        break;
1611:                    case PathIterator.SEG_CLOSE:
1612:                        if (subpathStarted && !skip) {
1613:                            skip = false;
1614:                            if (tCoords[0] != closeCoord[0]
1615:                                    || tCoords[1] != closeCoord[1]) {
1616:                                ProcessLine(hnd, tCoords[0], tCoords[1],
1617:                                        closeCoord[0], closeCoord[1], pixelInfo);
1618:
1619:                                /* Storing last path's point for using in following
1620:                                 * segments without initial moveTo
1621:                                 */
1622:                                tCoords[0] = closeCoord[0];
1623:                                tCoords[1] = closeCoord[1];
1624:                            }
1625:                            hnd.processEndSubPath();
1626:                        }
1627:                        break;
1628:                    }
1629:                    pi.next();
1630:                }
1631:
1632:                /* Performing closing of the unclosed segments */
1633:                if (subpathStarted & !skip) {
1634:                    if (hnd.clipMode == PH_MODE_FILL_CLIP) {
1635:                        if (tCoords[0] != closeCoord[0]
1636:                                || tCoords[1] != closeCoord[1]) {
1637:                            ProcessLine(hnd, tCoords[0], tCoords[1],
1638:                                    closeCoord[0], closeCoord[1], pixelInfo);
1639:                        }
1640:                    }
1641:                    hnd.processEndSubPath();
1642:                }
1643:                return true;
1644:            }
1645:
1646:            private static class Point {
1647:                public int x;
1648:                public int y;
1649:                public boolean lastPoint;
1650:                public Point prev;
1651:                public Point next;
1652:                public Point nextByY;
1653:                public Edge edge;
1654:
1655:                public Point(int x, int y, boolean lastPoint) {
1656:                    this .x = x;
1657:                    this .y = y;
1658:                    this .lastPoint = lastPoint;
1659:                }
1660:            };
1661:
1662:            private static class Edge {
1663:                int x;
1664:                int dx;
1665:                Point p;
1666:                int dir;
1667:                Edge prev;
1668:                Edge next;
1669:
1670:                public Edge(Point p, int x, int dx, int dir) {
1671:                    this .p = p;
1672:                    this .x = x;
1673:                    this .dx = dx;
1674:                    this .dir = dir;
1675:                }
1676:            };
1677:
1678:            /* Size of the default buffer in the FillData structure. This buffer is
1679:             * replaced with heap allocated in case of large paths.
1680:             */
1681:            private static final int DF_MAX_POINT = 256;
1682:
1683:            /* Following class accumulates points of the non-continuous flattened
1684:             * general path during iteration through the origin path's segments . The
1685:             * end of the each subpath is marked as lastPoint flag set at the last
1686:             * point 
1687:             */
1688:            private static class FillData {
1689:                List<Point> plgPnts;
1690:                public int plgYMin;
1691:                public int plgYMax;
1692:
1693:                public FillData() {
1694:                    plgPnts = new Vector<Point>(DF_MAX_POINT);
1695:                }
1696:
1697:                public void addPoint(int x, int y, boolean lastPoint) {
1698:                    if (plgPnts.size() == 0) {
1699:                        plgYMin = plgYMax = y;
1700:                    } else {
1701:                        plgYMin = (plgYMin > y) ? y : plgYMin;
1702:                        plgYMax = (plgYMax < y) ? y : plgYMax;
1703:                    }
1704:
1705:                    plgPnts.add(new Point(x, y, lastPoint));
1706:                }
1707:
1708:                public boolean isEmpty() {
1709:                    return plgPnts.size() == 0;
1710:                }
1711:
1712:                public boolean isEnded() {
1713:                    return plgPnts.get(plgPnts.size() - 1).lastPoint;
1714:                }
1715:
1716:                public boolean setEnded() {
1717:                    return plgPnts.get(plgPnts.size() - 1).lastPoint = true;
1718:                }
1719:            }
1720:
1721:            private static class ActiveEdgeList {
1722:                Edge head;
1723:
1724:                public boolean isEmpty() {
1725:                    return (head == null);
1726:                }
1727:
1728:                public void insert(Point pnt, int cy) {
1729:                    Point np = pnt.next;
1730:                    int X1 = pnt.x, Y1 = pnt.y;
1731:                    int X2 = np.x, Y2 = np.y;
1732:                    Edge ne;
1733:                    if (Y1 == Y2) {
1734:                        /* Skipping horizontal segments */
1735:                        return;
1736:                    } else {
1737:                        int dX = X2 - X1;
1738:                        int dY = Y2 - Y1;
1739:                        int stepx, x0, dy, dir;
1740:
1741:                        if (Y1 < Y2) {
1742:                            x0 = X1;
1743:                            dy = cy - Y1;
1744:                            dir = -1;
1745:                        } else { // (Y1 > Y2)
1746:                            x0 = X2;
1747:                            dy = cy - Y2;
1748:                            dir = 1;
1749:                        }
1750:
1751:                        /* We need to worry only about dX because dY is in denominator
1752:                         * and abs(dy) < MDP_MULT (cy is a first scanline of the scan
1753:                         * converted segment and we subtract y coordinate of the
1754:                         * nearest segment's end from it to obtain dy)
1755:                         */
1756:                        if (dX > CALC_UBND || dX < CALC_LBND) {
1757:                            stepx = (int) ((((double) dX) * MDP_MULT) / dY);
1758:                            x0 = x0 + (int) ((((double) dX) * dy) / dY);
1759:                        } else {
1760:                            stepx = (dX << MDP_PREC) / dY;
1761:                            x0 += (dX * dy) / dY;
1762:                        }
1763:
1764:                        ne = new Edge(pnt, x0, stepx, dir);
1765:                    }
1766:
1767:                    ne.next = head;
1768:                    ne.prev = null;
1769:                    if (head != null) {
1770:                        head.prev = ne;
1771:                    }
1772:                    head = pnt.edge = ne;
1773:                }
1774:
1775:                public void delete(Edge e) {
1776:                    Edge prevp = e.prev;
1777:                    Edge nextp = e.next;
1778:                    if (prevp != null) {
1779:                        prevp.next = nextp;
1780:                    } else {
1781:                        head = nextp;
1782:                    }
1783:                    if (nextp != null) {
1784:                        nextp.prev = prevp;
1785:                    }
1786:                }
1787:
1788:                /**
1789:                 * Bubble sorting in the ascending order of the linked list.  This
1790:                 * implementation stops processing the list if there were no changes
1791:                 * during the previous pass.
1792:                 *
1793:                 * We could not use O(N) Radix sort here because in most cases list of
1794:                 * edges almost sorted.  So, bubble sort (O(N^2)) is working much
1795:                 * better.  Note, in case of array of edges Shell sort is more
1796:                 * efficient.
1797:                 */
1798:                public void sort() {
1799:                    Edge p, q, r, s = null, temp;
1800:                    boolean wasSwap = true;
1801:
1802:                    // r precedes p and s points to the node up to which
1803:                    // comparisons are to be made
1804:                    while (s != head.next && wasSwap) {
1805:                        r = p = head;
1806:                        q = p.next;
1807:                        wasSwap = false;
1808:                        while (p != s) {
1809:                            if (p.x >= q.x) {
1810:                                wasSwap = true;
1811:                                if (p == head) {
1812:                                    temp = q.next;
1813:                                    q.next = p;
1814:                                    p.next = temp;
1815:                                    head = q;
1816:                                    r = q;
1817:                                } else {
1818:                                    temp = q.next;
1819:                                    q.next = p;
1820:                                    p.next = temp;
1821:                                    r.next = q;
1822:                                    r = q;
1823:                                }
1824:                            } else {
1825:                                r = p;
1826:                                p = p.next;
1827:                            }
1828:                            q = p.next;
1829:                            if (q == s)
1830:                                s = p;
1831:                        }
1832:                    }
1833:
1834:                    // correction of the back links in the double linked edge list
1835:                    p = head;
1836:                    q = null;
1837:                    while (p != null) {
1838:                        p.prev = q;
1839:                        q = p;
1840:                        p = p.next;
1841:                    }
1842:                }
1843:            }
1844:
1845:            private static void FillPolygon(FillProcessHandler hnd, int fillRule) {
1846:                int k, y, n;
1847:                boolean drawing;
1848:                Edge active;
1849:                int rightBnd = hnd.dhnd.xMax - 1;
1850:                FillData fd = hnd.fd;
1851:                int yMin = fd.plgYMin;
1852:                int yMax = fd.plgYMax;
1853:                int hashSize = ((yMax - yMin) >> MDP_PREC) + 4;
1854:
1855:                /* Because of support of the KEY_STROKE_CONTROL hint we are performing
1856:                 * shift of the coordinates at the higher level
1857:                 */
1858:                int hashOffset = ((yMin - 1) & MDP_W_MASK);
1859:
1860:                /* Winding counter */
1861:                int counter;
1862:
1863:                /* Calculating mask to be applied to the winding counter */
1864:                int counterMask = (fillRule == PathIterator.WIND_NON_ZERO) ? -1
1865:                        : 1;
1866:
1867:                int pntOffset;
1868:                List<Point> pnts = fd.plgPnts;
1869:                n = pnts.size();
1870:
1871:                if (n <= 1)
1872:                    return;
1873:
1874:                Point[] yHash = new Point[hashSize];
1875:
1876:                /* Creating double linked list (prev, next links) describing path order
1877:                 * and hash table with points which fall between scanlines. nextByY
1878:                 * link is used for the points which are between same scanlines.
1879:                 * Scanlines are passed through the centers of the pixels.
1880:                 */
1881:                Point curpt = pnts.get(0);
1882:                curpt.prev = null;
1883:                for (int i = 0; i < n - 1; i++) {
1884:                    curpt = pnts.get(i);
1885:                    Point nextpt = pnts.get(i + 1);
1886:                    int curHashInd = (curpt.y - hashOffset - 1) >> MDP_PREC;
1887:                    curpt.nextByY = yHash[curHashInd];
1888:                    yHash[curHashInd] = curpt;
1889:                    curpt.next = nextpt;
1890:                    nextpt.prev = curpt;
1891:                }
1892:
1893:                Point ept = pnts.get(n - 1);
1894:                int curHashInd = (ept.y - hashOffset - 1) >> MDP_PREC;
1895:                ept.nextByY = yHash[curHashInd];
1896:                yHash[curHashInd] = ept;
1897:
1898:                ActiveEdgeList activeList = new ActiveEdgeList();
1899:
1900:                for (y = hashOffset + MDP_MULT, k = 0; y <= yMax
1901:                        && k < hashSize; y += MDP_MULT, k++) {
1902:                    for (Point pt = yHash[k]; pt != null; pt = pt.nextByY) {
1903:                        /* pt.y should be inside hashed interval 
1904:                         * assert(y-MDP_MULT <= pt.y && pt.y < y); 
1905:                         */
1906:                        if (pt.prev != null && !pt.prev.lastPoint) {
1907:                            if (pt.prev.edge != null && pt.prev.y <= y) {
1908:                                activeList.delete(pt.prev.edge);
1909:                                pt.prev.edge = null;
1910:                            } else if (pt.prev.y > y) {
1911:                                activeList.insert(pt.prev, y);
1912:                            }
1913:                        }
1914:
1915:                        if (!pt.lastPoint && pt.next != null) {
1916:                            if (pt.edge != null && pt.next.y <= y) {
1917:                                activeList.delete(pt.edge);
1918:                                pt.edge = null;
1919:                            } else if (pt.next.y > y) {
1920:                                activeList.insert(pt, y);
1921:                            }
1922:                        }
1923:                    }
1924:
1925:                    if (activeList.isEmpty())
1926:                        continue;
1927:
1928:                    activeList.sort();
1929:
1930:                    counter = 0;
1931:                    drawing = false;
1932:                    int xl, xr;
1933:                    xl = xr = hnd.dhnd.xMin;
1934:                    Edge curEdge = activeList.head;
1935:                    while (curEdge != null) {
1936:                        counter += curEdge.dir;
1937:                        if ((counter & counterMask) != 0 && !drawing) {
1938:                            xl = (curEdge.x + MDP_MULT - 1) >> MDP_PREC;
1939:                            drawing = true;
1940:                        }
1941:
1942:                        if ((counter & counterMask) == 0 && drawing) {
1943:                            xr = (curEdge.x - 1) >> MDP_PREC;
1944:                            if (xl <= xr) {
1945:                                hnd.dhnd.drawScanline(xl, xr, y >> MDP_PREC);
1946:                            }
1947:                            drawing = false;
1948:                        }
1949:
1950:                        curEdge.x += curEdge.dx;
1951:                        curEdge = curEdge.next;
1952:                    }
1953:
1954:                    /* Performing drawing till the right boundary (for correct
1955:                     * rendering shapes clipped at the right side)
1956:                     */
1957:                    if (drawing && xl <= rightBnd) {
1958:
1959:                        /* Support of the strokeHint was added into the 
1960:                         * draw and fill methods of the sun.java2d.pipe.LoopPipe
1961:                         */
1962:                        hnd.dhnd.drawScanline(xl, rightBnd, y >> MDP_PREC);
1963:                    }
1964:                }
1965:            }
1966:
1967:            private static class FillProcessHandler extends ProcessHandler {
1968:
1969:                FillData fd;
1970:
1971:                /* Note: For more easy reading of the code below each java version of
1972:                 * the macros from the ProcessPath.c preceded by the commented
1973:                 * origin call containing verbose names of the parameters
1974:                 */
1975:                public void processFixedLine(int x1, int y1, int x2, int y2,
1976:                        int[] pixelInfo, boolean checkBounds, boolean endSubPath) {
1977:                    int outXMin, outXMax, outYMin, outYMax;
1978:                    int res;
1979:
1980:                    /* There is no need to round line coordinates to the forward
1981:                     * differencing precision anymore. Such a rounding was used for
1982:                     * preventing the curve go out the endpoint (this sometimes does
1983:                     * not help). The problem was fixed in the forward differencing
1984:                     * loops.
1985:                     */
1986:                    if (checkBounds) {
1987:                        boolean lastClipped;
1988:
1989:                        /* This function is used only for filling shapes, so there is no
1990:                         * check for the type of clipping
1991:                         */
1992:                        int c[] = new int[] { x1, y1, x2, y2, 0, 0 };
1993:                        outXMin = (int) (dhnd.xMinf * MDP_MULT);
1994:                        outXMax = (int) (dhnd.xMaxf * MDP_MULT);
1995:                        outYMin = (int) (dhnd.yMinf * MDP_MULT);
1996:                        outYMax = (int) (dhnd.yMaxf * MDP_MULT);
1997:
1998:                        /*
1999:                         * TESTANDCLIP(outYMin, outYMax, y1, x1, y2, x2, res);
2000:                         */
2001:                        res = TESTANDCLIP(outYMin, outYMax, c, 1, 0, 3, 2);
2002:                        if (res == CRES_INVISIBLE)
2003:                            return;
2004:
2005:                        /*
2006:                         * TESTANDCLIP(outYMin, outYMax, y2, x2, y1, x1, res);
2007:                         */
2008:                        res = TESTANDCLIP(outYMin, outYMax, c, 3, 2, 1, 0);
2009:                        if (res == CRES_INVISIBLE)
2010:                            return;
2011:                        lastClipped = IS_CLIPPED(res);
2012:
2013:                        /* Clamping starting from first vertex of the the processed 
2014:                         * segment 
2015:                         *
2016:                         * CLIPCLAMP(outXMin, outXMax, x1, y1, x2, y2, x3, y3, res);
2017:                         */
2018:                        res = CLIPCLAMP(outXMin, outXMax, c, 0, 1, 2, 3, 4, 5);
2019:
2020:                        /* Clamping only by left boundary */
2021:                        if (res == CRES_MIN_CLIPPED) {
2022:                            processFixedLine(c[4], c[5], c[0], c[1], pixelInfo,
2023:                                    false, lastClipped);
2024:
2025:                        } else if (res == CRES_INVISIBLE) {
2026:                            return;
2027:                        }
2028:
2029:                        /* Clamping starting from last vertex of the the processed 
2030:                         * segment 
2031:                         *
2032:                         * CLIPCLAMP(outXMin, outXMax, x2, y2, x1, y1, x3, y3, res);
2033:                         */
2034:                        res = CLIPCLAMP(outXMin, outXMax, c, 2, 3, 0, 1, 4, 5);
2035:
2036:                        /* Checking if there was a clip by right boundary */
2037:                        lastClipped = lastClipped || (res == CRES_MAX_CLIPPED);
2038:
2039:                        processFixedLine(c[0], c[1], c[2], c[3], pixelInfo,
2040:                                false, lastClipped);
2041:
2042:                        /* Clamping only by left boundary */
2043:                        if (res == CRES_MIN_CLIPPED) {
2044:                            processFixedLine(c[2], c[3], c[4], c[5], pixelInfo,
2045:                                    false, lastClipped);
2046:                        }
2047:
2048:                        return;
2049:                    }
2050:
2051:                    /* Adding first point of the line only in case of empty or just
2052:                     * finished path
2053:                     */
2054:                    if (fd.isEmpty() || fd.isEnded()) {
2055:                        fd.addPoint(x1, y1, false);
2056:                    }
2057:
2058:                    fd.addPoint(x2, y2, false);
2059:
2060:                    if (endSubPath) {
2061:                        fd.setEnded();
2062:                    }
2063:                }
2064:
2065:                FillProcessHandler(DrawHandler dhnd) {
2066:                    super (dhnd, PH_MODE_FILL_CLIP);
2067:                    this .fd = new FillData();
2068:                }
2069:
2070:                public void processEndSubPath() {
2071:                    if (!fd.isEmpty()) {
2072:                        fd.setEnded();
2073:                    }
2074:                }
2075:            }
2076:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.