text: /*
   * Copyright 2012 Google Inc.
   *
   * Use of this source code is governed by a BSD-style license that can be
   * found in the LICENSE file.
   */
  
  #include "GrAARectRenderer.h"
  #include "GrGpu.h"
  #include "gl/GrGLEffect.h"
  #include "gl/GrGLVertexEffect.h"
  #include "GrTBackendEffectFactory.h"
  #include "SkColorPriv.h"
  #include "effects/GrVertexEffect.h"
  
  ///////////////////////////////////////////////////////////////////////////////
  class GrGLAlignedRectEffect;
  
  // Axis Aligned special case
  class GrAlignedRectEffect : public GrVertexEffect {
  public:
      static GrEffectRef* Create() {
          GR_CREATE_STATIC_EFFECT(gAlignedRectEffect, GrAlignedRectEffect, ());
          gAlignedRectEffect->ref();
          return gAlignedRectEffect;
      }
  
      virtual ~GrAlignedRectEffect() {}
  
      static const char* Name() { return "AlignedRectEdge"; }
  
      virtual void getConstantColorComponents(GrColor* color,
                                              uint32_t* validFlags) const SK_OVERRIDE {
          *validFlags = 0;
      }
  
      virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
          return GrTBackendEffectFactory<GrAlignedRectEffect>::getInstance();
      }
  
      class GLEffect : public GrGLVertexEffect {
      public:
          GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
          : INHERITED (factory) {}
  
          virtual void emitCode(GrGLFullShaderBuilder* builder,
                                const GrDrawEffect& drawEffect,
                                EffectKey key,
                                const char* outputColor,
                                const char* inputColor,
                                const TransformedCoordsArray&,
                                const TextureSamplerArray& samplers) SK_OVERRIDE {
              // setup the varying for the Axis aligned rect effect
              //      xy -> interpolated offset
              //      zw -> w/2+0.5, h/2+0.5
              const char *vsRectName, *fsRectName;
              builder->addVarying(kVec4f_GrSLType, "Rect", &vsRectName, &fsRectName);
              const SkString* attr0Name =
                  builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
              builder->vsCodeAppendf("\t%s = %s;\n", vsRectName, attr0Name->c_str());
  
              // TODO: compute all these offsets, spans, and scales in the VS
              builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.z) - 0.5;\n", fsRectName);
              builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.w) - 0.5;\n", fsRectName);
              builder->fsCodeAppend("\tfloat outset = 0.5;\n");
              // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
              // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
              builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n");
              builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n");
              // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
              // value of coverage that is used. In other words it is the coverage that is
              // used in the interior of the rect after the ramp.
              builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
              builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
  
              // Compute the coverage for the rect's width
              builder->fsCodeAppendf(
                  "\tfloat coverage = scaleW*clamp((%s.z-abs(%s.x))/spanW, 0.0, 1.0);\n", fsRectName,
                  fsRectName);
              // Compute the coverage for the rect's height and merge with the width
              builder->fsCodeAppendf(
                  "\tcoverage = coverage*scaleH*clamp((%s.w-abs(%s.y))/spanH, 0.0, 1.0);\n",
                  fsRectName, fsRectName);
  
  
              builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
                                     (GrGLSLExpr4(inputColor) * GrGLSLExpr1("coverage")).c_str());
          }
  
          static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
              return 0;
          }
  
          virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
  
      private:
          typedef GrGLVertexEffect INHERITED;
      };
  
  
  private:
      GrAlignedRectEffect() : GrVertexEffect() {
          this->addVertexAttrib(kVec4f_GrSLType);
      }
  
      virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
  
      GR_DECLARE_EFFECT_TEST;
  
      typedef GrVertexEffect INHERITED;
  };
  
  
  GR_DEFINE_EFFECT_TEST(GrAlignedRectEffect);
  
  GrEffectRef* GrAlignedRectEffect::TestCreate(SkRandom* random,
                                               GrContext* context,
                                               const GrDrawTargetCaps&,
                                               GrTexture* textures[]) {
      return GrAlignedRectEffect::Create();
  }
  
  ///////////////////////////////////////////////////////////////////////////////
  class GrGLRectEffect;
  
  /**
   * The output of this effect is a modulation of the input color and coverage
   * for an arbitrarily oriented rect. The rect is specified as:
   *      Center of the rect
   *      Unit vector point down the height of the rect
   *      Half width + 0.5
   *      Half height + 0.5
   * The center and vector are stored in a vec4 varying ("RectEdge") with the
   * center in the xy components and the vector in the zw components.
   * The munged width and height are stored in a vec2 varying ("WidthHeight")
   * with the width in x and the height in y.
   */
  class GrRectEffect : public GrVertexEffect {
  public:
      static GrEffectRef* Create() {
          GR_CREATE_STATIC_EFFECT(gRectEffect, GrRectEffect, ());
          gRectEffect->ref();
          return gRectEffect;
      }
  
      virtual ~GrRectEffect() {}
  
      static const char* Name() { return "RectEdge"; }
  
      virtual void getConstantColorComponents(GrColor* color,
                                              uint32_t* validFlags) const SK_OVERRIDE {
          *validFlags = 0;
      }
  
      virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
          return GrTBackendEffectFactory<GrRectEffect>::getInstance();
      }
  
      class GLEffect : public GrGLVertexEffect {
      public:
          GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
          : INHERITED (factory) {}
  
          virtual void emitCode(GrGLFullShaderBuilder* builder,
                                const GrDrawEffect& drawEffect,
                                EffectKey key,
                                const char* outputColor,
                                const char* inputColor,
                                const TransformedCoordsArray&,
                                const TextureSamplerArray& samplers) SK_OVERRIDE {
              // setup the varying for the center point and the unit vector
              // that points down the height of the rect
              const char *vsRectEdgeName, *fsRectEdgeName;
              builder->addVarying(kVec4f_GrSLType, "RectEdge",
                                  &vsRectEdgeName, &fsRectEdgeName);
              const SkString* attr0Name =
                  builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
              builder->vsCodeAppendf("\t%s = %s;\n", vsRectEdgeName, attr0Name->c_str());
  
              // setup the varying for width/2+.5 and height/2+.5
              const char *vsWidthHeightName, *fsWidthHeightName;
              builder->addVarying(kVec2f_GrSLType, "WidthHeight",
                                  &vsWidthHeightName, &fsWidthHeightName);
              const SkString* attr1Name =
                  builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
              builder->vsCodeAppendf("\t%s = %s;\n", vsWidthHeightName, attr1Name->c_str());
  
              // TODO: compute all these offsets, spans, and scales in the VS
              builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.x) - 0.5;\n", fsWidthHeightName);
              builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.y) - 0.5;\n", fsWidthHeightName);
              builder->fsCodeAppend("\tfloat outset = 0.5;\n");
              // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
              // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
              builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n");
              builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n");
              // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
              // value of coverage that is used. In other words it is the coverage that is
              // used in the interior of the rect after the ramp.
              builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
              builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
  
              // Compute the coverage for the rect's width
              builder->fsCodeAppendf("\tvec2 offset = %s.xy - %s.xy;\n",
                                     builder->fragmentPosition(), fsRectEdgeName);
              builder->fsCodeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n",
                                     fsRectEdgeName, fsRectEdgeName);
              builder->fsCodeAppendf(
                  "\tfloat coverage = scaleW*clamp((%s.x-perpDot)/spanW, 0.0, 1.0);\n",
                  fsWidthHeightName);
  
              // Compute the coverage for the rect's height and merge with the width
              builder->fsCodeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n",
                                     fsRectEdgeName);
              builder->fsCodeAppendf(
                      "\tcoverage = coverage*scaleH*clamp((%s.y-perpDot)/spanH, 0.0, 1.0);\n",
                      fsWidthHeightName);
  
  
              builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
                                     (GrGLSLExpr4(inputColor) * GrGLSLExpr1("coverage")).c_str());
          }
  
          static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
              return 0;
          }
  
          virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
  
      private:
          typedef GrGLVertexEffect INHERITED;
      };
  
  
  private:
      GrRectEffect() : GrVertexEffect() {
          this->addVertexAttrib(kVec4f_GrSLType);
          this->addVertexAttrib(kVec2f_GrSLType);
          this->setWillReadFragmentPosition();
      }
  
      virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
  
      GR_DECLARE_EFFECT_TEST;
  
      typedef GrVertexEffect INHERITED;
  };
  
  
  GR_DEFINE_EFFECT_TEST(GrRectEffect);
  
  GrEffectRef* GrRectEffect::TestCreate(SkRandom* random,
                                        GrContext* context,
                                        const GrDrawTargetCaps&,
                                        GrTexture* textures[]) {
      return GrRectEffect::Create();
  }
  
  ///////////////////////////////////////////////////////////////////////////////
  
  namespace {
  
  extern const GrVertexAttrib gAARectCoverageAttribs[] = {
      {kVec2f_GrVertexAttribType,  0,               kPosition_GrVertexAttribBinding},
      {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kCoverage_GrVertexAttribBinding},
  };
  
  extern const GrVertexAttrib gAARectColorAttribs[] = {
      {kVec2f_GrVertexAttribType,  0,               kPosition_GrVertexAttribBinding},
      {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kColor_GrVertexAttribBinding},
  };
  
  static void set_aa_rect_vertex_attributes(GrDrawState* drawState, bool useCoverage) {
      if (useCoverage) {
          drawState->setVertexAttribs<gAARectCoverageAttribs>(SK_ARRAY_COUNT(gAARectCoverageAttribs));
      } else {
          drawState->setVertexAttribs<gAARectColorAttribs>(SK_ARRAY_COUNT(gAARectColorAttribs));
      }
  }
  
  static void set_inset_fan(SkPoint* pts, size_t stride,
                            const SkRect& r, SkScalar dx, SkScalar dy) {
      pts->setRectFan(r.fLeft + dx, r.fTop + dy,
                      r.fRight - dx, r.fBottom - dy, stride);
  }
  
  };
  
  void GrAARectRenderer::reset() {
      SkSafeSetNull(fAAFillRectIndexBuffer);
      SkSafeSetNull(fAAMiterStrokeRectIndexBuffer);
      SkSafeSetNull(fAABevelStrokeRectIndexBuffer);
  }
  
  static const uint16_t gFillAARectIdx[] = {
      0, 1, 5, 5, 4, 0,
      1, 2, 6, 6, 5, 1,
      2, 3, 7, 7, 6, 2,
      3, 0, 4, 4, 7, 3,
      4, 5, 6, 6, 7, 4,
  };
  
  static const int kIndicesPerAAFillRect = SK_ARRAY_COUNT(gFillAARectIdx);
  static const int kVertsPerAAFillRect = 8;
  static const int kNumAAFillRectsInIndexBuffer = 256;
  
  GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
      static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
                                                       sizeof(uint16_t) *
                                                       kNumAAFillRectsInIndexBuffer;
  
      if (NULL == fAAFillRectIndexBuffer) {
          fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
          if (NULL != fAAFillRectIndexBuffer) {
              uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->lock();
              bool useTempData = (NULL == data);
              if (useTempData) {
                  data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect);
              }
              for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) {
                  // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around
                  // the inner rect (for AA) and 2 for the inner rect.
                  int baseIdx = i * kIndicesPerAAFillRect;
                  uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect);
                  for (int j = 0; j < kIndicesPerAAFillRect; ++j) {
                      data[baseIdx+j] = baseVert + gFillAARectIdx[j];
                  }
              }
              if (useTempData) {
                  if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) {
                      GrCrash("Can't get AA Fill Rect indices into buffer!");
                  }
                  SkDELETE_ARRAY(data);
              } else {
                  fAAFillRectIndexBuffer->unlock();
              }
          }
      }
  
      return fAAFillRectIndexBuffer;
  }
  
  static const uint16_t gMiterStrokeAARectIdx[] = {
      0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
      1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
      2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
      3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
  
      0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
      1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
      2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
      3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
  
      0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
      1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
      2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
      3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
  };
  
  /**
   * As in miter-stroke, index = a + b, and a is the current index, b is the shift
   * from the first index. The index layout:
   * outer AA line: 0~3, 4~7
   * outer edge:    8~11, 12~15
   * inner edge:    16~19
   * inner AA line: 20~23
   * Following comes a bevel-stroke rect and its indices:
   *
   *           4                                 7
   *            *********************************
   *          *   ______________________________  *
   *         *  / 12                          15 \  *
   *        *  /                                  \  *
   *     0 *  |8     16_____________________19  11 |  * 3
   *       *  |       |                    |       |  *
   *       *  |       |  ****************  |       |  *
   *       *  |       |  * 20        23 *  |       |  *
   *       *  |       |  *              *  |       |  *
   *       *  |       |  * 21        22 *  |       |  *
   *       *  |       |  ****************  |       |  *
   *       *  |       |____________________|       |  *
   *     1 *  |9    17                      18   10|  * 2
   *        *  \                                  /  *
   *         *  \13 __________________________14/  *
   *          *                                   *
   *           **********************************
   *          5                                  6
   */
  static const uint16_t gBevelStrokeAARectIdx[] = {
      // Draw outer AA, from outer AA line to outer edge, shift is 0.
      0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0,
      1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0,
      5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0,
      6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0,
      2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0,
      3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0,
      7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0,
      4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0,
  
      // Draw the stroke, from outer edge to inner edge, shift is 8.
      0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8,
      1 + 8, 5 + 8, 9 + 8,
      5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8,
      6 + 8, 2 + 8, 10 + 8,
      2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8,
      3 + 8, 7 + 8, 11 + 8,
      7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8,
      4 + 8, 0 + 8, 8 + 8,
  
      // Draw the inner AA, from inner edge to inner AA line, shift is 16.
      0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16,
      1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16,
      2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16,
      3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16,
  };
  
  int GrAARectRenderer::aaStrokeRectIndexCount(bool miterStroke) {
      return miterStroke ? SK_ARRAY_COUNT(gMiterStrokeAARectIdx) :
                           SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
  }
  
  GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu, bool miterStroke) {
      if (miterStroke) {
          if (NULL == fAAMiterStrokeRectIndexBuffer) {
              fAAMiterStrokeRectIndexBuffer =
                  gpu->createIndexBuffer(sizeof(gMiterStrokeAARectIdx), false);
              if (NULL != fAAMiterStrokeRectIndexBuffer) {
  #ifdef SK_DEBUG
                  bool updated =
  #endif
                  fAAMiterStrokeRectIndexBuffer->updateData(gMiterStrokeAARectIdx,
                                                            sizeof(gMiterStrokeAARectIdx));
                  GR_DEBUGASSERT(updated);
              }
          }
          return fAAMiterStrokeRectIndexBuffer;
      } else {
          if (NULL == fAABevelStrokeRectIndexBuffer) {
              fAABevelStrokeRectIndexBuffer =
                  gpu->createIndexBuffer(sizeof(gBevelStrokeAARectIdx), false);
              if (NULL != fAABevelStrokeRectIndexBuffer) {
  #ifdef SK_DEBUG
                  bool updated =
  #endif
                  fAABevelStrokeRectIndexBuffer->updateData(gBevelStrokeAARectIdx,
                                                            sizeof(gBevelStrokeAARectIdx));
                  GR_DEBUGASSERT(updated);
              }
          }
          return fAABevelStrokeRectIndexBuffer;
      }
  }
  
  void GrAARectRenderer::geometryFillAARect(GrGpu* gpu,
                                            GrDrawTarget* target,
                                            const SkRect& rect,
                                            const SkMatrix& combinedMatrix,
                                            const SkRect& devRect,
                                            bool useVertexCoverage) {
      GrDrawState* drawState = target->drawState();
  
      set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
  
      GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
      if (!geo.succeeded()) {
          GrPrintf("Failed to get space for vertices!\n");
          return;
      }
  
      GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
      if (NULL == indexBuffer) {
          GrPrintf("Failed to create index buffer!\n");
          return;
      }
  
      intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
      size_t vsize = drawState->getVertexSize();
      SkASSERT(sizeof(SkPoint) + sizeof(GrColor) == vsize);
  
      SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
      SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vsize);
  
      SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
      inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
  
      if (combinedMatrix.rectStaysRect()) {
          // Temporarily #if'ed out. We don't want to pass in the devRect but
          // right now it is computed in GrContext::apply_aa_to_rect and we don't
          // want to throw away the work
  #if 0
          SkRect devRect;
          combinedMatrix.mapRect(&devRect, rect);
  #endif
  
          set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
          set_inset_fan(fan1Pos, vsize, devRect, inset,  inset);
      } else {
          // compute transformed (1, 0) and (0, 1) vectors
          SkVector vec[2] = {
            { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
            { combinedMatrix[SkMatrix::kMSkewX],  combinedMatrix[SkMatrix::kMScaleY] }
          };
  
          vec[0].normalize();
          vec[0].scale(SK_ScalarHalf);
          vec[1].normalize();
          vec[1].scale(SK_ScalarHalf);
  
          // create the rotated rect
          fan0Pos->setRectFan(rect.fLeft, rect.fTop,
                              rect.fRight, rect.fBottom, vsize);
          combinedMatrix.mapPointsWithStride(fan0Pos, vsize, 4);
  
          // Now create the inset points and then outset the original
          // rotated points
  
          // TL
          *((SkPoint*)((intptr_t)fan1Pos + 0 * vsize)) =
              *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) + vec[0] + vec[1];
          *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) -= vec[0] + vec[1];
          // BL
          *((SkPoint*)((intptr_t)fan1Pos + 1 * vsize)) =
              *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) + vec[0] - vec[1];
          *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) -= vec[0] - vec[1];
          // BR
          *((SkPoint*)((intptr_t)fan1Pos + 2 * vsize)) =
              *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) - vec[0] - vec[1];
          *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) += vec[0] + vec[1];
          // TR
          *((SkPoint*)((intptr_t)fan1Pos + 3 * vsize)) =
              *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) - vec[0] + vec[1];
          *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) += vec[0] - vec[1];
      }
  
      verts += sizeof(SkPoint);
      for (int i = 0; i < 4; ++i) {
          *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
      }
  
      int scale;
      if (inset < SK_ScalarHalf) {
          scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
          SkASSERT(scale >= 0 && scale <= 255);
      } else {
          scale = 0xff;
      }
  
      GrColor innerColor;
      if (useVertexCoverage) {
          innerColor = GrColorPackRGBA(scale, scale, scale, scale);
      } else {
          if (0xff == scale) {
              innerColor = target->getDrawState().getColor();
          } else {
              innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale);
          }
      }
  
      verts += 4 * vsize;
      for (int i = 0; i < 4; ++i) {
          *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
      }
  
      target->setIndexSourceToBuffer(indexBuffer);
      target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
                                   kVertsPerAAFillRect,
                                   kIndicesPerAAFillRect);
      target->resetIndexSource();
  }
  
  namespace {
  
  // Rotated
  struct RectVertex {
      SkPoint fPos;
      SkPoint fCenter;
      SkPoint fDir;
      SkPoint fWidthHeight;
  };
  
  // Rotated
  extern const GrVertexAttrib gAARectVertexAttribs[] = {
      { kVec2f_GrVertexAttribType, 0,                 kPosition_GrVertexAttribBinding },
      { kVec4f_GrVertexAttribType, sizeof(SkPoint),   kEffect_GrVertexAttribBinding },
      { kVec2f_GrVertexAttribType, 3*sizeof(SkPoint), kEffect_GrVertexAttribBinding }
  };
  
  // Axis Aligned
  struct AARectVertex {
      SkPoint fPos;
      SkPoint fOffset;
      SkPoint fWidthHeight;
  };
  
  // Axis Aligned
  extern const GrVertexAttrib gAAAARectVertexAttribs[] = {
      { kVec2f_GrVertexAttribType, 0,                 kPosition_GrVertexAttribBinding },
      { kVec4f_GrVertexAttribType, sizeof(SkPoint),   kEffect_GrVertexAttribBinding },
  };
  
  };
  
  void GrAARectRenderer::shaderFillAARect(GrGpu* gpu,
                                          GrDrawTarget* target,
                                          const SkRect& rect,
                                          const SkMatrix& combinedMatrix) {
      GrDrawState* drawState = target->drawState();
  
      SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
      combinedMatrix.mapPoints(&center, 1);
  
      // compute transformed (0, 1) vector
      SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
      dir.normalize();
  
      // compute transformed (width, 0) and (0, height) vectors
      SkVector vec[2] = {
        { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
        { combinedMatrix[SkMatrix::kMSkewX],  combinedMatrix[SkMatrix::kMScaleY] }
      };
  
      SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf;
      SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf;
      drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs));
      SkASSERT(sizeof(RectVertex) == drawState->getVertexSize());
  
      GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
      if (!geo.succeeded()) {
          GrPrintf("Failed to get space for vertices!\n");
          return;
      }
  
      RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
  
      GrEffectRef* effect = GrRectEffect::Create();
      static const int kRectAttrIndex = 1;
      static const int kWidthIndex = 2;
      drawState->addCoverageEffect(effect, kRectAttrIndex, kWidthIndex)->unref();
  
      for (int i = 0; i < 4; ++i) {
          verts[i].fCenter = center;
          verts[i].fDir = dir;
          verts[i].fWidthHeight.fX = newWidth;
          verts[i].fWidthHeight.fY = newHeight;
      }
  
      SkRect devRect;
      combinedMatrix.mapRect(&devRect, rect);
  
      SkRect devBounds = {
          devRect.fLeft   - SK_ScalarHalf,
          devRect.fTop    - SK_ScalarHalf,
          devRect.fRight  + SK_ScalarHalf,
          devRect.fBottom + SK_ScalarHalf
      };
  
      verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
      verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
      verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
      verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
  
      target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
      target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
      target->resetIndexSource();
  }
  
  void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu,
                                                 GrDrawTarget* target,
                                                 const SkRect& rect,
                                                 const SkMatrix& combinedMatrix) {
      GrDrawState* drawState = target->drawState();
      SkASSERT(combinedMatrix.rectStaysRect());
  
      drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs));
      SkASSERT(sizeof(AARectVertex) == drawState->getVertexSize());
  
      GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
      if (!geo.succeeded()) {
          GrPrintf("Failed to get space for vertices!\n");
          return;
      }
  
      AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
  
      GrEffectRef* effect = GrAlignedRectEffect::Create();
      static const int kOffsetIndex = 1;
      drawState->addCoverageEffect(effect, kOffsetIndex)->unref();
  
      SkRect devRect;
      combinedMatrix.mapRect(&devRect, rect);
  
      SkRect devBounds = {
          devRect.fLeft   - SK_ScalarHalf,
          devRect.fTop    - SK_ScalarHalf,
          devRect.fRight  + SK_ScalarHalf,
          devRect.fBottom + SK_ScalarHalf
      };
  
      SkPoint widthHeight = {
          SkScalarHalf(devRect.width()) + SK_ScalarHalf,
          SkScalarHalf(devRect.height()) + SK_ScalarHalf
      };
  
      verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
      verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY);
      verts[0].fWidthHeight = widthHeight;
  
      verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
      verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY);
      verts[1].fWidthHeight = widthHeight;
  
      verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
      verts[2].fOffset = widthHeight;
      verts[2].fWidthHeight = widthHeight;
  
      verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
      verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY);
      verts[3].fWidthHeight = widthHeight;
  
      target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
      target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
      target->resetIndexSource();
  }
  
  void GrAARectRenderer::strokeAARect(GrGpu* gpu,
                                      GrDrawTarget* target,
                                      const SkRect& rect,
                                      const SkMatrix& combinedMatrix,
                                      const SkRect& devRect,
                                      const SkStrokeRec* stroke,
                                      bool useVertexCoverage) {
      SkVector devStrokeSize;
      SkScalar width = stroke->getWidth();
      if (width > 0) {
          devStrokeSize.set(width, width);
          combinedMatrix.mapVectors(&devStrokeSize, 1);
          devStrokeSize.setAbs(devStrokeSize);
      } else {
          devStrokeSize.set(SK_Scalar1, SK_Scalar1);
      }
  
      const SkScalar dx = devStrokeSize.fX;
      const SkScalar dy = devStrokeSize.fY;
      const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
      const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
  
      // Temporarily #if'ed out. We don't want to pass in the devRect but
      // right now it is computed in GrContext::apply_aa_to_rect and we don't
      // want to throw away the work
  #if 0
      SkRect devRect;
      combinedMatrix.mapRect(&devRect, rect);
  #endif
  
      SkScalar spare;
      {
          SkScalar w = devRect.width() - dx;
          SkScalar h = devRect.height() - dy;
          spare = SkTMin(w, h);
      }
  
      SkRect devOutside(devRect);
      devOutside.outset(rx, ry);
  
      bool miterStroke = true;
      // small miter limit means right angles show bevel...
      if (stroke->getJoin() != SkPaint::kMiter_Join || stroke->getMiter() < SK_ScalarSqrt2) {
          miterStroke = false;
      }
  
      if (spare <= 0 && miterStroke) {
          this->fillAARect(gpu, target, devOutside, SkMatrix::I(),
                           devOutside, useVertexCoverage);
          return;
      }
  
      SkRect devInside(devRect);
      devInside.inset(rx, ry);
  
      SkRect devOutsideAssist(devRect);
  
      // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
      // to draw the outer of the rect. Because there are 8 vertices on the outer
      // edge, while vertex number of inner edge is 4, the same as miter-stroke.
      if (!miterStroke) {
          devOutside.inset(0, ry);
          devOutsideAssist.outset(0, ry);
      }
  
      this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist,
                                 devInside, useVertexCoverage, miterStroke);
  }
  
  void GrAARectRenderer::geometryStrokeAARect(GrGpu* gpu,
                                              GrDrawTarget* target,
                                              const SkRect& devOutside,
                                              const SkRect& devOutsideAssist,
                                              const SkRect& devInside,
                                              bool useVertexCoverage,
                                              bool miterStroke) {
      GrDrawState* drawState = target->drawState();
  
      set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
  
      int innerVertexNum = 4;
      int outerVertexNum = miterStroke ? 4 : 8;
      int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
  
      GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, 0);
      if (!geo.succeeded()) {
          GrPrintf("Failed to get space for vertices!\n");
          return;
      }
      GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu, miterStroke);
      if (NULL == indexBuffer) {
          GrPrintf("Failed to create index buffer!\n");
          return;
      }
  
      intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
      size_t vsize = drawState->getVertexSize();
      SkASSERT(sizeof(SkPoint) + sizeof(GrColor) == vsize);
  
      // We create vertices for four nested rectangles. There are two ramps from 0 to full
      // coverage, one on the exterior of the stroke and the other on the interior.
      // The following pointers refer to the four rects, from outermost to innermost.
      SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
      SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vsize);
      SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vsize);
      SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vsize);
  
  #ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
      // TODO: this only really works if the X & Y margins are the same all around
      // the rect
      SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
      inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
      inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
      if (miterStroke) {
          inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
      } else {
          inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom);
      }
      SkASSERT(inset >= 0);
  #else
      SkScalar inset = SK_ScalarHalf;
  #endif
  
      if (miterStroke) {
          // outermost
          set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
          // inner two
          set_inset_fan(fan1Pos, vsize, devOutside,  inset,  inset);
          set_inset_fan(fan2Pos, vsize, devInside,  -inset, -inset);
          // innermost
          set_inset_fan(fan3Pos, vsize, devInside,   SK_ScalarHalf,  SK_ScalarHalf);
      } else {
          SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vsize);
          SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts + (outerVertexNum + 4) * vsize);
          // outermost
          set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
          set_inset_fan(fan0AssistPos, vsize, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf);
          // outer one of the inner two
          set_inset_fan(fan1Pos, vsize, devOutside,  inset,  inset);
          set_inset_fan(fan1AssistPos, vsize, devOutsideAssist,  inset,  inset);
          // inner one of the inner two
          set_inset_fan(fan2Pos, vsize, devInside,  -inset, -inset);
          // innermost
          set_inset_fan(fan3Pos, vsize, devInside,   SK_ScalarHalf,  SK_ScalarHalf);
      }
  
      // The outermost rect has 0 coverage
      verts += sizeof(SkPoint);
      for (int i = 0; i < outerVertexNum; ++i) {
          *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
      }
  
      int scale;
      if (inset < SK_ScalarHalf) {
          scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
          SkASSERT(scale >= 0 && scale <= 255);
      } else {
          scale = 0xff;
      }
  
      // The inner two rects have full coverage
      GrColor innerColor;
      if (useVertexCoverage) {
          innerColor = GrColorPackRGBA(scale, scale, scale, scale);
      } else {
          if (0xff == scale) {
              innerColor = target->getDrawState().getColor();
          } else {
              innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale);
          }
      }
  
      verts += outerVertexNum * vsize;
      for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
          *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
      }
  
      // The innermost rect has 0 coverage
      verts += (outerVertexNum + innerVertexNum) * vsize;
      for (int i = 0; i < innerVertexNum; ++i) {
          *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
      }
  
      target->setIndexSourceToBuffer(indexBuffer);
      target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0,
                          totalVertexNum, aaStrokeRectIndexCount(miterStroke));
  }
  
  void GrAARectRenderer::fillAANestedRects(GrGpu* gpu,
                                           GrDrawTarget* target,
                                           const SkRect rects[2],
                                           const SkMatrix& combinedMatrix,
                                           bool useVertexCoverage) {
      SkASSERT(combinedMatrix.rectStaysRect());
      SkASSERT(!rects[1].isEmpty());
  
      SkRect devOutside, devOutsideAssist, devInside;
      combinedMatrix.mapRect(&devOutside, rects[0]);
      // can't call mapRect for devInside since it calls sort
      combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
  
      if (devInside.isEmpty()) {
          this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside, useVertexCoverage);
          return;
      }
  
      this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist,
                                 devInside, useVertexCoverage, true);
  }
  