src/java.desktop/share/classes/sun/java2d/marlin/DHelpers.java
changeset 49496 1ea202af7a97
parent 48284 fd7fbc929001
child 57929 13178f7e75d5
equal deleted inserted replaced
49495:f46bfa7a2956 49496:1ea202af7a97
     1 /*
     1 /*
     2  * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     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
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     7  * published by the Free Software Foundation.  Oracle designates this
    23  * questions.
    23  * questions.
    24  */
    24  */
    25 
    25 
    26 package sun.java2d.marlin;
    26 package sun.java2d.marlin;
    27 
    27 
    28 import static java.lang.Math.PI;
       
    29 import java.util.Arrays;
    28 import java.util.Arrays;
    30 import sun.java2d.marlin.stats.Histogram;
    29 import sun.java2d.marlin.stats.Histogram;
    31 import sun.java2d.marlin.stats.StatLong;
    30 import sun.java2d.marlin.stats.StatLong;
    32 
    31 
    33 final class DHelpers implements MarlinConst {
    32 final class DHelpers implements MarlinConst {
    39     static boolean within(final double x, final double y, final double err) {
    38     static boolean within(final double x, final double y, final double err) {
    40         final double d = y - x;
    39         final double d = y - x;
    41         return (d <= err && d >= -err);
    40         return (d <= err && d >= -err);
    42     }
    41     }
    43 
    42 
    44     static int quadraticRoots(final double a, final double b,
    43     static double evalCubic(final double a, final double b,
    45                               final double c, double[] zeroes, final int off)
    44                             final double c, final double d,
       
    45                             final double t)
       
    46     {
       
    47         return t * (t * (t * a + b) + c) + d;
       
    48     }
       
    49 
       
    50     static double evalQuad(final double a, final double b,
       
    51                            final double c, final double t)
       
    52     {
       
    53         return t * (t * a + b) + c;
       
    54     }
       
    55 
       
    56     static int quadraticRoots(final double a, final double b, final double c,
       
    57                               final double[] zeroes, final int off)
    46     {
    58     {
    47         int ret = off;
    59         int ret = off;
    48         double t;
       
    49         if (a != 0.0d) {
    60         if (a != 0.0d) {
    50             final double dis = b*b - 4*a*c;
    61             final double dis = b*b - 4.0d * a * c;
    51             if (dis > 0.0d) {
    62             if (dis > 0.0d) {
    52                 final double sqrtDis = Math.sqrt(dis);
    63                 final double sqrtDis = Math.sqrt(dis);
    53                 // depending on the sign of b we use a slightly different
    64                 // depending on the sign of b we use a slightly different
    54                 // algorithm than the traditional one to find one of the roots
    65                 // algorithm than the traditional one to find one of the roots
    55                 // so we can avoid adding numbers of different signs (which
    66                 // so we can avoid adding numbers of different signs (which
    60                 } else {
    71                 } else {
    61                     zeroes[ret++] = (-b + sqrtDis) / (2.0d * a);
    72                     zeroes[ret++] = (-b + sqrtDis) / (2.0d * a);
    62                     zeroes[ret++] = (2.0d * c) / (-b + sqrtDis);
    73                     zeroes[ret++] = (2.0d * c) / (-b + sqrtDis);
    63                 }
    74                 }
    64             } else if (dis == 0.0d) {
    75             } else if (dis == 0.0d) {
    65                 t = (-b) / (2.0d * a);
    76                 zeroes[ret++] = -b / (2.0d * a);
    66                 zeroes[ret++] = t;
    77             }
    67             }
    78         } else if (b != 0.0d) {
    68         } else {
    79             zeroes[ret++] = -c / b;
    69             if (b != 0.0d) {
       
    70                 t = (-c) / b;
       
    71                 zeroes[ret++] = t;
       
    72             }
       
    73         }
    80         }
    74         return ret - off;
    81         return ret - off;
    75     }
    82     }
    76 
    83 
    77     // find the roots of g(t) = d*t^3 + a*t^2 + b*t + c in [A,B)
    84     // find the roots of g(t) = d*t^3 + a*t^2 + b*t + c in [A,B)
    78     static int cubicRootsInAB(double d, double a, double b, double c,
    85     static int cubicRootsInAB(final double d, double a, double b, double c,
    79                               double[] pts, final int off,
    86                               final double[] pts, final int off,
    80                               final double A, final double B)
    87                               final double A, final double B)
    81     {
    88     {
    82         if (d == 0.0d) {
    89         if (d == 0.0d) {
    83             int num = quadraticRoots(a, b, c, pts, off);
    90             final int num = quadraticRoots(a, b, c, pts, off);
    84             return filterOutNotInAB(pts, off, num, A, B) - off;
    91             return filterOutNotInAB(pts, off, num, A, B) - off;
    85         }
    92         }
    86         // From Graphics Gems:
    93         // From Graphics Gems:
    87         // http://tog.acm.org/resources/GraphicsGems/gems/Roots3And4.c
    94         // https://github.com/erich666/GraphicsGems/blob/master/gems/Roots3And4.c
    88         // (also from awt.geom.CubicCurve2D. But here we don't need as
    95         // (also from awt.geom.CubicCurve2D. But here we don't need as
    89         // much accuracy and we don't want to create arrays so we use
    96         // much accuracy and we don't want to create arrays so we use
    90         // our own customized version).
    97         // our own customized version).
    91 
    98 
    92         // normal form: x^3 + ax^2 + bx + c = 0
    99         // normal form: x^3 + ax^2 + bx + c = 0
       
   100 
       
   101         /*
       
   102          * TODO: cleanup all that code after reading Roots3And4.c
       
   103          */
    93         a /= d;
   104         a /= d;
    94         b /= d;
   105         b /= d;
    95         c /= d;
   106         c /= d;
    96 
   107 
    97         //  substitute x = y - A/3 to eliminate quadratic term:
   108         //  substitute x = y - A/3 to eliminate quadratic term:
   100         // Since we actually need P/3 and Q/2 for all of the
   111         // Since we actually need P/3 and Q/2 for all of the
   101         // calculations that follow, we will calculate
   112         // calculations that follow, we will calculate
   102         // p = P/3
   113         // p = P/3
   103         // q = Q/2
   114         // q = Q/2
   104         // instead and use those values for simplicity of the code.
   115         // instead and use those values for simplicity of the code.
   105         double sq_A = a * a;
   116         final double sub = (1.0d / 3.0d) * a;
   106         double p = (1.0d/3.0d) * ((-1.0d/3.0d) * sq_A + b);
   117         final double sq_A = a * a;
   107         double q = (1.0d/2.0d) * ((2.0d/27.0d) * a * sq_A - (1.0d/3.0d) * a * b + c);
   118         final double p = (1.0d / 3.0d) * ((-1.0d / 3.0d) * sq_A + b);
       
   119         final double q = (1.0d / 2.0d) * ((2.0d / 27.0d) * a * sq_A - sub * b + c);
   108 
   120 
   109         // use Cardano's formula
   121         // use Cardano's formula
   110 
   122 
   111         double cb_p = p * p * p;
   123         final double cb_p = p * p * p;
   112         double D = q * q + cb_p;
   124         final double D = q * q + cb_p;
   113 
   125 
   114         int num;
   126         int num;
   115         if (D < 0.0d) {
   127         if (D < 0.0d) {
   116             // see: http://en.wikipedia.org/wiki/Cubic_function#Trigonometric_.28and_hyperbolic.29_method
   128             // see: http://en.wikipedia.org/wiki/Cubic_function#Trigonometric_.28and_hyperbolic.29_method
   117             final double phi = (1.0d/3.0d) * Math.acos(-q / Math.sqrt(-cb_p));
   129             final double phi = (1.0d / 3.0d) * Math.acos(-q / Math.sqrt(-cb_p));
   118             final double t = 2.0d * Math.sqrt(-p);
   130             final double t = 2.0d * Math.sqrt(-p);
   119 
   131 
   120             pts[ off+0 ] = ( t * Math.cos(phi));
   132             pts[off    ] = ( t * Math.cos(phi) - sub);
   121             pts[ off+1 ] = (-t * Math.cos(phi + (PI / 3.0d)));
   133             pts[off + 1] = (-t * Math.cos(phi + (Math.PI / 3.0d)) - sub);
   122             pts[ off+2 ] = (-t * Math.cos(phi - (PI / 3.0d)));
   134             pts[off + 2] = (-t * Math.cos(phi - (Math.PI / 3.0d)) - sub);
   123             num = 3;
   135             num = 3;
   124         } else {
   136         } else {
   125             final double sqrt_D = Math.sqrt(D);
   137             final double sqrt_D = Math.sqrt(D);
   126             final double u =   Math.cbrt(sqrt_D - q);
   138             final double u =   Math.cbrt(sqrt_D - q);
   127             final double v = - Math.cbrt(sqrt_D + q);
   139             final double v = - Math.cbrt(sqrt_D + q);
   128 
   140 
   129             pts[ off ] = (u + v);
   141             pts[off    ] = (u + v - sub);
   130             num = 1;
   142             num = 1;
   131 
   143 
   132             if (within(D, 0.0d, 1e-8d)) {
   144             if (within(D, 0.0d, 1e-8d)) {
   133                 pts[off+1] = -(pts[off] / 2.0d);
   145                 pts[off + 1] = ((-1.0d / 2.0d) * (u + v) - sub);
   134                 num = 2;
   146                 num = 2;
   135             }
   147             }
   136         }
   148         }
   137 
   149 
   138         final double sub = (1.0d/3.0d) * a;
       
   139 
       
   140         for (int i = 0; i < num; ++i) {
       
   141             pts[ off+i ] -= sub;
       
   142         }
       
   143 
       
   144         return filterOutNotInAB(pts, off, num, A, B) - off;
   150         return filterOutNotInAB(pts, off, num, A, B) - off;
   145     }
   151     }
   146 
   152 
   147     static double evalCubic(final double a, final double b,
       
   148                            final double c, final double d,
       
   149                            final double t)
       
   150     {
       
   151         return t * (t * (t * a + b) + c) + d;
       
   152     }
       
   153 
       
   154     static double evalQuad(final double a, final double b,
       
   155                           final double c, final double t)
       
   156     {
       
   157         return t * (t * a + b) + c;
       
   158     }
       
   159 
       
   160     // returns the index 1 past the last valid element remaining after filtering
   153     // returns the index 1 past the last valid element remaining after filtering
   161     static int filterOutNotInAB(double[] nums, final int off, final int len,
   154     static int filterOutNotInAB(final double[] nums, final int off, final int len,
   162                                 final double a, final double b)
   155                                 final double a, final double b)
   163     {
   156     {
   164         int ret = off;
   157         int ret = off;
   165         for (int i = off, end = off + len; i < end; i++) {
   158         for (int i = off, end = off + len; i < end; i++) {
   166             if (nums[i] >= a && nums[i] < b) {
   159             if (nums[i] >= a && nums[i] < b) {
   168             }
   161             }
   169         }
   162         }
   170         return ret;
   163         return ret;
   171     }
   164     }
   172 
   165 
   173     static double linelen(double x1, double y1, double x2, double y2) {
   166     static double fastLineLen(final double x0, final double y0,
   174         final double dx = x2 - x1;
   167                               final double x1, final double y1)
   175         final double dy = y2 - y1;
   168     {
   176         return Math.sqrt(dx*dx + dy*dy);
   169         final double dx = x1 - x0;
   177     }
   170         final double dy = y1 - y0;
   178 
   171 
   179     static void subdivide(double[] src, int srcoff, double[] left, int leftoff,
   172         // use manhattan norm:
   180                           double[] right, int rightoff, int type)
   173         return Math.abs(dx) + Math.abs(dy);
       
   174     }
       
   175 
       
   176     static double linelen(final double x0, final double y0,
       
   177                           final double x1, final double y1)
       
   178     {
       
   179         final double dx = x1 - x0;
       
   180         final double dy = y1 - y0;
       
   181         return Math.sqrt(dx * dx + dy * dy);
       
   182     }
       
   183 
       
   184     static double fastQuadLen(final double x0, final double y0,
       
   185                               final double x1, final double y1,
       
   186                               final double x2, final double y2)
       
   187     {
       
   188         final double dx1 = x1 - x0;
       
   189         final double dx2 = x2 - x1;
       
   190         final double dy1 = y1 - y0;
       
   191         final double dy2 = y2 - y1;
       
   192 
       
   193         // use manhattan norm:
       
   194         return Math.abs(dx1) + Math.abs(dx2)
       
   195              + Math.abs(dy1) + Math.abs(dy2);
       
   196     }
       
   197 
       
   198     static double quadlen(final double x0, final double y0,
       
   199                           final double x1, final double y1,
       
   200                           final double x2, final double y2)
       
   201     {
       
   202         return (linelen(x0, y0, x1, y1)
       
   203                 + linelen(x1, y1, x2, y2)
       
   204                 + linelen(x0, y0, x2, y2)) / 2.0d;
       
   205     }
       
   206 
       
   207     static double fastCurvelen(final double x0, final double y0,
       
   208                                final double x1, final double y1,
       
   209                                final double x2, final double y2,
       
   210                                final double x3, final double y3)
       
   211     {
       
   212         final double dx1 = x1 - x0;
       
   213         final double dx2 = x2 - x1;
       
   214         final double dx3 = x3 - x2;
       
   215         final double dy1 = y1 - y0;
       
   216         final double dy2 = y2 - y1;
       
   217         final double dy3 = y3 - y2;
       
   218 
       
   219         // use manhattan norm:
       
   220         return Math.abs(dx1) + Math.abs(dx2) + Math.abs(dx3)
       
   221              + Math.abs(dy1) + Math.abs(dy2) + Math.abs(dy3);
       
   222     }
       
   223 
       
   224     static double curvelen(final double x0, final double y0,
       
   225                            final double x1, final double y1,
       
   226                            final double x2, final double y2,
       
   227                            final double x3, final double y3)
       
   228     {
       
   229         return (linelen(x0, y0, x1, y1)
       
   230               + linelen(x1, y1, x2, y2)
       
   231               + linelen(x2, y2, x3, y3)
       
   232               + linelen(x0, y0, x3, y3)) / 2.0d;
       
   233     }
       
   234 
       
   235     // finds values of t where the curve in pts should be subdivided in order
       
   236     // to get good offset curves a distance of w away from the middle curve.
       
   237     // Stores the points in ts, and returns how many of them there were.
       
   238     static int findSubdivPoints(final DCurve c, final double[] pts,
       
   239                                 final double[] ts, final int type,
       
   240                                 final double w2)
       
   241     {
       
   242         final double x12 = pts[2] - pts[0];
       
   243         final double y12 = pts[3] - pts[1];
       
   244         // if the curve is already parallel to either axis we gain nothing
       
   245         // from rotating it.
       
   246         if ((y12 != 0.0d && x12 != 0.0d)) {
       
   247             // we rotate it so that the first vector in the control polygon is
       
   248             // parallel to the x-axis. This will ensure that rotated quarter
       
   249             // circles won't be subdivided.
       
   250             final double hypot = Math.sqrt(x12 * x12 + y12 * y12);
       
   251             final double cos = x12 / hypot;
       
   252             final double sin = y12 / hypot;
       
   253             final double x1 = cos * pts[0] + sin * pts[1];
       
   254             final double y1 = cos * pts[1] - sin * pts[0];
       
   255             final double x2 = cos * pts[2] + sin * pts[3];
       
   256             final double y2 = cos * pts[3] - sin * pts[2];
       
   257             final double x3 = cos * pts[4] + sin * pts[5];
       
   258             final double y3 = cos * pts[5] - sin * pts[4];
       
   259 
       
   260             switch(type) {
       
   261             case 8:
       
   262                 final double x4 = cos * pts[6] + sin * pts[7];
       
   263                 final double y4 = cos * pts[7] - sin * pts[6];
       
   264                 c.set(x1, y1, x2, y2, x3, y3, x4, y4);
       
   265                 break;
       
   266             case 6:
       
   267                 c.set(x1, y1, x2, y2, x3, y3);
       
   268                 break;
       
   269             default:
       
   270             }
       
   271         } else {
       
   272             c.set(pts, type);
       
   273         }
       
   274 
       
   275         int ret = 0;
       
   276         // we subdivide at values of t such that the remaining rotated
       
   277         // curves are monotonic in x and y.
       
   278         ret += c.dxRoots(ts, ret);
       
   279         ret += c.dyRoots(ts, ret);
       
   280 
       
   281         // subdivide at inflection points.
       
   282         if (type == 8) {
       
   283             // quadratic curves can't have inflection points
       
   284             ret += c.infPoints(ts, ret);
       
   285         }
       
   286 
       
   287         // now we must subdivide at points where one of the offset curves will have
       
   288         // a cusp. This happens at ts where the radius of curvature is equal to w.
       
   289         ret += c.rootsOfROCMinusW(ts, ret, w2, 0.0001d);
       
   290 
       
   291         ret = filterOutNotInAB(ts, 0, ret, 0.0001d, 0.9999d);
       
   292         isort(ts, ret);
       
   293         return ret;
       
   294     }
       
   295 
       
   296     // finds values of t where the curve in pts should be subdivided in order
       
   297     // to get intersections with the given clip rectangle.
       
   298     // Stores the points in ts, and returns how many of them there were.
       
   299     static int findClipPoints(final DCurve curve, final double[] pts,
       
   300                               final double[] ts, final int type,
       
   301                               final int outCodeOR,
       
   302                               final double[] clipRect)
       
   303     {
       
   304         curve.set(pts, type);
       
   305 
       
   306         // clip rectangle (ymin, ymax, xmin, xmax)
       
   307         int ret = 0;
       
   308 
       
   309         if ((outCodeOR & OUTCODE_LEFT) != 0) {
       
   310             ret += curve.xPoints(ts, ret, clipRect[2]);
       
   311         }
       
   312         if ((outCodeOR & OUTCODE_RIGHT) != 0) {
       
   313             ret += curve.xPoints(ts, ret, clipRect[3]);
       
   314         }
       
   315         if ((outCodeOR & OUTCODE_TOP) != 0) {
       
   316             ret += curve.yPoints(ts, ret, clipRect[0]);
       
   317         }
       
   318         if ((outCodeOR & OUTCODE_BOTTOM) != 0) {
       
   319             ret += curve.yPoints(ts, ret, clipRect[1]);
       
   320         }
       
   321         isort(ts, ret);
       
   322         return ret;
       
   323     }
       
   324 
       
   325     static void subdivide(final double[] src,
       
   326                           final double[] left, final double[] right,
       
   327                           final int type)
   181     {
   328     {
   182         switch(type) {
   329         switch(type) {
       
   330         case 8:
       
   331             subdivideCubic(src, left, right);
       
   332             return;
   183         case 6:
   333         case 6:
   184             DHelpers.subdivideQuad(src, srcoff, left, leftoff, right, rightoff);
   334             subdivideQuad(src, left, right);
   185             return;
       
   186         case 8:
       
   187             DHelpers.subdivideCubic(src, srcoff, left, leftoff, right, rightoff);
       
   188             return;
   335             return;
   189         default:
   336         default:
   190             throw new InternalError("Unsupported curve type");
   337             throw new InternalError("Unsupported curve type");
   191         }
   338         }
   192     }
   339     }
   193 
   340 
   194     static void isort(double[] a, int off, int len) {
   341     static void isort(final double[] a, final int len) {
   195         for (int i = off + 1, end = off + len; i < end; i++) {
   342         for (int i = 1, j; i < len; i++) {
   196             double ai = a[i];
   343             final double ai = a[i];
   197             int j = i - 1;
   344             j = i - 1;
   198             for (; j >= off && a[j] > ai; j--) {
   345             for (; j >= 0 && a[j] > ai; j--) {
   199                 a[j+1] = a[j];
   346                 a[j + 1] = a[j];
   200             }
   347             }
   201             a[j+1] = ai;
   348             a[j + 1] = ai;
   202         }
   349         }
   203     }
   350     }
   204 
   351 
   205     // Most of these are copied from classes in java.awt.geom because we need
   352     // Most of these are copied from classes in java.awt.geom because we need
   206     // both single and double precision variants of these functions, and Line2D,
   353     // both single and double precision variants of these functions, and Line2D,
   219      * it is possible to pass the same array for <code>left</code>
   366      * it is possible to pass the same array for <code>left</code>
   220      * and <code>right</code> and to use offsets, such as <code>rightoff</code>
   367      * and <code>right</code> and to use offsets, such as <code>rightoff</code>
   221      * equals (<code>leftoff</code> + 6), in order
   368      * equals (<code>leftoff</code> + 6), in order
   222      * to avoid allocating extra storage for this common point.
   369      * to avoid allocating extra storage for this common point.
   223      * @param src the array holding the coordinates for the source curve
   370      * @param src the array holding the coordinates for the source curve
   224      * @param srcoff the offset into the array of the beginning of the
       
   225      * the 6 source coordinates
       
   226      * @param left the array for storing the coordinates for the first
   371      * @param left the array for storing the coordinates for the first
   227      * half of the subdivided curve
   372      * half of the subdivided curve
   228      * @param leftoff the offset into the array of the beginning of the
       
   229      * the 6 left coordinates
       
   230      * @param right the array for storing the coordinates for the second
   373      * @param right the array for storing the coordinates for the second
   231      * half of the subdivided curve
   374      * half of the subdivided curve
   232      * @param rightoff the offset into the array of the beginning of the
       
   233      * the 6 right coordinates
       
   234      * @since 1.7
   375      * @since 1.7
   235      */
   376      */
   236     static void subdivideCubic(double[] src, int srcoff,
   377     static void subdivideCubic(final double[] src,
   237                                double[] left, int leftoff,
   378                                final double[] left,
   238                                double[] right, int rightoff)
   379                                final double[] right)
   239     {
   380     {
   240         double x1 = src[srcoff + 0];
   381         double  x1 = src[0];
   241         double y1 = src[srcoff + 1];
   382         double  y1 = src[1];
   242         double ctrlx1 = src[srcoff + 2];
   383         double cx1 = src[2];
   243         double ctrly1 = src[srcoff + 3];
   384         double cy1 = src[3];
   244         double ctrlx2 = src[srcoff + 4];
   385         double cx2 = src[4];
   245         double ctrly2 = src[srcoff + 5];
   386         double cy2 = src[5];
   246         double x2 = src[srcoff + 6];
   387         double  x2 = src[6];
   247         double y2 = src[srcoff + 7];
   388         double  y2 = src[7];
   248         if (left != null) {
   389 
   249             left[leftoff + 0] = x1;
   390         left[0]  = x1;
   250             left[leftoff + 1] = y1;
   391         left[1]  = y1;
   251         }
   392 
   252         if (right != null) {
   393         right[6] = x2;
   253             right[rightoff + 6] = x2;
   394         right[7] = y2;
   254             right[rightoff + 7] = y2;
   395 
   255         }
   396         x1 = (x1 + cx1) / 2.0d;
   256         x1 = (x1 + ctrlx1) / 2.0d;
   397         y1 = (y1 + cy1) / 2.0d;
   257         y1 = (y1 + ctrly1) / 2.0d;
   398         x2 = (x2 + cx2) / 2.0d;
   258         x2 = (x2 + ctrlx2) / 2.0d;
   399         y2 = (y2 + cy2) / 2.0d;
   259         y2 = (y2 + ctrly2) / 2.0d;
   400 
   260         double centerx = (ctrlx1 + ctrlx2) / 2.0d;
   401         double cx = (cx1 + cx2) / 2.0d;
   261         double centery = (ctrly1 + ctrly2) / 2.0d;
   402         double cy = (cy1 + cy2) / 2.0d;
   262         ctrlx1 = (x1 + centerx) / 2.0d;
   403 
   263         ctrly1 = (y1 + centery) / 2.0d;
   404         cx1 = (x1 + cx) / 2.0d;
   264         ctrlx2 = (x2 + centerx) / 2.0d;
   405         cy1 = (y1 + cy) / 2.0d;
   265         ctrly2 = (y2 + centery) / 2.0d;
   406         cx2 = (x2 + cx) / 2.0d;
   266         centerx = (ctrlx1 + ctrlx2) / 2.0d;
   407         cy2 = (y2 + cy) / 2.0d;
   267         centery = (ctrly1 + ctrly2) / 2.0d;
   408         cx  = (cx1 + cx2) / 2.0d;
   268         if (left != null) {
   409         cy  = (cy1 + cy2) / 2.0d;
   269             left[leftoff + 2] = x1;
   410 
   270             left[leftoff + 3] = y1;
   411         left[2] = x1;
   271             left[leftoff + 4] = ctrlx1;
   412         left[3] = y1;
   272             left[leftoff + 5] = ctrly1;
   413         left[4] = cx1;
   273             left[leftoff + 6] = centerx;
   414         left[5] = cy1;
   274             left[leftoff + 7] = centery;
   415         left[6] = cx;
   275         }
   416         left[7] = cy;
   276         if (right != null) {
   417 
   277             right[rightoff + 0] = centerx;
   418         right[0] = cx;
   278             right[rightoff + 1] = centery;
   419         right[1] = cy;
   279             right[rightoff + 2] = ctrlx2;
   420         right[2] = cx2;
   280             right[rightoff + 3] = ctrly2;
   421         right[3] = cy2;
   281             right[rightoff + 4] = x2;
   422         right[4] = x2;
   282             right[rightoff + 5] = y2;
   423         right[5] = y2;
   283         }
   424     }
   284     }
   425 
   285 
   426     static void subdivideCubicAt(final double t,
   286 
   427                                  final double[] src, final int offS,
   287     static void subdivideCubicAt(double t, double[] src, int srcoff,
   428                                  final double[] pts, final int offL, final int offR)
   288                                  double[] left, int leftoff,
   429     {
   289                                  double[] right, int rightoff)
   430         double  x1 = src[offS    ];
   290     {
   431         double  y1 = src[offS + 1];
   291         double x1 = src[srcoff + 0];
   432         double cx1 = src[offS + 2];
   292         double y1 = src[srcoff + 1];
   433         double cy1 = src[offS + 3];
   293         double ctrlx1 = src[srcoff + 2];
   434         double cx2 = src[offS + 4];
   294         double ctrly1 = src[srcoff + 3];
   435         double cy2 = src[offS + 5];
   295         double ctrlx2 = src[srcoff + 4];
   436         double  x2 = src[offS + 6];
   296         double ctrly2 = src[srcoff + 5];
   437         double  y2 = src[offS + 7];
   297         double x2 = src[srcoff + 6];
   438 
   298         double y2 = src[srcoff + 7];
   439         pts[offL    ] = x1;
   299         if (left != null) {
   440         pts[offL + 1] = y1;
   300             left[leftoff + 0] = x1;
   441 
   301             left[leftoff + 1] = y1;
   442         pts[offR + 6] = x2;
   302         }
   443         pts[offR + 7] = y2;
   303         if (right != null) {
   444 
   304             right[rightoff + 6] = x2;
   445         x1 =  x1 + t * (cx1 - x1);
   305             right[rightoff + 7] = y2;
   446         y1 =  y1 + t * (cy1 - y1);
   306         }
   447         x2 = cx2 + t * (x2 - cx2);
   307         x1 = x1 + t * (ctrlx1 - x1);
   448         y2 = cy2 + t * (y2 - cy2);
   308         y1 = y1 + t * (ctrly1 - y1);
   449 
   309         x2 = ctrlx2 + t * (x2 - ctrlx2);
   450         double cx = cx1 + t * (cx2 - cx1);
   310         y2 = ctrly2 + t * (y2 - ctrly2);
   451         double cy = cy1 + t * (cy2 - cy1);
   311         double centerx = ctrlx1 + t * (ctrlx2 - ctrlx1);
   452 
   312         double centery = ctrly1 + t * (ctrly2 - ctrly1);
   453         cx1 =  x1 + t * (cx - x1);
   313         ctrlx1 = x1 + t * (centerx - x1);
   454         cy1 =  y1 + t * (cy - y1);
   314         ctrly1 = y1 + t * (centery - y1);
   455         cx2 =  cx + t * (x2 - cx);
   315         ctrlx2 = centerx + t * (x2 - centerx);
   456         cy2 =  cy + t * (y2 - cy);
   316         ctrly2 = centery + t * (y2 - centery);
   457         cx  = cx1 + t * (cx2 - cx1);
   317         centerx = ctrlx1 + t * (ctrlx2 - ctrlx1);
   458         cy  = cy1 + t * (cy2 - cy1);
   318         centery = ctrly1 + t * (ctrly2 - ctrly1);
   459 
   319         if (left != null) {
   460         pts[offL + 2] = x1;
   320             left[leftoff + 2] = x1;
   461         pts[offL + 3] = y1;
   321             left[leftoff + 3] = y1;
   462         pts[offL + 4] = cx1;
   322             left[leftoff + 4] = ctrlx1;
   463         pts[offL + 5] = cy1;
   323             left[leftoff + 5] = ctrly1;
   464         pts[offL + 6] = cx;
   324             left[leftoff + 6] = centerx;
   465         pts[offL + 7] = cy;
   325             left[leftoff + 7] = centery;
   466 
   326         }
   467         pts[offR    ] = cx;
   327         if (right != null) {
   468         pts[offR + 1] = cy;
   328             right[rightoff + 0] = centerx;
   469         pts[offR + 2] = cx2;
   329             right[rightoff + 1] = centery;
   470         pts[offR + 3] = cy2;
   330             right[rightoff + 2] = ctrlx2;
   471         pts[offR + 4] = x2;
   331             right[rightoff + 3] = ctrly2;
   472         pts[offR + 5] = y2;
   332             right[rightoff + 4] = x2;
   473     }
   333             right[rightoff + 5] = y2;
   474 
   334         }
   475     static void subdivideQuad(final double[] src,
   335     }
   476                               final double[] left,
   336 
   477                               final double[] right)
   337     static void subdivideQuad(double[] src, int srcoff,
   478     {
   338                               double[] left, int leftoff,
   479         double x1 = src[0];
   339                               double[] right, int rightoff)
   480         double y1 = src[1];
   340     {
   481         double cx = src[2];
   341         double x1 = src[srcoff + 0];
   482         double cy = src[3];
   342         double y1 = src[srcoff + 1];
   483         double x2 = src[4];
   343         double ctrlx = src[srcoff + 2];
   484         double y2 = src[5];
   344         double ctrly = src[srcoff + 3];
   485 
   345         double x2 = src[srcoff + 4];
   486         left[0]  = x1;
   346         double y2 = src[srcoff + 5];
   487         left[1]  = y1;
   347         if (left != null) {
   488 
   348             left[leftoff + 0] = x1;
   489         right[4] = x2;
   349             left[leftoff + 1] = y1;
   490         right[5] = y2;
   350         }
   491 
   351         if (right != null) {
   492         x1 = (x1 + cx) / 2.0d;
   352             right[rightoff + 4] = x2;
   493         y1 = (y1 + cy) / 2.0d;
   353             right[rightoff + 5] = y2;
   494         x2 = (x2 + cx) / 2.0d;
   354         }
   495         y2 = (y2 + cy) / 2.0d;
   355         x1 = (x1 + ctrlx) / 2.0d;
   496         cx = (x1 + x2) / 2.0d;
   356         y1 = (y1 + ctrly) / 2.0d;
   497         cy = (y1 + y2) / 2.0d;
   357         x2 = (x2 + ctrlx) / 2.0d;
   498 
   358         y2 = (y2 + ctrly) / 2.0d;
   499         left[2] = x1;
   359         ctrlx = (x1 + x2) / 2.0d;
   500         left[3] = y1;
   360         ctrly = (y1 + y2) / 2.0d;
   501         left[4] = cx;
   361         if (left != null) {
   502         left[5] = cy;
   362             left[leftoff + 2] = x1;
   503 
   363             left[leftoff + 3] = y1;
   504         right[0] = cx;
   364             left[leftoff + 4] = ctrlx;
   505         right[1] = cy;
   365             left[leftoff + 5] = ctrly;
   506         right[2] = x2;
   366         }
   507         right[3] = y2;
   367         if (right != null) {
   508     }
   368             right[rightoff + 0] = ctrlx;
   509 
   369             right[rightoff + 1] = ctrly;
   510     static void subdivideQuadAt(final double t,
   370             right[rightoff + 2] = x2;
   511                                 final double[] src, final int offS,
   371             right[rightoff + 3] = y2;
   512                                 final double[] pts, final int offL, final int offR)
   372         }
   513     {
   373     }
   514         double x1 = src[offS    ];
   374 
   515         double y1 = src[offS + 1];
   375     static void subdivideQuadAt(double t, double[] src, int srcoff,
   516         double cx = src[offS + 2];
   376                                 double[] left, int leftoff,
   517         double cy = src[offS + 3];
   377                                 double[] right, int rightoff)
   518         double x2 = src[offS + 4];
   378     {
   519         double y2 = src[offS + 5];
   379         double x1 = src[srcoff + 0];
   520 
   380         double y1 = src[srcoff + 1];
   521         pts[offL    ] = x1;
   381         double ctrlx = src[srcoff + 2];
   522         pts[offL + 1] = y1;
   382         double ctrly = src[srcoff + 3];
   523 
   383         double x2 = src[srcoff + 4];
   524         pts[offR + 4] = x2;
   384         double y2 = src[srcoff + 5];
   525         pts[offR + 5] = y2;
   385         if (left != null) {
   526 
   386             left[leftoff + 0] = x1;
   527         x1 = x1 + t * (cx - x1);
   387             left[leftoff + 1] = y1;
   528         y1 = y1 + t * (cy - y1);
   388         }
   529         x2 = cx + t * (x2 - cx);
   389         if (right != null) {
   530         y2 = cy + t * (y2 - cy);
   390             right[rightoff + 4] = x2;
   531         cx = x1 + t * (x2 - x1);
   391             right[rightoff + 5] = y2;
   532         cy = y1 + t * (y2 - y1);
   392         }
   533 
   393         x1 = x1 + t * (ctrlx - x1);
   534         pts[offL + 2] = x1;
   394         y1 = y1 + t * (ctrly - y1);
   535         pts[offL + 3] = y1;
   395         x2 = ctrlx + t * (x2 - ctrlx);
   536         pts[offL + 4] = cx;
   396         y2 = ctrly + t * (y2 - ctrly);
   537         pts[offL + 5] = cy;
   397         ctrlx = x1 + t * (x2 - x1);
   538 
   398         ctrly = y1 + t * (y2 - y1);
   539         pts[offR    ] = cx;
   399         if (left != null) {
   540         pts[offR + 1] = cy;
   400             left[leftoff + 2] = x1;
   541         pts[offR + 2] = x2;
   401             left[leftoff + 3] = y1;
   542         pts[offR + 3] = y2;
   402             left[leftoff + 4] = ctrlx;
   543     }
   403             left[leftoff + 5] = ctrly;
   544 
   404         }
   545     static void subdivideLineAt(final double t,
   405         if (right != null) {
   546                                 final double[] src, final int offS,
   406             right[rightoff + 0] = ctrlx;
   547                                 final double[] pts, final int offL, final int offR)
   407             right[rightoff + 1] = ctrly;
   548     {
   408             right[rightoff + 2] = x2;
   549         double x1 = src[offS    ];
   409             right[rightoff + 3] = y2;
   550         double y1 = src[offS + 1];
   410         }
   551         double x2 = src[offS + 2];
   411     }
   552         double y2 = src[offS + 3];
   412 
   553 
   413     static void subdivideAt(double t, double[] src, int srcoff,
   554         pts[offL    ] = x1;
   414                             double[] left, int leftoff,
   555         pts[offL + 1] = y1;
   415                             double[] right, int rightoff, int size)
   556 
   416     {
   557         pts[offR + 2] = x2;
   417         switch(size) {
   558         pts[offR + 3] = y2;
   418         case 8:
   559 
   419             subdivideCubicAt(t, src, srcoff, left, leftoff, right, rightoff);
   560         x1 = x1 + t * (x2 - x1);
   420             return;
   561         y1 = y1 + t * (y2 - y1);
   421         case 6:
   562 
   422             subdivideQuadAt(t, src, srcoff, left, leftoff, right, rightoff);
   563         pts[offL + 2] = x1;
   423             return;
   564         pts[offL + 3] = y1;
       
   565 
       
   566         pts[offR    ] = x1;
       
   567         pts[offR + 1] = y1;
       
   568     }
       
   569 
       
   570     static void subdivideAt(final double t,
       
   571                             final double[] src, final int offS,
       
   572                             final double[] pts, final int offL, final int type)
       
   573     {
       
   574         // if instead of switch (perf + most probable cases first)
       
   575         if (type == 8) {
       
   576             subdivideCubicAt(t, src, offS, pts, offL, offL + type);
       
   577         } else if (type == 4) {
       
   578             subdivideLineAt(t, src, offS, pts, offL, offL + type);
       
   579         } else {
       
   580             subdivideQuadAt(t, src, offS, pts, offL, offL + type);
   424         }
   581         }
   425     }
   582     }
   426 
   583 
   427     // From sun.java2d.loops.GeneralRenderer:
   584     // From sun.java2d.loops.GeneralRenderer:
   428 
   585 
   606                 case TYPE_LINETO:
   763                 case TYPE_LINETO:
   607                     io.lineTo(_curves[e], _curves[e+1]);
   764                     io.lineTo(_curves[e], _curves[e+1]);
   608                     e += 2;
   765                     e += 2;
   609                     continue;
   766                     continue;
   610                 case TYPE_QUADTO:
   767                 case TYPE_QUADTO:
   611                     io.quadTo(_curves[e+0], _curves[e+1],
   768                     io.quadTo(_curves[e],   _curves[e+1],
   612                               _curves[e+2], _curves[e+3]);
   769                               _curves[e+2], _curves[e+3]);
   613                     e += 4;
   770                     e += 4;
   614                     continue;
   771                     continue;
   615                 case TYPE_CUBICTO:
   772                 case TYPE_CUBICTO:
   616                     io.curveTo(_curves[e+0], _curves[e+1],
   773                     io.curveTo(_curves[e],   _curves[e+1],
   617                                _curves[e+2], _curves[e+3],
   774                                _curves[e+2], _curves[e+3],
   618                                _curves[e+4], _curves[e+5]);
   775                                _curves[e+4], _curves[e+5]);
   619                     e += 6;
   776                     e += 6;
   620                     continue;
   777                     continue;
   621                 default:
   778                 default:
   649                     e -= 2;
   806                     e -= 2;
   650                     io.lineTo(_curves[e], _curves[e+1]);
   807                     io.lineTo(_curves[e], _curves[e+1]);
   651                     continue;
   808                     continue;
   652                 case TYPE_QUADTO:
   809                 case TYPE_QUADTO:
   653                     e -= 4;
   810                     e -= 4;
   654                     io.quadTo(_curves[e+0], _curves[e+1],
   811                     io.quadTo(_curves[e],   _curves[e+1],
   655                               _curves[e+2], _curves[e+3]);
   812                               _curves[e+2], _curves[e+3]);
   656                     continue;
   813                     continue;
   657                 case TYPE_CUBICTO:
   814                 case TYPE_CUBICTO:
   658                     e -= 6;
   815                     e -= 6;
   659                     io.curveTo(_curves[e+0], _curves[e+1],
   816                     io.curveTo(_curves[e],   _curves[e+1],
   660                                _curves[e+2], _curves[e+3],
   817                                _curves[e+2], _curves[e+3],
   661                                _curves[e+4], _curves[e+5]);
   818                                _curves[e+4], _curves[e+5]);
   662                     continue;
   819                     continue;
   663                 default:
   820                 default:
   664                 }
   821                 }