| Index: src/gpu/GrOvalRenderer.cpp
|
| diff --git a/src/gpu/GrOvalRenderer.cpp b/src/gpu/GrOvalRenderer.cpp
|
| index 2ade8cde07cad184f44c48bd34d6e27d243249ac..45564bcce049c8c3cbf457d39da9a1efe3cd702f 100644
|
| --- a/src/gpu/GrOvalRenderer.cpp
|
| +++ b/src/gpu/GrOvalRenderer.cpp
|
| @@ -19,8 +19,10 @@
|
|
|
| #include "SkRRect.h"
|
| #include "SkStrokeRec.h"
|
| +#include "SkTLazy.h"
|
|
|
| #include "effects/GrVertexEffect.h"
|
| +#include "effects/GrRRectEffect.h"
|
|
|
| namespace {
|
|
|
| @@ -519,12 +521,14 @@ void GrOvalRenderer::drawCircle(GrDrawTarget* target,
|
| CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices());
|
|
|
| SkStrokeRec::Style style = stroke.getStyle();
|
| - bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style);
|
| + bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
|
| + SkStrokeRec::kHairline_Style == style;
|
| + bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
|
|
|
| SkScalar innerRadius = 0.0f;
|
| SkScalar outerRadius = radius;
|
| SkScalar halfWidth = 0;
|
| - if (style != SkStrokeRec::kFill_Style) {
|
| + if (hasStroke) {
|
| if (SkScalarNearlyZero(strokeWidth)) {
|
| halfWidth = SK_ScalarHalf;
|
| } else {
|
| @@ -532,12 +536,12 @@ void GrOvalRenderer::drawCircle(GrDrawTarget* target,
|
| }
|
|
|
| outerRadius += halfWidth;
|
| - if (isStroked) {
|
| + if (isStrokeOnly) {
|
| innerRadius = radius - halfWidth;
|
| }
|
| }
|
|
|
| - GrEffectRef* effect = CircleEdgeEffect::Create(isStroked && innerRadius > 0);
|
| + GrEffectRef* effect = CircleEdgeEffect::Create(isStrokeOnly && innerRadius > 0);
|
| static const int kCircleEdgeAttrIndex = 1;
|
| drawState->addCoverageEffect(effect, kCircleEdgeAttrIndex)->unref();
|
|
|
| @@ -626,11 +630,13 @@ bool GrOvalRenderer::drawEllipse(GrDrawTarget* target,
|
| scaledStroke.fY = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMSkewX] + vm[SkMatrix::kMScaleY]));
|
|
|
| SkStrokeRec::Style style = stroke.getStyle();
|
| - bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style);
|
| + bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
|
| + SkStrokeRec::kHairline_Style == style;
|
| + bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
|
|
|
| SkScalar innerXRadius = 0;
|
| SkScalar innerYRadius = 0;
|
| - if (SkStrokeRec::kFill_Style != style) {
|
| + if (hasStroke) {
|
| if (SkScalarNearlyZero(scaledStroke.length())) {
|
| scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
|
| } else {
|
| @@ -650,7 +656,7 @@ bool GrOvalRenderer::drawEllipse(GrDrawTarget* target,
|
| }
|
|
|
| // this is legit only if scale & translation (which should be the case at the moment)
|
| - if (isStroked) {
|
| + if (isStrokeOnly) {
|
| innerXRadius = xRadius - scaledStroke.fX;
|
| innerYRadius = yRadius - scaledStroke.fY;
|
| }
|
| @@ -675,7 +681,7 @@ bool GrOvalRenderer::drawEllipse(GrDrawTarget* target,
|
|
|
| EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices());
|
|
|
| - GrEffectRef* effect = EllipseEdgeEffect::Create(isStroked &&
|
| + GrEffectRef* effect = EllipseEdgeEffect::Create(isStrokeOnly &&
|
| innerXRadius > 0 && innerYRadius > 0);
|
|
|
| static const int kEllipseCenterAttrIndex = 1;
|
| @@ -877,9 +883,39 @@ GrIndexBuffer* GrOvalRenderer::rRectIndexBuffer(GrGpu* gpu) {
|
| return fRRectIndexBuffer;
|
| }
|
|
|
| -bool GrOvalRenderer::drawSimpleRRect(GrDrawTarget* target, GrContext* context, bool useAA,
|
| - const SkRRect& rrect, const SkStrokeRec& stroke)
|
| -{
|
| +bool GrOvalRenderer::drawDRRect(GrDrawTarget* target, GrContext* context, bool useAA,
|
| + const SkRRect& outer, const SkRRect& origInner) {
|
| + GrDrawState::AutoRestoreEffects are;
|
| + if (!origInner.isEmpty()) {
|
| + SkTCopyOnFirstWrite<SkRRect> inner(origInner);
|
| + if (!context->getMatrix().isIdentity()) {
|
| + if (!origInner.transform(context->getMatrix(), inner.writable())) {
|
| + return false;
|
| + }
|
| + }
|
| + bool applyAA = useAA &&
|
| + !target->getDrawState().getRenderTarget()->isMultisampled() &&
|
| + !target->shouldDisableCoverageAAForBlend();
|
| + GrEffectEdgeType edgeType = applyAA ? kInverseFillAA_GrEffectEdgeType :
|
| + kInverseFillBW_GrEffectEdgeType;
|
| + GrEffectRef* effect = GrRRectEffect::Create(edgeType, *inner);
|
| + if (NULL == effect) {
|
| + return false;
|
| + }
|
| + are.set(target->drawState());
|
| + target->drawState()->addCoverageEffect(effect)->unref();
|
| + }
|
| +
|
| + SkStrokeRec fillRec(SkStrokeRec::kFill_InitStyle);
|
| + return this->drawRRect(target, context, useAA, outer, fillRec);
|
| +}
|
| +
|
| +bool GrOvalRenderer::drawRRect(GrDrawTarget* target, GrContext* context, bool useAA,
|
| + const SkRRect& rrect, const SkStrokeRec& stroke) {
|
| + if (rrect.isOval()) {
|
| + return this->drawOval(target, context, useAA, rrect.getBounds(), stroke);
|
| + }
|
| +
|
| bool useCoverageAA = useAA &&
|
| !target->getDrawState().getRenderTarget()->isMultisampled() &&
|
| !target->shouldDisableCoverageAAForBlend();
|
| @@ -890,12 +926,10 @@ bool GrOvalRenderer::drawSimpleRRect(GrDrawTarget* target, GrContext* context, b
|
| }
|
|
|
| const SkMatrix& vm = context->getMatrix();
|
| -#ifdef SK_DEBUG
|
| - {
|
| - // we should have checked for this previously
|
| - SkASSERT(useCoverageAA && vm.rectStaysRect() && rrect.isSimple());
|
| +
|
| + if (!vm.rectStaysRect() || !rrect.isSimple()) {
|
| + return false;
|
| }
|
| -#endif
|
|
|
| // do any matrix crunching before we reset the draw state for device coords
|
| const SkRect& rrectBounds = rrect.getBounds();
|
| @@ -908,21 +942,38 @@ bool GrOvalRenderer::drawSimpleRRect(GrDrawTarget* target, GrContext* context, b
|
| SkScalar yRadius = SkScalarAbs(vm[SkMatrix::kMSkewX]*radii.fX +
|
| vm[SkMatrix::kMScaleY]*radii.fY);
|
|
|
| - // if hairline stroke is greater than radius, we don't handle that right now
|
| SkStrokeRec::Style style = stroke.getStyle();
|
| - if (SkStrokeRec::kHairline_Style == style &&
|
| - (SK_ScalarHalf > xRadius || SK_ScalarHalf > yRadius)) {
|
| - return false;
|
| - }
|
|
|
| // do (potentially) anisotropic mapping of stroke
|
| SkVector scaledStroke;
|
| SkScalar strokeWidth = stroke.getWidth();
|
| - scaledStroke.fX = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMScaleX] + vm[SkMatrix::kMSkewY]));
|
| - scaledStroke.fY = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMSkewX] + vm[SkMatrix::kMScaleY]));
|
|
|
| - // if half of strokewidth is greater than radius, we don't handle that right now
|
| - if (SK_ScalarHalf*scaledStroke.fX > xRadius || SK_ScalarHalf*scaledStroke.fY > yRadius) {
|
| + bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
|
| + SkStrokeRec::kHairline_Style == style;
|
| + bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
|
| +
|
| + if (hasStroke) {
|
| + if (SkStrokeRec::kHairline_Style == style) {
|
| + scaledStroke.set(1, 1);
|
| + } else {
|
| + scaledStroke.fX = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMScaleX] +
|
| + vm[SkMatrix::kMSkewY]));
|
| + scaledStroke.fY = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMSkewX] +
|
| + vm[SkMatrix::kMScaleY]));
|
| + }
|
| +
|
| + // if half of strokewidth is greater than radius, we don't handle that right now
|
| + if (SK_ScalarHalf*scaledStroke.fX > xRadius || SK_ScalarHalf*scaledStroke.fY > yRadius) {
|
| + return false;
|
| + }
|
| + }
|
| +
|
| + // The way the effect interpolates the offset-to-ellipse/circle-center attribute only works on
|
| + // the interior of the rrect if the radii are >= 0.5. Otherwise, the inner rect of the nine-
|
| + // patch will have fractional coverage. This only matters when the interior is actually filled.
|
| + // We could consider falling back to rect rendering here, since a tiny radius is
|
| + // indistinguishable from a square corner.
|
| + if (!isStrokeOnly && (SK_ScalarHalf > xRadius || SK_ScalarHalf > yRadius)) {
|
| return false;
|
| }
|
|
|
| @@ -933,8 +984,6 @@ bool GrOvalRenderer::drawSimpleRRect(GrDrawTarget* target, GrContext* context, b
|
| return false;
|
| }
|
|
|
| - bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style);
|
| -
|
| GrIndexBuffer* indexBuffer = this->rRectIndexBuffer(context->getGpu());
|
| if (NULL == indexBuffer) {
|
| GrPrintf("Failed to create index buffer!\n");
|
| @@ -942,7 +991,7 @@ bool GrOvalRenderer::drawSimpleRRect(GrDrawTarget* target, GrContext* context, b
|
| }
|
|
|
| // if the corners are circles, use the circle renderer
|
| - if ((!isStroked || scaledStroke.fX == scaledStroke.fY) && xRadius == yRadius) {
|
| + if ((!hasStroke || scaledStroke.fX == scaledStroke.fY) && xRadius == yRadius) {
|
| drawState->setVertexAttribs<gCircleVertexAttribs>(SK_ARRAY_COUNT(gCircleVertexAttribs));
|
| SkASSERT(sizeof(CircleVertex) == drawState->getVertexSize());
|
|
|
| @@ -956,23 +1005,23 @@ bool GrOvalRenderer::drawSimpleRRect(GrDrawTarget* target, GrContext* context, b
|
| SkScalar innerRadius = 0.0f;
|
| SkScalar outerRadius = xRadius;
|
| SkScalar halfWidth = 0;
|
| - if (style != SkStrokeRec::kFill_Style) {
|
| + if (hasStroke) {
|
| if (SkScalarNearlyZero(scaledStroke.fX)) {
|
| halfWidth = SK_ScalarHalf;
|
| } else {
|
| halfWidth = SkScalarHalf(scaledStroke.fX);
|
| }
|
|
|
| - if (isStroked) {
|
| + if (isStrokeOnly) {
|
| innerRadius = xRadius - halfWidth;
|
| }
|
| outerRadius += halfWidth;
|
| bounds.outset(halfWidth, halfWidth);
|
| }
|
|
|
| - isStroked = (isStroked && innerRadius >= 0);
|
| + isStrokeOnly = (isStrokeOnly && innerRadius >= 0);
|
|
|
| - GrEffectRef* effect = CircleEdgeEffect::Create(isStroked);
|
| + GrEffectRef* effect = CircleEdgeEffect::Create(isStrokeOnly);
|
| static const int kCircleEdgeAttrIndex = 1;
|
| drawState->addCoverageEffect(effect, kCircleEdgeAttrIndex)->unref();
|
|
|
| @@ -1025,7 +1074,8 @@ bool GrOvalRenderer::drawSimpleRRect(GrDrawTarget* target, GrContext* context, b
|
| }
|
|
|
| // drop out the middle quad if we're stroked
|
| - int indexCnt = isStroked ? SK_ARRAY_COUNT(gRRectIndices)-6 : SK_ARRAY_COUNT(gRRectIndices);
|
| + int indexCnt = isStrokeOnly ? SK_ARRAY_COUNT(gRRectIndices) - 6 :
|
| + SK_ARRAY_COUNT(gRRectIndices);
|
| target->setIndexSourceToBuffer(indexBuffer);
|
| target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 16, indexCnt, &bounds);
|
|
|
| @@ -1036,7 +1086,7 @@ bool GrOvalRenderer::drawSimpleRRect(GrDrawTarget* target, GrContext* context, b
|
|
|
| SkScalar innerXRadius = 0.0f;
|
| SkScalar innerYRadius = 0.0f;
|
| - if (SkStrokeRec::kFill_Style != style) {
|
| + if (hasStroke) {
|
| if (SkScalarNearlyZero(scaledStroke.length())) {
|
| scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
|
| } else {
|
| @@ -1056,7 +1106,7 @@ bool GrOvalRenderer::drawSimpleRRect(GrDrawTarget* target, GrContext* context, b
|
| }
|
|
|
| // this is legit only if scale & translation (which should be the case at the moment)
|
| - if (isStroked) {
|
| + if (isStrokeOnly) {
|
| innerXRadius = xRadius - scaledStroke.fX;
|
| innerYRadius = yRadius - scaledStroke.fY;
|
| }
|
| @@ -1066,7 +1116,7 @@ bool GrOvalRenderer::drawSimpleRRect(GrDrawTarget* target, GrContext* context, b
|
| bounds.outset(scaledStroke.fX, scaledStroke.fY);
|
| }
|
|
|
| - isStroked = (isStroked && innerXRadius >= 0 && innerYRadius >= 0);
|
| + isStrokeOnly = (isStrokeOnly && innerXRadius >= 0 && innerYRadius >= 0);
|
|
|
| GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
|
| if (!geo.succeeded()) {
|
| @@ -1075,7 +1125,7 @@ bool GrOvalRenderer::drawSimpleRRect(GrDrawTarget* target, GrContext* context, b
|
| }
|
| EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices());
|
|
|
| - GrEffectRef* effect = EllipseEdgeEffect::Create(isStroked);
|
| + GrEffectRef* effect = EllipseEdgeEffect::Create(isStrokeOnly);
|
| static const int kEllipseOffsetAttrIndex = 1;
|
| static const int kEllipseRadiiAttrIndex = 2;
|
| drawState->addCoverageEffect(effect,
|
| @@ -1134,7 +1184,8 @@ bool GrOvalRenderer::drawSimpleRRect(GrDrawTarget* target, GrContext* context, b
|
| }
|
|
|
| // drop out the middle quad if we're stroked
|
| - int indexCnt = isStroked ? SK_ARRAY_COUNT(gRRectIndices)-6 : SK_ARRAY_COUNT(gRRectIndices);
|
| + int indexCnt = isStrokeOnly ? SK_ARRAY_COUNT(gRRectIndices) - 6 :
|
| + SK_ARRAY_COUNT(gRRectIndices);
|
| target->setIndexSourceToBuffer(indexBuffer);
|
| target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 16, indexCnt, &bounds);
|
| }
|
|
|