Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 /* | |
|
robertphillips
2013/03/21 13:12:39
2013
jvanverth1
2013/03/21 18:42:18
Done.
| |
| 2 * Copyright 2012 Google Inc. | |
| 3 * | |
| 4 * Use of this source code is governed by a BSD-style license that can be | |
| 5 * found in the LICENSE file. | |
| 6 */ | |
| 7 | |
| 8 #include "GrOvalRenderer.h" | |
| 9 | |
| 10 #include "effects/GrCircleEdgeEffect.h" | |
| 11 #include "effects/GrEllipseEdgeEffect.h" | |
| 12 | |
| 13 #include "GrContext.h" | |
| 14 #include "GrDrawState.h" | |
| 15 #include "GrDrawTarget.h" | |
| 16 #include "GrPaint.h" | |
| 17 #include "SkStrokeRec.h" | |
| 18 | |
| 19 SK_DEFINE_INST_COUNT(GrOvalRenderer) | |
| 20 | |
| 21 namespace { | |
| 22 | |
| 23 struct CircleVertex { | |
| 24 GrPoint fPos; | |
| 25 GrPoint fCenter; | |
| 26 SkScalar fOuterRadius; | |
| 27 SkScalar fInnerRadius; | |
| 28 }; | |
| 29 | |
| 30 struct EllipseVertex { | |
| 31 GrPoint fPos; | |
| 32 GrPoint fCenter; | |
| 33 SkScalar fOuterXRadius; | |
| 34 SkScalar fOuterXYRatio; | |
| 35 SkScalar fInnerXRadius; | |
| 36 SkScalar fInnerXYRatio; | |
| 37 }; | |
| 38 | |
|
robertphillips
2013/03/21 13:12:39
circle_stays_circle
jvanverth1
2013/03/21 18:42:18
Done.
| |
| 39 inline bool circleStaysCircle(const SkMatrix& m) { | |
| 40 return m.isSimilarity(); | |
| 41 } | |
| 42 | |
| 43 } | |
| 44 | |
| 45 bool GrOvalRenderer::canDrawOval(const GrContext* context, const GrPaint& paint, | |
| 46 const GrRect& oval, bool* isCircle) const | |
| 47 { | |
| 48 GrAssert(isCircle != NULL); | |
| 49 | |
| 50 if (!paint.isAntiAlias()) { | |
| 51 return false; | |
| 52 } | |
| 53 | |
| 54 // we can draw circles | |
| 55 *isCircle = SkScalarNearlyEqual(oval.width(), oval.height()) | |
| 56 && circleStaysCircle(context->getMatrix()); | |
| 57 // and axis-aligned ellipses only | |
| 58 bool isAxisAlignedEllipse = context->getMatrix().rectStaysRect(); | |
| 59 | |
| 60 return *isCircle || isAxisAlignedEllipse; | |
| 61 | |
| 62 } | |
| 63 | |
| 64 void GrOvalRenderer::drawEllipse(GrDrawTarget* target, | |
| 65 const GrPaint& paint, | |
| 66 const GrRect& ellipse, | |
| 67 const SkStrokeRec& stroke) | |
| 68 { | |
| 69 GrDrawState* drawState = target->drawState(); | |
| 70 #ifdef SK_DEBUG | |
| 71 { | |
| 72 // we should have checked for this previously | |
| 73 bool isAxisAlignedEllipse = drawState->getViewMatrix().rectStaysRect(); | |
| 74 SkASSERT(paint.isAntiAlias() && isAxisAlignedEllipse); | |
| 75 } | |
| 76 #endif | |
| 77 | |
|
robertphillips
2013/03/21 13:12:39
Do we even need "rt"?
jvanverth1
2013/03/21 18:42:18
Done.
| |
| 78 const GrRenderTarget* rt = drawState->getRenderTarget(); | |
| 79 if (NULL == rt) { | |
| 80 return; | |
| 81 } | |
| 82 | |
|
robertphillips
2013/03/21 13:12:39
&
jvanverth1
2013/03/21 18:42:18
Done.
| |
| 83 const SkMatrix vm = drawState->getViewMatrix(); | |
| 84 | |
| 85 GrDrawState::AutoDeviceCoordDraw adcd(drawState); | |
| 86 if (!adcd.succeeded()) { | |
| 87 return; | |
| 88 } | |
| 89 | |
| 90 // position + edge | |
| 91 static const GrVertexAttrib kVertexAttribs[] = { | |
| 92 {kVec2f_GrVertexAttribType, 0}, | |
| 93 {kVec2f_GrVertexAttribType, sizeof(GrPoint)}, | |
| 94 {kVec4f_GrVertexAttribType, 2*sizeof(GrPoint)} | |
| 95 }; | |
| 96 drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs)); | |
| 97 drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0); | |
| 98 GrAssert(sizeof(EllipseVertex) == drawState->getVertexSize()); | |
| 99 | |
| 100 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0); | |
| 101 if (!geo.succeeded()) { | |
| 102 GrPrintf("Failed to get space for vertices!\n"); | |
| 103 return; | |
| 104 } | |
| 105 | |
| 106 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices()); | |
| 107 | |
| 108 GrPoint center = GrPoint::Make(ellipse.centerX(), ellipse.centerY()); | |
| 109 vm.mapPoints(¢er, 1); | |
| 110 | |
| 111 SkStrokeRec::Style style = stroke.getStyle(); | |
| 112 bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairl ine_Style == style); | |
| 113 enum { | |
| 114 // the edge effects share this stage with glyph rendering | |
| 115 // (kGlyphMaskStage in GrTextContext) && SW path rendering | |
| 116 // (kPathMaskStage in GrSWMaskHelper) | |
| 117 kEdgeEffectStage = GrPaint::kTotalStages, | |
| 118 }; | |
| 119 drawState->setAttribBindings(GrDrawState::kDefault_AttribBindings); | |
| 120 | |
| 121 GrEffectRef* effect = GrEllipseEdgeEffect::Create(isStroked); | |
| 122 static const int kEllipseCenterAttrIndex = 1; | |
| 123 static const int kEllipseEdgeAttrIndex = 2; | |
| 124 drawState->setEffect(kEdgeEffectStage, effect, | |
| 125 kEllipseCenterAttrIndex, kEllipseEdgeAttrIndex)->unref( ); | |
| 126 | |
| 127 SkRect xformedRect; | |
| 128 vm.mapRect(&xformedRect, ellipse); | |
| 129 | |
| 130 SkScalar xRadius = SkScalarHalf(xformedRect.width()); | |
| 131 SkScalar yRadius = SkScalarHalf(xformedRect.height()); | |
| 132 SkScalar innerXRadius = 0.0f; | |
| 133 SkScalar innerRatio = 1.0f; | |
| 134 | |
| 135 if (SkStrokeRec::kFill_Style != style) { | |
| 136 SkScalar strokeWidth = stroke.getWidth(); | |
| 137 | |
| 138 // do (potentially) anisotropic mapping | |
| 139 SkVector scaledStroke; | |
| 140 scaledStroke.set(strokeWidth, strokeWidth); | |
| 141 vm.mapVectors(&scaledStroke, 1); | |
| 142 | |
| 143 if (SkScalarNearlyZero(scaledStroke.length())) { | |
| 144 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf); | |
| 145 } else { | |
| 146 scaledStroke.scale(0.5f); | |
| 147 } | |
| 148 | |
| 149 // this is legit only if scale & translation (which should be the case a t the moment) | |
| 150 if (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style) { | |
| 151 SkScalar innerYRadius = SkMaxScalar(0, yRadius - scaledStroke.fY); | |
| 152 if (innerYRadius > SK_ScalarNearlyZero) { | |
| 153 innerXRadius = SkMaxScalar(0, xRadius - scaledStroke.fX); | |
| 154 innerRatio = innerXRadius/innerYRadius; | |
| 155 } | |
| 156 } | |
| 157 xRadius += scaledStroke.fX; | |
| 158 yRadius += scaledStroke.fY; | |
| 159 } | |
| 160 | |
| 161 SkScalar outerRatio = SkScalarDiv(xRadius, yRadius); | |
| 162 | |
| 163 for (int i = 0; i < 4; ++i) { | |
| 164 verts[i].fCenter = center; | |
| 165 verts[i].fOuterXRadius = xRadius + 0.5f; | |
| 166 verts[i].fOuterXYRatio = outerRatio; | |
| 167 verts[i].fInnerXRadius = innerXRadius - 0.5f; | |
| 168 verts[i].fInnerXYRatio = innerRatio; | |
| 169 } | |
| 170 | |
| 171 SkScalar L = -xRadius; | |
| 172 SkScalar R = +xRadius; | |
| 173 SkScalar T = -yRadius; | |
| 174 SkScalar B = +yRadius; | |
| 175 | |
| 176 // We've extended the outer x radius out half a pixel to antialias. | |
| 177 // Expand the drawn rect here so all the pixels will be captured. | |
| 178 L += center.fX - SK_ScalarHalf; | |
| 179 R += center.fX + SK_ScalarHalf; | |
| 180 T += center.fY - SK_ScalarHalf; | |
| 181 B += center.fY + SK_ScalarHalf; | |
| 182 | |
| 183 verts[0].fPos = SkPoint::Make(L, T); | |
| 184 verts[1].fPos = SkPoint::Make(R, T); | |
| 185 verts[2].fPos = SkPoint::Make(L, B); | |
| 186 verts[3].fPos = SkPoint::Make(R, B); | |
| 187 | |
| 188 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4); | |
| 189 } | |
| 190 | |
| 191 void GrOvalRenderer::drawCircle(GrDrawTarget* target, | |
| 192 const GrPaint& paint, | |
| 193 const GrRect& circle, | |
| 194 const SkStrokeRec& stroke) | |
| 195 { | |
| 196 GrDrawState* drawState = target->drawState(); | |
|
robertphillips
2013/03/21 13:12:39
Do we even need "rt"?
jvanverth1
2013/03/21 18:42:18
Done.
| |
| 197 const GrRenderTarget* rt = drawState->getRenderTarget(); | |
| 198 if (NULL == rt) { | |
| 199 return; | |
| 200 } | |
| 201 | |
| 202 SkScalar radius = SkScalarHalf(circle.width()); | |
| 203 | |
| 204 SkScalar strokeWidth = stroke.getWidth(); | |
| 205 SkStrokeRec::Style style = stroke.getStyle(); | |
| 206 | |
|
robertphillips
2013/03/21 13:12:39
&
jvanverth1
2013/03/21 18:42:18
Done.
| |
| 207 const SkMatrix vm = drawState->getViewMatrix(); | |
| 208 | |
| 209 GrDrawState::AutoDeviceCoordDraw adcd(drawState); | |
| 210 if (!adcd.succeeded()) { | |
| 211 return; | |
| 212 } | |
| 213 | |
| 214 // position + edge | |
| 215 static const GrVertexAttrib kVertexAttribs[] = { | |
| 216 {kVec2f_GrVertexAttribType, 0}, | |
| 217 {kVec4f_GrVertexAttribType, sizeof(GrPoint)} | |
| 218 }; | |
| 219 drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs)); | |
| 220 drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0); | |
| 221 GrAssert(sizeof(CircleVertex) == drawState->getVertexSize()); | |
| 222 | |
| 223 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0); | |
| 224 if (!geo.succeeded()) { | |
| 225 GrPrintf("Failed to get space for vertices!\n"); | |
| 226 return; | |
| 227 } | |
| 228 | |
| 229 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices()); | |
| 230 | |
| 231 GrPoint center = GrPoint::Make(circle.centerX(), circle.centerY()); | |
| 232 vm.mapPoints(¢er, 1); | |
| 233 | |
| 234 bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairl ine_Style == style); | |
| 235 enum { | |
| 236 // the edge effects share this stage with glyph rendering | |
| 237 // (kGlyphMaskStage in GrTextContext) && SW path rendering | |
| 238 // (kPathMaskStage in GrSWMaskHelper) | |
| 239 kEdgeEffectStage = GrPaint::kTotalStages, | |
| 240 }; | |
| 241 drawState->setAttribBindings(GrDrawState::kDefault_AttribBindings); | |
| 242 | |
| 243 GrEffectRef* effect = GrCircleEdgeEffect::Create(isStroked); | |
| 244 static const int kCircleEdgeAttrIndex = 1; | |
| 245 drawState->setEffect(kEdgeEffectStage, effect, kCircleEdgeAttrIndex)->unref( ); | |
| 246 | |
| 247 radius = vm.mapRadius(radius); | |
| 248 | |
| 249 SkScalar innerRadius = 0.0f; | |
| 250 SkScalar outerRadius = radius; | |
| 251 SkScalar halfWidth = 0; | |
| 252 if (style != SkStrokeRec::kFill_Style) { | |
| 253 strokeWidth = vm.mapRadius(strokeWidth); | |
| 254 if (SkScalarNearlyZero(strokeWidth)) { | |
| 255 halfWidth = SK_ScalarHalf; | |
| 256 } else { | |
| 257 halfWidth = SkScalarHalf(strokeWidth); | |
| 258 } | |
| 259 | |
| 260 outerRadius += halfWidth; | |
| 261 if (isStroked) { | |
| 262 innerRadius = SkMaxScalar(0, radius - halfWidth); | |
| 263 } | |
| 264 } | |
| 265 | |
| 266 for (int i = 0; i < 4; ++i) { | |
| 267 verts[i].fCenter = center; | |
| 268 verts[i].fOuterRadius = outerRadius + 0.5f; | |
| 269 verts[i].fInnerRadius = innerRadius - 0.5f; | |
| 270 } | |
| 271 | |
| 272 SkScalar L = -outerRadius; | |
| 273 SkScalar R = +outerRadius; | |
| 274 SkScalar T = -outerRadius; | |
| 275 SkScalar B = +outerRadius; | |
| 276 | |
| 277 // We've extended the outer radius out half a pixel to antialias. | |
| 278 // Expand the drawn rect here so all the pixels will be captured. | |
| 279 L += center.fX - SK_ScalarHalf; | |
| 280 R += center.fX + SK_ScalarHalf; | |
| 281 T += center.fY - SK_ScalarHalf; | |
| 282 B += center.fY + SK_ScalarHalf; | |
| 283 | |
| 284 verts[0].fPos = SkPoint::Make(L, T); | |
| 285 verts[1].fPos = SkPoint::Make(R, T); | |
| 286 verts[2].fPos = SkPoint::Make(L, B); | |
| 287 verts[3].fPos = SkPoint::Make(R, B); | |
| 288 | |
| 289 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4); | |
| 290 } | |
| OLD | NEW |