gfx/skia/trunk/src/gpu/GrAARectRenderer.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /*
michael@0 2 * Copyright 2012 Google Inc.
michael@0 3 *
michael@0 4 * Use of this source code is governed by a BSD-style license that can be
michael@0 5 * found in the LICENSE file.
michael@0 6 */
michael@0 7
michael@0 8 #include "GrAARectRenderer.h"
michael@0 9 #include "GrGpu.h"
michael@0 10 #include "gl/GrGLEffect.h"
michael@0 11 #include "gl/GrGLVertexEffect.h"
michael@0 12 #include "GrTBackendEffectFactory.h"
michael@0 13 #include "SkColorPriv.h"
michael@0 14 #include "effects/GrVertexEffect.h"
michael@0 15
michael@0 16 ///////////////////////////////////////////////////////////////////////////////
michael@0 17 class GrGLAlignedRectEffect;
michael@0 18
michael@0 19 // Axis Aligned special case
michael@0 20 class GrAlignedRectEffect : public GrVertexEffect {
michael@0 21 public:
michael@0 22 static GrEffectRef* Create() {
michael@0 23 GR_CREATE_STATIC_EFFECT(gAlignedRectEffect, GrAlignedRectEffect, ());
michael@0 24 gAlignedRectEffect->ref();
michael@0 25 return gAlignedRectEffect;
michael@0 26 }
michael@0 27
michael@0 28 virtual ~GrAlignedRectEffect() {}
michael@0 29
michael@0 30 static const char* Name() { return "AlignedRectEdge"; }
michael@0 31
michael@0 32 virtual void getConstantColorComponents(GrColor* color,
michael@0 33 uint32_t* validFlags) const SK_OVERRIDE {
michael@0 34 *validFlags = 0;
michael@0 35 }
michael@0 36
michael@0 37 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
michael@0 38 return GrTBackendEffectFactory<GrAlignedRectEffect>::getInstance();
michael@0 39 }
michael@0 40
michael@0 41 class GLEffect : public GrGLVertexEffect {
michael@0 42 public:
michael@0 43 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
michael@0 44 : INHERITED (factory) {}
michael@0 45
michael@0 46 virtual void emitCode(GrGLFullShaderBuilder* builder,
michael@0 47 const GrDrawEffect& drawEffect,
michael@0 48 EffectKey key,
michael@0 49 const char* outputColor,
michael@0 50 const char* inputColor,
michael@0 51 const TransformedCoordsArray&,
michael@0 52 const TextureSamplerArray& samplers) SK_OVERRIDE {
michael@0 53 // setup the varying for the Axis aligned rect effect
michael@0 54 // xy -> interpolated offset
michael@0 55 // zw -> w/2+0.5, h/2+0.5
michael@0 56 const char *vsRectName, *fsRectName;
michael@0 57 builder->addVarying(kVec4f_GrSLType, "Rect", &vsRectName, &fsRectName);
michael@0 58 const SkString* attr0Name =
michael@0 59 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
michael@0 60 builder->vsCodeAppendf("\t%s = %s;\n", vsRectName, attr0Name->c_str());
michael@0 61
michael@0 62 // TODO: compute all these offsets, spans, and scales in the VS
michael@0 63 builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.z) - 0.5;\n", fsRectName);
michael@0 64 builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.w) - 0.5;\n", fsRectName);
michael@0 65 builder->fsCodeAppend("\tfloat outset = 0.5;\n");
michael@0 66 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
michael@0 67 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
michael@0 68 builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n");
michael@0 69 builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n");
michael@0 70 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
michael@0 71 // value of coverage that is used. In other words it is the coverage that is
michael@0 72 // used in the interior of the rect after the ramp.
michael@0 73 builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
michael@0 74 builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
michael@0 75
michael@0 76 // Compute the coverage for the rect's width
michael@0 77 builder->fsCodeAppendf(
michael@0 78 "\tfloat coverage = scaleW*clamp((%s.z-abs(%s.x))/spanW, 0.0, 1.0);\n", fsRectName,
michael@0 79 fsRectName);
michael@0 80 // Compute the coverage for the rect's height and merge with the width
michael@0 81 builder->fsCodeAppendf(
michael@0 82 "\tcoverage = coverage*scaleH*clamp((%s.w-abs(%s.y))/spanH, 0.0, 1.0);\n",
michael@0 83 fsRectName, fsRectName);
michael@0 84
michael@0 85
michael@0 86 builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
michael@0 87 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("coverage")).c_str());
michael@0 88 }
michael@0 89
michael@0 90 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
michael@0 91 return 0;
michael@0 92 }
michael@0 93
michael@0 94 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
michael@0 95
michael@0 96 private:
michael@0 97 typedef GrGLVertexEffect INHERITED;
michael@0 98 };
michael@0 99
michael@0 100
michael@0 101 private:
michael@0 102 GrAlignedRectEffect() : GrVertexEffect() {
michael@0 103 this->addVertexAttrib(kVec4f_GrSLType);
michael@0 104 }
michael@0 105
michael@0 106 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
michael@0 107
michael@0 108 GR_DECLARE_EFFECT_TEST;
michael@0 109
michael@0 110 typedef GrVertexEffect INHERITED;
michael@0 111 };
michael@0 112
michael@0 113
michael@0 114 GR_DEFINE_EFFECT_TEST(GrAlignedRectEffect);
michael@0 115
michael@0 116 GrEffectRef* GrAlignedRectEffect::TestCreate(SkRandom* random,
michael@0 117 GrContext* context,
michael@0 118 const GrDrawTargetCaps&,
michael@0 119 GrTexture* textures[]) {
michael@0 120 return GrAlignedRectEffect::Create();
michael@0 121 }
michael@0 122
michael@0 123 ///////////////////////////////////////////////////////////////////////////////
michael@0 124 class GrGLRectEffect;
michael@0 125
michael@0 126 /**
michael@0 127 * The output of this effect is a modulation of the input color and coverage
michael@0 128 * for an arbitrarily oriented rect. The rect is specified as:
michael@0 129 * Center of the rect
michael@0 130 * Unit vector point down the height of the rect
michael@0 131 * Half width + 0.5
michael@0 132 * Half height + 0.5
michael@0 133 * The center and vector are stored in a vec4 varying ("RectEdge") with the
michael@0 134 * center in the xy components and the vector in the zw components.
michael@0 135 * The munged width and height are stored in a vec2 varying ("WidthHeight")
michael@0 136 * with the width in x and the height in y.
michael@0 137 */
michael@0 138 class GrRectEffect : public GrVertexEffect {
michael@0 139 public:
michael@0 140 static GrEffectRef* Create() {
michael@0 141 GR_CREATE_STATIC_EFFECT(gRectEffect, GrRectEffect, ());
michael@0 142 gRectEffect->ref();
michael@0 143 return gRectEffect;
michael@0 144 }
michael@0 145
michael@0 146 virtual ~GrRectEffect() {}
michael@0 147
michael@0 148 static const char* Name() { return "RectEdge"; }
michael@0 149
michael@0 150 virtual void getConstantColorComponents(GrColor* color,
michael@0 151 uint32_t* validFlags) const SK_OVERRIDE {
michael@0 152 *validFlags = 0;
michael@0 153 }
michael@0 154
michael@0 155 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
michael@0 156 return GrTBackendEffectFactory<GrRectEffect>::getInstance();
michael@0 157 }
michael@0 158
michael@0 159 class GLEffect : public GrGLVertexEffect {
michael@0 160 public:
michael@0 161 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
michael@0 162 : INHERITED (factory) {}
michael@0 163
michael@0 164 virtual void emitCode(GrGLFullShaderBuilder* builder,
michael@0 165 const GrDrawEffect& drawEffect,
michael@0 166 EffectKey key,
michael@0 167 const char* outputColor,
michael@0 168 const char* inputColor,
michael@0 169 const TransformedCoordsArray&,
michael@0 170 const TextureSamplerArray& samplers) SK_OVERRIDE {
michael@0 171 // setup the varying for the center point and the unit vector
michael@0 172 // that points down the height of the rect
michael@0 173 const char *vsRectEdgeName, *fsRectEdgeName;
michael@0 174 builder->addVarying(kVec4f_GrSLType, "RectEdge",
michael@0 175 &vsRectEdgeName, &fsRectEdgeName);
michael@0 176 const SkString* attr0Name =
michael@0 177 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
michael@0 178 builder->vsCodeAppendf("\t%s = %s;\n", vsRectEdgeName, attr0Name->c_str());
michael@0 179
michael@0 180 // setup the varying for width/2+.5 and height/2+.5
michael@0 181 const char *vsWidthHeightName, *fsWidthHeightName;
michael@0 182 builder->addVarying(kVec2f_GrSLType, "WidthHeight",
michael@0 183 &vsWidthHeightName, &fsWidthHeightName);
michael@0 184 const SkString* attr1Name =
michael@0 185 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
michael@0 186 builder->vsCodeAppendf("\t%s = %s;\n", vsWidthHeightName, attr1Name->c_str());
michael@0 187
michael@0 188 // TODO: compute all these offsets, spans, and scales in the VS
michael@0 189 builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.x) - 0.5;\n", fsWidthHeightName);
michael@0 190 builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.y) - 0.5;\n", fsWidthHeightName);
michael@0 191 builder->fsCodeAppend("\tfloat outset = 0.5;\n");
michael@0 192 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
michael@0 193 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
michael@0 194 builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n");
michael@0 195 builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n");
michael@0 196 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
michael@0 197 // value of coverage that is used. In other words it is the coverage that is
michael@0 198 // used in the interior of the rect after the ramp.
michael@0 199 builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
michael@0 200 builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
michael@0 201
michael@0 202 // Compute the coverage for the rect's width
michael@0 203 builder->fsCodeAppendf("\tvec2 offset = %s.xy - %s.xy;\n",
michael@0 204 builder->fragmentPosition(), fsRectEdgeName);
michael@0 205 builder->fsCodeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n",
michael@0 206 fsRectEdgeName, fsRectEdgeName);
michael@0 207 builder->fsCodeAppendf(
michael@0 208 "\tfloat coverage = scaleW*clamp((%s.x-perpDot)/spanW, 0.0, 1.0);\n",
michael@0 209 fsWidthHeightName);
michael@0 210
michael@0 211 // Compute the coverage for the rect's height and merge with the width
michael@0 212 builder->fsCodeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n",
michael@0 213 fsRectEdgeName);
michael@0 214 builder->fsCodeAppendf(
michael@0 215 "\tcoverage = coverage*scaleH*clamp((%s.y-perpDot)/spanH, 0.0, 1.0);\n",
michael@0 216 fsWidthHeightName);
michael@0 217
michael@0 218
michael@0 219 builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
michael@0 220 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("coverage")).c_str());
michael@0 221 }
michael@0 222
michael@0 223 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
michael@0 224 return 0;
michael@0 225 }
michael@0 226
michael@0 227 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
michael@0 228
michael@0 229 private:
michael@0 230 typedef GrGLVertexEffect INHERITED;
michael@0 231 };
michael@0 232
michael@0 233
michael@0 234 private:
michael@0 235 GrRectEffect() : GrVertexEffect() {
michael@0 236 this->addVertexAttrib(kVec4f_GrSLType);
michael@0 237 this->addVertexAttrib(kVec2f_GrSLType);
michael@0 238 this->setWillReadFragmentPosition();
michael@0 239 }
michael@0 240
michael@0 241 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
michael@0 242
michael@0 243 GR_DECLARE_EFFECT_TEST;
michael@0 244
michael@0 245 typedef GrVertexEffect INHERITED;
michael@0 246 };
michael@0 247
michael@0 248
michael@0 249 GR_DEFINE_EFFECT_TEST(GrRectEffect);
michael@0 250
michael@0 251 GrEffectRef* GrRectEffect::TestCreate(SkRandom* random,
michael@0 252 GrContext* context,
michael@0 253 const GrDrawTargetCaps&,
michael@0 254 GrTexture* textures[]) {
michael@0 255 return GrRectEffect::Create();
michael@0 256 }
michael@0 257
michael@0 258 ///////////////////////////////////////////////////////////////////////////////
michael@0 259
michael@0 260 namespace {
michael@0 261
michael@0 262 extern const GrVertexAttrib gAARectCoverageAttribs[] = {
michael@0 263 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
michael@0 264 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kCoverage_GrVertexAttribBinding},
michael@0 265 };
michael@0 266
michael@0 267 extern const GrVertexAttrib gAARectColorAttribs[] = {
michael@0 268 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
michael@0 269 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kColor_GrVertexAttribBinding},
michael@0 270 };
michael@0 271
michael@0 272 static void set_aa_rect_vertex_attributes(GrDrawState* drawState, bool useCoverage) {
michael@0 273 if (useCoverage) {
michael@0 274 drawState->setVertexAttribs<gAARectCoverageAttribs>(SK_ARRAY_COUNT(gAARectCoverageAttribs));
michael@0 275 } else {
michael@0 276 drawState->setVertexAttribs<gAARectColorAttribs>(SK_ARRAY_COUNT(gAARectColorAttribs));
michael@0 277 }
michael@0 278 }
michael@0 279
michael@0 280 static void set_inset_fan(GrPoint* pts, size_t stride,
michael@0 281 const SkRect& r, SkScalar dx, SkScalar dy) {
michael@0 282 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
michael@0 283 r.fRight - dx, r.fBottom - dy, stride);
michael@0 284 }
michael@0 285
michael@0 286 };
michael@0 287
michael@0 288 void GrAARectRenderer::reset() {
michael@0 289 SkSafeSetNull(fAAFillRectIndexBuffer);
michael@0 290 SkSafeSetNull(fAAMiterStrokeRectIndexBuffer);
michael@0 291 SkSafeSetNull(fAABevelStrokeRectIndexBuffer);
michael@0 292 }
michael@0 293
michael@0 294 static const uint16_t gFillAARectIdx[] = {
michael@0 295 0, 1, 5, 5, 4, 0,
michael@0 296 1, 2, 6, 6, 5, 1,
michael@0 297 2, 3, 7, 7, 6, 2,
michael@0 298 3, 0, 4, 4, 7, 3,
michael@0 299 4, 5, 6, 6, 7, 4,
michael@0 300 };
michael@0 301
michael@0 302 static const int kIndicesPerAAFillRect = GR_ARRAY_COUNT(gFillAARectIdx);
michael@0 303 static const int kVertsPerAAFillRect = 8;
michael@0 304 static const int kNumAAFillRectsInIndexBuffer = 256;
michael@0 305
michael@0 306 GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
michael@0 307 static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
michael@0 308 sizeof(uint16_t) *
michael@0 309 kNumAAFillRectsInIndexBuffer;
michael@0 310
michael@0 311 if (NULL == fAAFillRectIndexBuffer) {
michael@0 312 fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
michael@0 313 if (NULL != fAAFillRectIndexBuffer) {
michael@0 314 uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->lock();
michael@0 315 bool useTempData = (NULL == data);
michael@0 316 if (useTempData) {
michael@0 317 data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect);
michael@0 318 }
michael@0 319 for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) {
michael@0 320 // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around
michael@0 321 // the inner rect (for AA) and 2 for the inner rect.
michael@0 322 int baseIdx = i * kIndicesPerAAFillRect;
michael@0 323 uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect);
michael@0 324 for (int j = 0; j < kIndicesPerAAFillRect; ++j) {
michael@0 325 data[baseIdx+j] = baseVert + gFillAARectIdx[j];
michael@0 326 }
michael@0 327 }
michael@0 328 if (useTempData) {
michael@0 329 if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) {
michael@0 330 GrCrash("Can't get AA Fill Rect indices into buffer!");
michael@0 331 }
michael@0 332 SkDELETE_ARRAY(data);
michael@0 333 } else {
michael@0 334 fAAFillRectIndexBuffer->unlock();
michael@0 335 }
michael@0 336 }
michael@0 337 }
michael@0 338
michael@0 339 return fAAFillRectIndexBuffer;
michael@0 340 }
michael@0 341
michael@0 342 static const uint16_t gMiterStrokeAARectIdx[] = {
michael@0 343 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
michael@0 344 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
michael@0 345 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
michael@0 346 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
michael@0 347
michael@0 348 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
michael@0 349 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
michael@0 350 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
michael@0 351 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
michael@0 352
michael@0 353 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
michael@0 354 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
michael@0 355 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
michael@0 356 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
michael@0 357 };
michael@0 358
michael@0 359 /**
michael@0 360 * As in miter-stroke, index = a + b, and a is the current index, b is the shift
michael@0 361 * from the first index. The index layout:
michael@0 362 * outer AA line: 0~3, 4~7
michael@0 363 * outer edge: 8~11, 12~15
michael@0 364 * inner edge: 16~19
michael@0 365 * inner AA line: 20~23
michael@0 366 * Following comes a bevel-stroke rect and its indices:
michael@0 367 *
michael@0 368 * 4 7
michael@0 369 * *********************************
michael@0 370 * * ______________________________ *
michael@0 371 * * / 12 15 \ *
michael@0 372 * * / \ *
michael@0 373 * 0 * |8 16_____________________19 11 | * 3
michael@0 374 * * | | | | *
michael@0 375 * * | | **************** | | *
michael@0 376 * * | | * 20 23 * | | *
michael@0 377 * * | | * * | | *
michael@0 378 * * | | * 21 22 * | | *
michael@0 379 * * | | **************** | | *
michael@0 380 * * | |____________________| | *
michael@0 381 * 1 * |9 17 18 10| * 2
michael@0 382 * * \ / *
michael@0 383 * * \13 __________________________14/ *
michael@0 384 * * *
michael@0 385 * **********************************
michael@0 386 * 5 6
michael@0 387 */
michael@0 388 static const uint16_t gBevelStrokeAARectIdx[] = {
michael@0 389 // Draw outer AA, from outer AA line to outer edge, shift is 0.
michael@0 390 0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0,
michael@0 391 1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0,
michael@0 392 5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0,
michael@0 393 6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0,
michael@0 394 2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0,
michael@0 395 3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0,
michael@0 396 7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0,
michael@0 397 4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0,
michael@0 398
michael@0 399 // Draw the stroke, from outer edge to inner edge, shift is 8.
michael@0 400 0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8,
michael@0 401 1 + 8, 5 + 8, 9 + 8,
michael@0 402 5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8,
michael@0 403 6 + 8, 2 + 8, 10 + 8,
michael@0 404 2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8,
michael@0 405 3 + 8, 7 + 8, 11 + 8,
michael@0 406 7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8,
michael@0 407 4 + 8, 0 + 8, 8 + 8,
michael@0 408
michael@0 409 // Draw the inner AA, from inner edge to inner AA line, shift is 16.
michael@0 410 0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16,
michael@0 411 1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16,
michael@0 412 2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16,
michael@0 413 3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16,
michael@0 414 };
michael@0 415
michael@0 416 int GrAARectRenderer::aaStrokeRectIndexCount(bool miterStroke) {
michael@0 417 return miterStroke ? GR_ARRAY_COUNT(gMiterStrokeAARectIdx) :
michael@0 418 GR_ARRAY_COUNT(gBevelStrokeAARectIdx);
michael@0 419 }
michael@0 420
michael@0 421 GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu, bool miterStroke) {
michael@0 422 if (miterStroke) {
michael@0 423 if (NULL == fAAMiterStrokeRectIndexBuffer) {
michael@0 424 fAAMiterStrokeRectIndexBuffer =
michael@0 425 gpu->createIndexBuffer(sizeof(gMiterStrokeAARectIdx), false);
michael@0 426 if (NULL != fAAMiterStrokeRectIndexBuffer) {
michael@0 427 #ifdef SK_DEBUG
michael@0 428 bool updated =
michael@0 429 #endif
michael@0 430 fAAMiterStrokeRectIndexBuffer->updateData(gMiterStrokeAARectIdx,
michael@0 431 sizeof(gMiterStrokeAARectIdx));
michael@0 432 GR_DEBUGASSERT(updated);
michael@0 433 }
michael@0 434 }
michael@0 435 return fAAMiterStrokeRectIndexBuffer;
michael@0 436 } else {
michael@0 437 if (NULL == fAABevelStrokeRectIndexBuffer) {
michael@0 438 fAABevelStrokeRectIndexBuffer =
michael@0 439 gpu->createIndexBuffer(sizeof(gBevelStrokeAARectIdx), false);
michael@0 440 if (NULL != fAABevelStrokeRectIndexBuffer) {
michael@0 441 #ifdef SK_DEBUG
michael@0 442 bool updated =
michael@0 443 #endif
michael@0 444 fAABevelStrokeRectIndexBuffer->updateData(gBevelStrokeAARectIdx,
michael@0 445 sizeof(gBevelStrokeAARectIdx));
michael@0 446 GR_DEBUGASSERT(updated);
michael@0 447 }
michael@0 448 }
michael@0 449 return fAABevelStrokeRectIndexBuffer;
michael@0 450 }
michael@0 451 }
michael@0 452
michael@0 453 void GrAARectRenderer::geometryFillAARect(GrGpu* gpu,
michael@0 454 GrDrawTarget* target,
michael@0 455 const SkRect& rect,
michael@0 456 const SkMatrix& combinedMatrix,
michael@0 457 const SkRect& devRect,
michael@0 458 bool useVertexCoverage) {
michael@0 459 GrDrawState* drawState = target->drawState();
michael@0 460
michael@0 461 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
michael@0 462
michael@0 463 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
michael@0 464 if (!geo.succeeded()) {
michael@0 465 GrPrintf("Failed to get space for vertices!\n");
michael@0 466 return;
michael@0 467 }
michael@0 468
michael@0 469 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
michael@0 470 if (NULL == indexBuffer) {
michael@0 471 GrPrintf("Failed to create index buffer!\n");
michael@0 472 return;
michael@0 473 }
michael@0 474
michael@0 475 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
michael@0 476 size_t vsize = drawState->getVertexSize();
michael@0 477 SkASSERT(sizeof(GrPoint) + sizeof(GrColor) == vsize);
michael@0 478
michael@0 479 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
michael@0 480 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
michael@0 481
michael@0 482 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
michael@0 483 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
michael@0 484
michael@0 485 if (combinedMatrix.rectStaysRect()) {
michael@0 486 // Temporarily #if'ed out. We don't want to pass in the devRect but
michael@0 487 // right now it is computed in GrContext::apply_aa_to_rect and we don't
michael@0 488 // want to throw away the work
michael@0 489 #if 0
michael@0 490 SkRect devRect;
michael@0 491 combinedMatrix.mapRect(&devRect, rect);
michael@0 492 #endif
michael@0 493
michael@0 494 set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
michael@0 495 set_inset_fan(fan1Pos, vsize, devRect, inset, inset);
michael@0 496 } else {
michael@0 497 // compute transformed (1, 0) and (0, 1) vectors
michael@0 498 SkVector vec[2] = {
michael@0 499 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
michael@0 500 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
michael@0 501 };
michael@0 502
michael@0 503 vec[0].normalize();
michael@0 504 vec[0].scale(SK_ScalarHalf);
michael@0 505 vec[1].normalize();
michael@0 506 vec[1].scale(SK_ScalarHalf);
michael@0 507
michael@0 508 // create the rotated rect
michael@0 509 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
michael@0 510 rect.fRight, rect.fBottom, vsize);
michael@0 511 combinedMatrix.mapPointsWithStride(fan0Pos, vsize, 4);
michael@0 512
michael@0 513 // Now create the inset points and then outset the original
michael@0 514 // rotated points
michael@0 515
michael@0 516 // TL
michael@0 517 *((SkPoint*)((intptr_t)fan1Pos + 0 * vsize)) =
michael@0 518 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) + vec[0] + vec[1];
michael@0 519 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) -= vec[0] + vec[1];
michael@0 520 // BL
michael@0 521 *((SkPoint*)((intptr_t)fan1Pos + 1 * vsize)) =
michael@0 522 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) + vec[0] - vec[1];
michael@0 523 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) -= vec[0] - vec[1];
michael@0 524 // BR
michael@0 525 *((SkPoint*)((intptr_t)fan1Pos + 2 * vsize)) =
michael@0 526 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) - vec[0] - vec[1];
michael@0 527 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) += vec[0] + vec[1];
michael@0 528 // TR
michael@0 529 *((SkPoint*)((intptr_t)fan1Pos + 3 * vsize)) =
michael@0 530 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) - vec[0] + vec[1];
michael@0 531 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) += vec[0] - vec[1];
michael@0 532 }
michael@0 533
michael@0 534 verts += sizeof(GrPoint);
michael@0 535 for (int i = 0; i < 4; ++i) {
michael@0 536 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
michael@0 537 }
michael@0 538
michael@0 539 int scale;
michael@0 540 if (inset < SK_ScalarHalf) {
michael@0 541 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
michael@0 542 SkASSERT(scale >= 0 && scale <= 255);
michael@0 543 } else {
michael@0 544 scale = 0xff;
michael@0 545 }
michael@0 546
michael@0 547 GrColor innerColor;
michael@0 548 if (useVertexCoverage) {
michael@0 549 innerColor = GrColorPackRGBA(scale, scale, scale, scale);
michael@0 550 } else {
michael@0 551 if (0xff == scale) {
michael@0 552 innerColor = target->getDrawState().getColor();
michael@0 553 } else {
michael@0 554 innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale);
michael@0 555 }
michael@0 556 }
michael@0 557
michael@0 558 verts += 4 * vsize;
michael@0 559 for (int i = 0; i < 4; ++i) {
michael@0 560 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
michael@0 561 }
michael@0 562
michael@0 563 target->setIndexSourceToBuffer(indexBuffer);
michael@0 564 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
michael@0 565 kVertsPerAAFillRect,
michael@0 566 kIndicesPerAAFillRect);
michael@0 567 target->resetIndexSource();
michael@0 568 }
michael@0 569
michael@0 570 namespace {
michael@0 571
michael@0 572 // Rotated
michael@0 573 struct RectVertex {
michael@0 574 GrPoint fPos;
michael@0 575 GrPoint fCenter;
michael@0 576 GrPoint fDir;
michael@0 577 GrPoint fWidthHeight;
michael@0 578 };
michael@0 579
michael@0 580 // Rotated
michael@0 581 extern const GrVertexAttrib gAARectVertexAttribs[] = {
michael@0 582 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
michael@0 583 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
michael@0 584 { kVec2f_GrVertexAttribType, 3*sizeof(GrPoint), kEffect_GrVertexAttribBinding }
michael@0 585 };
michael@0 586
michael@0 587 // Axis Aligned
michael@0 588 struct AARectVertex {
michael@0 589 GrPoint fPos;
michael@0 590 GrPoint fOffset;
michael@0 591 GrPoint fWidthHeight;
michael@0 592 };
michael@0 593
michael@0 594 // Axis Aligned
michael@0 595 extern const GrVertexAttrib gAAAARectVertexAttribs[] = {
michael@0 596 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
michael@0 597 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
michael@0 598 };
michael@0 599
michael@0 600 };
michael@0 601
michael@0 602 void GrAARectRenderer::shaderFillAARect(GrGpu* gpu,
michael@0 603 GrDrawTarget* target,
michael@0 604 const SkRect& rect,
michael@0 605 const SkMatrix& combinedMatrix) {
michael@0 606 GrDrawState* drawState = target->drawState();
michael@0 607
michael@0 608 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
michael@0 609 combinedMatrix.mapPoints(&center, 1);
michael@0 610
michael@0 611 // compute transformed (0, 1) vector
michael@0 612 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
michael@0 613 dir.normalize();
michael@0 614
michael@0 615 // compute transformed (width, 0) and (0, height) vectors
michael@0 616 SkVector vec[2] = {
michael@0 617 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
michael@0 618 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
michael@0 619 };
michael@0 620
michael@0 621 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf;
michael@0 622 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf;
michael@0 623 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs));
michael@0 624 SkASSERT(sizeof(RectVertex) == drawState->getVertexSize());
michael@0 625
michael@0 626 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
michael@0 627 if (!geo.succeeded()) {
michael@0 628 GrPrintf("Failed to get space for vertices!\n");
michael@0 629 return;
michael@0 630 }
michael@0 631
michael@0 632 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
michael@0 633
michael@0 634 GrEffectRef* effect = GrRectEffect::Create();
michael@0 635 static const int kRectAttrIndex = 1;
michael@0 636 static const int kWidthIndex = 2;
michael@0 637 drawState->addCoverageEffect(effect, kRectAttrIndex, kWidthIndex)->unref();
michael@0 638
michael@0 639 for (int i = 0; i < 4; ++i) {
michael@0 640 verts[i].fCenter = center;
michael@0 641 verts[i].fDir = dir;
michael@0 642 verts[i].fWidthHeight.fX = newWidth;
michael@0 643 verts[i].fWidthHeight.fY = newHeight;
michael@0 644 }
michael@0 645
michael@0 646 SkRect devRect;
michael@0 647 combinedMatrix.mapRect(&devRect, rect);
michael@0 648
michael@0 649 SkRect devBounds = {
michael@0 650 devRect.fLeft - SK_ScalarHalf,
michael@0 651 devRect.fTop - SK_ScalarHalf,
michael@0 652 devRect.fRight + SK_ScalarHalf,
michael@0 653 devRect.fBottom + SK_ScalarHalf
michael@0 654 };
michael@0 655
michael@0 656 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
michael@0 657 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
michael@0 658 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
michael@0 659 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
michael@0 660
michael@0 661 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
michael@0 662 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
michael@0 663 target->resetIndexSource();
michael@0 664 }
michael@0 665
michael@0 666 void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu,
michael@0 667 GrDrawTarget* target,
michael@0 668 const SkRect& rect,
michael@0 669 const SkMatrix& combinedMatrix) {
michael@0 670 GrDrawState* drawState = target->drawState();
michael@0 671 SkASSERT(combinedMatrix.rectStaysRect());
michael@0 672
michael@0 673 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs));
michael@0 674 SkASSERT(sizeof(AARectVertex) == drawState->getVertexSize());
michael@0 675
michael@0 676 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
michael@0 677 if (!geo.succeeded()) {
michael@0 678 GrPrintf("Failed to get space for vertices!\n");
michael@0 679 return;
michael@0 680 }
michael@0 681
michael@0 682 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
michael@0 683
michael@0 684 GrEffectRef* effect = GrAlignedRectEffect::Create();
michael@0 685 static const int kOffsetIndex = 1;
michael@0 686 drawState->addCoverageEffect(effect, kOffsetIndex)->unref();
michael@0 687
michael@0 688 SkRect devRect;
michael@0 689 combinedMatrix.mapRect(&devRect, rect);
michael@0 690
michael@0 691 SkRect devBounds = {
michael@0 692 devRect.fLeft - SK_ScalarHalf,
michael@0 693 devRect.fTop - SK_ScalarHalf,
michael@0 694 devRect.fRight + SK_ScalarHalf,
michael@0 695 devRect.fBottom + SK_ScalarHalf
michael@0 696 };
michael@0 697
michael@0 698 GrPoint widthHeight = {
michael@0 699 SkScalarHalf(devRect.width()) + SK_ScalarHalf,
michael@0 700 SkScalarHalf(devRect.height()) + SK_ScalarHalf
michael@0 701 };
michael@0 702
michael@0 703 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
michael@0 704 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY);
michael@0 705 verts[0].fWidthHeight = widthHeight;
michael@0 706
michael@0 707 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
michael@0 708 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY);
michael@0 709 verts[1].fWidthHeight = widthHeight;
michael@0 710
michael@0 711 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
michael@0 712 verts[2].fOffset = widthHeight;
michael@0 713 verts[2].fWidthHeight = widthHeight;
michael@0 714
michael@0 715 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
michael@0 716 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY);
michael@0 717 verts[3].fWidthHeight = widthHeight;
michael@0 718
michael@0 719 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
michael@0 720 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
michael@0 721 target->resetIndexSource();
michael@0 722 }
michael@0 723
michael@0 724 void GrAARectRenderer::strokeAARect(GrGpu* gpu,
michael@0 725 GrDrawTarget* target,
michael@0 726 const SkRect& rect,
michael@0 727 const SkMatrix& combinedMatrix,
michael@0 728 const SkRect& devRect,
michael@0 729 const SkStrokeRec* stroke,
michael@0 730 bool useVertexCoverage) {
michael@0 731 GrVec devStrokeSize;
michael@0 732 SkScalar width = stroke->getWidth();
michael@0 733 if (width > 0) {
michael@0 734 devStrokeSize.set(width, width);
michael@0 735 combinedMatrix.mapVectors(&devStrokeSize, 1);
michael@0 736 devStrokeSize.setAbs(devStrokeSize);
michael@0 737 } else {
michael@0 738 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
michael@0 739 }
michael@0 740
michael@0 741 const SkScalar dx = devStrokeSize.fX;
michael@0 742 const SkScalar dy = devStrokeSize.fY;
michael@0 743 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
michael@0 744 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
michael@0 745
michael@0 746 // Temporarily #if'ed out. We don't want to pass in the devRect but
michael@0 747 // right now it is computed in GrContext::apply_aa_to_rect and we don't
michael@0 748 // want to throw away the work
michael@0 749 #if 0
michael@0 750 SkRect devRect;
michael@0 751 combinedMatrix.mapRect(&devRect, rect);
michael@0 752 #endif
michael@0 753
michael@0 754 SkScalar spare;
michael@0 755 {
michael@0 756 SkScalar w = devRect.width() - dx;
michael@0 757 SkScalar h = devRect.height() - dy;
michael@0 758 spare = GrMin(w, h);
michael@0 759 }
michael@0 760
michael@0 761 SkRect devOutside(devRect);
michael@0 762 devOutside.outset(rx, ry);
michael@0 763
michael@0 764 bool miterStroke = true;
michael@0 765 // small miter limit means right angles show bevel...
michael@0 766 if (stroke->getJoin() != SkPaint::kMiter_Join || stroke->getMiter() < SK_ScalarSqrt2) {
michael@0 767 miterStroke = false;
michael@0 768 }
michael@0 769
michael@0 770 if (spare <= 0 && miterStroke) {
michael@0 771 this->fillAARect(gpu, target, devOutside, SkMatrix::I(),
michael@0 772 devOutside, useVertexCoverage);
michael@0 773 return;
michael@0 774 }
michael@0 775
michael@0 776 SkRect devInside(devRect);
michael@0 777 devInside.inset(rx, ry);
michael@0 778
michael@0 779 SkRect devOutsideAssist(devRect);
michael@0 780
michael@0 781 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
michael@0 782 // to draw the outer of the rect. Because there are 8 vertices on the outer
michael@0 783 // edge, while vertex number of inner edge is 4, the same as miter-stroke.
michael@0 784 if (!miterStroke) {
michael@0 785 devOutside.inset(0, ry);
michael@0 786 devOutsideAssist.outset(0, ry);
michael@0 787 }
michael@0 788
michael@0 789 this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist,
michael@0 790 devInside, useVertexCoverage, miterStroke);
michael@0 791 }
michael@0 792
michael@0 793 void GrAARectRenderer::geometryStrokeAARect(GrGpu* gpu,
michael@0 794 GrDrawTarget* target,
michael@0 795 const SkRect& devOutside,
michael@0 796 const SkRect& devOutsideAssist,
michael@0 797 const SkRect& devInside,
michael@0 798 bool useVertexCoverage,
michael@0 799 bool miterStroke) {
michael@0 800 GrDrawState* drawState = target->drawState();
michael@0 801
michael@0 802 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
michael@0 803
michael@0 804 int innerVertexNum = 4;
michael@0 805 int outerVertexNum = miterStroke ? 4 : 8;
michael@0 806 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
michael@0 807
michael@0 808 GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, 0);
michael@0 809 if (!geo.succeeded()) {
michael@0 810 GrPrintf("Failed to get space for vertices!\n");
michael@0 811 return;
michael@0 812 }
michael@0 813 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu, miterStroke);
michael@0 814 if (NULL == indexBuffer) {
michael@0 815 GrPrintf("Failed to create index buffer!\n");
michael@0 816 return;
michael@0 817 }
michael@0 818
michael@0 819 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
michael@0 820 size_t vsize = drawState->getVertexSize();
michael@0 821 SkASSERT(sizeof(GrPoint) + sizeof(GrColor) == vsize);
michael@0 822
michael@0 823 // We create vertices for four nested rectangles. There are two ramps from 0 to full
michael@0 824 // coverage, one on the exterior of the stroke and the other on the interior.
michael@0 825 // The following pointers refer to the four rects, from outermost to innermost.
michael@0 826 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
michael@0 827 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + outerVertexNum * vsize);
michael@0 828 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 2 * outerVertexNum * vsize);
michael@0 829 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vsize);
michael@0 830
michael@0 831 #ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
michael@0 832 // TODO: this only really works if the X & Y margins are the same all around
michael@0 833 // the rect
michael@0 834 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
michael@0 835 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
michael@0 836 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
michael@0 837 if (miterStroke) {
michael@0 838 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
michael@0 839 } else {
michael@0 840 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom);
michael@0 841 }
michael@0 842 SkASSERT(inset >= 0);
michael@0 843 #else
michael@0 844 SkScalar inset = SK_ScalarHalf;
michael@0 845 #endif
michael@0 846
michael@0 847 if (miterStroke) {
michael@0 848 // outermost
michael@0 849 set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
michael@0 850 // inner two
michael@0 851 set_inset_fan(fan1Pos, vsize, devOutside, inset, inset);
michael@0 852 set_inset_fan(fan2Pos, vsize, devInside, -inset, -inset);
michael@0 853 // innermost
michael@0 854 set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf);
michael@0 855 } else {
michael@0 856 GrPoint* fan0AssistPos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
michael@0 857 GrPoint* fan1AssistPos = reinterpret_cast<GrPoint*>(verts + (outerVertexNum + 4) * vsize);
michael@0 858 // outermost
michael@0 859 set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
michael@0 860 set_inset_fan(fan0AssistPos, vsize, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf);
michael@0 861 // outer one of the inner two
michael@0 862 set_inset_fan(fan1Pos, vsize, devOutside, inset, inset);
michael@0 863 set_inset_fan(fan1AssistPos, vsize, devOutsideAssist, inset, inset);
michael@0 864 // inner one of the inner two
michael@0 865 set_inset_fan(fan2Pos, vsize, devInside, -inset, -inset);
michael@0 866 // innermost
michael@0 867 set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf);
michael@0 868 }
michael@0 869
michael@0 870 // The outermost rect has 0 coverage
michael@0 871 verts += sizeof(GrPoint);
michael@0 872 for (int i = 0; i < outerVertexNum; ++i) {
michael@0 873 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
michael@0 874 }
michael@0 875
michael@0 876 int scale;
michael@0 877 if (inset < SK_ScalarHalf) {
michael@0 878 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
michael@0 879 SkASSERT(scale >= 0 && scale <= 255);
michael@0 880 } else {
michael@0 881 scale = 0xff;
michael@0 882 }
michael@0 883
michael@0 884 // The inner two rects have full coverage
michael@0 885 GrColor innerColor;
michael@0 886 if (useVertexCoverage) {
michael@0 887 innerColor = GrColorPackRGBA(scale, scale, scale, scale);
michael@0 888 } else {
michael@0 889 if (0xff == scale) {
michael@0 890 innerColor = target->getDrawState().getColor();
michael@0 891 } else {
michael@0 892 innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale);
michael@0 893 }
michael@0 894 }
michael@0 895
michael@0 896 verts += outerVertexNum * vsize;
michael@0 897 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
michael@0 898 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
michael@0 899 }
michael@0 900
michael@0 901 // The innermost rect has 0 coverage
michael@0 902 verts += (outerVertexNum + innerVertexNum) * vsize;
michael@0 903 for (int i = 0; i < innerVertexNum; ++i) {
michael@0 904 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
michael@0 905 }
michael@0 906
michael@0 907 target->setIndexSourceToBuffer(indexBuffer);
michael@0 908 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0,
michael@0 909 totalVertexNum, aaStrokeRectIndexCount(miterStroke));
michael@0 910 }
michael@0 911
michael@0 912 void GrAARectRenderer::fillAANestedRects(GrGpu* gpu,
michael@0 913 GrDrawTarget* target,
michael@0 914 const SkRect rects[2],
michael@0 915 const SkMatrix& combinedMatrix,
michael@0 916 bool useVertexCoverage) {
michael@0 917 SkASSERT(combinedMatrix.rectStaysRect());
michael@0 918 SkASSERT(!rects[1].isEmpty());
michael@0 919
michael@0 920 SkRect devOutside, devOutsideAssist, devInside;
michael@0 921 combinedMatrix.mapRect(&devOutside, rects[0]);
michael@0 922 // can't call mapRect for devInside since it calls sort
michael@0 923 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
michael@0 924
michael@0 925 if (devInside.isEmpty()) {
michael@0 926 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside, useVertexCoverage);
michael@0 927 return;
michael@0 928 }
michael@0 929
michael@0 930 this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist,
michael@0 931 devInside, useVertexCoverage, true);
michael@0 932 }

mercurial