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.
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(¢er, 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 | } |