1/*
2 * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package sun.java2d.loops;
27
28import java.awt.geom.Path2D;
29import java.awt.geom.PathIterator;
30import java.awt.geom.QuadCurve2D;
31import sun.awt.SunHints;
32import java.util.*;
33
34/* This is the java implementation of the native code from
35 * src/share/native/sun/java2d/loops/ProcessPath.[c,h]
36 * This code is written to be as much similar to the native
37 * as it possible. So, it sometimes does not follow java naming conventions.
38 *
39 * It's important to keep this code synchronized with native one.  See more
40 * comments, description and high level scheme of the rendering process in the
41 * ProcessPath.c
42 */
43
44public class ProcessPath {
45
46    /* Public interfaces and methods for drawing and filling general paths */
47
48    public abstract static class DrawHandler {
49        public int xMin;
50        public int yMin;
51        public int xMax;
52        public int yMax;
53        public float xMinf;
54        public float yMinf;
55        public float xMaxf;
56        public float yMaxf;
57
58        public int strokeControl;
59
60        public DrawHandler(int xMin, int yMin, int xMax, int yMax,
61                           int strokeControl)
62        {
63            setBounds(xMin, yMin, xMax, yMax, strokeControl);
64        }
65
66        public void setBounds(int xMin, int yMin, int xMax, int yMax)
67        {
68            this.xMin = xMin;
69            this.yMin = yMin;
70            this.xMax = xMax;
71            this.yMax = yMax;
72
73            /*                Setting up fractional clipping box
74             *
75             * We are using following float -> int mapping:
76             *
77             *      xi = floor(xf + 0.5)
78             *
79             * So, fractional values that hit the [xmin, xmax) integer interval
80             * will be situated inside the [xmin-0.5, xmax - 0.5) fractional
81             * interval. We are using EPSF constant to provide that upper
82             * boundary is not included.
83             */
84            xMinf = xMin - 0.5f;
85            yMinf = yMin - 0.5f;
86            xMaxf = xMax - 0.5f - EPSF;
87            yMaxf = yMax - 0.5f - EPSF;
88        }
89
90        public void setBounds(int xMin, int yMin, int xMax, int yMax,
91                              int strokeControl)
92        {
93            this.strokeControl = strokeControl;
94            setBounds(xMin, yMin, xMax, yMax);
95        }
96
97        public void adjustBounds(int bxMin, int byMin, int bxMax, int byMax)
98        {
99            if (xMin > bxMin) bxMin = xMin;
100            if (xMax < bxMax) bxMax = xMax;
101            if (yMin > byMin) byMin = yMin;
102            if (yMax < byMax) byMax = yMax;
103            setBounds(bxMin, byMin, bxMax, byMax);
104        }
105
106        public DrawHandler(int xMin, int yMin, int xMax, int yMax) {
107            this(xMin, yMin, xMax, yMax, SunHints.INTVAL_STROKE_DEFAULT);
108        }
109
110        public abstract void drawLine(int x0, int y0, int x1, int y1);
111
112        public abstract void drawPixel(int x0, int y0);
113
114        public abstract void drawScanline(int x0, int x1, int y0);
115    }
116
117    public interface EndSubPathHandler {
118        public void processEndSubPath();
119    }
120
121    public static final int PH_MODE_DRAW_CLIP = 0;
122    public static final int PH_MODE_FILL_CLIP = 1;
123
124    public abstract static class ProcessHandler implements EndSubPathHandler {
125        DrawHandler dhnd;
126        int clipMode;
127
128        public ProcessHandler(DrawHandler dhnd,
129                              int clipMode) {
130            this.dhnd = dhnd;
131            this.clipMode = clipMode;
132        }
133
134        public abstract void processFixedLine(int x1, int y1,
135                                              int x2, int y2, int [] pixelInfo,
136                                              boolean checkBounds,
137                                              boolean endSubPath);
138    }
139
140    public static EndSubPathHandler noopEndSubPathHandler =
141        new EndSubPathHandler() {
142            public void processEndSubPath() { }
143        };
144
145    public static boolean fillPath(DrawHandler dhnd, Path2D.Float p2df,
146                                   int transX, int transY)
147    {
148        FillProcessHandler fhnd = new FillProcessHandler(dhnd);
149        if (!doProcessPath(fhnd, p2df, transX, transY)) {
150            return false;
151        }
152        FillPolygon(fhnd, p2df.getWindingRule());
153        return true;
154    }
155
156    public static boolean drawPath(DrawHandler dhnd,
157                                   EndSubPathHandler endSubPath,
158                                   Path2D.Float p2df,
159                                   int transX, int transY)
160    {
161        return doProcessPath(new DrawProcessHandler(dhnd, endSubPath),
162                             p2df, transX, transY);
163    }
164
165    public static boolean drawPath(DrawHandler dhnd,
166                                   Path2D.Float p2df,
167                                   int transX, int transY)
168    {
169        return doProcessPath(new DrawProcessHandler(dhnd,
170                                                    noopEndSubPathHandler),
171                             p2df, transX, transY);
172    }
173
174    /* Private implementation of the rendering process */
175
176    /* Boundaries used for skipping huge path segments */
177    private static final float UPPER_BND = Float.MAX_VALUE/4.0f;
178    private static final float LOWER_BND = -UPPER_BND;
179
180    /* Precision (in bits) used in forward differencing */
181    private static final int FWD_PREC = 7;
182
183    /* Precision (in bits) used for the rounding in the midpoint test */
184    private static final int MDP_PREC = 10;
185
186    private static final int MDP_MULT = 1 << MDP_PREC;
187    private static final int MDP_HALF_MULT = MDP_MULT >> 1;
188
189    /* Boundaries used for clipping large path segments (those are inside
190     * [UPPER/LOWER]_BND boundaries)
191     */
192    private static final int UPPER_OUT_BND = 1 << (30 - MDP_PREC);
193    private static final int LOWER_OUT_BND = -UPPER_OUT_BND;
194
195
196    /* Calculation boundaries. They are used for switching to the more slow but
197     * allowing larger input values method of calculation of the initial values
198     * of the scan converted line segments inside the FillPolygon
199     */
200    private static final float CALC_UBND = 1 << (30 - MDP_PREC);
201    private static final float CALC_LBND = -CALC_UBND;
202
203
204    /* Following constants are used for providing open boundaries of the
205     * intervals
206     */
207    public static final int EPSFX = 1;
208    public static final float EPSF = ((float)EPSFX)/MDP_MULT;
209
210    /* Bit mask used to separate whole part from the fraction part of the
211     * number
212     */
213    private static final int MDP_W_MASK = -MDP_MULT;
214
215    /* Bit mask used to separate fractional part from the whole part of the
216     * number
217     */
218    private static final int MDP_F_MASK = MDP_MULT - 1;
219
220    /*
221     *                  Constants for the forward differencing
222     *                      of the cubic and quad curves
223     */
224
225    /* Maximum size of the cubic curve (calculated as the size of the bounding
226     * box of the control points) which could be rendered without splitting
227     */
228    private static final int MAX_CUB_SIZE = 256;
229
230    /* Maximum size of the quad curve (calculated as the size of the bounding
231     * box of the control points) which could be rendered without splitting
232     */
233    private static final int MAX_QUAD_SIZE = 1024;
234
235    /* Default power of 2 steps used in the forward differencing. Here DF prefix
236     * stands for DeFault. Constants below are used as initial values for the
237     * adaptive forward differencing algorithm.
238     */
239    private static final int DF_CUB_STEPS = 3;
240    private static final int DF_QUAD_STEPS = 2;
241
242    /* Shift of the current point of the curve for preparing to the midpoint
243     * rounding
244     */
245    private static final int DF_CUB_SHIFT = FWD_PREC + DF_CUB_STEPS*3 -
246                                            MDP_PREC;
247    private static final int DF_QUAD_SHIFT = FWD_PREC + DF_QUAD_STEPS*2 -
248                                             MDP_PREC;
249
250    /* Default amount of steps of the forward differencing */
251    private static final int DF_CUB_COUNT = (1<<DF_CUB_STEPS);
252    private static final int DF_QUAD_COUNT = (1<<DF_QUAD_STEPS);
253
254    /* Default boundary constants used to check the necessity of the restepping
255     */
256    private static final int DF_CUB_DEC_BND = 1<<DF_CUB_STEPS*3 + FWD_PREC + 2;
257    private static final int DF_CUB_INC_BND = 1<<DF_CUB_STEPS*3 + FWD_PREC - 1;
258    private static final int DF_QUAD_DEC_BND = 1<<DF_QUAD_STEPS*2 +
259                                                  FWD_PREC + 2;
260    private static final int DF_QUAD_INC_BND = 1<<DF_QUAD_STEPS*2 +
261                                                  FWD_PREC - 1;
262
263    /* Multipliers for the coefficients of the polynomial form of the cubic and
264     * quad curves representation
265     */
266    private static final int CUB_A_SHIFT = FWD_PREC;
267    private static final int CUB_B_SHIFT = (DF_CUB_STEPS + FWD_PREC + 1);
268    private static final int CUB_C_SHIFT = (DF_CUB_STEPS*2 + FWD_PREC);
269
270    private static final int CUB_A_MDP_MULT = (1<<CUB_A_SHIFT);
271    private static final int CUB_B_MDP_MULT = (1<<CUB_B_SHIFT);
272    private static final int CUB_C_MDP_MULT = (1<<CUB_C_SHIFT);
273
274    private static final int QUAD_A_SHIFT = FWD_PREC;
275    private static final int QUAD_B_SHIFT = (DF_QUAD_STEPS + FWD_PREC);
276
277    private static final int QUAD_A_MDP_MULT = (1<<QUAD_A_SHIFT);
278    private static final int QUAD_B_MDP_MULT = (1<<QUAD_B_SHIFT);
279
280    /* Clipping macros for drawing and filling algorithms */
281    private static float CLIP(float a1, float b1, float a2, float b2,
282                              double t) {
283        return (float)(b1 + (t - a1)*(b2 - b1) / (a2 - a1));
284    }
285
286    private static int CLIP(int a1, int b1, int a2, int b2, double t) {
287        return (int)(b1 + (t - a1)*(b2 - b1) / (a2 - a1));
288    }
289
290
291    private static final int CRES_MIN_CLIPPED = 0;
292    private static final int CRES_MAX_CLIPPED = 1;
293    private static final int CRES_NOT_CLIPPED = 3;
294    private static final int CRES_INVISIBLE = 4;
295
296    private static boolean IS_CLIPPED(int res) {
297        return res == CRES_MIN_CLIPPED || res == CRES_MAX_CLIPPED;
298    }
299
300    /* This is java implementation of the macro from ProcessGeneralPath.c.
301     * To keep the logic of the java code similar to the native one
302     * array and set of indexes are used to point out the data.
303     */
304    private static int TESTANDCLIP(float LINE_MIN, float LINE_MAX, float[] c,
305                                   int a1, int b1, int a2, int b2) {
306        double t;
307        int res = CRES_NOT_CLIPPED;
308        if (c[a1] < (LINE_MIN) || c[a1] > (LINE_MAX)) {
309            if (c[a1] < (LINE_MIN)) {
310                if (c[a2] < (LINE_MIN)) {
311                    return CRES_INVISIBLE;
312                };
313                res = CRES_MIN_CLIPPED;
314                t = (LINE_MIN);
315            } else {
316                if (c[a2] > (LINE_MAX)) {
317                    return CRES_INVISIBLE;
318                };
319                res = CRES_MAX_CLIPPED;
320                t = (LINE_MAX);
321            }
322            c[b1] = CLIP(c[a1], c[b1], c[a2], c[b2], t);
323            c[a1] = (float)t;
324        }
325        return res;
326    }
327
328    /* Integer version of the method above */
329    private static int TESTANDCLIP(int LINE_MIN, int LINE_MAX, int[] c,
330                                   int a1, int b1, int a2, int b2) {
331        double t;
332        int res = CRES_NOT_CLIPPED;
333        if (c[a1] < (LINE_MIN) || c[a1] > (LINE_MAX)) {
334            if (c[a1] < (LINE_MIN)) {
335                if (c[a2] < (LINE_MIN)) {
336                    return CRES_INVISIBLE;
337                };
338                res = CRES_MIN_CLIPPED;
339                t = (LINE_MIN);
340            } else {
341                if (c[a2] > (LINE_MAX)) {
342                    return CRES_INVISIBLE;
343                };
344                res = CRES_MAX_CLIPPED;
345                t = (LINE_MAX);
346            }
347            c[b1] = CLIP(c[a1], c[b1], c[a2], c[b2], t);
348            c[a1] = (int)t;
349        }
350        return res;
351    }
352
353
354
355    /* Following method is used for clipping and clumping filled shapes.
356     * An example of this process is shown on the picture below:
357     *                      ----+          ----+
358     *                    |/    |        |/    |
359     *                    +     |        +     |
360     *                   /|     |        I     |
361     *                  / |     |        I     |
362     *                  | |     |  ===>  I     |
363     *                  \ |     |        I     |
364     *                   \|     |        I     |
365     *                    +     |        +     |
366     *                    |\    |        |\    |
367     *                    | ----+        | ----+
368     *                 boundary       boundary
369     *
370     * We can only perform clipping in case of right side of the output area
371     * because all segments passed out the right boundary don't influence on the
372     * result of scan conversion algorithm (it correctly handles half open
373     * contours).
374     *
375     * This is java implementation of the macro from ProcessGeneralPath.c.
376     * To keep the logic of the java code similar to the native one
377     * array and set of indexes are used to point out the data.
378     *
379     */
380    private static int CLIPCLAMP(float LINE_MIN, float LINE_MAX, float[] c,
381                                 int a1, int b1, int a2, int b2,
382                                 int a3, int b3) {
383        c[a3] = c[a1];
384        c[b3] = c[b1];
385        int res = TESTANDCLIP(LINE_MIN, LINE_MAX, c, a1, b1, a2, b2);
386        if (res == CRES_MIN_CLIPPED) {
387            c[a3] = c[a1];
388        } else if (res == CRES_MAX_CLIPPED) {
389            c[a3] = c[a1];
390            res = CRES_MAX_CLIPPED;
391        } else if (res == CRES_INVISIBLE) {
392            if (c[a1] > LINE_MAX) {
393                res =  CRES_INVISIBLE;
394            } else {
395                c[a1] = LINE_MIN;
396                c[a2] = LINE_MIN;
397                res = CRES_NOT_CLIPPED;
398            }
399        }
400        return res;
401    }
402
403    /* Integer version of the method above */
404    private static int CLIPCLAMP(int LINE_MIN, int LINE_MAX, int[] c,
405                                 int a1, int b1, int a2, int b2,
406                                 int a3, int b3) {
407        c[a3] = c[a1];
408        c[b3] = c[b1];
409        int res = TESTANDCLIP(LINE_MIN, LINE_MAX, c, a1, b1, a2, b2);
410        if (res == CRES_MIN_CLIPPED) {
411            c[a3] = c[a1];
412        } else if (res == CRES_MAX_CLIPPED) {
413            c[a3] = c[a1];
414            res = CRES_MAX_CLIPPED;
415        } else if (res == CRES_INVISIBLE) {
416            if (c[a1] > LINE_MAX) {
417                res =  CRES_INVISIBLE;
418            } else {
419                c[a1] = LINE_MIN;
420                c[a2] = LINE_MIN;
421                res = CRES_NOT_CLIPPED;
422            }
423        }
424        return res;
425    }
426
427    private static class DrawProcessHandler extends ProcessHandler {
428
429        EndSubPathHandler processESP;
430
431        public DrawProcessHandler(DrawHandler dhnd,
432                                  EndSubPathHandler processESP) {
433            super(dhnd, PH_MODE_DRAW_CLIP);
434            this.dhnd = dhnd;
435            this.processESP = processESP;
436        }
437
438        public void processEndSubPath() {
439            processESP.processEndSubPath();
440        }
441
442        void PROCESS_LINE(int fX0, int fY0, int fX1, int fY1,
443                          boolean checkBounds, int[] pixelInfo) {
444            int X0 = fX0 >> MDP_PREC;
445            int Y0 = fY0 >> MDP_PREC;
446            int X1 = fX1 >> MDP_PREC;
447            int Y1 = fY1 >> MDP_PREC;
448
449           /* Handling lines having just one pixel */
450            if (((X0^X1) | (Y0^Y1)) == 0) {
451                if (checkBounds &&
452                    (dhnd.yMin > Y0  ||
453                     dhnd.yMax <= Y0 ||
454                     dhnd.xMin > X0  ||
455                     dhnd.xMax <= X0)) return;
456
457                if (pixelInfo[0] == 0) {
458                    pixelInfo[0] = 1;
459                    pixelInfo[1] = X0;
460                    pixelInfo[2] = Y0;
461                    pixelInfo[3] = X0;
462                    pixelInfo[4] = Y0;
463                    dhnd.drawPixel(X0, Y0);
464                } else if ((X0 != pixelInfo[3] || Y0 != pixelInfo[4]) &&
465                           (X0 != pixelInfo[1] || Y0 != pixelInfo[2])) {
466                    dhnd.drawPixel(X0, Y0);
467                    pixelInfo[3] = X0;
468                    pixelInfo[4] = Y0;
469                }
470                return;
471            }
472
473            if (!checkBounds ||
474                (dhnd.yMin <= Y0  &&
475                 dhnd.yMax > Y0 &&
476                 dhnd.xMin <= X0  &&
477                 dhnd.xMax > X0))
478            {
479                /* Switch off first pixel of the line before drawing */
480                if (pixelInfo[0] == 1 &&
481                    ((pixelInfo[1] == X0 && pixelInfo[2] == Y0) ||
482                     (pixelInfo[3] == X0 && pixelInfo[4] == Y0)))
483                {
484                    dhnd.drawPixel(X0, Y0);
485                }
486            }
487
488            dhnd.drawLine(X0, Y0, X1, Y1);
489
490            if (pixelInfo[0] == 0) {
491                pixelInfo[0] = 1;
492                pixelInfo[1] = X0;
493                pixelInfo[2] = Y0;
494                pixelInfo[3] = X0;
495                pixelInfo[4] = Y0;
496            }
497
498            /* Switch on last pixel of the line if it was already
499             * drawn during rendering of the previous segments
500             */
501            if ((pixelInfo[1] == X1 && pixelInfo[2] == Y1) ||
502                (pixelInfo[3] == X1 && pixelInfo[4] == Y1))
503            {
504                if (checkBounds &&
505                    (dhnd.yMin > Y1  ||
506                     dhnd.yMax <= Y1 ||
507                     dhnd.xMin > X1  ||
508                     dhnd.xMax <= X1)) {
509                    return;
510                }
511
512                dhnd.drawPixel(X1, Y1);
513            }
514            pixelInfo[3] = X1;
515            pixelInfo[4] = Y1;
516        }
517
518        void PROCESS_POINT(int fX, int fY, boolean checkBounds,
519                           int[] pixelInfo) {
520            int _X = fX>> MDP_PREC;
521            int _Y = fY>> MDP_PREC;
522            if (checkBounds &&
523                (dhnd.yMin > _Y  ||
524                 dhnd.yMax <= _Y ||
525                 dhnd.xMin > _X  ||
526                 dhnd.xMax <= _X)) return;
527            /*
528             *  (_X,_Y) should be inside boundaries
529             *
530             *  assert(dhnd.yMin <= _Y &&
531             *         dhnd.yMax >  _Y &&
532             *         dhnd.xMin <= _X &&
533             *         dhnd.xMax >  _X);
534             *
535             */
536            if (pixelInfo[0] == 0) {
537                pixelInfo[0] = 1;
538                pixelInfo[1] = _X;
539                pixelInfo[2] = _Y;
540                pixelInfo[3] = _X;
541                pixelInfo[4] = _Y;
542                dhnd.drawPixel(_X, _Y);
543            } else if ((_X != pixelInfo[3] || _Y != pixelInfo[4]) &&
544                       (_X != pixelInfo[1] || _Y != pixelInfo[2])) {
545                dhnd.drawPixel(_X, _Y);
546                pixelInfo[3] = _X;
547                pixelInfo[4] = _Y;
548            }
549        }
550
551        /*                  Drawing line with subpixel endpoints
552         *
553         * (x1, y1), (x2, y2) -  fixed point coordinates of the endpoints
554         *                       with MDP_PREC bits for the fractional part
555         *
556         * pixelInfo          -  structure which keeps drawing info for avoiding
557         *                       multiple drawing at the same position on the
558         *                       screen (required for the XOR mode of drawing)
559         *
560         *                          pixelInfo[0]   - state of the drawing
561         *                                           0 - no pixel drawn between
562         *                                           moveTo/close of the path
563         *                                           1 - there are drawn pixels
564         *
565         *                          pixelInfo[1,2] - first pixel of the path
566         *                                           between moveTo/close of the
567         *                                           path
568         *
569         *                          pixelInfo[3,4] - last drawn pixel between
570         *                                           moveTo/close of the path
571         *
572         * checkBounds        - flag showing necessity of checking the clip
573         *
574         */
575        public void  processFixedLine(int x1, int y1, int x2, int y2,
576                                      int[] pixelInfo, boolean checkBounds,
577                                      boolean endSubPath)  {
578
579            /* Checking if line is inside a (X,Y),(X+MDP_MULT,Y+MDP_MULT) box */
580            int c = ((x1 ^ x2) | (y1 ^ y2));
581            int rx1, ry1, rx2, ry2;
582            if ((c & MDP_W_MASK) == 0) {
583                /* Checking for the segments with integer coordinates having
584                 * the same start and end points
585                 */
586                if (c == 0) {
587                    PROCESS_POINT(x1 + MDP_HALF_MULT, y1 + MDP_HALF_MULT,
588                                  checkBounds, pixelInfo);
589                }
590                return;
591            }
592
593            if (x1 == x2 || y1 == y2) {
594                rx1 = x1 + MDP_HALF_MULT;
595                rx2 = x2 + MDP_HALF_MULT;
596                ry1 = y1 + MDP_HALF_MULT;
597                ry2 = y2 + MDP_HALF_MULT;
598            } else {
599                /* Neither dx nor dy can be zero because of the check above */
600                int dx = x2 - x1;
601                int dy = y2 - y1;
602
603                /* Floor of x1, y1, x2, y2 */
604                int fx1 = x1 & MDP_W_MASK;
605                int fy1 = y1 & MDP_W_MASK;
606                int fx2 = x2 & MDP_W_MASK;
607                int fy2 = y2 & MDP_W_MASK;
608
609                /* Processing first endpoint */
610                if (fx1 == x1 || fy1 == y1) {
611                    /* Adding MDP_HALF_MULT to the [xy]1 if f[xy]1 == [xy]1
612                     * will not affect the result
613                     */
614                    rx1 = x1 + MDP_HALF_MULT;
615                    ry1 = y1 + MDP_HALF_MULT;
616                } else {
617                    /* Boundary at the direction from (x1,y1) to (x2,y2) */
618                    int bx1 = (x1 < x2) ? fx1 + MDP_MULT : fx1;
619                    int by1 = (y1 < y2) ? fy1 + MDP_MULT : fy1;
620
621                    /* intersection with column bx1 */
622                    int cross = y1 + ((bx1 - x1)*dy)/dx;
623                    if (cross >= fy1 && cross <= fy1 + MDP_MULT) {
624                        rx1 = bx1;
625                        ry1 = cross + MDP_HALF_MULT;
626                    } else {
627                        /* intersection with row by1 */
628                        cross = x1 + ((by1 - y1)*dx)/dy;
629                        rx1 = cross + MDP_HALF_MULT;
630                        ry1 = by1;
631                    }
632                }
633
634                /* Processing second endpoint */
635                if (fx2 == x2 || fy2 == y2) {
636                    /* Adding MDP_HALF_MULT to the [xy]2 if f[xy]2 == [xy]2
637                     * will not affect the result
638                     */
639                    rx2 = x2 + MDP_HALF_MULT;
640                    ry2 = y2 + MDP_HALF_MULT;
641                } else {
642                    /* Boundary at the direction from (x2,y2) to (x1,y1) */
643                    int bx2 = (x1 > x2) ? fx2 + MDP_MULT : fx2;
644                    int by2 = (y1 > y2) ? fy2 + MDP_MULT : fy2;
645
646                    /* intersection with column bx2 */
647                    int cross = y2 + ((bx2 - x2)*dy)/dx;
648                    if (cross >= fy2 && cross <= fy2 + MDP_MULT) {
649                        rx2 = bx2;
650                        ry2 = cross + MDP_HALF_MULT;
651                    } else {
652                        /* intersection with row by2 */
653                        cross = x2 + ((by2 - y2)*dx)/dy;
654                        rx2 = cross + MDP_HALF_MULT;
655                        ry2 = by2;
656                    }
657                }
658            }
659            PROCESS_LINE(rx1, ry1, rx2, ry2, checkBounds, pixelInfo);
660        }
661    }
662
663    /* Performing drawing of the monotonic in X and Y quadratic curves with
664     * sizes less than MAX_QUAD_SIZE by using forward differencing method of
665     * calculation. See comments to the DrawMonotonicQuad in the
666     * ProcessGeneralPath.c
667     */
668    private static void DrawMonotonicQuad(ProcessHandler hnd,
669                                          float[] coords,
670                                          boolean checkBounds,
671                                          int[] pixelInfo) {
672
673        int x0 = (int)(coords[0]*MDP_MULT);
674        int y0 = (int)(coords[1]*MDP_MULT);
675
676        int xe = (int)(coords[4]*MDP_MULT);
677        int ye = (int)(coords[5]*MDP_MULT);
678
679        /* Extracting fractional part of coordinates of first control point */
680        int px = (x0 & (~MDP_W_MASK)) << DF_QUAD_SHIFT;
681        int py = (y0 & (~MDP_W_MASK)) << DF_QUAD_SHIFT;
682
683        /* Setting default amount of steps */
684        int count = DF_QUAD_COUNT;
685
686        /* Setting default shift for preparing to the midpoint rounding */
687        int shift =  DF_QUAD_SHIFT;
688
689        int ax = (int)((coords[0] - 2*coords[2] +
690                         coords[4])*QUAD_A_MDP_MULT);
691        int ay = (int)((coords[1] - 2*coords[3] +
692                         coords[5])*QUAD_A_MDP_MULT);
693
694        int bx = (int)((-2*coords[0] + 2*coords[2])*QUAD_B_MDP_MULT);
695        int by = (int)((-2*coords[1] + 2*coords[3])*QUAD_B_MDP_MULT);
696
697        int ddpx = 2*ax;
698        int ddpy = 2*ay;
699
700        int dpx = ax + bx;
701        int dpy = ay + by;
702
703        int x1, y1;
704
705        int x2 = x0;
706        int y2 = y0;
707
708        int maxDD = Math.max(Math.abs(ddpx),Math.abs(ddpy));
709
710        int dx = xe - x0;
711        int dy = ye - y0;
712
713        int x0w = x0 & MDP_W_MASK;
714        int y0w = y0 & MDP_W_MASK;
715
716        /* Perform decreasing step in 2 times if slope of the first forward
717         * difference changes too quickly (more than a pixel per step in X or Y
718         * direction).  We can perform adjusting of the step size before the
719         * rendering loop because the curvature of the quad curve remains the
720         * same along all the curve
721         */
722        while (maxDD > DF_QUAD_DEC_BND) {
723            dpx = (dpx<<1) - ax;
724            dpy = (dpy<<1) - ay;
725            count <<= 1;
726            maxDD >>= 2;
727            px <<=2;
728            py <<=2;
729            shift += 2;
730        }
731
732        while(count-- > 1) {
733            px += dpx;
734            py += dpy;
735
736            dpx += ddpx;
737            dpy += ddpy;
738
739            x1 = x2;
740            y1 = y2;
741
742            x2 = x0w + (px >> shift);
743            y2 = y0w + (py >> shift);
744
745            /* Checking that we are not running out of the endpoint and bounding
746             * violating coordinate.  The check is pretty simple because the
747             * curve passed to the DrawCubic already split into the
748             * monotonic in X and Y pieces
749             */
750
751            /* Bounding x2 by xe */
752            if (((xe-x2)^dx) < 0) {
753                x2 = xe;
754            }
755
756            /* Bounding y2 by ye */
757            if (((ye-y2)^dy) < 0) {
758                y2 = ye;
759            }
760
761            hnd.processFixedLine(x1, y1, x2, y2, pixelInfo, checkBounds, false);
762        }
763
764        /* We are performing one step less than necessary and use actual
765         * (xe,ye) endpoint of the curve instead of calculated. This prevent us
766         * from running above the curve endpoint due to the accumulated errors
767         * during the iterations.
768         */
769
770        hnd.processFixedLine(x2, y2, xe, ye, pixelInfo, checkBounds, false);
771    }
772
773    /*
774     * Checking size of the quad curves and split them if necessary.
775     * Calling DrawMonotonicQuad for the curves of the appropriate size.
776     * Note: coords array could be changed
777     */
778    private static void ProcessMonotonicQuad(ProcessHandler hnd,
779                                             float[] coords,
780                                             int[] pixelInfo) {
781
782        float[] coords1 = new float[6];
783        float tx, ty;
784        float xMin, yMin, xMax, yMax;
785
786        xMin = xMax = coords[0];
787        yMin = yMax = coords[1];
788        for (int i = 2; i < 6; i += 2) {
789            xMin = (xMin > coords[i])? coords[i] : xMin;
790            xMax = (xMax < coords[i])? coords[i] : xMax;
791            yMin = (yMin > coords[i + 1])? coords[i + 1] : yMin;
792            yMax = (yMax < coords[i + 1])? coords[i + 1] : yMax;
793        }
794
795        if (hnd.clipMode == PH_MODE_DRAW_CLIP) {
796
797           /* In case of drawing we could just skip curves which are
798            * completely out of bounds
799            */
800           if (hnd.dhnd.xMaxf < xMin || hnd.dhnd.xMinf > xMax ||
801               hnd.dhnd.yMaxf < yMin || hnd.dhnd.yMinf > yMax) {
802               return;
803           }
804        } else {
805
806            /* In case of filling we could skip curves which are above,
807             * below and behind the right boundary of the visible area
808             */
809
810            if (hnd.dhnd.yMaxf < yMin || hnd.dhnd.yMinf > yMax ||
811                hnd.dhnd.xMaxf < xMin)
812            {
813                return;
814            }
815
816            /* We could clamp x coordinates to the corresponding boundary
817             * if the curve is completely behind the left one
818             */
819
820            if (hnd.dhnd.xMinf > xMax) {
821                coords[0] = coords[2] = coords[4] = hnd.dhnd.xMinf;
822            }
823        }
824
825        if (xMax - xMin > MAX_QUAD_SIZE || yMax - yMin > MAX_QUAD_SIZE) {
826            coords1[4] = coords[4];
827            coords1[5] = coords[5];
828            coords1[2] = (coords[2] + coords[4])/2.0f;
829            coords1[3] = (coords[3] + coords[5])/2.0f;
830            coords[2] = (coords[0] + coords[2])/2.0f;
831            coords[3] = (coords[1] + coords[3])/2.0f;
832            coords[4] = coords1[0] = (coords[2] + coords1[2])/2.0f;
833            coords[5] = coords1[1] = (coords[3] + coords1[3])/2.0f;
834
835            ProcessMonotonicQuad(hnd, coords, pixelInfo);
836
837            ProcessMonotonicQuad(hnd, coords1, pixelInfo);
838        } else {
839            DrawMonotonicQuad(hnd, coords,
840                              /* Set checkBounds parameter if curve intersects
841                               * boundary of the visible area. We know that the
842                               * curve is visible, so the check is pretty
843                               * simple
844                               */
845                              hnd.dhnd.xMinf >= xMin ||
846                              hnd.dhnd.xMaxf <= xMax ||
847                              hnd.dhnd.yMinf >= yMin ||
848                              hnd.dhnd.yMaxf <= yMax,
849                              pixelInfo);
850        }
851    }
852
853    /*
854     * Split quadratic curve into monotonic in X and Y parts. Calling
855     * ProcessMonotonicQuad for each monotonic piece of the curve.
856     * Note: coords array could be changed
857     */
858    private static void ProcessQuad(ProcessHandler hnd, float[] coords,
859                                    int[] pixelInfo) {
860        /* Temporary array for holding parameters corresponding to the extreme
861         * in X and Y points
862         */
863        double params[] = new double[2];
864        int cnt = 0;
865        double param;
866
867        /* Simple check for monotonicity in X before searching for the extreme
868         * points of the X(t) function. We first check if the curve is
869         * monotonic in X by seeing if all of the X coordinates are strongly
870         * ordered.
871         */
872        if ((coords[0] > coords[2] || coords[2] > coords[4]) &&
873            (coords[0] < coords[2] || coords[2] < coords[4]))
874        {
875            /* Searching for extreme points of the X(t) function  by solving
876             * dX(t)
877             * ----  = 0 equation
878             *  dt
879             */
880            double ax = coords[0] - 2*coords[2] + coords[4];
881            if (ax != 0) {
882                /* Calculating root of the following equation
883                 * ax*t + bx = 0
884                 */
885                double bx = coords[0] - coords[2];
886
887                param = bx/ax;
888                if (param < 1.0 && param > 0.0) {
889                    params[cnt++] = param;
890                }
891            }
892        }
893
894        /* Simple check for monotonicity in Y before searching for the extreme
895         * points of the Y(t) function. We first check if the curve is
896         * monotonic in Y by seeing if all of the Y coordinates are strongly
897         * ordered.
898         */
899        if ((coords[1] > coords[3] || coords[3] > coords[5]) &&
900            (coords[1] < coords[3] || coords[3] < coords[5]))
901        {
902            /* Searching for extreme points of the Y(t) function by solving
903             * dY(t)
904             * ----- = 0 equation
905             *  dt
906             */
907            double ay = coords[1] - 2*coords[3] + coords[5];
908
909            if (ay != 0) {
910                /* Calculating root of the following equation
911                 * ay*t + by = 0
912                 */
913                double by = coords[1] - coords[3];
914
915                param = by/ay;
916                if (param < 1.0 && param > 0.0) {
917                    if (cnt > 0) {
918                        /* Inserting parameter only if it differs from
919                         * already stored
920                         */
921                        if (params[0] >  param) {
922                            params[cnt++] = params[0];
923                            params[0] = param;
924                        } else if (params[0] <  param) {
925                            params[cnt++] = param;
926                        }
927                    } else {
928                        params[cnt++] = param;
929                    }
930                }
931            }
932        }
933
934        /* Processing obtained monotonic parts */
935        switch(cnt) {
936            case 0:
937                break;
938            case 1:
939                ProcessFirstMonotonicPartOfQuad(hnd, coords, pixelInfo,
940                                                (float)params[0]);
941                break;
942            case 2:
943                ProcessFirstMonotonicPartOfQuad(hnd, coords, pixelInfo,
944                                                (float)params[0]);
945                param = params[1] - params[0];
946                if (param > 0) {
947                    ProcessFirstMonotonicPartOfQuad(hnd, coords, pixelInfo,
948                                           /* Scale parameter to match with
949                                            * rest of the curve
950                                            */
951                                           (float)(param/(1.0 - params[0])));
952                }
953                break;
954        }
955
956        ProcessMonotonicQuad(hnd,coords,pixelInfo);
957    }
958
959    /*
960     * Bite the piece of the quadratic curve from start point till the point
961     * corresponding to the specified parameter then call ProcessQuad for the
962     * bitten part.
963     * Note: coords array will be changed
964     */
965    private static void ProcessFirstMonotonicPartOfQuad(ProcessHandler hnd,
966                                                        float[] coords,
967                                                        int[] pixelInfo,
968                                                        float t) {
969        float[] coords1 = new float[6];
970
971        coords1[0] = coords[0];
972        coords1[1] = coords[1];
973        coords1[2] = coords[0] + t*(coords[2] - coords[0]);
974        coords1[3] = coords[1] + t*(coords[3] - coords[1]);
975        coords[2] = coords[2] + t*(coords[4] - coords[2]);
976        coords[3] = coords[3] + t*(coords[5] - coords[3]);
977        coords[0] = coords1[4] = coords1[2] + t*(coords[2] - coords1[2]);
978        coords[1] = coords1[5] = coords1[3] + t*(coords[3] - coords1[3]);
979
980        ProcessMonotonicQuad(hnd, coords1, pixelInfo);
981    }
982
983    /* Performing drawing of the monotonic in X and Y cubic curves with sizes
984     * less than MAX_CUB_SIZE by using forward differencing method of
985     * calculation.  See comments to the DrawMonotonicCubic in the
986     * ProcessGeneralPath.c
987     */
988    private static void DrawMonotonicCubic(ProcessHandler hnd,
989                                           float[] coords,
990                                           boolean checkBounds,
991                                           int[] pixelInfo) {
992        int x0 = (int)(coords[0]*MDP_MULT);
993        int y0 = (int)(coords[1]*MDP_MULT);
994
995        int xe = (int)(coords[6]*MDP_MULT);
996        int ye = (int)(coords[7]*MDP_MULT);
997
998        /* Extracting fractional part of coordinates of first control point */
999        int px = (x0 & (~MDP_W_MASK)) << DF_CUB_SHIFT;
1000        int py = (y0 & (~MDP_W_MASK)) << DF_CUB_SHIFT;
1001
1002        /* Setting default boundary values for checking first and second forward
1003         * difference for the necessity of the restepping. See comments to the
1004         * boundary values in ProcessQuad for more info.
1005         */
1006        int incStepBnd = DF_CUB_INC_BND;
1007        int decStepBnd = DF_CUB_DEC_BND;
1008
1009        /* Setting default amount of steps */
1010        int count = DF_CUB_COUNT;
1011
1012        /* Setting default shift for preparing to the midpoint rounding */
1013        int shift =  DF_CUB_SHIFT;
1014
1015        int ax = (int)((-coords[0] + 3*coords[2] - 3*coords[4] +
1016                 coords[6])*CUB_A_MDP_MULT);
1017        int ay = (int)((-coords[1] + 3*coords[3] - 3*coords[5] +
1018                 coords[7])*CUB_A_MDP_MULT);
1019
1020        int bx = (int)((3*coords[0] - 6*coords[2] +
1021                 3*coords[4])*CUB_B_MDP_MULT);
1022        int by = (int)((3*coords[1] - 6*coords[3] +
1023                 3*coords[5])*CUB_B_MDP_MULT);
1024
1025        int cx = (int)((-3*coords[0] + 3*coords[2])*(CUB_C_MDP_MULT));
1026        int cy = (int)((-3*coords[1] + 3*coords[3])*(CUB_C_MDP_MULT));
1027
1028        int dddpx = 6*ax;
1029        int dddpy = 6*ay;
1030
1031        int ddpx = dddpx + bx;
1032        int ddpy = dddpy + by;
1033
1034        int dpx = ax + (bx>>1) + cx;
1035        int dpy = ay + (by>>1) + cy;
1036
1037        int x1, y1;
1038
1039        int x2 = x0;
1040        int y2 = y0;
1041
1042        /* Calculating whole part of the first point of the curve */
1043        int x0w = x0 & MDP_W_MASK;
1044        int y0w = y0 & MDP_W_MASK;
1045
1046        int dx = xe - x0;
1047        int dy = ye - y0;
1048
1049        while (count > 0) {
1050            /* Perform decreasing step in 2 times if necessary */
1051            while (Math.abs(ddpx) > decStepBnd ||
1052                   Math.abs(ddpy) > decStepBnd) {
1053                ddpx = (ddpx<<1) - dddpx;
1054                ddpy = (ddpy<<1) - dddpy;
1055                dpx = (dpx<<2) - (ddpx>>1);
1056                dpy = (dpy<<2) - (ddpy>>1);
1057                count <<=1;
1058                decStepBnd <<=3;
1059                incStepBnd <<=3;
1060                px <<=3;
1061                py <<=3;
1062                shift += 3;
1063            }
1064
1065            /* Perform increasing step in 2 times if necessary.
1066             * Note: we could do it only in even steps
1067             */
1068
1069            while ((count & 1) == 0 && shift > DF_CUB_SHIFT &&
1070                   Math.abs(dpx) <= incStepBnd &&
1071                   Math.abs(dpy) <= incStepBnd) {
1072                dpx = (dpx>>2) + (ddpx>>3);
1073                dpy = (dpy>>2) + (ddpy>>3);
1074                ddpx = (ddpx + dddpx)>>1;
1075                ddpy = (ddpy + dddpy)>>1;
1076                count >>=1;
1077                decStepBnd >>=3;
1078                incStepBnd >>=3;
1079                px >>=3;
1080                py >>=3;
1081                shift -= 3;
1082            }
1083
1084            count--;
1085
1086            /* Performing one step less than necessary and use actual (xe,ye)
1087             * curve's endpoint instead of calculated. This prevent us from
1088             * running above the curve endpoint due to the accumulated errors
1089             * during the iterations.
1090             */
1091            if (count > 0) {
1092                px += dpx;
1093                py += dpy;
1094
1095                dpx += ddpx;
1096                dpy += ddpy;
1097                ddpx += dddpx;
1098                ddpy += dddpy;
1099
1100                x1 = x2;
1101                y1 = y2;
1102
1103                x2 = x0w + (px >> shift);
1104                y2 = y0w + (py >> shift);
1105
1106                /* Checking that we are not running out of the endpoint and
1107                 * bounding violating coordinate.  The check is pretty simple
1108                 * because the curve passed to the DrawCubic already split
1109                 * into the monotonic in X and Y pieces
1110                 */
1111
1112                /* Bounding x2 by xe */
1113                if (((xe-x2)^dx) < 0) {
1114                    x2 = xe;
1115                }
1116
1117                /* Bounding y2 by ye */
1118                if (((ye-y2)^dy) < 0) {
1119                    y2 = ye;
1120                }
1121
1122                hnd.processFixedLine(x1, y1, x2, y2, pixelInfo, checkBounds,
1123                                     false);
1124            } else {
1125                hnd.processFixedLine(x2, y2, xe, ye, pixelInfo, checkBounds,
1126                                     false);
1127            }
1128        }
1129    }
1130
1131    /*
1132     * Checking size of the cubic curves and split them if necessary.
1133     * Calling DrawMonotonicCubic for the curves of the appropriate size.
1134     * Note: coords array could be changed
1135     */
1136    private static void ProcessMonotonicCubic(ProcessHandler hnd,
1137                                              float[] coords,
1138                                              int[] pixelInfo) {
1139
1140        float[] coords1 = new float[8];
1141        float tx, ty;
1142        float xMin, xMax;
1143        float yMin, yMax;
1144
1145        xMin = xMax = coords[0];
1146        yMin = yMax = coords[1];
1147
1148        for (int i = 2; i < 8; i += 2) {
1149            xMin = (xMin > coords[i])? coords[i] : xMin;
1150            xMax = (xMax < coords[i])? coords[i] : xMax;
1151            yMin = (yMin > coords[i + 1])? coords[i + 1] : yMin;
1152            yMax = (yMax < coords[i + 1])? coords[i + 1] : yMax;
1153        }
1154
1155        if (hnd.clipMode == PH_MODE_DRAW_CLIP) {
1156            /* In case of drawing we could just skip curves which are
1157             * completely out of bounds
1158             */
1159            if (hnd.dhnd.xMaxf < xMin || hnd.dhnd.xMinf > xMax ||
1160                hnd.dhnd.yMaxf < yMin || hnd.dhnd.yMinf > yMax) {
1161                return;
1162            }
1163        } else {
1164
1165            /* In case of filling we could skip curves which are above,
1166             * below and behind the right boundary of the visible area
1167             */
1168
1169            if (hnd.dhnd.yMaxf < yMin || hnd.dhnd.yMinf > yMax ||
1170                hnd.dhnd.xMaxf < xMin)
1171            {
1172                return;
1173            }
1174
1175            /* We could clamp x coordinates to the corresponding boundary
1176             * if the curve is completely behind the left one
1177             */
1178
1179            if (hnd.dhnd.xMinf > xMax) {
1180                coords[0] = coords[2] = coords[4] = coords[6] =
1181                    hnd.dhnd.xMinf;
1182            }
1183        }
1184
1185        if (xMax - xMin > MAX_CUB_SIZE || yMax - yMin > MAX_CUB_SIZE) {
1186            coords1[6] = coords[6];
1187            coords1[7] = coords[7];
1188            coords1[4] = (coords[4] + coords[6])/2.0f;
1189            coords1[5] = (coords[5] + coords[7])/2.0f;
1190            tx = (coords[2] + coords[4])/2.0f;
1191            ty = (coords[3] + coords[5])/2.0f;
1192            coords1[2] = (tx + coords1[4])/2.0f;
1193            coords1[3] = (ty + coords1[5])/2.0f;
1194            coords[2] =  (coords[0] + coords[2])/2.0f;
1195            coords[3] =  (coords[1] + coords[3])/2.0f;
1196            coords[4] = (coords[2] + tx)/2.0f;
1197            coords[5] = (coords[3] + ty)/2.0f;
1198            coords[6]=coords1[0]=(coords[4] + coords1[2])/2.0f;
1199            coords[7]=coords1[1]=(coords[5] + coords1[3])/2.0f;
1200
1201            ProcessMonotonicCubic(hnd, coords, pixelInfo);
1202
1203            ProcessMonotonicCubic(hnd, coords1, pixelInfo);
1204        } else {
1205            DrawMonotonicCubic(hnd, coords,
1206                               /* Set checkBounds parameter if curve intersects
1207                                * boundary of the visible area. We know that
1208                                * the curve is visible, so the check is pretty
1209                                * simple
1210                                */
1211                                hnd.dhnd.xMinf > xMin ||
1212                                hnd.dhnd.xMaxf < xMax ||
1213                                hnd.dhnd.yMinf > yMin ||
1214                                hnd.dhnd.yMaxf < yMax,
1215                                pixelInfo);
1216        }
1217    }
1218
1219    /*
1220     * Split cubic curve into monotonic in X and Y parts. Calling
1221     * ProcessMonotonicCubic for each monotonic piece of the curve.
1222     *
1223     * Note: coords array could be changed
1224     */
1225    private static void ProcessCubic(ProcessHandler hnd,
1226                                     float[] coords,
1227                                     int[] pixelInfo) {
1228        /* Temporary array for holding parameters corresponding to the extreme
1229         * in X and Y points
1230         */
1231        double params[] = new double[4];
1232        double eqn[] = new double[3];
1233        double res[] = new double[2];
1234        int cnt = 0;
1235
1236        /* Simple check for monotonicity in X before searching for the extreme
1237         * points of the X(t) function. We first check if the curve is
1238         * monotonic in X by seeing if all of the X coordinates are strongly
1239         * ordered.
1240         */
1241        if ((coords[0] > coords[2] || coords[2] > coords[4] ||
1242             coords[4] > coords[6]) &&
1243            (coords[0] < coords[2] || coords[2] < coords[4] ||
1244             coords[4] < coords[6]))
1245        {
1246            /* Searching for extreme points of the X(t) function  by solving
1247             * dX(t)
1248             * ----  = 0 equation
1249             *  dt
1250             */
1251            eqn[2] = -coords[0] + 3*coords[2] - 3*coords[4] + coords[6];
1252            eqn[1] = 2*(coords[0] - 2*coords[2] + coords[4]);
1253            eqn[0] = -coords[0] + coords[2];
1254
1255            int nr = QuadCurve2D.solveQuadratic(eqn, res);
1256
1257            /* Following code also correctly works in degenerate case of
1258             * the quadratic equation (nr = -1) because we do not need
1259             * splitting in this case.
1260             */
1261            for (int i = 0; i < nr; i++) {
1262                if (res[i] > 0 && res[i] < 1) {
1263                    params[cnt++] = res[i];
1264                }
1265            }
1266        }
1267
1268        /* Simple check for monotonicity in Y before searching for the extreme
1269         * points of the Y(t) function. We first check if the curve is
1270         * monotonic in Y by seeing if all of the Y coordinates are strongly
1271         * ordered.
1272         */
1273        if ((coords[1] > coords[3] || coords[3] > coords[5] ||
1274             coords[5] > coords[7]) &&
1275            (coords[1] < coords[3] || coords[3] < coords[5] ||
1276             coords[5] < coords[7]))
1277        {
1278            /* Searching for extreme points of the Y(t) function by solving
1279             * dY(t)
1280             * ----- = 0 equation
1281             *  dt
1282             */
1283            eqn[2] = -coords[1] + 3*coords[3] - 3*coords[5] + coords[7];
1284            eqn[1] = 2*(coords[1] - 2*coords[3] + coords[5]);
1285            eqn[0] = -coords[1] + coords[3];
1286
1287            int nr = QuadCurve2D.solveQuadratic(eqn, res);
1288
1289            /* Following code also correctly works in degenerate case of
1290             * the quadratic equation (nr = -1) because we do not need
1291             * splitting in this case.
1292             */
1293            for (int i = 0; i < nr; i++) {
1294                if (res[i] > 0 && res[i] < 1) {
1295                    params[cnt++] = res[i];
1296                }
1297            }
1298        }
1299
1300        if (cnt > 0) {
1301            /* Sorting parameter values corresponding to the extreme points
1302             * of the curve
1303             */
1304            Arrays.sort(params, 0, cnt);
1305
1306            /* Processing obtained monotonic parts */
1307            ProcessFirstMonotonicPartOfCubic(hnd, coords, pixelInfo,
1308                                             (float)params[0]);
1309            for (int i = 1; i < cnt; i++) {
1310                double param = params[i] - params[i-1];
1311                if (param > 0) {
1312                    ProcessFirstMonotonicPartOfCubic(hnd, coords, pixelInfo,
1313                        /* Scale parameter to match with rest of the curve */
1314                        (float)(param/(1.0 - params[i - 1])));
1315                }
1316            }
1317        }
1318
1319        ProcessMonotonicCubic(hnd,coords,pixelInfo);
1320    }
1321
1322    /*
1323     * Bite the piece of the cubic curve from start point till the point
1324     * corresponding to the specified parameter then call ProcessCubic for the
1325     * bitten part.
1326     * Note: coords array will be changed
1327     */
1328    private static void ProcessFirstMonotonicPartOfCubic(ProcessHandler hnd,
1329                                                         float[] coords,
1330                                                         int[] pixelInfo,
1331                                                         float t)
1332    {
1333        float[] coords1 = new float[8];
1334        float tx, ty;
1335
1336        coords1[0] = coords[0];
1337        coords1[1] = coords[1];
1338        tx = coords[2] + t*(coords[4] - coords[2]);
1339        ty = coords[3] + t*(coords[5] - coords[3]);
1340        coords1[2] =  coords[0] + t*(coords[2] - coords[0]);
1341        coords1[3] =  coords[1] + t*(coords[3] - coords[1]);
1342        coords1[4] = coords1[2] + t*(tx - coords1[2]);
1343        coords1[5] = coords1[3] + t*(ty - coords1[3]);
1344        coords[4] = coords[4] + t*(coords[6] - coords[4]);
1345        coords[5] = coords[5] + t*(coords[7] - coords[5]);
1346        coords[2] = tx + t*(coords[4] - tx);
1347        coords[3] = ty + t*(coords[5] - ty);
1348        coords[0]=coords1[6]=coords1[4] + t*(coords[2] - coords1[4]);
1349        coords[1]=coords1[7]=coords1[5] + t*(coords[3] - coords1[5]);
1350
1351        ProcessMonotonicCubic(hnd, coords1, pixelInfo);
1352    }
1353
1354    /* Note:
1355     * For more easy reading of the code below each java version of the macros
1356     * from the ProcessPath.c preceded by the commented origin call
1357     * containing verbose names of the parameters
1358     */
1359    private static void ProcessLine(ProcessHandler hnd, float x1, float y1,
1360                                    float x2, float y2, int[] pixelInfo) {
1361        float xMin, yMin, xMax, yMax;
1362        int X1, Y1, X2, Y2, X3, Y3, res;
1363        boolean clipped = false;
1364        float x3,y3;
1365        float c[] = new float[]{x1, y1, x2, y2, 0, 0};
1366
1367        boolean lastClipped;
1368
1369        xMin = hnd.dhnd.xMinf;
1370        yMin = hnd.dhnd.yMinf;
1371        xMax = hnd.dhnd.xMaxf;
1372        yMax = hnd.dhnd.yMaxf;
1373
1374        //
1375        // TESTANDCLIP(yMin, yMax, y1, x1, y2, x2, res);
1376        //
1377        res = TESTANDCLIP(yMin, yMax, c, 1, 0, 3, 2);
1378        if (res == CRES_INVISIBLE) return;
1379        clipped = IS_CLIPPED(res);
1380        //
1381        // TESTANDCLIP(yMin, yMax, y2, x2, y1, x1, res);
1382        //
1383        res = TESTANDCLIP(yMin, yMax, c, 3, 2, 1, 0);
1384        if (res == CRES_INVISIBLE) return;
1385        lastClipped = IS_CLIPPED(res);
1386        clipped = clipped || lastClipped;
1387
1388        if (hnd.clipMode == PH_MODE_DRAW_CLIP) {
1389            //
1390            // TESTANDCLIP(xMin, xMax, x1, y1, x2, y2, res);
1391            //
1392            res = TESTANDCLIP(xMin, xMax, c, 0, 1, 2, 3);
1393            if (res == CRES_INVISIBLE) return;
1394            clipped = clipped || IS_CLIPPED(res);
1395            //
1396            // TESTANDCLIP(xMin, xMax, x2, y2, x1, y1, res);
1397            //
1398            res = TESTANDCLIP(xMin, xMax, c, 2, 3, 0, 1);
1399            if (res == CRES_INVISIBLE) return;
1400            lastClipped = lastClipped || IS_CLIPPED(res);
1401            clipped = clipped || lastClipped;
1402            X1 = (int)(c[0]*MDP_MULT);
1403            Y1 = (int)(c[1]*MDP_MULT);
1404            X2 = (int)(c[2]*MDP_MULT);
1405            Y2 = (int)(c[3]*MDP_MULT);
1406
1407            hnd.processFixedLine(X1, Y1, X2, Y2, pixelInfo,
1408                                 clipped, /* enable boundary checking in
1409                                             case of clipping to avoid
1410                                             entering out of bounds which
1411                                             could happens during rounding
1412                                           */
1413                                 lastClipped /* Notify pProcessFixedLine
1414                                                that
1415                                                this is the end of the
1416                                                subpath (because of exiting
1417                                                out of boundaries)
1418                                              */
1419                                 );
1420        } else {
1421            /* Clamping starting from first vertex of the processed
1422             * segment
1423             *
1424             * CLIPCLAMP(xMin, xMax, x1, y1, x2, y2, x3, y3, res);
1425             */
1426            res = CLIPCLAMP(xMin, xMax, c, 0, 1, 2, 3, 4, 5);
1427            X1 = (int)(c[0]*MDP_MULT);
1428            Y1 = (int)(c[1]*MDP_MULT);
1429
1430            /* Clamping only by left boundary */
1431            if (res == CRES_MIN_CLIPPED) {
1432                X3 = (int)(c[4]*MDP_MULT);
1433                Y3 = (int)(c[5]*MDP_MULT);
1434                hnd.processFixedLine(X3, Y3, X1, Y1, pixelInfo,
1435                                     false, lastClipped);
1436
1437            } else if (res == CRES_INVISIBLE) {
1438                return;
1439            }
1440
1441            /* Clamping starting from last vertex of the processed
1442             * segment
1443             *
1444             * CLIPCLAMP(xMin, xMax, x2, y2, x1, y1, x3, y3, res);
1445             */
1446            res = CLIPCLAMP(xMin, xMax, c, 2, 3, 0, 1, 4, 5);
1447
1448            /* Checking if there was a clip by right boundary */
1449            lastClipped = lastClipped || (res == CRES_MAX_CLIPPED);
1450
1451            X2 = (int)(c[2]*MDP_MULT);
1452            Y2 = (int)(c[3]*MDP_MULT);
1453            hnd.processFixedLine(X1, Y1, X2, Y2, pixelInfo,
1454                                 false, lastClipped);
1455
1456            /* Clamping only by left boundary */
1457            if (res == CRES_MIN_CLIPPED) {
1458                X3 = (int)(c[4]*MDP_MULT);
1459                Y3 = (int)(c[5]*MDP_MULT);
1460                hnd.processFixedLine(X2, Y2, X3, Y3, pixelInfo,
1461                                     false, lastClipped);
1462            }
1463        }
1464    }
1465
1466    private static boolean doProcessPath(ProcessHandler hnd,
1467                                         Path2D.Float p2df,
1468                                         float transXf, float transYf) {
1469        float coords[] = new float[8];
1470        float tCoords[] = new float[8];
1471        float closeCoord[] = new float[] {0.0f, 0.0f};
1472        float firstCoord[] = new float[2];
1473        int pixelInfo[] = new int[5];
1474        boolean subpathStarted = false;
1475        boolean skip = false;
1476        float lastX, lastY;
1477        pixelInfo[0] = 0;
1478
1479        /* Adjusting boundaries to the capabilities of the
1480         * ProcessPath code
1481         */
1482        hnd.dhnd.adjustBounds(LOWER_OUT_BND, LOWER_OUT_BND,
1483                              UPPER_OUT_BND, UPPER_OUT_BND);
1484
1485        /* Adding support of the KEY_STROKE_CONTROL rendering hint.
1486         * Now we are supporting two modes: "pixels at centers" and
1487         * "pixels at corners".
1488         * First one is disabled by default but could be enabled by setting
1489         * VALUE_STROKE_PURE to the rendering hint. It means that pixel at the
1490         * screen (x,y) has (x + 0.5, y + 0.5) float coordinates.
1491         *
1492         * Second one is enabled by default and means straightforward mapping
1493         * (x,y) --> (x,y)
1494         */
1495        if (hnd.dhnd.strokeControl == SunHints.INTVAL_STROKE_PURE) {
1496            closeCoord[0] = -0.5f;
1497            closeCoord[1] = -0.5f;
1498            transXf -= 0.5;
1499            transYf -= 0.5;
1500        }
1501
1502        PathIterator pi = p2df.getPathIterator(null);
1503
1504        while (!pi.isDone()) {
1505            switch (pi.currentSegment(coords)) {
1506                case PathIterator.SEG_MOVETO:
1507                    /* Performing closing of the unclosed segments */
1508                    if (subpathStarted && !skip) {
1509                        if (hnd.clipMode == PH_MODE_FILL_CLIP) {
1510                            if (tCoords[0] != closeCoord[0] ||
1511                                tCoords[1] != closeCoord[1])
1512                            {
1513                                ProcessLine(hnd, tCoords[0], tCoords[1],
1514                                            closeCoord[0], closeCoord[1],
1515                                            pixelInfo);
1516                            }
1517                        }
1518                        hnd.processEndSubPath();
1519                    }
1520
1521                    tCoords[0] = coords[0] + transXf;
1522                    tCoords[1] = coords[1] + transYf;
1523
1524                    /* Checking SEG_MOVETO coordinates if they are out of the
1525                     * [LOWER_BND, UPPER_BND] range.  This check also handles
1526                     * NaN and Infinity values. Skipping next path segment in
1527                     * case of invalid data.
1528                     */
1529
1530                    if (tCoords[0] < UPPER_BND &&
1531                        tCoords[0] > LOWER_BND &&
1532                        tCoords[1] < UPPER_BND &&
1533                        tCoords[1] > LOWER_BND)
1534                    {
1535                        subpathStarted = true;
1536                        skip = false;
1537                        closeCoord[0] = tCoords[0];
1538                        closeCoord[1] = tCoords[1];
1539                    } else {
1540                        skip = true;
1541                    }
1542                    pixelInfo[0] = 0;
1543                    break;
1544                case PathIterator.SEG_LINETO:
1545                    lastX = tCoords[2] = coords[0] + transXf;
1546                    lastY = tCoords[3] = coords[1] + transYf;
1547
1548                    /* Checking SEG_LINETO coordinates if they are out of the
1549                     * [LOWER_BND, UPPER_BND] range.  This check also handles
1550                     * NaN and Infinity values. Ignoring current path segment
1551                     * in case  of invalid data. If segment is skipped its
1552                     * endpoint (if valid) is used to begin new subpath.
1553                     */
1554
1555                    if (lastX < UPPER_BND &&
1556                        lastX > LOWER_BND &&
1557                        lastY < UPPER_BND &&
1558                        lastY > LOWER_BND)
1559                    {
1560                        if (skip) {
1561                            tCoords[0] = closeCoord[0] = lastX;
1562                            tCoords[1] = closeCoord[1] = lastY;
1563                            subpathStarted = true;
1564                            skip = false;
1565                        } else {
1566                            ProcessLine(hnd, tCoords[0], tCoords[1],
1567                                        tCoords[2], tCoords[3], pixelInfo);
1568                            tCoords[0] = lastX;
1569                            tCoords[1] = lastY;
1570                        }
1571                    }
1572                    break;
1573                case PathIterator.SEG_QUADTO:
1574                    tCoords[2] = coords[0] + transXf;
1575                    tCoords[3] = coords[1] + transYf;
1576                    lastX = tCoords[4] = coords[2] + transXf;
1577                    lastY = tCoords[5] = coords[3] + transYf;
1578
1579                    /* Checking SEG_QUADTO coordinates if they are out of the
1580                     * [LOWER_BND, UPPER_BND] range.  This check also handles
1581                     * NaN and Infinity values. Ignoring current path segment
1582                     * in case  of invalid endpoints's data.  Equivalent to
1583                     * the SEG_LINETO if endpoint coordinates are valid but
1584                     * there are invalid data among other coordinates
1585                     */
1586
1587                    if (lastX < UPPER_BND &&
1588                        lastX > LOWER_BND &&
1589                        lastY < UPPER_BND &&
1590                        lastY > LOWER_BND)
1591                    {
1592                        if (skip) {
1593                            tCoords[0] = closeCoord[0] = lastX;
1594                            tCoords[1] = closeCoord[1] = lastY;
1595                            subpathStarted = true;
1596                            skip = false;
1597                        } else {
1598                            if (tCoords[2] < UPPER_BND &&
1599                                tCoords[2] > LOWER_BND &&
1600                                tCoords[3] < UPPER_BND &&
1601                                tCoords[3] > LOWER_BND)
1602                            {
1603                                ProcessQuad(hnd, tCoords, pixelInfo);
1604                            } else {
1605                                ProcessLine(hnd, tCoords[0], tCoords[1],
1606                                            tCoords[4], tCoords[5],
1607                                            pixelInfo);
1608                            }
1609                            tCoords[0] = lastX;
1610                            tCoords[1] = lastY;
1611                        }
1612                    }
1613                    break;
1614                case PathIterator.SEG_CUBICTO:
1615                    tCoords[2] = coords[0] + transXf;
1616                    tCoords[3] = coords[1] + transYf;
1617                    tCoords[4] = coords[2] + transXf;
1618                    tCoords[5] = coords[3] + transYf;
1619                    lastX = tCoords[6] = coords[4] + transXf;
1620                    lastY = tCoords[7] = coords[5] + transYf;
1621
1622                    /* Checking SEG_CUBICTO coordinates if they are out of the
1623                     * [LOWER_BND, UPPER_BND] range.  This check also handles
1624                     * NaN and Infinity values. Ignoring current path segment
1625                     * in case  of invalid endpoints's data.  Equivalent to
1626                     * the SEG_LINETO if endpoint coordinates are valid but
1627                     * there are invalid data among other coordinates
1628                     */
1629
1630                    if (lastX < UPPER_BND &&
1631                        lastX > LOWER_BND &&
1632                        lastY < UPPER_BND &&
1633                        lastY > LOWER_BND)
1634                    {
1635                        if (skip) {
1636                            tCoords[0] = closeCoord[0] = tCoords[6];
1637                            tCoords[1] = closeCoord[1] = tCoords[7];
1638                            subpathStarted = true;
1639                            skip = false;
1640                        } else {
1641                            if (tCoords[2] < UPPER_BND &&
1642                                tCoords[2] > LOWER_BND &&
1643                                tCoords[3] < UPPER_BND &&
1644                                tCoords[3] > LOWER_BND &&
1645                                tCoords[4] < UPPER_BND &&
1646                                tCoords[4] > LOWER_BND &&
1647                                tCoords[5] < UPPER_BND &&
1648                                tCoords[5] > LOWER_BND)
1649                            {
1650                                ProcessCubic(hnd, tCoords, pixelInfo);
1651                            } else {
1652                                ProcessLine(hnd, tCoords[0], tCoords[1],
1653                                            tCoords[6], tCoords[7],
1654                                            pixelInfo);
1655                            }
1656                            tCoords[0] = lastX;
1657                            tCoords[1] = lastY;
1658                        }
1659                    }
1660                    break;
1661                case PathIterator.SEG_CLOSE:
1662                    if (subpathStarted && !skip) {
1663                        skip = false;
1664                        if (tCoords[0] != closeCoord[0] ||
1665                            tCoords[1] != closeCoord[1])
1666                        {
1667                            ProcessLine(hnd, tCoords[0], tCoords[1],
1668                                        closeCoord[0], closeCoord[1],
1669                                        pixelInfo);
1670
1671                            /* Storing last path's point for using in following
1672                             * segments without initial moveTo
1673                             */
1674                            tCoords[0] = closeCoord[0];
1675                            tCoords[1] = closeCoord[1];
1676                        }
1677                        hnd.processEndSubPath();
1678                    }
1679                    break;
1680            }
1681            pi.next();
1682        }
1683
1684        /* Performing closing of the unclosed segments */
1685        if (subpathStarted & !skip) {
1686            if (hnd.clipMode == PH_MODE_FILL_CLIP) {
1687                if (tCoords[0] != closeCoord[0] ||
1688                    tCoords[1] != closeCoord[1])
1689                {
1690                    ProcessLine(hnd, tCoords[0], tCoords[1],
1691                                closeCoord[0], closeCoord[1],
1692                                pixelInfo);
1693                }
1694            }
1695            hnd.processEndSubPath();
1696        }
1697        return true;
1698    }
1699
1700    private static class Point {
1701        public int x;
1702        public int y;
1703        public boolean lastPoint;
1704        public Point prev;
1705        public Point next;
1706        public Point nextByY;
1707        public Edge edge;
1708        public Point(int x, int y, boolean lastPoint) {
1709            this.x = x;
1710            this.y = y;
1711            this.lastPoint = lastPoint;
1712        }
1713    };
1714
1715    private static class Edge {
1716        int x;
1717        int dx;
1718        Point p;
1719        int  dir;
1720        Edge prev;
1721        Edge next;
1722
1723        public Edge(Point p, int x, int dx, int dir) {
1724            this.p = p;
1725            this.x = x;
1726            this.dx = dx;
1727            this.dir = dir;
1728        }
1729    };
1730
1731    /* Size of the default buffer in the FillData structure. This buffer is
1732     * replaced with heap allocated in case of large paths.
1733     */
1734    private static final int DF_MAX_POINT = 256;
1735
1736    /* Following class accumulates points of the non-continuous flattened
1737     * general path during iteration through the origin path's segments . The
1738     * end of the each subpath is marked as lastPoint flag set at the last
1739     * point
1740     */
1741    private static class FillData {
1742        List<Point>  plgPnts;
1743        public int  plgYMin;
1744        public int  plgYMax;
1745
1746        public FillData() {
1747            plgPnts = new Vector<Point>(DF_MAX_POINT);
1748        }
1749
1750        public void addPoint(int x, int y, boolean lastPoint) {
1751            if (plgPnts.size() == 0) {
1752                plgYMin = plgYMax = y;
1753            } else {
1754                plgYMin = (plgYMin > y)?y:plgYMin;
1755                plgYMax = (plgYMax < y)?y:plgYMax;
1756            }
1757
1758            plgPnts.add(new Point(x, y, lastPoint));
1759        }
1760
1761        public boolean isEmpty() {
1762            return plgPnts.size() == 0;
1763        }
1764
1765        public boolean isEnded() {
1766            return plgPnts.get(plgPnts.size() - 1).lastPoint;
1767        }
1768
1769        public boolean setEnded() {
1770            return plgPnts.get(plgPnts.size() - 1).lastPoint = true;
1771        }
1772    }
1773
1774    private static class ActiveEdgeList {
1775        Edge head;
1776
1777        public boolean isEmpty() {
1778            return (head == null);
1779        }
1780
1781        public void insert(Point pnt, int cy) {
1782            Point np = pnt.next;
1783            int X1 = pnt.x, Y1 = pnt.y;
1784            int X2 = np.x, Y2 = np.y;
1785            Edge ne;
1786            if (Y1 == Y2) {
1787                /* Skipping horizontal segments */
1788                return;
1789            } else {
1790                int dX = X2 - X1;
1791                int dY = Y2 - Y1;
1792                int stepx, x0, dy, dir;
1793
1794                if (Y1 < Y2) {
1795                    x0 = X1;
1796                    dy = cy - Y1;
1797                    dir = -1;
1798                } else { // (Y1 > Y2)
1799                    x0 = X2;
1800                    dy = cy - Y2;
1801                    dir = 1;
1802                }
1803
1804                /* We need to worry only about dX because dY is in denominator
1805                 * and abs(dy) < MDP_MULT (cy is a first scanline of the scan
1806                 * converted segment and we subtract y coordinate of the
1807                 * nearest segment's end from it to obtain dy)
1808                 */
1809                if (dX > CALC_UBND || dX < CALC_LBND)  {
1810                    stepx = (int)((((double)dX)*MDP_MULT)/dY);
1811                    x0 = x0 + (int)((((double)dX)*dy)/dY);
1812                } else {
1813                    stepx = (dX<<MDP_PREC)/dY;
1814                    x0 += (dX*dy)/dY;
1815                }
1816
1817                ne = new Edge(pnt, x0, stepx, dir);
1818            }
1819
1820            ne.next = head;
1821            ne.prev = null;
1822            if (head != null) {
1823                head.prev = ne;
1824            }
1825            head = pnt.edge = ne;
1826        }
1827
1828        public void delete(Edge e) {
1829            Edge prevp = e.prev;
1830            Edge nextp = e.next;
1831            if (prevp != null) {
1832                prevp.next = nextp;
1833            } else {
1834                head = nextp;
1835            }
1836            if (nextp != null) {
1837                nextp.prev = prevp;
1838            }
1839        }
1840
1841        /**
1842         * Bubble sorting in the ascending order of the linked list.  This
1843         * implementation stops processing the list if there were no changes
1844         * during the previous pass.
1845         *
1846         * We could not use O(N) Radix sort here because in most cases list of
1847         * edges almost sorted.  So, bubble sort (O(N^2)) is working much
1848         * better.  Note, in case of array of edges Shell sort is more
1849         * efficient.
1850         */
1851        public void sort() {
1852            Edge p, q, r, s = null, temp;
1853            boolean wasSwap = true;
1854
1855            // r precedes p and s points to the node up to which
1856            // comparisons are to be made
1857            while (s != head.next && wasSwap) {
1858                r = p = head;
1859                q = p.next;
1860                wasSwap = false;
1861                while (p != s) {
1862                    if (p.x >= q.x) {
1863                        wasSwap = true;
1864                        if (p == head) {
1865                            temp = q.next;
1866                            q.next = p;
1867                            p.next = temp;
1868                            head = q;
1869                            r = q;
1870                        } else {
1871                            temp = q.next;
1872                            q.next = p;
1873                            p.next = temp;
1874                            r.next = q;
1875                            r = q;
1876                        }
1877                    } else {
1878                        r = p;
1879                        p = p.next;
1880                    }
1881                    q = p.next;
1882                    if (q == s) s = p;
1883                }
1884            }
1885
1886            // correction of the back links in the double linked edge list
1887            p = head;
1888            q = null;
1889            while (p != null) {
1890                p.prev = q;
1891                q = p;
1892                p = p.next;
1893            }
1894        }
1895    }
1896
1897    private static void FillPolygon(FillProcessHandler hnd,
1898                                    int fillRule) {
1899        int k, y, n;
1900        boolean drawing;
1901        Edge active;
1902        int rightBnd = hnd.dhnd.xMax - 1;
1903        FillData fd = hnd.fd;
1904        int yMin = fd.plgYMin;
1905        int yMax = fd.plgYMax;
1906        int hashSize = ((yMax - yMin)>>MDP_PREC) + 4;
1907
1908        /* Because of support of the KEY_STROKE_CONTROL hint we are performing
1909         * shift of the coordinates at the higher level
1910         */
1911        int hashOffset = ((yMin - 1) & MDP_W_MASK);
1912
1913        /* Winding counter */
1914        int counter;
1915
1916        /* Calculating mask to be applied to the winding counter */
1917        int counterMask =
1918            (fillRule == PathIterator.WIND_NON_ZERO)? -1:1;
1919
1920        int pntOffset;
1921        List<Point> pnts = fd.plgPnts;
1922        n = pnts.size();
1923
1924        if (n <=1) return;
1925
1926        Point[] yHash = new Point[hashSize];
1927
1928        /* Creating double linked list (prev, next links) describing path order
1929         * and hash table with points which fall between scanlines. nextByY
1930         * link is used for the points which are between same scanlines.
1931         * Scanlines are passed through the centers of the pixels.
1932         */
1933        Point curpt = pnts.get(0);
1934        curpt.prev = null;
1935        for (int i = 0; i < n - 1; i++) {
1936            curpt = pnts.get(i);
1937            Point nextpt = pnts.get(i + 1);
1938            int curHashInd = (curpt.y - hashOffset - 1) >> MDP_PREC;
1939            curpt.nextByY = yHash[curHashInd];
1940            yHash[curHashInd] = curpt;
1941            curpt.next = nextpt;
1942            nextpt.prev = curpt;
1943        }
1944
1945        Point ept = pnts.get(n - 1);
1946        int curHashInd = (ept.y - hashOffset - 1) >> MDP_PREC;
1947        ept.nextByY = yHash[curHashInd];
1948        yHash[curHashInd] = ept;
1949
1950        ActiveEdgeList activeList = new ActiveEdgeList();
1951
1952        for (y=hashOffset + MDP_MULT,k = 0;
1953             y<=yMax && k < hashSize; y += MDP_MULT, k++)
1954        {
1955            for(Point pt = yHash[k];pt != null; pt=pt.nextByY) {
1956                /* pt.y should be inside hashed interval
1957                 * assert(y-MDP_MULT <= pt.y && pt.y < y);
1958                 */
1959                if (pt.prev != null && !pt.prev.lastPoint) {
1960                    if (pt.prev.edge != null && pt.prev.y <= y) {
1961                        activeList.delete(pt.prev.edge);
1962                        pt.prev.edge = null;
1963                    } else  if (pt.prev.y > y) {
1964                        activeList.insert(pt.prev, y);
1965                    }
1966                }
1967
1968                if (!pt.lastPoint && pt.next != null) {
1969                    if (pt.edge != null && pt.next.y <= y) {
1970                        activeList.delete(pt.edge);
1971                        pt.edge = null;
1972                    } else if (pt.next.y > y) {
1973                        activeList.insert(pt, y);
1974                    }
1975                }
1976            }
1977
1978            if (activeList.isEmpty()) continue;
1979
1980            activeList.sort();
1981
1982            counter = 0;
1983            drawing = false;
1984            int xl, xr;
1985            xl = xr = hnd.dhnd.xMin;
1986            Edge curEdge = activeList.head;
1987            while (curEdge != null) {
1988                counter += curEdge.dir;
1989                if ((counter & counterMask) != 0 && !drawing) {
1990                    xl = (curEdge.x + MDP_MULT - 1)>>MDP_PREC;
1991                    drawing = true;
1992                }
1993
1994                if ((counter & counterMask) == 0 && drawing) {
1995                    xr = (curEdge.x - 1) >> MDP_PREC;
1996                    if (xl <= xr) {
1997                        hnd.dhnd.drawScanline(xl, xr, y >> MDP_PREC);
1998                    }
1999                    drawing = false;
2000                }
2001
2002                curEdge.x += curEdge.dx;
2003                curEdge = curEdge.next;
2004            }
2005
2006            /* Performing drawing till the right boundary (for correct
2007             * rendering shapes clipped at the right side)
2008             */
2009            if (drawing && xl <= rightBnd) {
2010
2011                /* Support of the strokeHint was added into the
2012                 * draw and fill methods of the sun.java2d.pipe.LoopPipe
2013                 */
2014                hnd.dhnd.drawScanline(xl, rightBnd, y  >> MDP_PREC);
2015            }
2016        }
2017    }
2018
2019    private static class FillProcessHandler extends ProcessHandler {
2020
2021        FillData fd;
2022
2023        /* Note: For more easy reading of the code below each java version of
2024         * the macros from the ProcessPath.c preceded by the commented
2025         * origin call containing verbose names of the parameters
2026         */
2027        public void  processFixedLine(int x1, int y1, int x2, int y2,
2028                                      int[] pixelInfo, boolean checkBounds,
2029                                      boolean endSubPath)
2030        {
2031            int outXMin, outXMax, outYMin, outYMax;
2032            int res;
2033
2034            /* There is no need to round line coordinates to the forward
2035             * differencing precision anymore. Such a rounding was used for
2036             * preventing the curve go out the endpoint (this sometimes does
2037             * not help). The problem was fixed in the forward differencing
2038             * loops.
2039             */
2040            if (checkBounds) {
2041                boolean lastClipped;
2042
2043                /* This function is used only for filling shapes, so there is no
2044                 * check for the type of clipping
2045                 */
2046                int c[] = new int[]{x1, y1, x2, y2, 0, 0};
2047                outXMin = (int)(dhnd.xMinf * MDP_MULT);
2048                outXMax = (int)(dhnd.xMaxf * MDP_MULT);
2049                outYMin = (int)(dhnd.yMinf * MDP_MULT);
2050                outYMax = (int)(dhnd.yMaxf * MDP_MULT);
2051
2052                /*
2053                 * TESTANDCLIP(outYMin, outYMax, y1, x1, y2, x2, res);
2054                 */
2055                res = TESTANDCLIP(outYMin, outYMax, c, 1, 0, 3, 2);
2056                if (res == CRES_INVISIBLE) return;
2057
2058                /*
2059                 * TESTANDCLIP(outYMin, outYMax, y2, x2, y1, x1, res);
2060                 */
2061                res = TESTANDCLIP(outYMin, outYMax, c, 3, 2, 1, 0);
2062                if (res == CRES_INVISIBLE) return;
2063                lastClipped = IS_CLIPPED(res);
2064
2065                /* Clamping starting from first vertex of the processed
2066                 * segment
2067                 *
2068                 * CLIPCLAMP(outXMin, outXMax, x1, y1, x2, y2, x3, y3, res);
2069                 */
2070                res = CLIPCLAMP(outXMin, outXMax, c, 0, 1, 2, 3, 4, 5);
2071
2072                /* Clamping only by left boundary */
2073                if (res == CRES_MIN_CLIPPED) {
2074                    processFixedLine(c[4], c[5], c[0], c[1], pixelInfo,
2075                                     false, lastClipped);
2076
2077                } else if (res == CRES_INVISIBLE) {
2078                    return;
2079                }
2080
2081                /* Clamping starting from last vertex of the processed
2082                 * segment
2083                 *
2084                 * CLIPCLAMP(outXMin, outXMax, x2, y2, x1, y1, x3, y3, res);
2085                 */
2086                res = CLIPCLAMP(outXMin, outXMax, c, 2, 3, 0, 1, 4, 5);
2087
2088                /* Checking if there was a clip by right boundary */
2089                lastClipped = lastClipped || (res == CRES_MAX_CLIPPED);
2090
2091                processFixedLine(c[0], c[1], c[2], c[3], pixelInfo,
2092                                 false, lastClipped);
2093
2094                /* Clamping only by left boundary */
2095                if (res == CRES_MIN_CLIPPED) {
2096                    processFixedLine(c[2], c[3], c[4], c[5], pixelInfo,
2097                                     false, lastClipped);
2098                }
2099
2100                return;
2101            }
2102
2103            /* Adding first point of the line only in case of empty or just
2104             * finished path
2105             */
2106            if (fd.isEmpty() || fd.isEnded()) {
2107                fd.addPoint(x1, y1, false);
2108            }
2109
2110            fd.addPoint(x2, y2, false);
2111
2112            if (endSubPath) {
2113                fd.setEnded();
2114            }
2115        }
2116
2117        FillProcessHandler(DrawHandler dhnd) {
2118            super(dhnd, PH_MODE_FILL_CLIP);
2119            this.fd = new FillData();
2120        }
2121
2122        public void processEndSubPath() {
2123            if (!fd.isEmpty()) {
2124                fd.setEnded();
2125            }
2126        }
2127    }
2128}
2129