aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu
diff options
context:
space:
mode:
authorGravatar commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-03-22 18:34:09 +0000
committerGravatar commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-03-22 18:34:09 +0000
commit81312830ef73420efdc4821feb7c2d6fd9152af8 (patch)
treeeed904a41dc717fe1ac1c9c757e416b99c69f85d /src/gpu
parent6f6568b27eae62fea23ab8192c6da02ab892bb5e (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.cpp321
-rw-r--r--src/gpu/GrOvalRenderer.cpp278
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(&center, 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(&center, 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(&center, 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(&center, 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);
+}
+