diff options
author | commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-03-22 18:34:09 +0000 |
---|---|---|
committer | commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-03-22 18:34:09 +0000 |
commit | 81312830ef73420efdc4821feb7c2d6fd9152af8 (patch) | |
tree | eed904a41dc717fe1ac1c9c757e416b99c69f85d /src/gpu | |
parent | 6f6568b27eae62fea23ab8192c6da02ab892bb5e (diff) |
Move oval rendering code to GrOvalRenderer.
Author: jvanverth@google.com
Reviewed By: bsalomon@google.com,robertphillips@google.com
Review URL: https://chromiumcodereview.appspot.com/12657003
git-svn-id: http://skia.googlecode.com/svn/trunk@8345 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/gpu')
-rw-r--r-- | src/gpu/GrContext.cpp | 321 | ||||
-rw-r--r-- | src/gpu/GrOvalRenderer.cpp | 278 |
2 files changed, 298 insertions, 301 deletions
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index 4798297a3a..eee3307c40 100644 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -12,13 +12,12 @@ #include "effects/GrConvolutionEffect.h" #include "effects/GrSingleTextureEffect.h" #include "effects/GrConfigConversionEffect.h" -#include "effects/GrCircleEdgeEffect.h" -#include "effects/GrEllipseEdgeEffect.h" #include "GrBufferAllocPool.h" #include "GrGpu.h" #include "GrIndexBuffer.h" #include "GrInOrderDrawBuffer.h" +#include "GrOvalRenderer.h" #include "GrPathRenderer.h" #include "GrPathUtils.h" #include "GrResourceCache.h" @@ -99,6 +98,7 @@ GrContext::GrContext() { fDrawBufferVBAllocPool = NULL; fDrawBufferIBAllocPool = NULL; fAARectRenderer = NULL; + fOvalRenderer = NULL; } bool GrContext::init(GrBackend backend, GrBackendContext backendContext) { @@ -121,6 +121,7 @@ bool GrContext::init(GrBackend backend, GrBackendContext backendContext) { fLastDrawWasBuffered = kNo_BufferedDraw; fAARectRenderer = SkNEW(GrAARectRenderer); + fOvalRenderer = SkNEW(GrOvalRenderer); fDidTestPMConversions = false; @@ -152,6 +153,7 @@ GrContext::~GrContext() { delete fDrawBufferIBAllocPool; fAARectRenderer->unref(); + fOvalRenderer->unref(); fGpu->unref(); GrSafeUnref(fPathRendererChain); @@ -989,295 +991,19 @@ void GrContext::drawVertices(const GrPaint& paint, } /////////////////////////////////////////////////////////////////////////////// -namespace { - -struct CircleVertex { - GrPoint fPos; - GrPoint fCenter; - SkScalar fOuterRadius; - SkScalar fInnerRadius; -}; - -struct EllipseVertex { - GrPoint fPos; - GrPoint fCenter; - SkScalar fOuterXRadius; - SkScalar fOuterXYRatio; - SkScalar fInnerXRadius; - SkScalar fInnerXYRatio; -}; - -inline bool circleStaysCircle(const SkMatrix& m) { - return m.isSimilarity(); -} - -} void GrContext::drawOval(const GrPaint& paint, const GrRect& oval, const SkStrokeRec& stroke) { - bool isCircle; - if (!canDrawOval(paint, oval, &isCircle)) { - SkPath path; - path.addOval(oval); - this->drawPath(paint, path, stroke); - return; - } - - if (isCircle) { - this->internalDrawCircle(paint, oval, stroke); - } else { - this->internalDrawOval(paint, oval, stroke); - } -} - -bool GrContext::canDrawOval(const GrPaint& paint, const GrRect& oval, bool* isCircle) const { - GrAssert(isCircle != NULL); - - if (!paint.isAntiAlias()) { - return false; - } - - // we can draw circles - *isCircle = SkScalarNearlyEqual(oval.width(), oval.height()) - && circleStaysCircle(this->getMatrix()); - // and axis-aligned ellipses only - bool isAxisAlignedEllipse = this->getMatrix().rectStaysRect(); - - return *isCircle || isAxisAlignedEllipse; -} - -void GrContext::internalDrawOval(const GrPaint& paint, - const GrRect& oval, - const SkStrokeRec& stroke) { -#ifdef SK_DEBUG - { - // we should have checked for this previously - bool isAxisAlignedEllipse = this->getMatrix().rectStaysRect(); - SkASSERT(paint.isAntiAlias() && isAxisAlignedEllipse); - } -#endif - GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW); - - GrDrawState* drawState = target->drawState(); - GrDrawState::AutoStageDisable atr(fDrawState); - - const GrRenderTarget* rt = drawState->getRenderTarget(); - if (NULL == rt) { - return; - } - - const SkMatrix vm = drawState->getViewMatrix(); - - GrDrawState::AutoDeviceCoordDraw adcd(drawState); - if (!adcd.succeeded()) { - return; - } - - // position + edge - static const GrVertexAttrib kVertexAttribs[] = { - {kVec2f_GrVertexAttribType, 0}, - {kVec2f_GrVertexAttribType, sizeof(GrPoint)}, - {kVec4f_GrVertexAttribType, 2*sizeof(GrPoint)} - }; - drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs)); - drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0); - GrAssert(sizeof(EllipseVertex) == drawState->getVertexSize()); - - GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0); - if (!geo.succeeded()) { - GrPrintf("Failed to get space for vertices!\n"); - return; - } - - EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices()); - - GrPoint center = GrPoint::Make(oval.centerX(), oval.centerY()); - vm.mapPoints(¢er, 1); - - SkStrokeRec::Style style = stroke.getStyle(); - bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style); - enum { - // the edge effects share this stage with glyph rendering - // (kGlyphMaskStage in GrTextContext) && SW path rendering - // (kPathMaskStage in GrSWMaskHelper) - kEdgeEffectStage = GrPaint::kTotalStages, - }; - drawState->setAttribBindings(GrDrawState::kDefault_AttribBindings); - - GrEffectRef* effect = GrEllipseEdgeEffect::Create(isStroked); - static const int kEllipseCenterAttrIndex = 1; - static const int kEllipseEdgeAttrIndex = 2; - drawState->setEffect(kEdgeEffectStage, effect, - kEllipseCenterAttrIndex, kEllipseEdgeAttrIndex)->unref(); - - SkRect xformedRect; - vm.mapRect(&xformedRect, oval); - - SkScalar xRadius = SkScalarHalf(xformedRect.width()); - SkScalar yRadius = SkScalarHalf(xformedRect.height()); - SkScalar innerXRadius = 0.0f; - SkScalar innerRatio = 1.0f; - - if (SkStrokeRec::kFill_Style != style) { - SkScalar strokeWidth = stroke.getWidth(); - - // do (potentially) anisotropic mapping - SkVector scaledStroke; - scaledStroke.set(strokeWidth, strokeWidth); - vm.mapVectors(&scaledStroke, 1); - - if (SkScalarNearlyZero(scaledStroke.length())) { - scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf); - } else { - scaledStroke.scale(0.5f); - } - - // this is legit only if scale & translation (which should be the case at the moment) - if (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style) { - SkScalar innerYRadius = SkMaxScalar(0, yRadius - scaledStroke.fY); - if (innerYRadius > SK_ScalarNearlyZero) { - innerXRadius = SkMaxScalar(0, xRadius - scaledStroke.fX); - innerRatio = innerXRadius/innerYRadius; - } - } - xRadius += scaledStroke.fX; - yRadius += scaledStroke.fY; - } - - SkScalar outerRatio = SkScalarDiv(xRadius, yRadius); - - for (int i = 0; i < 4; ++i) { - verts[i].fCenter = center; - verts[i].fOuterXRadius = xRadius + 0.5f; - verts[i].fOuterXYRatio = outerRatio; - verts[i].fInnerXRadius = innerXRadius - 0.5f; - verts[i].fInnerXYRatio = innerRatio; - } - - SkScalar L = -xRadius; - SkScalar R = +xRadius; - SkScalar T = -yRadius; - SkScalar B = +yRadius; - - // We've extended the outer x radius out half a pixel to antialias. - // Expand the drawn rect here so all the pixels will be captured. - L += center.fX - SK_ScalarHalf; - R += center.fX + SK_ScalarHalf; - T += center.fY - SK_ScalarHalf; - B += center.fY + SK_ScalarHalf; - - verts[0].fPos = SkPoint::Make(L, T); - verts[1].fPos = SkPoint::Make(R, T); - verts[2].fPos = SkPoint::Make(L, B); - verts[3].fPos = SkPoint::Make(R, B); - - target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4); -} - -void GrContext::internalDrawCircle(const GrPaint& paint, - const GrRect& circle, - const SkStrokeRec& stroke) { - - SkScalar radius = SkScalarHalf(circle.width()); - - SkScalar strokeWidth = stroke.getWidth(); - SkStrokeRec::Style style = stroke.getStyle(); - GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW); - - GrDrawState* drawState = target->drawState(); GrDrawState::AutoStageDisable atr(fDrawState); - const GrRenderTarget* rt = drawState->getRenderTarget(); - if (NULL == rt) { - return; - } - - const SkMatrix vm = drawState->getViewMatrix(); - - GrDrawState::AutoDeviceCoordDraw adcd(drawState); - if (!adcd.succeeded()) { - return; - } - - // position + edge - static const GrVertexAttrib kVertexAttribs[] = { - {kVec2f_GrVertexAttribType, 0}, - {kVec4f_GrVertexAttribType, sizeof(GrPoint)} - }; - drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs)); - drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0); - GrAssert(sizeof(CircleVertex) == drawState->getVertexSize()); - - GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0); - if (!geo.succeeded()) { - GrPrintf("Failed to get space for vertices!\n"); - return; - } - - CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices()); - - GrPoint center = GrPoint::Make(circle.centerX(), circle.centerY()); - vm.mapPoints(¢er, 1); - - bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style); - enum { - // the edge effects share this stage with glyph rendering - // (kGlyphMaskStage in GrTextContext) && SW path rendering - // (kPathMaskStage in GrSWMaskHelper) - kEdgeEffectStage = GrPaint::kTotalStages, - }; - drawState->setAttribBindings(GrDrawState::kDefault_AttribBindings); - - GrEffectRef* effect = GrCircleEdgeEffect::Create(isStroked); - static const int kCircleEdgeAttrIndex = 1; - drawState->setEffect(kEdgeEffectStage, effect, kCircleEdgeAttrIndex)->unref(); - - radius = vm.mapRadius(radius); - - SkScalar innerRadius = -2.0f; - SkScalar outerRadius = radius; - SkScalar halfWidth = 0; - if (style != SkStrokeRec::kFill_Style) { - strokeWidth = vm.mapRadius(strokeWidth); - if (SkScalarNearlyZero(strokeWidth)) { - halfWidth = SK_ScalarHalf; - } else { - halfWidth = SkScalarHalf(strokeWidth); - } - - outerRadius += halfWidth; - if (isStroked) { - innerRadius = SkMaxScalar(0, radius - halfWidth); - } - } - - for (int i = 0; i < 4; ++i) { - verts[i].fCenter = center; - verts[i].fOuterRadius = outerRadius + 0.5f; - verts[i].fInnerRadius = innerRadius - 0.5f; + if (!fOvalRenderer->drawOval(target, this, paint, oval, stroke)) { + SkPath path; + path.addOval(oval); + this->internalDrawPath(target, paint, path, stroke); } - - SkScalar L = -outerRadius; - SkScalar R = +outerRadius; - SkScalar T = -outerRadius; - SkScalar B = +outerRadius; - - // We've extended the outer radius out half a pixel to antialias. - // Expand the drawn rect here so all the pixels will be captured. - L += center.fX - SK_ScalarHalf; - R += center.fX + SK_ScalarHalf; - T += center.fY - SK_ScalarHalf; - B += center.fY + SK_ScalarHalf; - - verts[0].fPos = SkPoint::Make(L, T); - verts[1].fPos = SkPoint::Make(R, T); - verts[2].fPos = SkPoint::Make(L, B); - verts[3].fPos = SkPoint::Make(R, B); - - target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4); } void GrContext::drawPath(const GrPaint& paint, const SkPath& path, const SkStrokeRec& stroke) { @@ -1289,33 +1015,26 @@ void GrContext::drawPath(const GrPaint& paint, const SkPath& path, const SkStrok return; } + // Note that internalDrawPath may sw-rasterize the path into a scratch texture. + // Scratch textures can be recycled after they are returned to the texture + // cache. This presents a potential hazard for buffered drawing. However, + // the writePixels that uploads to the scratch will perform a flush so we're + // OK. + GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW); + GrDrawState::AutoStageDisable atr(fDrawState); + SkRect ovalRect; bool isOval = path.isOval(&ovalRect); - bool isCircle; - if (isOval && !path.isInverseFillType() && this->canDrawOval(paint, ovalRect, &isCircle)) { - if (isCircle) { - this->internalDrawCircle(paint, ovalRect, stroke); - } else { - this->internalDrawOval(paint, ovalRect, stroke); - } - return; + if (!isOval || path.isInverseFillType() + || !fOvalRenderer->drawOval(target, this, paint, ovalRect, stroke)) { + this->internalDrawPath(target, paint, path, stroke); } - - this->internalDrawPath(paint, path, stroke); } -void GrContext::internalDrawPath(const GrPaint& paint, const SkPath& path, +void GrContext::internalDrawPath(GrDrawTarget* target, const GrPaint& paint, const SkPath& path, const SkStrokeRec& stroke) { - // Note that below we may sw-rasterize the path into a scratch texture. - // Scratch textures can be recycled after they are returned to the texture - // cache. This presents a potential hazard for buffered drawing. However, - // the writePixels that uploads to the scratch will perform a flush so we're - // OK. - GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW); - GrDrawState::AutoStageDisable atr(fDrawState); - bool prAA = paint.isAntiAlias() && !this->getRenderTarget()->isMultisampled(); // An Assumption here is that path renderer would use some form of tweaking diff --git a/src/gpu/GrOvalRenderer.cpp b/src/gpu/GrOvalRenderer.cpp new file mode 100644 index 0000000000..4847e0e9e1 --- /dev/null +++ b/src/gpu/GrOvalRenderer.cpp @@ -0,0 +1,278 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrOvalRenderer.h" + +#include "effects/GrCircleEdgeEffect.h" +#include "effects/GrEllipseEdgeEffect.h" + +#include "GrDrawState.h" +#include "GrDrawTarget.h" +#include "SkStrokeRec.h" + +SK_DEFINE_INST_COUNT(GrOvalRenderer) + +namespace { + +struct CircleVertex { + GrPoint fPos; + GrPoint fCenter; + SkScalar fOuterRadius; + SkScalar fInnerRadius; +}; + +struct EllipseVertex { + GrPoint fPos; + GrPoint fCenter; + SkScalar fOuterXRadius; + SkScalar fOuterXYRatio; + SkScalar fInnerXRadius; + SkScalar fInnerXYRatio; +}; + +inline bool circle_stays_circle(const SkMatrix& m) { + return m.isSimilarity(); +} + +} + +bool GrOvalRenderer::drawOval(GrDrawTarget* target, const GrContext* context, const GrPaint& paint, + const GrRect& oval, const SkStrokeRec& stroke) +{ + if (!paint.isAntiAlias()) { + return false; + } + + const SkMatrix& vm = context->getMatrix(); + + // we can draw circles + if (SkScalarNearlyEqual(oval.width(), oval.height()) + && circle_stays_circle(vm)) { + drawCircle(target, paint, oval, stroke); + + // and axis-aligned ellipses only + } else if (vm.rectStaysRect()) { + drawEllipse(target, paint, oval, stroke); + + } else { + return false; + } + + return true; +} + +void GrOvalRenderer::drawCircle(GrDrawTarget* target, + const GrPaint& paint, + const GrRect& circle, + const SkStrokeRec& stroke) +{ + GrDrawState* drawState = target->drawState(); + + const SkMatrix& vm = drawState->getViewMatrix(); + GrPoint center = GrPoint::Make(circle.centerX(), circle.centerY()); + vm.mapPoints(¢er, 1); + SkScalar radius = vm.mapRadius(SkScalarHalf(circle.width())); + SkScalar strokeWidth = vm.mapRadius(stroke.getWidth()); + + GrDrawState::AutoDeviceCoordDraw adcd(drawState); + if (!adcd.succeeded()) { + return; + } + + // position + edge + static const GrVertexAttrib kVertexAttribs[] = { + {kVec2f_GrVertexAttribType, 0}, + {kVec4f_GrVertexAttribType, sizeof(GrPoint)} + }; + drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs)); + drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0); + GrAssert(sizeof(CircleVertex) == drawState->getVertexSize()); + + GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0); + if (!geo.succeeded()) { + GrPrintf("Failed to get space for vertices!\n"); + return; + } + + CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices()); + + SkStrokeRec::Style style = stroke.getStyle(); + bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style); + enum { + // the edge effects share this stage with glyph rendering + // (kGlyphMaskStage in GrTextContext) && SW path rendering + // (kPathMaskStage in GrSWMaskHelper) + kEdgeEffectStage = GrPaint::kTotalStages, + }; + drawState->setAttribBindings(GrDrawState::kDefault_AttribBindings); + + GrEffectRef* effect = GrCircleEdgeEffect::Create(isStroked); + static const int kCircleEdgeAttrIndex = 1; + drawState->setEffect(kEdgeEffectStage, effect, kCircleEdgeAttrIndex)->unref(); + + SkScalar innerRadius = 0.0f; + SkScalar outerRadius = radius; + SkScalar halfWidth = 0; + if (style != SkStrokeRec::kFill_Style) { + if (SkScalarNearlyZero(strokeWidth)) { + halfWidth = SK_ScalarHalf; + } else { + halfWidth = SkScalarHalf(strokeWidth); + } + + outerRadius += halfWidth; + if (isStroked) { + innerRadius = SkMaxScalar(0, radius - halfWidth); + } + } + + for (int i = 0; i < 4; ++i) { + verts[i].fCenter = center; + verts[i].fOuterRadius = outerRadius + 0.5f; + verts[i].fInnerRadius = innerRadius - 0.5f; + } + + SkScalar L = -outerRadius; + SkScalar R = +outerRadius; + SkScalar T = -outerRadius; + SkScalar B = +outerRadius; + + // We've extended the outer radius out half a pixel to antialias. + // Expand the drawn rect here so all the pixels will be captured. + L += center.fX - SK_ScalarHalf; + R += center.fX + SK_ScalarHalf; + T += center.fY - SK_ScalarHalf; + B += center.fY + SK_ScalarHalf; + + verts[0].fPos = SkPoint::Make(L, T); + verts[1].fPos = SkPoint::Make(R, T); + verts[2].fPos = SkPoint::Make(L, B); + verts[3].fPos = SkPoint::Make(R, B); + + target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4); +} + +void GrOvalRenderer::drawEllipse(GrDrawTarget* target, + const GrPaint& paint, + const GrRect& ellipse, + const SkStrokeRec& stroke) +{ + GrDrawState* drawState = target->drawState(); +#ifdef SK_DEBUG + { + // we should have checked for this previously + bool isAxisAlignedEllipse = drawState->getViewMatrix().rectStaysRect(); + SkASSERT(paint.isAntiAlias() && isAxisAlignedEllipse); + } +#endif + + const SkMatrix& vm = drawState->getViewMatrix(); + GrPoint center = GrPoint::Make(ellipse.centerX(), ellipse.centerY()); + vm.mapPoints(¢er, 1); + SkRect xformedRect; + vm.mapRect(&xformedRect, ellipse); + + GrDrawState::AutoDeviceCoordDraw adcd(drawState); + if (!adcd.succeeded()) { + return; + } + + // position + edge + static const GrVertexAttrib kVertexAttribs[] = { + {kVec2f_GrVertexAttribType, 0}, + {kVec2f_GrVertexAttribType, sizeof(GrPoint)}, + {kVec4f_GrVertexAttribType, 2*sizeof(GrPoint)} + }; + drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs)); + drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0); + GrAssert(sizeof(EllipseVertex) == drawState->getVertexSize()); + + GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0); + if (!geo.succeeded()) { + GrPrintf("Failed to get space for vertices!\n"); + return; + } + + EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices()); + + SkStrokeRec::Style style = stroke.getStyle(); + bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style); + enum { + // the edge effects share this stage with glyph rendering + // (kGlyphMaskStage in GrTextContext) && SW path rendering + // (kPathMaskStage in GrSWMaskHelper) + kEdgeEffectStage = GrPaint::kTotalStages, + }; + drawState->setAttribBindings(GrDrawState::kDefault_AttribBindings); + + GrEffectRef* effect = GrEllipseEdgeEffect::Create(isStroked); + static const int kEllipseCenterAttrIndex = 1; + static const int kEllipseEdgeAttrIndex = 2; + drawState->setEffect(kEdgeEffectStage, effect, + kEllipseCenterAttrIndex, kEllipseEdgeAttrIndex)->unref(); + + SkScalar xRadius = SkScalarHalf(xformedRect.width()); + SkScalar yRadius = SkScalarHalf(xformedRect.height()); + SkScalar innerXRadius = 0.0f; + SkScalar innerRatio = 1.0f; + + if (SkStrokeRec::kFill_Style != style) { + SkScalar strokeWidth = stroke.getWidth(); + + // do (potentially) anisotropic mapping + SkVector scaledStroke; + scaledStroke.set(strokeWidth, strokeWidth); + vm.mapVectors(&scaledStroke, 1); + + if (SkScalarNearlyZero(scaledStroke.length())) { + scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf); + } else { + scaledStroke.scale(0.5f); + } + + // this is legit only if scale & translation (which should be the case at the moment) + if (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style) { + SkScalar innerYRadius = SkMaxScalar(0, yRadius - scaledStroke.fY); + if (innerYRadius > SK_ScalarNearlyZero) { + innerXRadius = SkMaxScalar(0, xRadius - scaledStroke.fX); + innerRatio = innerXRadius/innerYRadius; + } + } + xRadius += scaledStroke.fX; + yRadius += scaledStroke.fY; + } + + SkScalar outerRatio = SkScalarDiv(xRadius, yRadius); + + for (int i = 0; i < 4; ++i) { + verts[i].fCenter = center; + verts[i].fOuterXRadius = xRadius + 0.5f; + verts[i].fOuterXYRatio = outerRatio; + verts[i].fInnerXRadius = innerXRadius - 0.5f; + verts[i].fInnerXYRatio = innerRatio; + } + + SkScalar L = -xRadius; + SkScalar R = +xRadius; + SkScalar T = -yRadius; + SkScalar B = +yRadius; + + // We've extended the outer x radius out half a pixel to antialias. + // Expand the drawn rect here so all the pixels will be captured. + L += center.fX - SK_ScalarHalf; + R += center.fX + SK_ScalarHalf; + T += center.fY - SK_ScalarHalf; + B += center.fY + SK_ScalarHalf; + + verts[0].fPos = SkPoint::Make(L, T); + verts[1].fPos = SkPoint::Make(R, T); + verts[2].fPos = SkPoint::Make(L, B); + verts[3].fPos = SkPoint::Make(R, B); + + target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4); +} + |