431 case 6: |
421 case 6: |
432 subdivideQuadAt(t, src, srcoff, left, leftoff, right, rightoff); |
422 subdivideQuadAt(t, src, srcoff, left, leftoff, right, rightoff); |
433 return; |
423 return; |
434 } |
424 } |
435 } |
425 } |
|
426 |
|
427 // From sun.java2d.loops.GeneralRenderer: |
|
428 |
|
429 static int outcode(final double x, final double y, |
|
430 final double[] clipRect) |
|
431 { |
|
432 int code; |
|
433 if (y < clipRect[0]) { |
|
434 code = OUTCODE_TOP; |
|
435 } else if (y >= clipRect[1]) { |
|
436 code = OUTCODE_BOTTOM; |
|
437 } else { |
|
438 code = 0; |
|
439 } |
|
440 if (x < clipRect[2]) { |
|
441 code |= OUTCODE_LEFT; |
|
442 } else if (x >= clipRect[3]) { |
|
443 code |= OUTCODE_RIGHT; |
|
444 } |
|
445 return code; |
|
446 } |
|
447 |
|
448 // a stack of polynomial curves where each curve shares endpoints with |
|
449 // adjacent ones. |
|
450 static final class PolyStack { |
|
451 private static final byte TYPE_LINETO = (byte) 0; |
|
452 private static final byte TYPE_QUADTO = (byte) 1; |
|
453 private static final byte TYPE_CUBICTO = (byte) 2; |
|
454 |
|
455 // curves capacity = edges count (8192) = edges x 2 (coords) |
|
456 private static final int INITIAL_CURVES_COUNT = INITIAL_EDGES_COUNT << 1; |
|
457 |
|
458 // types capacity = edges count (4096) |
|
459 private static final int INITIAL_TYPES_COUNT = INITIAL_EDGES_COUNT; |
|
460 |
|
461 double[] curves; |
|
462 int end; |
|
463 byte[] curveTypes; |
|
464 int numCurves; |
|
465 |
|
466 // curves ref (dirty) |
|
467 final DoubleArrayCache.Reference curves_ref; |
|
468 // curveTypes ref (dirty) |
|
469 final ByteArrayCache.Reference curveTypes_ref; |
|
470 |
|
471 // used marks (stats only) |
|
472 int curveTypesUseMark; |
|
473 int curvesUseMark; |
|
474 |
|
475 private final StatLong stat_polystack_types; |
|
476 private final StatLong stat_polystack_curves; |
|
477 private final Histogram hist_polystack_curves; |
|
478 private final StatLong stat_array_polystack_curves; |
|
479 private final StatLong stat_array_polystack_curveTypes; |
|
480 |
|
481 PolyStack(final DRendererContext rdrCtx) { |
|
482 this(rdrCtx, null, null, null, null, null); |
|
483 } |
|
484 |
|
485 PolyStack(final DRendererContext rdrCtx, |
|
486 final StatLong stat_polystack_types, |
|
487 final StatLong stat_polystack_curves, |
|
488 final Histogram hist_polystack_curves, |
|
489 final StatLong stat_array_polystack_curves, |
|
490 final StatLong stat_array_polystack_curveTypes) |
|
491 { |
|
492 curves_ref = rdrCtx.newDirtyDoubleArrayRef(INITIAL_CURVES_COUNT); // 32K |
|
493 curves = curves_ref.initial; |
|
494 |
|
495 curveTypes_ref = rdrCtx.newDirtyByteArrayRef(INITIAL_TYPES_COUNT); // 4K |
|
496 curveTypes = curveTypes_ref.initial; |
|
497 numCurves = 0; |
|
498 end = 0; |
|
499 |
|
500 if (DO_STATS) { |
|
501 curveTypesUseMark = 0; |
|
502 curvesUseMark = 0; |
|
503 } |
|
504 this.stat_polystack_types = stat_polystack_types; |
|
505 this.stat_polystack_curves = stat_polystack_curves; |
|
506 this.hist_polystack_curves = hist_polystack_curves; |
|
507 this.stat_array_polystack_curves = stat_array_polystack_curves; |
|
508 this.stat_array_polystack_curveTypes = stat_array_polystack_curveTypes; |
|
509 } |
|
510 |
|
511 /** |
|
512 * Disposes this PolyStack: |
|
513 * clean up before reusing this instance |
|
514 */ |
|
515 void dispose() { |
|
516 end = 0; |
|
517 numCurves = 0; |
|
518 |
|
519 if (DO_STATS) { |
|
520 stat_polystack_types.add(curveTypesUseMark); |
|
521 stat_polystack_curves.add(curvesUseMark); |
|
522 hist_polystack_curves.add(curvesUseMark); |
|
523 |
|
524 // reset marks |
|
525 curveTypesUseMark = 0; |
|
526 curvesUseMark = 0; |
|
527 } |
|
528 |
|
529 // Return arrays: |
|
530 // curves and curveTypes are kept dirty |
|
531 curves = curves_ref.putArray(curves); |
|
532 curveTypes = curveTypes_ref.putArray(curveTypes); |
|
533 } |
|
534 |
|
535 private void ensureSpace(final int n) { |
|
536 // use substraction to avoid integer overflow: |
|
537 if (curves.length - end < n) { |
|
538 if (DO_STATS) { |
|
539 stat_array_polystack_curves.add(end + n); |
|
540 } |
|
541 curves = curves_ref.widenArray(curves, end, end + n); |
|
542 } |
|
543 if (curveTypes.length <= numCurves) { |
|
544 if (DO_STATS) { |
|
545 stat_array_polystack_curveTypes.add(numCurves + 1); |
|
546 } |
|
547 curveTypes = curveTypes_ref.widenArray(curveTypes, |
|
548 numCurves, |
|
549 numCurves + 1); |
|
550 } |
|
551 } |
|
552 |
|
553 void pushCubic(double x0, double y0, |
|
554 double x1, double y1, |
|
555 double x2, double y2) |
|
556 { |
|
557 ensureSpace(6); |
|
558 curveTypes[numCurves++] = TYPE_CUBICTO; |
|
559 // we reverse the coordinate order to make popping easier |
|
560 final double[] _curves = curves; |
|
561 int e = end; |
|
562 _curves[e++] = x2; _curves[e++] = y2; |
|
563 _curves[e++] = x1; _curves[e++] = y1; |
|
564 _curves[e++] = x0; _curves[e++] = y0; |
|
565 end = e; |
|
566 } |
|
567 |
|
568 void pushQuad(double x0, double y0, |
|
569 double x1, double y1) |
|
570 { |
|
571 ensureSpace(4); |
|
572 curveTypes[numCurves++] = TYPE_QUADTO; |
|
573 final double[] _curves = curves; |
|
574 int e = end; |
|
575 _curves[e++] = x1; _curves[e++] = y1; |
|
576 _curves[e++] = x0; _curves[e++] = y0; |
|
577 end = e; |
|
578 } |
|
579 |
|
580 void pushLine(double x, double y) { |
|
581 ensureSpace(2); |
|
582 curveTypes[numCurves++] = TYPE_LINETO; |
|
583 curves[end++] = x; curves[end++] = y; |
|
584 } |
|
585 |
|
586 void pullAll(final DPathConsumer2D io) { |
|
587 final int nc = numCurves; |
|
588 if (nc == 0) { |
|
589 return; |
|
590 } |
|
591 if (DO_STATS) { |
|
592 // update used marks: |
|
593 if (numCurves > curveTypesUseMark) { |
|
594 curveTypesUseMark = numCurves; |
|
595 } |
|
596 if (end > curvesUseMark) { |
|
597 curvesUseMark = end; |
|
598 } |
|
599 } |
|
600 final byte[] _curveTypes = curveTypes; |
|
601 final double[] _curves = curves; |
|
602 int e = 0; |
|
603 |
|
604 for (int i = 0; i < nc; i++) { |
|
605 switch(_curveTypes[i]) { |
|
606 case TYPE_LINETO: |
|
607 io.lineTo(_curves[e], _curves[e+1]); |
|
608 e += 2; |
|
609 continue; |
|
610 case TYPE_QUADTO: |
|
611 io.quadTo(_curves[e+0], _curves[e+1], |
|
612 _curves[e+2], _curves[e+3]); |
|
613 e += 4; |
|
614 continue; |
|
615 case TYPE_CUBICTO: |
|
616 io.curveTo(_curves[e+0], _curves[e+1], |
|
617 _curves[e+2], _curves[e+3], |
|
618 _curves[e+4], _curves[e+5]); |
|
619 e += 6; |
|
620 continue; |
|
621 default: |
|
622 } |
|
623 } |
|
624 numCurves = 0; |
|
625 end = 0; |
|
626 } |
|
627 |
|
628 void popAll(final DPathConsumer2D io) { |
|
629 int nc = numCurves; |
|
630 if (nc == 0) { |
|
631 return; |
|
632 } |
|
633 if (DO_STATS) { |
|
634 // update used marks: |
|
635 if (numCurves > curveTypesUseMark) { |
|
636 curveTypesUseMark = numCurves; |
|
637 } |
|
638 if (end > curvesUseMark) { |
|
639 curvesUseMark = end; |
|
640 } |
|
641 } |
|
642 final byte[] _curveTypes = curveTypes; |
|
643 final double[] _curves = curves; |
|
644 int e = end; |
|
645 |
|
646 while (nc != 0) { |
|
647 switch(_curveTypes[--nc]) { |
|
648 case TYPE_LINETO: |
|
649 e -= 2; |
|
650 io.lineTo(_curves[e], _curves[e+1]); |
|
651 continue; |
|
652 case TYPE_QUADTO: |
|
653 e -= 4; |
|
654 io.quadTo(_curves[e+0], _curves[e+1], |
|
655 _curves[e+2], _curves[e+3]); |
|
656 continue; |
|
657 case TYPE_CUBICTO: |
|
658 e -= 6; |
|
659 io.curveTo(_curves[e+0], _curves[e+1], |
|
660 _curves[e+2], _curves[e+3], |
|
661 _curves[e+4], _curves[e+5]); |
|
662 continue; |
|
663 default: |
|
664 } |
|
665 } |
|
666 numCurves = 0; |
|
667 end = 0; |
|
668 } |
|
669 |
|
670 @Override |
|
671 public String toString() { |
|
672 String ret = ""; |
|
673 int nc = numCurves; |
|
674 int last = end; |
|
675 int len; |
|
676 while (nc != 0) { |
|
677 switch(curveTypes[--nc]) { |
|
678 case TYPE_LINETO: |
|
679 len = 2; |
|
680 ret += "line: "; |
|
681 break; |
|
682 case TYPE_QUADTO: |
|
683 len = 4; |
|
684 ret += "quad: "; |
|
685 break; |
|
686 case TYPE_CUBICTO: |
|
687 len = 6; |
|
688 ret += "cubic: "; |
|
689 break; |
|
690 default: |
|
691 len = 0; |
|
692 } |
|
693 last -= len; |
|
694 ret += Arrays.toString(Arrays.copyOfRange(curves, last, last+len)) |
|
695 + "\n"; |
|
696 } |
|
697 return ret; |
|
698 } |
|
699 } |
|
700 |
|
701 // a stack of integer indices |
|
702 static final class IndexStack { |
|
703 |
|
704 // integer capacity = edges count / 4 ~ 1024 |
|
705 private static final int INITIAL_COUNT = INITIAL_EDGES_COUNT >> 2; |
|
706 |
|
707 private int end; |
|
708 private int[] indices; |
|
709 |
|
710 // indices ref (dirty) |
|
711 private final IntArrayCache.Reference indices_ref; |
|
712 |
|
713 // used marks (stats only) |
|
714 private int indicesUseMark; |
|
715 |
|
716 private final StatLong stat_idxstack_indices; |
|
717 private final Histogram hist_idxstack_indices; |
|
718 private final StatLong stat_array_idxstack_indices; |
|
719 |
|
720 IndexStack(final DRendererContext rdrCtx) { |
|
721 this(rdrCtx, null, null, null); |
|
722 } |
|
723 |
|
724 IndexStack(final DRendererContext rdrCtx, |
|
725 final StatLong stat_idxstack_indices, |
|
726 final Histogram hist_idxstack_indices, |
|
727 final StatLong stat_array_idxstack_indices) |
|
728 { |
|
729 indices_ref = rdrCtx.newDirtyIntArrayRef(INITIAL_COUNT); // 4K |
|
730 indices = indices_ref.initial; |
|
731 end = 0; |
|
732 |
|
733 if (DO_STATS) { |
|
734 indicesUseMark = 0; |
|
735 } |
|
736 this.stat_idxstack_indices = stat_idxstack_indices; |
|
737 this.hist_idxstack_indices = hist_idxstack_indices; |
|
738 this.stat_array_idxstack_indices = stat_array_idxstack_indices; |
|
739 } |
|
740 |
|
741 /** |
|
742 * Disposes this PolyStack: |
|
743 * clean up before reusing this instance |
|
744 */ |
|
745 void dispose() { |
|
746 end = 0; |
|
747 |
|
748 if (DO_STATS) { |
|
749 stat_idxstack_indices.add(indicesUseMark); |
|
750 hist_idxstack_indices.add(indicesUseMark); |
|
751 |
|
752 // reset marks |
|
753 indicesUseMark = 0; |
|
754 } |
|
755 |
|
756 // Return arrays: |
|
757 // values is kept dirty |
|
758 indices = indices_ref.putArray(indices); |
|
759 } |
|
760 |
|
761 boolean isEmpty() { |
|
762 return (end == 0); |
|
763 } |
|
764 |
|
765 void reset() { |
|
766 end = 0; |
|
767 } |
|
768 |
|
769 void push(final int v) { |
|
770 // remove redundant values (reverse order): |
|
771 int[] _values = indices; |
|
772 final int nc = end; |
|
773 if (nc != 0) { |
|
774 if (_values[nc - 1] == v) { |
|
775 // remove both duplicated values: |
|
776 end--; |
|
777 return; |
|
778 } |
|
779 } |
|
780 if (_values.length <= nc) { |
|
781 if (DO_STATS) { |
|
782 stat_array_idxstack_indices.add(nc + 1); |
|
783 } |
|
784 indices = _values = indices_ref.widenArray(_values, nc, nc + 1); |
|
785 } |
|
786 _values[end++] = v; |
|
787 |
|
788 if (DO_STATS) { |
|
789 // update used marks: |
|
790 if (end > indicesUseMark) { |
|
791 indicesUseMark = end; |
|
792 } |
|
793 } |
|
794 } |
|
795 |
|
796 void pullAll(final double[] points, final DPathConsumer2D io) { |
|
797 final int nc = end; |
|
798 if (nc == 0) { |
|
799 return; |
|
800 } |
|
801 final int[] _values = indices; |
|
802 |
|
803 for (int i = 0, j; i < nc; i++) { |
|
804 j = _values[i] << 1; |
|
805 io.lineTo(points[j], points[j + 1]); |
|
806 } |
|
807 end = 0; |
|
808 } |
|
809 } |
436 } |
810 } |