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