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