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.marlin;
27
28 import java.awt.geom.AffineTransform;
29 import java.awt.geom.Path2D;
30
31 final class DTransformingPathConsumer2D {
32
33 DTransformingPathConsumer2D() {
34 // used by DRendererContext
35 }
36
37 // recycled DPathConsumer2D instance from wrapPath2d()
38 private final Path2DWrapper wp_Path2DWrapper = new Path2DWrapper();
39
40 DPathConsumer2D wrapPath2d(Path2D.Double p2d)
41 {
42 return wp_Path2DWrapper.init(p2d);
43 }
44
45 // recycled DPathConsumer2D instances from deltaTransformConsumer()
46 private final DeltaScaleFilter dt_DeltaScaleFilter = new DeltaScaleFilter();
47 private final DeltaTransformFilter dt_DeltaTransformFilter = new DeltaTransformFilter();
48
49 DPathConsumer2D deltaTransformConsumer(DPathConsumer2D out,
50 AffineTransform at)
51 {
52 if (at == null) {
53 return out;
54 }
55 double mxx = at.getScaleX();
56 double mxy = at.getShearX();
57 double myx = at.getShearY();
58 double myy = at.getScaleY();
59
60 if (mxy == 0.0d && myx == 0.0d) {
61 if (mxx == 1.0d && myy == 1.0d) {
62 return out;
63 } else {
64 return dt_DeltaScaleFilter.init(out, mxx, myy);
65 }
66 } else {
67 return dt_DeltaTransformFilter.init(out, mxx, mxy, myx, myy);
68 }
69 }
70
71 // recycled DPathConsumer2D instances from inverseDeltaTransformConsumer()
72 private final DeltaScaleFilter iv_DeltaScaleFilter = new DeltaScaleFilter();
73 private final DeltaTransformFilter iv_DeltaTransformFilter = new DeltaTransformFilter();
74
75 DPathConsumer2D inverseDeltaTransformConsumer(DPathConsumer2D out,
76 AffineTransform at)
77 {
78 if (at == null) {
79 return out;
80 }
81 double mxx = at.getScaleX();
82 double mxy = at.getShearX();
83 double myx = at.getShearY();
84 double myy = at.getScaleY();
85
86 if (mxy == 0.0d && myx == 0.0d) {
87 if (mxx == 1.0d && myy == 1.0d) {
88 return out;
89 } else {
90 return iv_DeltaScaleFilter.init(out, 1.0d/mxx, 1.0d/myy);
91 }
92 } else {
93 double det = mxx * myy - mxy * myx;
94 return iv_DeltaTransformFilter.init(out,
95 myy / det,
96 -mxy / det,
97 -myx / det,
98 mxx / det);
99 }
100 }
101
102
103 static final class DeltaScaleFilter implements DPathConsumer2D {
104 private DPathConsumer2D out;
105 private double sx, sy;
106
107 DeltaScaleFilter() {}
108
109 DeltaScaleFilter init(DPathConsumer2D out,
110 double mxx, double myy)
111 {
112 this.out = out;
113 sx = mxx;
114 sy = myy;
115 return this; // fluent API
116 }
117
118 @Override
119 public void moveTo(double x0, double y0) {
120 out.moveTo(x0 * sx, y0 * sy);
121 }
122
250
251 @Override
252 public void closePath() {
253 p2d.closePath();
254 }
255
256 @Override
257 public void pathDone() {}
258
259 @Override
260 public void curveTo(double x1, double y1,
261 double x2, double y2,
262 double x3, double y3)
263 {
264 p2d.curveTo(x1, y1, x2, y2, x3, y3);
265 }
266
267 @Override
268 public void quadTo(double x1, double y1, double x2, double y2) {
269 p2d.quadTo(x1, y1, x2, y2);
270 }
271
272 @Override
273 public long getNativeConsumer() {
274 throw new InternalError("Not using a native peer");
275 }
276 }
277 }
|
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.marlin;
27
28 import java.awt.geom.AffineTransform;
29 import java.awt.geom.Path2D;
30 import sun.java2d.marlin.DHelpers.IndexStack;
31 import sun.java2d.marlin.DHelpers.PolyStack;
32
33 final class DTransformingPathConsumer2D {
34
35 private final DRendererContext rdrCtx;
36
37 // recycled ClosedPathDetector instance from detectClosedPath()
38 private final ClosedPathDetector cpDetector;
39
40 // recycled PathClipFilter instance from pathClipper()
41 private final PathClipFilter pathClipper;
42
43 // recycled DPathConsumer2D instance from wrapPath2D()
44 private final Path2DWrapper wp_Path2DWrapper = new Path2DWrapper();
45
46 // recycled DPathConsumer2D instances from deltaTransformConsumer()
47 private final DeltaScaleFilter dt_DeltaScaleFilter = new DeltaScaleFilter();
48 private final DeltaTransformFilter dt_DeltaTransformFilter = new DeltaTransformFilter();
49
50 // recycled DPathConsumer2D instances from inverseDeltaTransformConsumer()
51 private final DeltaScaleFilter iv_DeltaScaleFilter = new DeltaScaleFilter();
52 private final DeltaTransformFilter iv_DeltaTransformFilter = new DeltaTransformFilter();
53
54 // recycled PathTracer instances from tracer...() methods
55 private final PathTracer tracerInput = new PathTracer("[Input]");
56 private final PathTracer tracerCPDetector = new PathTracer("ClosedPathDetector");
57 private final PathTracer tracerFiller = new PathTracer("Filler");
58 private final PathTracer tracerStroker = new PathTracer("Stroker");
59
60 DTransformingPathConsumer2D(final DRendererContext rdrCtx) {
61 // used by RendererContext
62 this.rdrCtx = rdrCtx;
63 this.cpDetector = new ClosedPathDetector(rdrCtx);
64 this.pathClipper = new PathClipFilter(rdrCtx);
65 }
66
67 DPathConsumer2D wrapPath2D(Path2D.Double p2d) {
68 return wp_Path2DWrapper.init(p2d);
69 }
70
71 DPathConsumer2D traceInput(DPathConsumer2D out) {
72 return tracerInput.init(out);
73 }
74
75 DPathConsumer2D traceClosedPathDetector(DPathConsumer2D out) {
76 return tracerCPDetector.init(out);
77 }
78
79 DPathConsumer2D traceFiller(DPathConsumer2D out) {
80 return tracerFiller.init(out);
81 }
82
83 DPathConsumer2D traceStroker(DPathConsumer2D out) {
84 return tracerStroker.init(out);
85 }
86
87 DPathConsumer2D detectClosedPath(DPathConsumer2D out) {
88 return cpDetector.init(out);
89 }
90
91 DPathConsumer2D pathClipper(DPathConsumer2D out) {
92 return pathClipper.init(out);
93 }
94
95 DPathConsumer2D deltaTransformConsumer(DPathConsumer2D out,
96 AffineTransform at)
97 {
98 if (at == null) {
99 return out;
100 }
101 final double mxx = at.getScaleX();
102 final double mxy = at.getShearX();
103 final double myx = at.getShearY();
104 final double myy = at.getScaleY();
105
106 if (mxy == 0.0d && myx == 0.0d) {
107 if (mxx == 1.0d && myy == 1.0d) {
108 return out;
109 } else {
110 // Scale only
111 if (rdrCtx.doClip) {
112 // adjust clip rectangle (ymin, ymax, xmin, xmax):
113 adjustClipScale(rdrCtx.clipRect, mxx, myy);
114 }
115 return dt_DeltaScaleFilter.init(out, mxx, myy);
116 }
117 } else {
118 if (rdrCtx.doClip) {
119 // adjust clip rectangle (ymin, ymax, xmin, xmax):
120 adjustClipInverseDelta(rdrCtx.clipRect, mxx, mxy, myx, myy);
121 }
122 return dt_DeltaTransformFilter.init(out, mxx, mxy, myx, myy);
123 }
124 }
125
126 private static void adjustClipOffset(final double[] clipRect) {
127 clipRect[0] += Renderer.RDR_OFFSET_Y;
128 clipRect[1] += Renderer.RDR_OFFSET_Y;
129 clipRect[2] += Renderer.RDR_OFFSET_X;
130 clipRect[3] += Renderer.RDR_OFFSET_X;
131 }
132
133 private static void adjustClipScale(final double[] clipRect,
134 final double mxx, final double myy)
135 {
136 adjustClipOffset(clipRect);
137
138 // Adjust the clipping rectangle (iv_DeltaScaleFilter):
139 clipRect[0] /= myy;
140 clipRect[1] /= myy;
141 clipRect[2] /= mxx;
142 clipRect[3] /= mxx;
143 }
144
145 private static void adjustClipInverseDelta(final double[] clipRect,
146 final double mxx, final double mxy,
147 final double myx, final double myy)
148 {
149 adjustClipOffset(clipRect);
150
151 // Adjust the clipping rectangle (iv_DeltaTransformFilter):
152 final double det = mxx * myy - mxy * myx;
153 final double imxx = myy / det;
154 final double imxy = -mxy / det;
155 final double imyx = -myx / det;
156 final double imyy = mxx / det;
157
158 double xmin, xmax, ymin, ymax;
159 double x, y;
160 // xmin, ymin:
161 x = clipRect[2] * imxx + clipRect[0] * imxy;
162 y = clipRect[2] * imyx + clipRect[0] * imyy;
163
164 xmin = xmax = x;
165 ymin = ymax = y;
166
167 // xmax, ymin:
168 x = clipRect[3] * imxx + clipRect[0] * imxy;
169 y = clipRect[3] * imyx + clipRect[0] * imyy;
170
171 if (x < xmin) { xmin = x; } else if (x > xmax) { xmax = x; }
172 if (y < ymin) { ymin = y; } else if (y > ymax) { ymax = y; }
173
174 // xmin, ymax:
175 x = clipRect[2] * imxx + clipRect[1] * imxy;
176 y = clipRect[2] * imyx + clipRect[1] * imyy;
177
178 if (x < xmin) { xmin = x; } else if (x > xmax) { xmax = x; }
179 if (y < ymin) { ymin = y; } else if (y > ymax) { ymax = y; }
180
181 // xmax, ymax:
182 x = clipRect[3] * imxx + clipRect[1] * imxy;
183 y = clipRect[3] * imyx + clipRect[1] * imyy;
184
185 if (x < xmin) { xmin = x; } else if (x > xmax) { xmax = x; }
186 if (y < ymin) { ymin = y; } else if (y > ymax) { ymax = y; }
187
188 clipRect[0] = ymin;
189 clipRect[1] = ymax;
190 clipRect[2] = xmin;
191 clipRect[3] = xmax;
192 }
193
194 DPathConsumer2D inverseDeltaTransformConsumer(DPathConsumer2D out,
195 AffineTransform at)
196 {
197 if (at == null) {
198 return out;
199 }
200 double mxx = at.getScaleX();
201 double mxy = at.getShearX();
202 double myx = at.getShearY();
203 double myy = at.getScaleY();
204
205 if (mxy == 0.0d && myx == 0.0d) {
206 if (mxx == 1.0d && myy == 1.0d) {
207 return out;
208 } else {
209 return iv_DeltaScaleFilter.init(out, 1.0d/mxx, 1.0d/myy);
210 }
211 } else {
212 final double det = mxx * myy - mxy * myx;
213 return iv_DeltaTransformFilter.init(out,
214 myy / det,
215 -mxy / det,
216 -myx / det,
217 mxx / det);
218 }
219 }
220
221 static final class DeltaScaleFilter implements DPathConsumer2D {
222 private DPathConsumer2D out;
223 private double sx, sy;
224
225 DeltaScaleFilter() {}
226
227 DeltaScaleFilter init(DPathConsumer2D out,
228 double mxx, double myy)
229 {
230 this.out = out;
231 sx = mxx;
232 sy = myy;
233 return this; // fluent API
234 }
235
236 @Override
237 public void moveTo(double x0, double y0) {
238 out.moveTo(x0 * sx, y0 * sy);
239 }
240
368
369 @Override
370 public void closePath() {
371 p2d.closePath();
372 }
373
374 @Override
375 public void pathDone() {}
376
377 @Override
378 public void curveTo(double x1, double y1,
379 double x2, double y2,
380 double x3, double y3)
381 {
382 p2d.curveTo(x1, y1, x2, y2, x3, y3);
383 }
384
385 @Override
386 public void quadTo(double x1, double y1, double x2, double y2) {
387 p2d.quadTo(x1, y1, x2, y2);
388 }
389
390 @Override
391 public long getNativeConsumer() {
392 throw new InternalError("Not using a native peer");
393 }
394 }
395
396 static final class ClosedPathDetector implements DPathConsumer2D {
397
398 private final DRendererContext rdrCtx;
399 private final PolyStack stack;
400
401 private DPathConsumer2D out;
402
403 ClosedPathDetector(final DRendererContext rdrCtx) {
404 this.rdrCtx = rdrCtx;
405 this.stack = (rdrCtx.stats != null) ?
406 new PolyStack(rdrCtx,
407 rdrCtx.stats.stat_cpd_polystack_types,
408 rdrCtx.stats.stat_cpd_polystack_curves,
409 rdrCtx.stats.hist_cpd_polystack_curves,
410 rdrCtx.stats.stat_array_cpd_polystack_curves,
411 rdrCtx.stats.stat_array_cpd_polystack_types)
412 : new PolyStack(rdrCtx);
413 }
414
415 ClosedPathDetector init(DPathConsumer2D out) {
416 this.out = out;
417 return this; // fluent API
418 }
419
420 /**
421 * Disposes this instance:
422 * clean up before reusing this instance
423 */
424 void dispose() {
425 stack.dispose();
426 }
427
428 @Override
429 public void pathDone() {
430 // previous path is not closed:
431 finish(false);
432 out.pathDone();
433
434 // TODO: fix possible leak if exception happened
435 // Dispose this instance:
436 dispose();
437 }
438
439 @Override
440 public void closePath() {
441 // path is closed
442 finish(true);
443 out.closePath();
444 }
445
446 @Override
447 public void moveTo(double x0, double y0) {
448 // previous path is not closed:
449 finish(false);
450 out.moveTo(x0, y0);
451 }
452
453 private void finish(final boolean closed) {
454 rdrCtx.closedPath = closed;
455 stack.pullAll(out);
456 }
457
458 @Override
459 public void lineTo(double x1, double y1) {
460 stack.pushLine(x1, y1);
461 }
462
463 @Override
464 public void curveTo(double x3, double y3,
465 double x2, double y2,
466 double x1, double y1)
467 {
468 stack.pushCubic(x1, y1, x2, y2, x3, y3);
469 }
470
471 @Override
472 public void quadTo(double x2, double y2, double x1, double y1) {
473 stack.pushQuad(x1, y1, x2, y2);
474 }
475
476 @Override
477 public long getNativeConsumer() {
478 throw new InternalError("Not using a native peer");
479 }
480 }
481
482 static final class PathClipFilter implements DPathConsumer2D {
483
484 private DPathConsumer2D out;
485
486 // Bounds of the drawing region, at pixel precision.
487 private final double[] clipRect;
488
489 private final double[] corners = new double[8];
490 private boolean init_corners = false;
491
492 private final IndexStack stack;
493
494 // the current outcode of the current sub path
495 private int cOutCode = 0;
496
497 // the cumulated (and) outcode of the complete path
498 private int gOutCode = MarlinConst.OUTCODE_MASK_T_B_L_R;
499
500 private boolean outside = false;
501
502 // The current point OUTSIDE
503 private double cx0, cy0;
504
505 PathClipFilter(final DRendererContext rdrCtx) {
506 this.clipRect = rdrCtx.clipRect;
507 this.stack = (rdrCtx.stats != null) ?
508 new IndexStack(rdrCtx,
509 rdrCtx.stats.stat_pcf_idxstack_indices,
510 rdrCtx.stats.hist_pcf_idxstack_indices,
511 rdrCtx.stats.stat_array_pcf_idxstack_indices)
512 : new IndexStack(rdrCtx);
513 }
514
515 PathClipFilter init(final DPathConsumer2D out) {
516 this.out = out;
517
518 // Adjust the clipping rectangle with the renderer offsets
519 final double rdrOffX = DRenderer.RDR_OFFSET_X;
520 final double rdrOffY = DRenderer.RDR_OFFSET_Y;
521
522 // add a small rounding error:
523 final double margin = 1e-3d;
524
525 final double[] _clipRect = this.clipRect;
526 _clipRect[0] -= margin - rdrOffY;
527 _clipRect[1] += margin + rdrOffY;
528 _clipRect[2] -= margin - rdrOffX;
529 _clipRect[3] += margin + rdrOffX;
530
531 this.init_corners = true;
532 this.gOutCode = MarlinConst.OUTCODE_MASK_T_B_L_R;
533
534 return this; // fluent API
535 }
536
537 /**
538 * Disposes this instance:
539 * clean up before reusing this instance
540 */
541 void dispose() {
542 stack.dispose();
543 }
544
545 private void finishPath() {
546 if (outside) {
547 // criteria: inside or totally outside ?
548 if (gOutCode == 0) {
549 finish();
550 } else {
551 this.outside = false;
552 stack.reset();
553 }
554 }
555 }
556
557 private void finish() {
558 this.outside = false;
559
560 if (!stack.isEmpty()) {
561 if (init_corners) {
562 init_corners = false;
563
564 final double[] _corners = corners;
565 final double[] _clipRect = clipRect;
566 // Top Left (0):
567 _corners[0] = _clipRect[2];
568 _corners[1] = _clipRect[0];
569 // Bottom Left (1):
570 _corners[2] = _clipRect[2];
571 _corners[3] = _clipRect[1];
572 // Top right (2):
573 _corners[4] = _clipRect[3];
574 _corners[5] = _clipRect[0];
575 // Bottom Right (3):
576 _corners[6] = _clipRect[3];
577 _corners[7] = _clipRect[1];
578 }
579 stack.pullAll(corners, out);
580 }
581 out.lineTo(cx0, cy0);
582 }
583
584 @Override
585 public void pathDone() {
586 finishPath();
587
588 out.pathDone();
589
590 // TODO: fix possible leak if exception happened
591 // Dispose this instance:
592 dispose();
593 }
594
595 @Override
596 public void closePath() {
597 finishPath();
598
599 out.closePath();
600 }
601
602 @Override
603 public void moveTo(final double x0, final double y0) {
604 finishPath();
605
606 final int outcode = DHelpers.outcode(x0, y0, clipRect);
607 this.cOutCode = outcode;
608 this.outside = false;
609 out.moveTo(x0, y0);
610 }
611
612 @Override
613 public void lineTo(final double xe, final double ye) {
614 final int outcode0 = this.cOutCode;
615 final int outcode1 = DHelpers.outcode(xe, ye, clipRect);
616 this.cOutCode = outcode1;
617
618 final int sideCode = (outcode0 & outcode1);
619
620 // basic rejection criteria:
621 if (sideCode == 0) {
622 this.gOutCode = 0;
623 } else {
624 this.gOutCode &= sideCode;
625 // keep last point coordinate before entering the clip again:
626 this.outside = true;
627 this.cx0 = xe;
628 this.cy0 = ye;
629
630 clip(sideCode, outcode0, outcode1);
631 return;
632 }
633 if (outside) {
634 finish();
635 }
636 // clipping disabled:
637 out.lineTo(xe, ye);
638 }
639
640 private void clip(final int sideCode,
641 final int outcode0,
642 final int outcode1)
643 {
644 // corner or cross-boundary on left or right side:
645 if ((outcode0 != outcode1)
646 && ((sideCode & MarlinConst.OUTCODE_MASK_L_R) != 0))
647 {
648 // combine outcodes:
649 final int mergeCode = (outcode0 | outcode1);
650 final int tbCode = mergeCode & MarlinConst.OUTCODE_MASK_T_B;
651 final int lrCode = mergeCode & MarlinConst.OUTCODE_MASK_L_R;
652 final int off = (lrCode == MarlinConst.OUTCODE_LEFT) ? 0 : 2;
653
654 // add corners to outside stack:
655 switch (tbCode) {
656 case MarlinConst.OUTCODE_TOP:
657 // System.out.println("TOP "+ ((off == 0) ? "LEFT" : "RIGHT"));
658 stack.push(off); // top
659 return;
660 case MarlinConst.OUTCODE_BOTTOM:
661 // System.out.println("BOTTOM "+ ((off == 0) ? "LEFT" : "RIGHT"));
662 stack.push(off + 1); // bottom
663 return;
664 default:
665 // both TOP / BOTTOM:
666 if ((outcode0 & MarlinConst.OUTCODE_TOP) != 0) {
667 // System.out.println("TOP + BOTTOM "+ ((off == 0) ? "LEFT" : "RIGHT"));
668 // top to bottom
669 stack.push(off); // top
670 stack.push(off + 1); // bottom
671 } else {
672 // System.out.println("BOTTOM + TOP "+ ((off == 0) ? "LEFT" : "RIGHT"));
673 // bottom to top
674 stack.push(off + 1); // bottom
675 stack.push(off); // top
676 }
677 }
678 }
679 }
680
681 @Override
682 public void curveTo(final double x1, final double y1,
683 final double x2, final double y2,
684 final double xe, final double ye)
685 {
686 final int outcode0 = this.cOutCode;
687 final int outcode3 = DHelpers.outcode(xe, ye, clipRect);
688 this.cOutCode = outcode3;
689
690 int sideCode = outcode0 & outcode3;
691
692 if (sideCode == 0) {
693 this.gOutCode = 0;
694 } else {
695 sideCode &= DHelpers.outcode(x1, y1, clipRect);
696 sideCode &= DHelpers.outcode(x2, y2, clipRect);
697 this.gOutCode &= sideCode;
698
699 // basic rejection criteria:
700 if (sideCode != 0) {
701 // keep last point coordinate before entering the clip again:
702 this.outside = true;
703 this.cx0 = xe;
704 this.cy0 = ye;
705
706 clip(sideCode, outcode0, outcode3);
707 return;
708 }
709 }
710 if (outside) {
711 finish();
712 }
713 // clipping disabled:
714 out.curveTo(x1, y1, x2, y2, xe, ye);
715 }
716
717 @Override
718 public void quadTo(final double x1, final double y1,
719 final double xe, final double ye)
720 {
721 final int outcode0 = this.cOutCode;
722 final int outcode2 = DHelpers.outcode(xe, ye, clipRect);
723 this.cOutCode = outcode2;
724
725 int sideCode = outcode0 & outcode2;
726
727 if (sideCode == 0) {
728 this.gOutCode = 0;
729 } else {
730 sideCode &= DHelpers.outcode(x1, y1, clipRect);
731 this.gOutCode &= sideCode;
732
733 // basic rejection criteria:
734 if (sideCode != 0) {
735 // keep last point coordinate before entering the clip again:
736 this.outside = true;
737 this.cx0 = xe;
738 this.cy0 = ye;
739
740 clip(sideCode, outcode0, outcode2);
741 return;
742 }
743 }
744 if (outside) {
745 finish();
746 }
747 // clipping disabled:
748 out.quadTo(x1, y1, xe, ye);
749 }
750
751 @Override
752 public long getNativeConsumer() {
753 throw new InternalError("Not using a native peer");
754 }
755 }
756
757 static final class PathTracer implements DPathConsumer2D {
758 private final String prefix;
759 private DPathConsumer2D out;
760
761 PathTracer(String name) {
762 this.prefix = name + ": ";
763 }
764
765 PathTracer init(DPathConsumer2D out) {
766 this.out = out;
767 return this; // fluent API
768 }
769
770 @Override
771 public void moveTo(double x0, double y0) {
772 log("moveTo (" + x0 + ", " + y0 + ')');
773 out.moveTo(x0, y0);
774 }
775
776 @Override
777 public void lineTo(double x1, double y1) {
778 log("lineTo (" + x1 + ", " + y1 + ')');
779 out.lineTo(x1, y1);
780 }
781
782 @Override
783 public void curveTo(double x1, double y1,
784 double x2, double y2,
785 double x3, double y3)
786 {
787 log("curveTo P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2 + ") P3(" + x3 + ", " + y3 + ')');
788 out.curveTo(x1, y1, x2, y2, x3, y3);
789 }
790
791 @Override
792 public void quadTo(double x1, double y1, double x2, double y2) {
793 log("quadTo P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2 + ')');
794 out.quadTo(x1, y1, x2, y2);
795 }
796
797 @Override
798 public void closePath() {
799 log("closePath");
800 out.closePath();
801 }
802
803 @Override
804 public void pathDone() {
805 log("pathDone");
806 out.pathDone();
807 }
808
809 private void log(final String message) {
810 System.out.println(prefix + message);
811 }
812
813 @Override
814 public long getNativeConsumer() {
815 throw new InternalError("Not using a native peer");
816 }
817 }
818 }
|