OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "GrOvalRenderer.h" | 8 #include "GrOvalRenderer.h" |
9 | 9 |
10 #include "GrEffect.h" | 10 #include "GrEffect.h" |
11 #include "gl/GrGLEffect.h" | 11 #include "gl/GrGLEffect.h" |
12 #include "gl/GrGLSL.h" | 12 #include "gl/GrGLSL.h" |
13 #include "gl/GrGLVertexEffect.h" | 13 #include "gl/GrGLVertexEffect.h" |
14 #include "GrTBackendEffectFactory.h" | 14 #include "GrTBackendEffectFactory.h" |
15 | 15 |
16 #include "GrDrawState.h" | 16 #include "GrDrawState.h" |
17 #include "GrDrawTarget.h" | 17 #include "GrDrawTarget.h" |
18 #include "GrGpu.h" | 18 #include "GrGpu.h" |
19 | 19 |
20 #include "SkRRect.h" | 20 #include "SkRRect.h" |
21 #include "SkStrokeRec.h" | 21 #include "SkStrokeRec.h" |
| 22 #include "SkTLazy.h" |
22 | 23 |
23 #include "effects/GrVertexEffect.h" | 24 #include "effects/GrVertexEffect.h" |
| 25 #include "effects/GrRRectEffect.h" |
24 | 26 |
25 namespace { | 27 namespace { |
26 | 28 |
27 struct CircleVertex { | 29 struct CircleVertex { |
28 SkPoint fPos; | 30 SkPoint fPos; |
29 SkPoint fOffset; | 31 SkPoint fOffset; |
30 SkScalar fOuterRadius; | 32 SkScalar fOuterRadius; |
31 SkScalar fInnerRadius; | 33 SkScalar fInnerRadius; |
32 }; | 34 }; |
33 | 35 |
(...skipping 478 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
512 | 514 |
513 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0); | 515 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0); |
514 if (!geo.succeeded()) { | 516 if (!geo.succeeded()) { |
515 GrPrintf("Failed to get space for vertices!\n"); | 517 GrPrintf("Failed to get space for vertices!\n"); |
516 return; | 518 return; |
517 } | 519 } |
518 | 520 |
519 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices()); | 521 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices()); |
520 | 522 |
521 SkStrokeRec::Style style = stroke.getStyle(); | 523 SkStrokeRec::Style style = stroke.getStyle(); |
522 bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairl
ine_Style == style); | 524 bool isStrokeOnly = SkStrokeRec::kStroke_Style == style || |
| 525 SkStrokeRec::kHairline_Style == style; |
| 526 bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style; |
523 | 527 |
524 SkScalar innerRadius = 0.0f; | 528 SkScalar innerRadius = 0.0f; |
525 SkScalar outerRadius = radius; | 529 SkScalar outerRadius = radius; |
526 SkScalar halfWidth = 0; | 530 SkScalar halfWidth = 0; |
527 if (style != SkStrokeRec::kFill_Style) { | 531 if (hasStroke) { |
528 if (SkScalarNearlyZero(strokeWidth)) { | 532 if (SkScalarNearlyZero(strokeWidth)) { |
529 halfWidth = SK_ScalarHalf; | 533 halfWidth = SK_ScalarHalf; |
530 } else { | 534 } else { |
531 halfWidth = SkScalarHalf(strokeWidth); | 535 halfWidth = SkScalarHalf(strokeWidth); |
532 } | 536 } |
533 | 537 |
534 outerRadius += halfWidth; | 538 outerRadius += halfWidth; |
535 if (isStroked) { | 539 if (isStrokeOnly) { |
536 innerRadius = radius - halfWidth; | 540 innerRadius = radius - halfWidth; |
537 } | 541 } |
538 } | 542 } |
539 | 543 |
540 GrEffectRef* effect = CircleEdgeEffect::Create(isStroked && innerRadius > 0)
; | 544 GrEffectRef* effect = CircleEdgeEffect::Create(isStrokeOnly && innerRadius >
0); |
541 static const int kCircleEdgeAttrIndex = 1; | 545 static const int kCircleEdgeAttrIndex = 1; |
542 drawState->addCoverageEffect(effect, kCircleEdgeAttrIndex)->unref(); | 546 drawState->addCoverageEffect(effect, kCircleEdgeAttrIndex)->unref(); |
543 | 547 |
544 // The radii are outset for two reasons. First, it allows the shader to simp
ly perform | 548 // The radii are outset for two reasons. First, it allows the shader to simp
ly perform |
545 // clamp(distance-to-center - radius, 0, 1). Second, the outer radius is use
d to compute the | 549 // clamp(distance-to-center - radius, 0, 1). Second, the outer radius is use
d to compute the |
546 // verts of the bounding box that is rendered and the outset ensures the box
will cover all | 550 // verts of the bounding box that is rendered and the outset ensures the box
will cover all |
547 // pixels partially covered by the circle. | 551 // pixels partially covered by the circle. |
548 outerRadius += SK_ScalarHalf; | 552 outerRadius += SK_ScalarHalf; |
549 innerRadius -= SK_ScalarHalf; | 553 innerRadius -= SK_ScalarHalf; |
550 | 554 |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
619 SkScalar yRadius = SkScalarAbs(vm[SkMatrix::kMSkewX]*ellipseXRadius + | 623 SkScalar yRadius = SkScalarAbs(vm[SkMatrix::kMSkewX]*ellipseXRadius + |
620 vm[SkMatrix::kMScaleY]*ellipseYRadius); | 624 vm[SkMatrix::kMScaleY]*ellipseYRadius); |
621 | 625 |
622 // do (potentially) anisotropic mapping of stroke | 626 // do (potentially) anisotropic mapping of stroke |
623 SkVector scaledStroke; | 627 SkVector scaledStroke; |
624 SkScalar strokeWidth = stroke.getWidth(); | 628 SkScalar strokeWidth = stroke.getWidth(); |
625 scaledStroke.fX = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMScaleX] + vm[SkMat
rix::kMSkewY])); | 629 scaledStroke.fX = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMScaleX] + vm[SkMat
rix::kMSkewY])); |
626 scaledStroke.fY = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMSkewX] + vm[SkMatr
ix::kMScaleY])); | 630 scaledStroke.fY = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMSkewX] + vm[SkMatr
ix::kMScaleY])); |
627 | 631 |
628 SkStrokeRec::Style style = stroke.getStyle(); | 632 SkStrokeRec::Style style = stroke.getStyle(); |
629 bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairl
ine_Style == style); | 633 bool isStrokeOnly = SkStrokeRec::kStroke_Style == style || |
| 634 SkStrokeRec::kHairline_Style == style; |
| 635 bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style; |
630 | 636 |
631 SkScalar innerXRadius = 0; | 637 SkScalar innerXRadius = 0; |
632 SkScalar innerYRadius = 0; | 638 SkScalar innerYRadius = 0; |
633 if (SkStrokeRec::kFill_Style != style) { | 639 if (hasStroke) { |
634 if (SkScalarNearlyZero(scaledStroke.length())) { | 640 if (SkScalarNearlyZero(scaledStroke.length())) { |
635 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf); | 641 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf); |
636 } else { | 642 } else { |
637 scaledStroke.scale(SK_ScalarHalf); | 643 scaledStroke.scale(SK_ScalarHalf); |
638 } | 644 } |
639 | 645 |
640 // we only handle thick strokes for near-circular ellipses | 646 // we only handle thick strokes for near-circular ellipses |
641 if (scaledStroke.length() > SK_ScalarHalf && | 647 if (scaledStroke.length() > SK_ScalarHalf && |
642 (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)
) { | 648 (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)
) { |
643 return false; | 649 return false; |
644 } | 650 } |
645 | 651 |
646 // we don't handle it if curvature of the stroke is less than curvature
of the ellipse | 652 // we don't handle it if curvature of the stroke is less than curvature
of the ellipse |
647 if (scaledStroke.fX*(yRadius*yRadius) < (scaledStroke.fY*scaledStroke.fY
)*xRadius || | 653 if (scaledStroke.fX*(yRadius*yRadius) < (scaledStroke.fY*scaledStroke.fY
)*xRadius || |
648 scaledStroke.fY*(xRadius*xRadius) < (scaledStroke.fX*scaledStroke.fX
)*yRadius) { | 654 scaledStroke.fY*(xRadius*xRadius) < (scaledStroke.fX*scaledStroke.fX
)*yRadius) { |
649 return false; | 655 return false; |
650 } | 656 } |
651 | 657 |
652 // this is legit only if scale & translation (which should be the case a
t the moment) | 658 // this is legit only if scale & translation (which should be the case a
t the moment) |
653 if (isStroked) { | 659 if (isStrokeOnly) { |
654 innerXRadius = xRadius - scaledStroke.fX; | 660 innerXRadius = xRadius - scaledStroke.fX; |
655 innerYRadius = yRadius - scaledStroke.fY; | 661 innerYRadius = yRadius - scaledStroke.fY; |
656 } | 662 } |
657 | 663 |
658 xRadius += scaledStroke.fX; | 664 xRadius += scaledStroke.fX; |
659 yRadius += scaledStroke.fY; | 665 yRadius += scaledStroke.fY; |
660 } | 666 } |
661 | 667 |
662 GrDrawState::AutoViewMatrixRestore avmr; | 668 GrDrawState::AutoViewMatrixRestore avmr; |
663 if (!avmr.setIdentity(drawState)) { | 669 if (!avmr.setIdentity(drawState)) { |
664 return false; | 670 return false; |
665 } | 671 } |
666 | 672 |
667 drawState->setVertexAttribs<gEllipseVertexAttribs>(SK_ARRAY_COUNT(gEllipseVe
rtexAttribs)); | 673 drawState->setVertexAttribs<gEllipseVertexAttribs>(SK_ARRAY_COUNT(gEllipseVe
rtexAttribs)); |
668 SkASSERT(sizeof(EllipseVertex) == drawState->getVertexSize()); | 674 SkASSERT(sizeof(EllipseVertex) == drawState->getVertexSize()); |
669 | 675 |
670 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0); | 676 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0); |
671 if (!geo.succeeded()) { | 677 if (!geo.succeeded()) { |
672 GrPrintf("Failed to get space for vertices!\n"); | 678 GrPrintf("Failed to get space for vertices!\n"); |
673 return false; | 679 return false; |
674 } | 680 } |
675 | 681 |
676 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices()); | 682 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices()); |
677 | 683 |
678 GrEffectRef* effect = EllipseEdgeEffect::Create(isStroked && | 684 GrEffectRef* effect = EllipseEdgeEffect::Create(isStrokeOnly && |
679 innerXRadius > 0 && innerYRa
dius > 0); | 685 innerXRadius > 0 && innerYRa
dius > 0); |
680 | 686 |
681 static const int kEllipseCenterAttrIndex = 1; | 687 static const int kEllipseCenterAttrIndex = 1; |
682 static const int kEllipseEdgeAttrIndex = 2; | 688 static const int kEllipseEdgeAttrIndex = 2; |
683 drawState->addCoverageEffect(effect, kEllipseCenterAttrIndex, kEllipseEdgeAt
trIndex)->unref(); | 689 drawState->addCoverageEffect(effect, kEllipseCenterAttrIndex, kEllipseEdgeAt
trIndex)->unref(); |
684 | 690 |
685 // Compute the reciprocals of the radii here to save time in the shader | 691 // Compute the reciprocals of the radii here to save time in the shader |
686 SkScalar xRadRecip = SkScalarInvert(xRadius); | 692 SkScalar xRadRecip = SkScalarInvert(xRadius); |
687 SkScalar yRadRecip = SkScalarInvert(yRadius); | 693 SkScalar yRadRecip = SkScalarInvert(yRadius); |
688 SkScalar xInnerRadRecip = SkScalarInvert(innerXRadius); | 694 SkScalar xInnerRadRecip = SkScalarInvert(innerXRadius); |
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
870 bool updated = | 876 bool updated = |
871 #endif | 877 #endif |
872 fRRectIndexBuffer->updateData(gRRectIndices, | 878 fRRectIndexBuffer->updateData(gRRectIndices, |
873 sizeof(gRRectIndices)); | 879 sizeof(gRRectIndices)); |
874 GR_DEBUGASSERT(updated); | 880 GR_DEBUGASSERT(updated); |
875 } | 881 } |
876 } | 882 } |
877 return fRRectIndexBuffer; | 883 return fRRectIndexBuffer; |
878 } | 884 } |
879 | 885 |
880 bool GrOvalRenderer::drawSimpleRRect(GrDrawTarget* target, GrContext* context, b
ool useAA, | 886 bool GrOvalRenderer::drawDRRect(GrDrawTarget* target, GrContext* context, bool u
seAA, |
881 const SkRRect& rrect, const SkStrokeRec& st
roke) | 887 const SkRRect& outer, const SkRRect& origInner)
{ |
882 { | 888 GrDrawState::AutoRestoreEffects are; |
| 889 if (!origInner.isEmpty()) { |
| 890 SkTCopyOnFirstWrite<SkRRect> inner(origInner); |
| 891 if (!context->getMatrix().isIdentity()) { |
| 892 if (!origInner.transform(context->getMatrix(), inner.writable())) { |
| 893 return false; |
| 894 } |
| 895 } |
| 896 bool applyAA = useAA && |
| 897 !target->getDrawState().getRenderTarget()->isMultisampled
() && |
| 898 !target->shouldDisableCoverageAAForBlend(); |
| 899 GrEffectEdgeType edgeType = applyAA ? kInverseFillAA_GrEffectEdgeType : |
| 900 kInverseFillBW_GrEffectEdgeType; |
| 901 GrEffectRef* effect = GrRRectEffect::Create(edgeType, *inner); |
| 902 if (NULL == effect) { |
| 903 return false; |
| 904 } |
| 905 are.set(target->drawState()); |
| 906 target->drawState()->addCoverageEffect(effect)->unref(); |
| 907 } |
| 908 |
| 909 SkStrokeRec fillRec(SkStrokeRec::kFill_InitStyle); |
| 910 return this->drawRRect(target, context, useAA, outer, fillRec); |
| 911 } |
| 912 |
| 913 bool GrOvalRenderer::drawRRect(GrDrawTarget* target, GrContext* context, bool us
eAA, |
| 914 const SkRRect& rrect, const SkStrokeRec& stroke)
{ |
| 915 if (rrect.isOval()) { |
| 916 return this->drawOval(target, context, useAA, rrect.getBounds(), stroke)
; |
| 917 } |
| 918 |
883 bool useCoverageAA = useAA && | 919 bool useCoverageAA = useAA && |
884 !target->getDrawState().getRenderTarget()->isMultisampled() && | 920 !target->getDrawState().getRenderTarget()->isMultisampled() && |
885 !target->shouldDisableCoverageAAForBlend(); | 921 !target->shouldDisableCoverageAAForBlend(); |
886 | 922 |
887 // only anti-aliased rrects for now | 923 // only anti-aliased rrects for now |
888 if (!useCoverageAA) { | 924 if (!useCoverageAA) { |
889 return false; | 925 return false; |
890 } | 926 } |
891 | 927 |
892 const SkMatrix& vm = context->getMatrix(); | 928 const SkMatrix& vm = context->getMatrix(); |
893 #ifdef SK_DEBUG | 929 |
894 { | 930 if (!vm.rectStaysRect() || !rrect.isSimple()) { |
895 // we should have checked for this previously | 931 return false; |
896 SkASSERT(useCoverageAA && vm.rectStaysRect() && rrect.isSimple()); | |
897 } | 932 } |
898 #endif | |
899 | 933 |
900 // do any matrix crunching before we reset the draw state for device coords | 934 // do any matrix crunching before we reset the draw state for device coords |
901 const SkRect& rrectBounds = rrect.getBounds(); | 935 const SkRect& rrectBounds = rrect.getBounds(); |
902 SkRect bounds; | 936 SkRect bounds; |
903 vm.mapRect(&bounds, rrectBounds); | 937 vm.mapRect(&bounds, rrectBounds); |
904 | 938 |
905 SkVector radii = rrect.getSimpleRadii(); | 939 SkVector radii = rrect.getSimpleRadii(); |
906 SkScalar xRadius = SkScalarAbs(vm[SkMatrix::kMScaleX]*radii.fX + | 940 SkScalar xRadius = SkScalarAbs(vm[SkMatrix::kMScaleX]*radii.fX + |
907 vm[SkMatrix::kMSkewY]*radii.fY); | 941 vm[SkMatrix::kMSkewY]*radii.fY); |
908 SkScalar yRadius = SkScalarAbs(vm[SkMatrix::kMSkewX]*radii.fX + | 942 SkScalar yRadius = SkScalarAbs(vm[SkMatrix::kMSkewX]*radii.fX + |
909 vm[SkMatrix::kMScaleY]*radii.fY); | 943 vm[SkMatrix::kMScaleY]*radii.fY); |
910 | 944 |
911 // if hairline stroke is greater than radius, we don't handle that right now | |
912 SkStrokeRec::Style style = stroke.getStyle(); | 945 SkStrokeRec::Style style = stroke.getStyle(); |
913 if (SkStrokeRec::kHairline_Style == style && | |
914 (SK_ScalarHalf > xRadius || SK_ScalarHalf > yRadius)) { | |
915 return false; | |
916 } | |
917 | 946 |
918 // do (potentially) anisotropic mapping of stroke | 947 // do (potentially) anisotropic mapping of stroke |
919 SkVector scaledStroke; | 948 SkVector scaledStroke; |
920 SkScalar strokeWidth = stroke.getWidth(); | 949 SkScalar strokeWidth = stroke.getWidth(); |
921 scaledStroke.fX = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMScaleX] + vm[SkMat
rix::kMSkewY])); | |
922 scaledStroke.fY = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMSkewX] + vm[SkMatr
ix::kMScaleY])); | |
923 | 950 |
924 // if half of strokewidth is greater than radius, we don't handle that right
now | 951 bool isStrokeOnly = SkStrokeRec::kStroke_Style == style || |
925 if (SK_ScalarHalf*scaledStroke.fX > xRadius || SK_ScalarHalf*scaledStroke.fY
> yRadius) { | 952 SkStrokeRec::kHairline_Style == style; |
| 953 bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style; |
| 954 |
| 955 if (hasStroke) { |
| 956 if (SkStrokeRec::kHairline_Style == style) { |
| 957 scaledStroke.set(1, 1); |
| 958 } else { |
| 959 scaledStroke.fX = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMScaleX] + |
| 960 vm[SkMatrix::kMSkewY])); |
| 961 scaledStroke.fY = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMSkewX] + |
| 962 vm[SkMatrix::kMScaleY])); |
| 963 } |
| 964 |
| 965 // if half of strokewidth is greater than radius, we don't handle that r
ight now |
| 966 if (SK_ScalarHalf*scaledStroke.fX > xRadius || SK_ScalarHalf*scaledStrok
e.fY > yRadius) { |
| 967 return false; |
| 968 } |
| 969 } |
| 970 |
| 971 // The way the effect interpolates the offset-to-ellipse/circle-center attri
bute only works on |
| 972 // the interior of the rrect if the radii are >= 0.5. Otherwise, the inner r
ect of the nine- |
| 973 // patch will have fractional coverage. This only matters when the interior
is actually filled. |
| 974 // We could consider falling back to rect rendering here, since a tiny radiu
s is |
| 975 // indistinguishable from a square corner. |
| 976 if (!isStrokeOnly && (SK_ScalarHalf > xRadius || SK_ScalarHalf > yRadius)) { |
926 return false; | 977 return false; |
927 } | 978 } |
928 | 979 |
929 // reset to device coordinates | 980 // reset to device coordinates |
930 GrDrawState* drawState = target->drawState(); | 981 GrDrawState* drawState = target->drawState(); |
931 GrDrawState::AutoViewMatrixRestore avmr; | 982 GrDrawState::AutoViewMatrixRestore avmr; |
932 if (!avmr.setIdentity(drawState)) { | 983 if (!avmr.setIdentity(drawState)) { |
933 return false; | 984 return false; |
934 } | 985 } |
935 | 986 |
936 bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairl
ine_Style == style); | |
937 | |
938 GrIndexBuffer* indexBuffer = this->rRectIndexBuffer(context->getGpu()); | 987 GrIndexBuffer* indexBuffer = this->rRectIndexBuffer(context->getGpu()); |
939 if (NULL == indexBuffer) { | 988 if (NULL == indexBuffer) { |
940 GrPrintf("Failed to create index buffer!\n"); | 989 GrPrintf("Failed to create index buffer!\n"); |
941 return false; | 990 return false; |
942 } | 991 } |
943 | 992 |
944 // if the corners are circles, use the circle renderer | 993 // if the corners are circles, use the circle renderer |
945 if ((!isStroked || scaledStroke.fX == scaledStroke.fY) && xRadius == yRadius
) { | 994 if ((!hasStroke || scaledStroke.fX == scaledStroke.fY) && xRadius == yRadius
) { |
946 drawState->setVertexAttribs<gCircleVertexAttribs>(SK_ARRAY_COUNT(gCircle
VertexAttribs)); | 995 drawState->setVertexAttribs<gCircleVertexAttribs>(SK_ARRAY_COUNT(gCircle
VertexAttribs)); |
947 SkASSERT(sizeof(CircleVertex) == drawState->getVertexSize()); | 996 SkASSERT(sizeof(CircleVertex) == drawState->getVertexSize()); |
948 | 997 |
949 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0); | 998 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0); |
950 if (!geo.succeeded()) { | 999 if (!geo.succeeded()) { |
951 GrPrintf("Failed to get space for vertices!\n"); | 1000 GrPrintf("Failed to get space for vertices!\n"); |
952 return false; | 1001 return false; |
953 } | 1002 } |
954 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices()); | 1003 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices()); |
955 | 1004 |
956 SkScalar innerRadius = 0.0f; | 1005 SkScalar innerRadius = 0.0f; |
957 SkScalar outerRadius = xRadius; | 1006 SkScalar outerRadius = xRadius; |
958 SkScalar halfWidth = 0; | 1007 SkScalar halfWidth = 0; |
959 if (style != SkStrokeRec::kFill_Style) { | 1008 if (hasStroke) { |
960 if (SkScalarNearlyZero(scaledStroke.fX)) { | 1009 if (SkScalarNearlyZero(scaledStroke.fX)) { |
961 halfWidth = SK_ScalarHalf; | 1010 halfWidth = SK_ScalarHalf; |
962 } else { | 1011 } else { |
963 halfWidth = SkScalarHalf(scaledStroke.fX); | 1012 halfWidth = SkScalarHalf(scaledStroke.fX); |
964 } | 1013 } |
965 | 1014 |
966 if (isStroked) { | 1015 if (isStrokeOnly) { |
967 innerRadius = xRadius - halfWidth; | 1016 innerRadius = xRadius - halfWidth; |
968 } | 1017 } |
969 outerRadius += halfWidth; | 1018 outerRadius += halfWidth; |
970 bounds.outset(halfWidth, halfWidth); | 1019 bounds.outset(halfWidth, halfWidth); |
971 } | 1020 } |
972 | 1021 |
973 isStroked = (isStroked && innerRadius >= 0); | 1022 isStrokeOnly = (isStrokeOnly && innerRadius >= 0); |
974 | 1023 |
975 GrEffectRef* effect = CircleEdgeEffect::Create(isStroked); | 1024 GrEffectRef* effect = CircleEdgeEffect::Create(isStrokeOnly); |
976 static const int kCircleEdgeAttrIndex = 1; | 1025 static const int kCircleEdgeAttrIndex = 1; |
977 drawState->addCoverageEffect(effect, kCircleEdgeAttrIndex)->unref(); | 1026 drawState->addCoverageEffect(effect, kCircleEdgeAttrIndex)->unref(); |
978 | 1027 |
979 // The radii are outset for two reasons. First, it allows the shader to
simply perform | 1028 // The radii are outset for two reasons. First, it allows the shader to
simply perform |
980 // clamp(distance-to-center - radius, 0, 1). Second, the outer radius is
used to compute the | 1029 // clamp(distance-to-center - radius, 0, 1). Second, the outer radius is
used to compute the |
981 // verts of the bounding box that is rendered and the outset ensures the
box will cover all | 1030 // verts of the bounding box that is rendered and the outset ensures the
box will cover all |
982 // pixels partially covered by the circle. | 1031 // pixels partially covered by the circle. |
983 outerRadius += SK_ScalarHalf; | 1032 outerRadius += SK_ScalarHalf; |
984 innerRadius -= SK_ScalarHalf; | 1033 innerRadius -= SK_ScalarHalf; |
985 | 1034 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1018 verts++; | 1067 verts++; |
1019 | 1068 |
1020 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]); | 1069 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]); |
1021 verts->fOffset = SkPoint::Make(outerRadius, yOuterRadii[i]); | 1070 verts->fOffset = SkPoint::Make(outerRadius, yOuterRadii[i]); |
1022 verts->fOuterRadius = outerRadius; | 1071 verts->fOuterRadius = outerRadius; |
1023 verts->fInnerRadius = innerRadius; | 1072 verts->fInnerRadius = innerRadius; |
1024 verts++; | 1073 verts++; |
1025 } | 1074 } |
1026 | 1075 |
1027 // drop out the middle quad if we're stroked | 1076 // drop out the middle quad if we're stroked |
1028 int indexCnt = isStroked ? SK_ARRAY_COUNT(gRRectIndices)-6 : SK_ARRAY_CO
UNT(gRRectIndices); | 1077 int indexCnt = isStrokeOnly ? SK_ARRAY_COUNT(gRRectIndices) - 6 : |
| 1078 SK_ARRAY_COUNT(gRRectIndices); |
1029 target->setIndexSourceToBuffer(indexBuffer); | 1079 target->setIndexSourceToBuffer(indexBuffer); |
1030 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 16, indexCnt, &bou
nds); | 1080 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 16, indexCnt, &bou
nds); |
1031 | 1081 |
1032 // otherwise we use the ellipse renderer | 1082 // otherwise we use the ellipse renderer |
1033 } else { | 1083 } else { |
1034 drawState->setVertexAttribs<gEllipseVertexAttribs>(SK_ARRAY_COUNT(gEllip
seVertexAttribs)); | 1084 drawState->setVertexAttribs<gEllipseVertexAttribs>(SK_ARRAY_COUNT(gEllip
seVertexAttribs)); |
1035 SkASSERT(sizeof(EllipseVertex) == drawState->getVertexSize()); | 1085 SkASSERT(sizeof(EllipseVertex) == drawState->getVertexSize()); |
1036 | 1086 |
1037 SkScalar innerXRadius = 0.0f; | 1087 SkScalar innerXRadius = 0.0f; |
1038 SkScalar innerYRadius = 0.0f; | 1088 SkScalar innerYRadius = 0.0f; |
1039 if (SkStrokeRec::kFill_Style != style) { | 1089 if (hasStroke) { |
1040 if (SkScalarNearlyZero(scaledStroke.length())) { | 1090 if (SkScalarNearlyZero(scaledStroke.length())) { |
1041 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf); | 1091 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf); |
1042 } else { | 1092 } else { |
1043 scaledStroke.scale(SK_ScalarHalf); | 1093 scaledStroke.scale(SK_ScalarHalf); |
1044 } | 1094 } |
1045 | 1095 |
1046 // we only handle thick strokes for near-circular ellipses | 1096 // we only handle thick strokes for near-circular ellipses |
1047 if (scaledStroke.length() > SK_ScalarHalf && | 1097 if (scaledStroke.length() > SK_ScalarHalf && |
1048 (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRad
ius)) { | 1098 (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRad
ius)) { |
1049 return false; | 1099 return false; |
1050 } | 1100 } |
1051 | 1101 |
1052 // we don't handle it if curvature of the stroke is less than curvat
ure of the ellipse | 1102 // we don't handle it if curvature of the stroke is less than curvat
ure of the ellipse |
1053 if (scaledStroke.fX*(yRadius*yRadius) < (scaledStroke.fY*scaledStrok
e.fY)*xRadius || | 1103 if (scaledStroke.fX*(yRadius*yRadius) < (scaledStroke.fY*scaledStrok
e.fY)*xRadius || |
1054 scaledStroke.fY*(xRadius*xRadius) < (scaledStroke.fX*scaledStrok
e.fX)*yRadius) { | 1104 scaledStroke.fY*(xRadius*xRadius) < (scaledStroke.fX*scaledStrok
e.fX)*yRadius) { |
1055 return false; | 1105 return false; |
1056 } | 1106 } |
1057 | 1107 |
1058 // this is legit only if scale & translation (which should be the ca
se at the moment) | 1108 // this is legit only if scale & translation (which should be the ca
se at the moment) |
1059 if (isStroked) { | 1109 if (isStrokeOnly) { |
1060 innerXRadius = xRadius - scaledStroke.fX; | 1110 innerXRadius = xRadius - scaledStroke.fX; |
1061 innerYRadius = yRadius - scaledStroke.fY; | 1111 innerYRadius = yRadius - scaledStroke.fY; |
1062 } | 1112 } |
1063 | 1113 |
1064 xRadius += scaledStroke.fX; | 1114 xRadius += scaledStroke.fX; |
1065 yRadius += scaledStroke.fY; | 1115 yRadius += scaledStroke.fY; |
1066 bounds.outset(scaledStroke.fX, scaledStroke.fY); | 1116 bounds.outset(scaledStroke.fX, scaledStroke.fY); |
1067 } | 1117 } |
1068 | 1118 |
1069 isStroked = (isStroked && innerXRadius >= 0 && innerYRadius >= 0); | 1119 isStrokeOnly = (isStrokeOnly && innerXRadius >= 0 && innerYRadius >= 0); |
1070 | 1120 |
1071 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0); | 1121 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0); |
1072 if (!geo.succeeded()) { | 1122 if (!geo.succeeded()) { |
1073 GrPrintf("Failed to get space for vertices!\n"); | 1123 GrPrintf("Failed to get space for vertices!\n"); |
1074 return false; | 1124 return false; |
1075 } | 1125 } |
1076 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices()); | 1126 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices()); |
1077 | 1127 |
1078 GrEffectRef* effect = EllipseEdgeEffect::Create(isStroked); | 1128 GrEffectRef* effect = EllipseEdgeEffect::Create(isStrokeOnly); |
1079 static const int kEllipseOffsetAttrIndex = 1; | 1129 static const int kEllipseOffsetAttrIndex = 1; |
1080 static const int kEllipseRadiiAttrIndex = 2; | 1130 static const int kEllipseRadiiAttrIndex = 2; |
1081 drawState->addCoverageEffect(effect, | 1131 drawState->addCoverageEffect(effect, |
1082 kEllipseOffsetAttrIndex, kEllipseRadiiAttrI
ndex)->unref(); | 1132 kEllipseOffsetAttrIndex, kEllipseRadiiAttrI
ndex)->unref(); |
1083 | 1133 |
1084 // Compute the reciprocals of the radii here to save time in the shader | 1134 // Compute the reciprocals of the radii here to save time in the shader |
1085 SkScalar xRadRecip = SkScalarInvert(xRadius); | 1135 SkScalar xRadRecip = SkScalarInvert(xRadius); |
1086 SkScalar yRadRecip = SkScalarInvert(yRadius); | 1136 SkScalar yRadRecip = SkScalarInvert(yRadius); |
1087 SkScalar xInnerRadRecip = SkScalarInvert(innerXRadius); | 1137 SkScalar xInnerRadRecip = SkScalarInvert(innerXRadius); |
1088 SkScalar yInnerRadRecip = SkScalarInvert(innerYRadius); | 1138 SkScalar yInnerRadRecip = SkScalarInvert(innerYRadius); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1127 verts++; | 1177 verts++; |
1128 | 1178 |
1129 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]); | 1179 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]); |
1130 verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]); | 1180 verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]); |
1131 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip); | 1181 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip); |
1132 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip); | 1182 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip); |
1133 verts++; | 1183 verts++; |
1134 } | 1184 } |
1135 | 1185 |
1136 // drop out the middle quad if we're stroked | 1186 // drop out the middle quad if we're stroked |
1137 int indexCnt = isStroked ? SK_ARRAY_COUNT(gRRectIndices)-6 : SK_ARRAY_CO
UNT(gRRectIndices); | 1187 int indexCnt = isStrokeOnly ? SK_ARRAY_COUNT(gRRectIndices) - 6 : |
| 1188 SK_ARRAY_COUNT(gRRectIndices); |
1138 target->setIndexSourceToBuffer(indexBuffer); | 1189 target->setIndexSourceToBuffer(indexBuffer); |
1139 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 16, indexCnt, &bou
nds); | 1190 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 16, indexCnt, &bou
nds); |
1140 } | 1191 } |
1141 | 1192 |
1142 return true; | 1193 return true; |
1143 } | 1194 } |
OLD | NEW |