src/java.desktop/share/classes/sun/java2d/marlin/DDasher.java
changeset 48284 fd7fbc929001
parent 47216 71c04702a3d5
child 49496 1ea202af7a97
equal deleted inserted replaced
48283:da1b57b17101 48284:fd7fbc929001
   135                     }
   135                     }
   136                     phase += dash[sidx];
   136                     phase += dash[sidx];
   137                     dashOn = !dashOn;
   137                     dashOn = !dashOn;
   138                 }
   138                 }
   139             }
   139             }
   140         } else if (phase > 0) {
   140         } else if (phase > 0.0d) {
   141             if (cycles >= MAX_CYCLES) {
   141             if (cycles >= MAX_CYCLES) {
   142                 phase = 0.0d;
   142                 phase = 0.0d;
   143             } else {
   143             } else {
   144                 int fullcycles = FloatMath.floor_int(cycles);
   144                 int fullcycles = FloatMath.floor_int(cycles);
   145                 if ((fullcycles & dash.length & 1) != 0) {
   145                 if ((fullcycles & dash.length & 1) != 0) {
   155             }
   155             }
   156         }
   156         }
   157 
   157 
   158         this.dash = dash;
   158         this.dash = dash;
   159         this.dashLen = dashLen;
   159         this.dashLen = dashLen;
   160         this.startPhase = this.phase = phase;
   160         this.phase = phase;
       
   161         this.startPhase = phase;
   161         this.startDashOn = dashOn;
   162         this.startDashOn = dashOn;
   162         this.startIdx = sidx;
   163         this.startIdx = sidx;
   163         this.starting = true;
   164         this.starting = true;
   164         needsMoveTo = false;
   165         this.needsMoveTo = false;
   165         firstSegidx = 0;
   166         this.firstSegidx = 0;
   166 
   167 
   167         this.recycleDashes = recycleDashes;
   168         this.recycleDashes = recycleDashes;
   168 
   169 
   169         return this; // fluent API
   170         return this; // fluent API
   170     }
   171     }
   199         for (int i = 0; i < len; i++) { newDashes[i] = dashes[i]; }
   200         for (int i = 0; i < len; i++) { newDashes[i] = dashes[i]; }
   200         return newDashes;
   201         return newDashes;
   201     }
   202     }
   202 
   203 
   203     @Override
   204     @Override
   204     public void moveTo(double x0, double y0) {
   205     public void moveTo(final double x0, final double y0) {
   205         if (firstSegidx > 0) {
   206         if (firstSegidx != 0) {
   206             out.moveTo(sx, sy);
   207             out.moveTo(sx, sy);
   207             emitFirstSegments();
   208             emitFirstSegments();
   208         }
   209         }
   209         needsMoveTo = true;
   210         needsMoveTo = true;
   210         this.idx = startIdx;
   211         this.idx = startIdx;
   211         this.dashOn = this.startDashOn;
   212         this.dashOn = this.startDashOn;
   212         this.phase = this.startPhase;
   213         this.phase = this.startPhase;
   213         this.sx = this.x0 = x0;
   214         this.sx = x0;
   214         this.sy = this.y0 = y0;
   215         this.sy = y0;
       
   216         this.x0 = x0;
       
   217         this.y0 = y0;
   215         this.starting = true;
   218         this.starting = true;
   216     }
   219     }
   217 
   220 
   218     private void emitSeg(double[] buf, int off, int type) {
   221     private void emitSeg(double[] buf, int off, int type) {
   219         switch (type) {
   222         switch (type) {
   234     }
   237     }
   235 
   238 
   236     private void emitFirstSegments() {
   239     private void emitFirstSegments() {
   237         final double[] fSegBuf = firstSegmentsBuffer;
   240         final double[] fSegBuf = firstSegmentsBuffer;
   238 
   241 
   239         for (int i = 0; i < firstSegidx; ) {
   242         for (int i = 0, len = firstSegidx; i < len; ) {
   240             int type = (int)fSegBuf[i];
   243             int type = (int)fSegBuf[i];
   241             emitSeg(fSegBuf, i + 1, type);
   244             emitSeg(fSegBuf, i + 1, type);
   242             i += (type - 1);
   245             i += (type - 1);
   243         }
   246         }
   244         firstSegidx = 0;
   247         firstSegidx = 0;
   249     // buffer below.
   252     // buffer below.
   250     private double[] firstSegmentsBuffer; // dynamic array
   253     private double[] firstSegmentsBuffer; // dynamic array
   251     private int firstSegidx;
   254     private int firstSegidx;
   252 
   255 
   253     // precondition: pts must be in relative coordinates (relative to x0,y0)
   256     // precondition: pts must be in relative coordinates (relative to x0,y0)
   254     private void goTo(double[] pts, int off, final int type) {
   257     private void goTo(final double[] pts, final int off, final int type,
   255         double x = pts[off + type - 4];
   258                       final boolean on)
   256         double y = pts[off + type - 3];
   259     {
   257         if (dashOn) {
   260         final int index = off + type;
       
   261         final double x = pts[index - 4];
       
   262         final double y = pts[index - 3];
       
   263 
       
   264         if (on) {
   258             if (starting) {
   265             if (starting) {
   259                 int len = type - 1; // - 2 + 1
   266                 goTo_starting(pts, off, type);
   260                 int segIdx = firstSegidx;
       
   261                 double[] buf = firstSegmentsBuffer;
       
   262                 if (segIdx + len  > buf.length) {
       
   263                     if (DO_STATS) {
       
   264                         rdrCtx.stats.stat_array_dasher_firstSegmentsBuffer
       
   265                             .add(segIdx + len);
       
   266                     }
       
   267                     firstSegmentsBuffer = buf
       
   268                         = firstSegmentsBuffer_ref.widenArray(buf, segIdx,
       
   269                                                              segIdx + len);
       
   270                 }
       
   271                 buf[segIdx++] = type;
       
   272                 len--;
       
   273                 // small arraycopy (2, 4 or 6) but with offset:
       
   274                 System.arraycopy(pts, off, buf, segIdx, len);
       
   275                 segIdx += len;
       
   276                 firstSegidx = segIdx;
       
   277             } else {
   267             } else {
   278                 if (needsMoveTo) {
   268                 if (needsMoveTo) {
       
   269                     needsMoveTo = false;
   279                     out.moveTo(x0, y0);
   270                     out.moveTo(x0, y0);
   280                     needsMoveTo = false;
       
   281                 }
   271                 }
   282                 emitSeg(pts, off, type);
   272                 emitSeg(pts, off, type);
   283             }
   273             }
   284         } else {
   274         } else {
   285             starting = false;
   275             if (starting) {
       
   276                 // low probability test (hotspot)
       
   277                 starting = false;
       
   278             }
   286             needsMoveTo = true;
   279             needsMoveTo = true;
   287         }
   280         }
   288         this.x0 = x;
   281         this.x0 = x;
   289         this.y0 = y;
   282         this.y0 = y;
   290     }
   283     }
   291 
   284 
       
   285     private void goTo_starting(final double[] pts, final int off, final int type) {
       
   286         int len = type - 1; // - 2 + 1
       
   287         int segIdx = firstSegidx;
       
   288         double[] buf = firstSegmentsBuffer;
       
   289 
       
   290         if (segIdx + len  > buf.length) {
       
   291             if (DO_STATS) {
       
   292                 rdrCtx.stats.stat_array_dasher_firstSegmentsBuffer
       
   293                     .add(segIdx + len);
       
   294             }
       
   295             firstSegmentsBuffer = buf
       
   296                 = firstSegmentsBuffer_ref.widenArray(buf, segIdx,
       
   297                                                      segIdx + len);
       
   298         }
       
   299         buf[segIdx++] = type;
       
   300         len--;
       
   301         // small arraycopy (2, 4 or 6) but with offset:
       
   302         System.arraycopy(pts, off, buf, segIdx, len);
       
   303         firstSegidx = segIdx + len;
       
   304     }
       
   305 
   292     @Override
   306     @Override
   293     public void lineTo(double x1, double y1) {
   307     public void lineTo(final double x1, final double y1) {
   294         double dx = x1 - x0;
   308         final double dx = x1 - x0;
   295         double dy = y1 - y0;
   309         final double dy = y1 - y0;
   296 
   310 
   297         double len = dx*dx + dy*dy;
   311         double len = dx*dx + dy*dy;
   298         if (len == 0.0d) {
   312         if (len == 0.0d) {
   299             return;
   313             return;
   300         }
   314         }
   305         final double cx = dx / len;
   319         final double cx = dx / len;
   306         final double cy = dy / len;
   320         final double cy = dy / len;
   307 
   321 
   308         final double[] _curCurvepts = curCurvepts;
   322         final double[] _curCurvepts = curCurvepts;
   309         final double[] _dash = dash;
   323         final double[] _dash = dash;
       
   324         final int _dashLen = this.dashLen;
       
   325 
       
   326         int _idx = idx;
       
   327         boolean _dashOn = dashOn;
       
   328         double _phase = phase;
   310 
   329 
   311         double leftInThisDashSegment;
   330         double leftInThisDashSegment;
   312         double dashdx, dashdy, p;
   331         double d, dashdx, dashdy, p;
   313 
   332 
   314         while (true) {
   333         while (true) {
   315             leftInThisDashSegment = _dash[idx] - phase;
   334             d = _dash[_idx];
       
   335             leftInThisDashSegment = d - _phase;
   316 
   336 
   317             if (len <= leftInThisDashSegment) {
   337             if (len <= leftInThisDashSegment) {
   318                 _curCurvepts[0] = x1;
   338                 _curCurvepts[0] = x1;
   319                 _curCurvepts[1] = y1;
   339                 _curCurvepts[1] = y1;
   320                 goTo(_curCurvepts, 0, 4);
   340 
       
   341                 goTo(_curCurvepts, 0, 4, _dashOn);
   321 
   342 
   322                 // Advance phase within current dash segment
   343                 // Advance phase within current dash segment
   323                 phase += len;
   344                 _phase += len;
       
   345 
   324                 // TODO: compare double values using epsilon:
   346                 // TODO: compare double values using epsilon:
   325                 if (len == leftInThisDashSegment) {
   347                 if (len == leftInThisDashSegment) {
   326                     phase = 0.0d;
   348                     _phase = 0.0d;
   327                     idx = (idx + 1) % dashLen;
   349                     _idx = (_idx + 1) % _dashLen;
   328                     dashOn = !dashOn;
   350                     _dashOn = !_dashOn;
   329                 }
   351                 }
       
   352 
       
   353                 // Save local state:
       
   354                 idx = _idx;
       
   355                 dashOn = _dashOn;
       
   356                 phase = _phase;
   330                 return;
   357                 return;
   331             }
   358             }
   332 
   359 
   333             dashdx = _dash[idx] * cx;
   360             dashdx = d * cx;
   334             dashdy = _dash[idx] * cy;
   361             dashdy = d * cy;
   335 
   362 
   336             if (phase == 0.0d) {
   363             if (_phase == 0.0d) {
   337                 _curCurvepts[0] = x0 + dashdx;
   364                 _curCurvepts[0] = x0 + dashdx;
   338                 _curCurvepts[1] = y0 + dashdy;
   365                 _curCurvepts[1] = y0 + dashdy;
   339             } else {
   366             } else {
   340                 p = leftInThisDashSegment / _dash[idx];
   367                 p = leftInThisDashSegment / d;
   341                 _curCurvepts[0] = x0 + p * dashdx;
   368                 _curCurvepts[0] = x0 + p * dashdx;
   342                 _curCurvepts[1] = y0 + p * dashdy;
   369                 _curCurvepts[1] = y0 + p * dashdy;
   343             }
   370             }
   344 
   371 
   345             goTo(_curCurvepts, 0, 4);
   372             goTo(_curCurvepts, 0, 4, _dashOn);
   346 
   373 
   347             len -= leftInThisDashSegment;
   374             len -= leftInThisDashSegment;
   348             // Advance to next dash segment
   375             // Advance to next dash segment
   349             idx = (idx + 1) % dashLen;
   376             _idx = (_idx + 1) % _dashLen;
   350             dashOn = !dashOn;
   377             _dashOn = !_dashOn;
   351             phase = 0.0d;
   378             _phase = 0.0d;
   352         }
   379         }
   353     }
   380     }
   354 
   381 
   355     // shared instance in DDasher
   382     // shared instance in DDasher
   356     private final LengthIterator li = new LengthIterator();
   383     private final LengthIterator li = new LengthIterator();
   357 
   384 
   358     // preconditions: curCurvepts must be an array of length at least 2 * type,
   385     // preconditions: curCurvepts must be an array of length at least 2 * type,
   359     // that contains the curve we want to dash in the first type elements
   386     // that contains the curve we want to dash in the first type elements
   360     private void somethingTo(int type) {
   387     private void somethingTo(final int type) {
   361         if (pointCurve(curCurvepts, type)) {
   388         if (pointCurve(curCurvepts, type)) {
   362             return;
   389             return;
   363         }
   390         }
   364         li.initializeIterationOnCurve(curCurvepts, type);
   391         final LengthIterator _li = li;
       
   392         final double[] _curCurvepts = curCurvepts;
       
   393         final double[] _dash = dash;
       
   394         final int _dashLen = this.dashLen;
       
   395 
       
   396         _li.initializeIterationOnCurve(_curCurvepts, type);
       
   397 
       
   398         int _idx = idx;
       
   399         boolean _dashOn = dashOn;
       
   400         double _phase = phase;
   365 
   401 
   366         // initially the current curve is at curCurvepts[0...type]
   402         // initially the current curve is at curCurvepts[0...type]
   367         int curCurveoff = 0;
   403         int curCurveoff = 0;
   368         double lastSplitT = 0.0d;
   404         double lastSplitT = 0.0d;
   369         double t;
   405         double t;
   370         double leftInThisDashSegment = dash[idx] - phase;
   406         double leftInThisDashSegment = _dash[_idx] - _phase;
   371 
   407 
   372         while ((t = li.next(leftInThisDashSegment)) < 1.0d) {
   408         while ((t = _li.next(leftInThisDashSegment)) < 1.0d) {
   373             if (t != 0.0d) {
   409             if (t != 0.0d) {
   374                 DHelpers.subdivideAt((t - lastSplitT) / (1.0d - lastSplitT),
   410                 DHelpers.subdivideAt((t - lastSplitT) / (1.0d - lastSplitT),
   375                                     curCurvepts, curCurveoff,
   411                                     _curCurvepts, curCurveoff,
   376                                     curCurvepts, 0,
   412                                     _curCurvepts, 0,
   377                                     curCurvepts, type, type);
   413                                     _curCurvepts, type, type);
   378                 lastSplitT = t;
   414                 lastSplitT = t;
   379                 goTo(curCurvepts, 2, type);
   415                 goTo(_curCurvepts, 2, type, _dashOn);
   380                 curCurveoff = type;
   416                 curCurveoff = type;
   381             }
   417             }
   382             // Advance to next dash segment
   418             // Advance to next dash segment
   383             idx = (idx + 1) % dashLen;
   419             _idx = (_idx + 1) % _dashLen;
   384             dashOn = !dashOn;
   420             _dashOn = !_dashOn;
   385             phase = 0.0d;
   421             _phase = 0.0d;
   386             leftInThisDashSegment = dash[idx];
   422             leftInThisDashSegment = _dash[_idx];
   387         }
   423         }
   388         goTo(curCurvepts, curCurveoff+2, type);
   424 
   389         phase += li.lastSegLen();
   425         goTo(_curCurvepts, curCurveoff + 2, type, _dashOn);
   390         if (phase >= dash[idx]) {
   426 
   391             phase = 0.0d;
   427         _phase += _li.lastSegLen();
   392             idx = (idx + 1) % dashLen;
   428         if (_phase >= _dash[_idx]) {
   393             dashOn = !dashOn;
   429             _phase = 0.0d;
   394         }
   430             _idx = (_idx + 1) % _dashLen;
       
   431             _dashOn = !_dashOn;
       
   432         }
       
   433         // Save local state:
       
   434         idx = _idx;
       
   435         dashOn = _dashOn;
       
   436         phase = _phase;
       
   437 
   395         // reset LengthIterator:
   438         // reset LengthIterator:
   396         li.reset();
   439         _li.reset();
   397     }
   440     }
   398 
   441 
   399     private static boolean pointCurve(double[] curve, int type) {
   442     private static boolean pointCurve(double[] curve, int type) {
   400         for (int i = 2; i < type; i++) {
   443         for (int i = 2; i < type; i++) {
   401             if (curve[i] != curve[i-2]) {
   444             if (curve[i] != curve[i-2]) {
   417     // limit+1 curves - one for each level of the tree + 1.
   460     // limit+1 curves - one for each level of the tree + 1.
   418     // NOTE: the way we do things here is not enough to traverse a general
   461     // NOTE: the way we do things here is not enough to traverse a general
   419     // tree; however, the trees we are interested in have the property that
   462     // tree; however, the trees we are interested in have the property that
   420     // every non leaf node has exactly 2 children
   463     // every non leaf node has exactly 2 children
   421     static final class LengthIterator {
   464     static final class LengthIterator {
   422         private enum Side {LEFT, RIGHT};
   465         private enum Side {LEFT, RIGHT}
   423         // Holds the curves at various levels of the recursion. The root
   466         // Holds the curves at various levels of the recursion. The root
   424         // (i.e. the original curve) is at recCurveStack[0] (but then it
   467         // (i.e. the original curve) is at recCurveStack[0] (but then it
   425         // gets subdivided, the left half is put at 1, so most of the time
   468         // gets subdivided, the left half is put at 1, so most of the time
   426         // only the right half of the original curve is at 0)
   469         // only the right half of the original curve is at 0)
   427         private final double[][] recCurveStack; // dirty
   470         private final double[][] recCurveStack; // dirty
   667         }
   710         }
   668 
   711 
   669         // this is a bit of a hack. It returns -1 if we're not on a leaf, and
   712         // this is a bit of a hack. It returns -1 if we're not on a leaf, and
   670         // the length of the leaf if we are on a leaf.
   713         // the length of the leaf if we are on a leaf.
   671         private double onLeaf() {
   714         private double onLeaf() {
   672             double[] curve = recCurveStack[recLevel];
   715             final double[] curve = recCurveStack[recLevel];
       
   716             final int _curveType = curveType;
   673             double polyLen = 0.0d;
   717             double polyLen = 0.0d;
   674 
   718 
   675             double x0 = curve[0], y0 = curve[1];
   719             double x0 = curve[0], y0 = curve[1];
   676             for (int i = 2; i < curveType; i += 2) {
   720             for (int i = 2; i < _curveType; i += 2) {
   677                 final double x1 = curve[i], y1 = curve[i+1];
   721                 final double x1 = curve[i], y1 = curve[i+1];
   678                 final double len = DHelpers.linelen(x0, y0, x1, y1);
   722                 final double len = DHelpers.linelen(x0, y0, x1, y1);
   679                 polyLen += len;
   723                 polyLen += len;
   680                 curLeafCtrlPolyLengths[i/2 - 1] = len;
   724                 curLeafCtrlPolyLengths[(i >> 1) - 1] = len;
   681                 x0 = x1;
   725                 x0 = x1;
   682                 y0 = y1;
   726                 y0 = y1;
   683             }
   727             }
   684 
   728 
   685             final double lineLen = DHelpers.linelen(curve[0], curve[1],
   729             final double lineLen = DHelpers.linelen(curve[0], curve[1],
   686                                                   curve[curveType-2],
   730                                                     curve[_curveType-2],
   687                                                   curve[curveType-1]);
   731                                                     curve[_curveType-1]);
   688             if ((polyLen - lineLen) < ERR || recLevel == REC_LIMIT) {
   732             if ((polyLen - lineLen) < ERR || recLevel == REC_LIMIT) {
   689                 return (polyLen + lineLen) / 2.0d;
   733                 return (polyLen + lineLen) / 2.0d;
   690             }
   734             }
   691             return -1.0d;
   735             return -1.0d;
   692         }
   736         }
   693     }
   737     }
   694 
   738 
   695     @Override
   739     @Override
   696     public void curveTo(double x1, double y1,
   740     public void curveTo(final double x1, final double y1,
   697                         double x2, double y2,
   741                         final double x2, final double y2,
   698                         double x3, double y3)
   742                         final double x3, final double y3)
   699     {
   743     {
   700         final double[] _curCurvepts = curCurvepts;
   744         final double[] _curCurvepts = curCurvepts;
   701         _curCurvepts[0] = x0;        _curCurvepts[1] = y0;
   745         _curCurvepts[0] = x0;        _curCurvepts[1] = y0;
   702         _curCurvepts[2] = x1;        _curCurvepts[3] = y1;
   746         _curCurvepts[2] = x1;        _curCurvepts[3] = y1;
   703         _curCurvepts[4] = x2;        _curCurvepts[5] = y2;
   747         _curCurvepts[4] = x2;        _curCurvepts[5] = y2;
   704         _curCurvepts[6] = x3;        _curCurvepts[7] = y3;
   748         _curCurvepts[6] = x3;        _curCurvepts[7] = y3;
   705         somethingTo(8);
   749         somethingTo(8);
   706     }
   750     }
   707 
   751 
   708     @Override
   752     @Override
   709     public void quadTo(double x1, double y1, double x2, double y2) {
   753     public void quadTo(final double x1, final double y1,
       
   754                        final double x2, final double y2)
       
   755     {
   710         final double[] _curCurvepts = curCurvepts;
   756         final double[] _curCurvepts = curCurvepts;
   711         _curCurvepts[0] = x0;        _curCurvepts[1] = y0;
   757         _curCurvepts[0] = x0;        _curCurvepts[1] = y0;
   712         _curCurvepts[2] = x1;        _curCurvepts[3] = y1;
   758         _curCurvepts[2] = x1;        _curCurvepts[3] = y1;
   713         _curCurvepts[4] = x2;        _curCurvepts[5] = y2;
   759         _curCurvepts[4] = x2;        _curCurvepts[5] = y2;
   714         somethingTo(6);
   760         somethingTo(6);
   715     }
   761     }
   716 
   762 
   717     @Override
   763     @Override
   718     public void closePath() {
   764     public void closePath() {
   719         lineTo(sx, sy);
   765         lineTo(sx, sy);
   720         if (firstSegidx > 0) {
   766         if (firstSegidx != 0) {
   721             if (!dashOn || needsMoveTo) {
   767             if (!dashOn || needsMoveTo) {
   722                 out.moveTo(sx, sy);
   768                 out.moveTo(sx, sy);
   723             }
   769             }
   724             emitFirstSegments();
   770             emitFirstSegments();
   725         }
   771         }
   726         moveTo(sx, sy);
   772         moveTo(sx, sy);
   727     }
   773     }
   728 
   774 
   729     @Override
   775     @Override
   730     public void pathDone() {
   776     public void pathDone() {
   731         if (firstSegidx > 0) {
   777         if (firstSegidx != 0) {
   732             out.moveTo(sx, sy);
   778             out.moveTo(sx, sy);
   733             emitFirstSegments();
   779             emitFirstSegments();
   734         }
   780         }
   735         out.pathDone();
   781         out.pathDone();
   736 
   782