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 
  26 package sun.java2d.loops;
  27 
  28 import java.awt.geom.Path2D;
  29 import java.awt.geom.PathIterator;
  30 import java.awt.geom.QuadCurve2D;
  31 import sun.awt.SunHints;
  32 import 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 
  44 public class ProcessPath {
  45 
  46     /* Public interfaces and methods for drawing and filling general paths */
  47 
  48     public static abstract 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 static abstract 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 }