Home | History | Annotate | Download | only in ops
      1 /*
      2  * Copyright 2016 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "GrShadowRRectOp.h"
      9 #include "GrDrawOpTest.h"
     10 #include "GrOpFlushState.h"
     11 #include "SkRRect.h"
     12 #include "effects/GrShadowGeoProc.h"
     13 
     14 ///////////////////////////////////////////////////////////////////////////////
     15 // Circle Data
     16 //
     17 // We have two possible cases for geometry for a circle:
     18 
     19 // In the case of a normal fill, we draw geometry for the circle as an octagon.
     20 static const uint16_t gFillCircleIndices[] = {
     21         // enter the octagon
     22         // clang-format off
     23         0, 1, 8, 1, 2, 8,
     24         2, 3, 8, 3, 4, 8,
     25         4, 5, 8, 5, 6, 8,
     26         6, 7, 8, 7, 0, 8,
     27         // clang-format on
     28 };
     29 
     30 // For stroked circles, we use two nested octagons.
     31 static const uint16_t gStrokeCircleIndices[] = {
     32         // enter the octagon
     33         // clang-format off
     34         0, 1,  9, 0,  9,  8,
     35         1, 2, 10, 1, 10,  9,
     36         2, 3, 11, 2, 11, 10,
     37         3, 4, 12, 3, 12, 11,
     38         4, 5, 13, 4, 13, 12,
     39         5, 6, 14, 5, 14, 13,
     40         6, 7, 15, 6, 15, 14,
     41         7, 0,  8, 7,  8, 15,
     42         // clang-format on
     43 };
     44 
     45 static const int kIndicesPerFillCircle = SK_ARRAY_COUNT(gFillCircleIndices);
     46 static const int kIndicesPerStrokeCircle = SK_ARRAY_COUNT(gStrokeCircleIndices);
     47 static const int kVertsPerStrokeCircle = 16;
     48 static const int kVertsPerFillCircle = 9;
     49 
     50 static int circle_type_to_vert_count(bool stroked) {
     51     return stroked ? kVertsPerStrokeCircle : kVertsPerFillCircle;
     52 }
     53 
     54 static int circle_type_to_index_count(bool stroked) {
     55     return stroked ? kIndicesPerStrokeCircle : kIndicesPerFillCircle;
     56 }
     57 
     58 static const uint16_t* circle_type_to_indices(bool stroked) {
     59     return stroked ? gStrokeCircleIndices : gFillCircleIndices;
     60 }
     61 
     62 ///////////////////////////////////////////////////////////////////////////////
     63 // RoundRect Data
     64 //
     65 // The geometry for a shadow roundrect is similar to a 9-patch:
     66 //    ____________
     67 //   |_|________|_|
     68 //   | |        | |
     69 //   | |        | |
     70 //   | |        | |
     71 //   |_|________|_|
     72 //   |_|________|_|
     73 //
     74 // However, each corner is rendered as a fan rather than a simple quad, as below. (The diagram
     75 // shows the upper part of the upper left corner. The bottom triangle would similarly be split
     76 // into two triangles.)
     77 //    ________
     78 //   |\  \   |
     79 //   |  \ \  |
     80 //   |    \\ |
     81 //   |      \|
     82 //   --------
     83 //
     84 // The center of the fan handles the curve of the corner. For roundrects where the stroke width
     85 // is greater than the corner radius, the outer triangles blend from the curve to the straight
     86 // sides. Otherwise these triangles will be degenerate.
     87 //
     88 // In the case where the stroke width is greater than the corner radius and the
     89 // blur radius (overstroke), we add additional geometry to mark out the rectangle in the center.
     90 // This rectangle extends the coverage values of the center edges of the 9-patch.
     91 //    ____________
     92 //   |_|________|_|
     93 //   | |\ ____ /| |
     94 //   | | |    | | |
     95 //   | | |____| | |
     96 //   |_|/______\|_|
     97 //   |_|________|_|
     98 //
     99 // For filled rrects we reuse the stroke geometry but add an additional quad to the center.
    100 
    101 static const uint16_t gRRectIndices[] = {
    102     // clang-format off
    103     // overstroke quads
    104     // we place this at the beginning so that we can skip these indices when rendering as filled
    105     0, 6, 25, 0, 25, 24,
    106     6, 18, 27, 6, 27, 25,
    107     18, 12, 26, 18, 26, 27,
    108     12, 0, 24, 12, 24, 26,
    109 
    110     // corners
    111     0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5,
    112     6, 11, 10, 6, 10, 9, 6, 9, 8, 6, 8, 7,
    113     12, 17, 16, 12, 16, 15, 12, 15, 14, 12, 14, 13,
    114     18, 19, 20, 18, 20, 21, 18, 21, 22, 18, 22, 23,
    115 
    116     // edges
    117     0, 5, 11, 0, 11, 6,
    118     6, 7, 19, 6, 19, 18,
    119     18, 23, 17, 18, 17, 12,
    120     12, 13, 1, 12, 1, 0,
    121 
    122     // fill quad
    123     // we place this at the end so that we can skip these indices when rendering as stroked
    124     0, 6, 18, 0, 18, 12,
    125     // clang-format on
    126 };
    127 
    128 // overstroke count
    129 static const int kIndicesPerOverstrokeRRect = SK_ARRAY_COUNT(gRRectIndices) - 6;
    130 // simple stroke count skips overstroke indices
    131 static const int kIndicesPerStrokeRRect = kIndicesPerOverstrokeRRect - 6*4;
    132 // fill count adds final quad to stroke count
    133 static const int kIndicesPerFillRRect = kIndicesPerStrokeRRect + 6;
    134 static const int kVertsPerStrokeRRect = 24;
    135 static const int kVertsPerOverstrokeRRect = 28;
    136 static const int kVertsPerFillRRect = 24;
    137 
    138 enum RRectType {
    139     kFill_RRectType,
    140     kStroke_RRectType,
    141     kOverstroke_RRectType,
    142 };
    143 
    144 static int rrect_type_to_vert_count(RRectType type) {
    145     switch (type) {
    146         case kFill_RRectType:
    147             return kVertsPerFillRRect;
    148         case kStroke_RRectType:
    149             return kVertsPerStrokeRRect;
    150         case kOverstroke_RRectType:
    151             return kVertsPerOverstrokeRRect;
    152     }
    153     SkFAIL("Invalid type");
    154     return 0;
    155 }
    156 
    157 static int rrect_type_to_index_count(RRectType type) {
    158     switch (type) {
    159         case kFill_RRectType:
    160             return kIndicesPerFillRRect;
    161         case kStroke_RRectType:
    162             return kIndicesPerStrokeRRect;
    163         case kOverstroke_RRectType:
    164             return kIndicesPerOverstrokeRRect;
    165     }
    166     SkFAIL("Invalid type");
    167     return 0;
    168 }
    169 
    170 static const uint16_t* rrect_type_to_indices(RRectType type) {
    171     switch (type) {
    172         case kFill_RRectType:
    173         case kStroke_RRectType:
    174             return gRRectIndices + 6*4;
    175         case kOverstroke_RRectType:
    176             return gRRectIndices;
    177     }
    178     SkFAIL("Invalid type");
    179     return nullptr;
    180 }
    181 
    182 ///////////////////////////////////////////////////////////////////////////////
    183 namespace {
    184 
    185 class ShadowCircularRRectOp final : public GrMeshDrawOp {
    186 public:
    187     DEFINE_OP_CLASS_ID
    188 
    189     // An insetWidth > 1/2 rect width or height indicates a simple fill.
    190     ShadowCircularRRectOp(GrColor color, const SkRect& devRect,
    191                           float devRadius, bool isCircle, float blurRadius, float insetWidth,
    192                           float blurClamp)
    193             : INHERITED(ClassID()) {
    194         SkRect bounds = devRect;
    195         SkASSERT(insetWidth > 0);
    196         SkScalar innerRadius = 0.0f;
    197         SkScalar outerRadius = devRadius;
    198         SkScalar umbraInset;
    199 
    200         RRectType type = kFill_RRectType;
    201         if (isCircle) {
    202             umbraInset = 0;
    203         } else if (insetWidth > 0 && insetWidth <= outerRadius) {
    204             // If the client has requested a stroke smaller than the outer radius,
    205             // we will assume they want no special umbra inset (this is for ambient shadows).
    206             umbraInset = outerRadius;
    207         } else {
    208             umbraInset = SkTMax(outerRadius, blurRadius);
    209         }
    210 
    211         // If stroke is greater than width or height, this is still a fill,
    212         // otherwise we compute stroke params.
    213         if (isCircle) {
    214             innerRadius = devRadius - insetWidth;
    215             type = innerRadius > 0 ? kStroke_RRectType : kFill_RRectType;
    216         } else {
    217             if (insetWidth <= 0.5f*SkTMin(devRect.width(), devRect.height())) {
    218                 // We don't worry about a real inner radius, we just need to know if we
    219                 // need to create overstroke vertices.
    220                 innerRadius = SkTMax(insetWidth - umbraInset, 0.0f);
    221                 type = innerRadius > 0 ? kOverstroke_RRectType : kStroke_RRectType;
    222             }
    223         }
    224 
    225         this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
    226 
    227         fGeoData.emplace_back(Geometry{color, outerRadius, umbraInset, innerRadius,
    228                                        blurRadius, blurClamp, bounds, type, isCircle});
    229         if (isCircle) {
    230             fVertCount = circle_type_to_vert_count(kStroke_RRectType == type);
    231             fIndexCount = circle_type_to_index_count(kStroke_RRectType == type);
    232         } else {
    233             fVertCount = rrect_type_to_vert_count(type);
    234             fIndexCount = rrect_type_to_index_count(type);
    235         }
    236     }
    237 
    238     const char* name() const override { return "ShadowCircularRRectOp"; }
    239 
    240     SkString dumpInfo() const override {
    241         SkString string;
    242         for (int i = 0; i < fGeoData.count(); ++i) {
    243             string.appendf(
    244                     "Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f],"
    245                     "OuterRad: %.2f, Umbra: %.2f, InnerRad: %.2f, BlurRad: %.2f\n",
    246                     fGeoData[i].fColor, fGeoData[i].fDevBounds.fLeft, fGeoData[i].fDevBounds.fTop,
    247                     fGeoData[i].fDevBounds.fRight, fGeoData[i].fDevBounds.fBottom,
    248                     fGeoData[i].fOuterRadius, fGeoData[i].fUmbraInset,
    249                     fGeoData[i].fInnerRadius, fGeoData[i].fBlurRadius);
    250         }
    251         string.append(INHERITED::dumpInfo());
    252         return string;
    253     }
    254 
    255     FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
    256 
    257     RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*) override {
    258         return RequiresDstTexture::kNo;
    259     }
    260 
    261 private:
    262     struct Geometry {
    263         GrColor   fColor;
    264         SkScalar  fOuterRadius;
    265         SkScalar  fUmbraInset;
    266         SkScalar  fInnerRadius;
    267         SkScalar  fBlurRadius;
    268         SkScalar  fClampValue;
    269         SkRect    fDevBounds;
    270         RRectType fType;
    271         bool      fIsCircle;
    272     };
    273 
    274     struct CircleVertex {
    275         SkPoint fPos;
    276         GrColor fColor;
    277         SkPoint fOffset;
    278         SkScalar fDistanceCorrection;
    279         SkScalar fClampValue;
    280     };
    281 
    282     void fillInCircleVerts(const Geometry& args, bool isStroked, CircleVertex** verts) const {
    283 
    284         GrColor color = args.fColor;
    285         SkScalar outerRadius = args.fOuterRadius;
    286         SkScalar innerRadius = args.fInnerRadius;
    287         SkScalar blurRadius = args.fBlurRadius;
    288         SkScalar distanceCorrection = outerRadius / blurRadius;
    289         SkScalar clampValue = args.fClampValue;
    290 
    291         const SkRect& bounds = args.fDevBounds;
    292 
    293         // The inner radius in the vertex data must be specified in normalized space.
    294         innerRadius = innerRadius / outerRadius;
    295 
    296         SkPoint center = SkPoint::Make(bounds.centerX(), bounds.centerY());
    297         SkScalar halfWidth = 0.5f * bounds.width();
    298         SkScalar octOffset = 0.41421356237f;  // sqrt(2) - 1
    299 
    300         (*verts)->fPos = center + SkPoint::Make(-octOffset * halfWidth, -halfWidth);
    301         (*verts)->fColor = color;
    302         (*verts)->fOffset = SkPoint::Make(-octOffset, -1);
    303         (*verts)->fDistanceCorrection = distanceCorrection;
    304         (*verts)->fClampValue = clampValue;
    305         (*verts)++;
    306 
    307         (*verts)->fPos = center + SkPoint::Make(octOffset * halfWidth, -halfWidth);
    308         (*verts)->fColor = color;
    309         (*verts)->fOffset = SkPoint::Make(octOffset, -1);
    310         (*verts)->fDistanceCorrection = distanceCorrection;
    311         (*verts)->fClampValue = clampValue;
    312         (*verts)++;
    313 
    314         (*verts)->fPos = center + SkPoint::Make(halfWidth, -octOffset * halfWidth);
    315         (*verts)->fColor = color;
    316         (*verts)->fOffset = SkPoint::Make(1, -octOffset);
    317         (*verts)->fDistanceCorrection = distanceCorrection;
    318         (*verts)->fClampValue = clampValue;
    319         (*verts)++;
    320 
    321         (*verts)->fPos = center + SkPoint::Make(halfWidth, octOffset * halfWidth);
    322         (*verts)->fColor = color;
    323         (*verts)->fOffset = SkPoint::Make(1, octOffset);
    324         (*verts)->fDistanceCorrection = distanceCorrection;
    325         (*verts)->fClampValue = clampValue;
    326         (*verts)++;
    327 
    328         (*verts)->fPos = center + SkPoint::Make(octOffset * halfWidth, halfWidth);
    329         (*verts)->fColor = color;
    330         (*verts)->fOffset = SkPoint::Make(octOffset, 1);
    331         (*verts)->fDistanceCorrection = distanceCorrection;
    332         (*verts)->fClampValue = clampValue;
    333         (*verts)++;
    334 
    335         (*verts)->fPos = center + SkPoint::Make(-octOffset * halfWidth, halfWidth);
    336         (*verts)->fColor = color;
    337         (*verts)->fOffset = SkPoint::Make(-octOffset, 1);
    338         (*verts)->fDistanceCorrection = distanceCorrection;
    339         (*verts)->fClampValue = clampValue;
    340         (*verts)++;
    341 
    342         (*verts)->fPos = center + SkPoint::Make(-halfWidth, octOffset * halfWidth);
    343         (*verts)->fColor = color;
    344         (*verts)->fOffset = SkPoint::Make(-1, octOffset);
    345         (*verts)->fDistanceCorrection = distanceCorrection;
    346         (*verts)->fClampValue = clampValue;
    347         (*verts)++;
    348 
    349         (*verts)->fPos = center + SkPoint::Make(-halfWidth, -octOffset * halfWidth);
    350         (*verts)->fColor = color;
    351         (*verts)->fOffset = SkPoint::Make(-1, -octOffset);
    352         (*verts)->fDistanceCorrection = distanceCorrection;
    353         (*verts)->fClampValue = clampValue;
    354         (*verts)++;
    355 
    356         if (isStroked) {
    357             // compute the inner ring
    358 
    359             // cosine and sine of pi/8
    360             SkScalar c = 0.923579533f;
    361             SkScalar s = 0.382683432f;
    362             SkScalar r = args.fInnerRadius;
    363 
    364             (*verts)->fPos = center + SkPoint::Make(-s * r, -c * r);
    365             (*verts)->fColor = color;
    366             (*verts)->fOffset = SkPoint::Make(-s * innerRadius, -c * innerRadius);
    367             (*verts)->fDistanceCorrection = distanceCorrection;
    368             (*verts)->fClampValue = clampValue;
    369             (*verts)++;
    370 
    371             (*verts)->fPos = center + SkPoint::Make(s * r, -c * r);
    372             (*verts)->fColor = color;
    373             (*verts)->fOffset = SkPoint::Make(s * innerRadius, -c * innerRadius);
    374             (*verts)->fDistanceCorrection = distanceCorrection;
    375             (*verts)->fClampValue = clampValue;
    376             (*verts)++;
    377 
    378             (*verts)->fPos = center + SkPoint::Make(c * r, -s * r);
    379             (*verts)->fColor = color;
    380             (*verts)->fOffset = SkPoint::Make(c * innerRadius, -s * innerRadius);
    381             (*verts)->fDistanceCorrection = distanceCorrection;
    382             (*verts)->fClampValue = clampValue;
    383             (*verts)++;
    384 
    385             (*verts)->fPos = center + SkPoint::Make(c * r, s * r);
    386             (*verts)->fColor = color;
    387             (*verts)->fOffset = SkPoint::Make(c * innerRadius, s * innerRadius);
    388             (*verts)->fDistanceCorrection = distanceCorrection;
    389             (*verts)->fClampValue = clampValue;
    390             (*verts)++;
    391 
    392             (*verts)->fPos = center + SkPoint::Make(s * r, c * r);
    393             (*verts)->fColor = color;
    394             (*verts)->fOffset = SkPoint::Make(s * innerRadius, c * innerRadius);
    395             (*verts)->fDistanceCorrection = distanceCorrection;
    396             (*verts)->fClampValue = clampValue;
    397             (*verts)++;
    398 
    399             (*verts)->fPos = center + SkPoint::Make(-s * r, c * r);
    400             (*verts)->fColor = color;
    401             (*verts)->fOffset = SkPoint::Make(-s * innerRadius, c * innerRadius);
    402             (*verts)->fDistanceCorrection = distanceCorrection;
    403             (*verts)->fClampValue = clampValue;
    404             (*verts)++;
    405 
    406             (*verts)->fPos = center + SkPoint::Make(-c * r, s * r);
    407             (*verts)->fColor = color;
    408             (*verts)->fOffset = SkPoint::Make(-c * innerRadius, s * innerRadius);
    409             (*verts)->fDistanceCorrection = distanceCorrection;
    410             (*verts)->fClampValue = clampValue;
    411             (*verts)++;
    412 
    413             (*verts)->fPos = center + SkPoint::Make(-c * r, -s * r);
    414             (*verts)->fColor = color;
    415             (*verts)->fOffset = SkPoint::Make(-c * innerRadius, -s * innerRadius);
    416             (*verts)->fDistanceCorrection = distanceCorrection;
    417             (*verts)->fClampValue = clampValue;
    418             (*verts)++;
    419         } else {
    420             // filled
    421             (*verts)->fPos = center;
    422             (*verts)->fColor = color;
    423             (*verts)->fOffset = SkPoint::Make(0, 0);
    424             (*verts)->fDistanceCorrection = distanceCorrection;
    425             (*verts)->fClampValue = clampValue;
    426             (*verts)++;
    427         }
    428     }
    429 
    430     void fillInRRectVerts(const Geometry& args, CircleVertex** verts) const {
    431         GrColor color = args.fColor;
    432         SkScalar outerRadius = args.fOuterRadius;
    433 
    434         const SkRect& bounds = args.fDevBounds;
    435 
    436         SkScalar umbraInset = args.fUmbraInset;
    437         SkScalar minDim = 0.5f*SkTMin(bounds.width(), bounds.height());
    438         if (umbraInset > minDim) {
    439             umbraInset = minDim;
    440         }
    441 
    442         SkScalar xInner[4] = { bounds.fLeft + umbraInset, bounds.fRight - umbraInset,
    443             bounds.fLeft + umbraInset, bounds.fRight - umbraInset };
    444         SkScalar xMid[4] = { bounds.fLeft + outerRadius, bounds.fRight - outerRadius,
    445             bounds.fLeft + outerRadius, bounds.fRight - outerRadius };
    446         SkScalar xOuter[4] = { bounds.fLeft, bounds.fRight,
    447             bounds.fLeft, bounds.fRight };
    448         SkScalar yInner[4] = { bounds.fTop + umbraInset, bounds.fTop + umbraInset,
    449             bounds.fBottom - umbraInset, bounds.fBottom - umbraInset };
    450         SkScalar yMid[4] = { bounds.fTop + outerRadius, bounds.fTop + outerRadius,
    451             bounds.fBottom - outerRadius, bounds.fBottom - outerRadius };
    452         SkScalar yOuter[4] = { bounds.fTop, bounds.fTop,
    453             bounds.fBottom, bounds.fBottom };
    454 
    455         SkScalar blurRadius = args.fBlurRadius;
    456 
    457         // In the case where we have to inset more for the umbra, our two triangles in the
    458         // corner get skewed to a diamond rather than a square. To correct for that,
    459         // we also skew the vectors we send to the shader that help define the circle.
    460         // By doing so, we end up with a quarter circle in the corner rather than the
    461         // elliptical curve.
    462         SkVector outerVec = SkVector::Make(0.5f*(outerRadius - umbraInset), -umbraInset);
    463         outerVec.normalize();
    464         SkVector diagVec = SkVector::Make(outerVec.fX + outerVec.fY,
    465                                           outerVec.fX + outerVec.fY);
    466         diagVec *= umbraInset / (2 * umbraInset - outerRadius);
    467         SkScalar distanceCorrection = umbraInset / blurRadius;
    468         SkScalar clampValue = args.fClampValue;
    469 
    470         // build corner by corner
    471         for (int i = 0; i < 4; ++i) {
    472             // inner point
    473             (*verts)->fPos = SkPoint::Make(xInner[i], yInner[i]);
    474             (*verts)->fColor = color;
    475             (*verts)->fOffset = SkVector::Make(0, 0);
    476             (*verts)->fDistanceCorrection = distanceCorrection;
    477             (*verts)->fClampValue = clampValue;
    478             (*verts)++;
    479 
    480             // outer points
    481             (*verts)->fPos = SkPoint::Make(xOuter[i], yInner[i]);
    482             (*verts)->fColor = color;
    483             (*verts)->fOffset = SkVector::Make(0, -1);
    484             (*verts)->fDistanceCorrection = distanceCorrection;
    485             (*verts)->fClampValue = clampValue;
    486             (*verts)++;
    487 
    488             (*verts)->fPos = SkPoint::Make(xOuter[i], yMid[i]);
    489             (*verts)->fColor = color;
    490             (*verts)->fOffset = outerVec;
    491             (*verts)->fDistanceCorrection = distanceCorrection;
    492             (*verts)->fClampValue = clampValue;
    493             (*verts)++;
    494 
    495             (*verts)->fPos = SkPoint::Make(xOuter[i], yOuter[i]);
    496             (*verts)->fColor = color;
    497             (*verts)->fOffset = diagVec;
    498             (*verts)->fDistanceCorrection = distanceCorrection;
    499             (*verts)->fClampValue = clampValue;
    500             (*verts)++;
    501 
    502             (*verts)->fPos = SkPoint::Make(xMid[i], yOuter[i]);
    503             (*verts)->fColor = color;
    504             (*verts)->fOffset = outerVec;
    505             (*verts)->fDistanceCorrection = distanceCorrection;
    506             (*verts)->fClampValue = clampValue;
    507             (*verts)++;
    508 
    509             (*verts)->fPos = SkPoint::Make(xInner[i], yOuter[i]);
    510             (*verts)->fColor = color;
    511             (*verts)->fOffset = SkVector::Make(0, -1);
    512             (*verts)->fDistanceCorrection = distanceCorrection;
    513             (*verts)->fClampValue = clampValue;
    514             (*verts)++;
    515         }
    516 
    517         // Add the additional vertices for overstroked rrects.
    518         // Effectively this is an additional stroked rrect, with its
    519         // parameters equal to those in the center of the 9-patch. This will
    520         // give constant values across this inner ring.
    521         if (kOverstroke_RRectType == args.fType) {
    522             SkASSERT(args.fInnerRadius > 0.0f);
    523 
    524             SkScalar inset =  umbraInset + args.fInnerRadius;
    525 
    526             // TL
    527             (*verts)->fPos = SkPoint::Make(bounds.fLeft + inset, bounds.fTop + inset);
    528             (*verts)->fColor = color;
    529             (*verts)->fOffset = SkPoint::Make(0, 0);
    530             (*verts)->fDistanceCorrection = distanceCorrection;
    531             (*verts)->fClampValue = clampValue;
    532             (*verts)++;
    533 
    534             // TR
    535             (*verts)->fPos = SkPoint::Make(bounds.fRight - inset, bounds.fTop + inset);
    536             (*verts)->fColor = color;
    537             (*verts)->fOffset = SkPoint::Make(0, 0);
    538             (*verts)->fDistanceCorrection = distanceCorrection;
    539             (*verts)->fClampValue = clampValue;
    540             (*verts)++;
    541 
    542             // BL
    543             (*verts)->fPos = SkPoint::Make(bounds.fLeft + inset, bounds.fBottom - inset);
    544             (*verts)->fColor = color;
    545             (*verts)->fOffset = SkPoint::Make(0, 0);
    546             (*verts)->fDistanceCorrection = distanceCorrection;
    547             (*verts)->fClampValue = clampValue;
    548             (*verts)++;
    549 
    550             // BR
    551             (*verts)->fPos = SkPoint::Make(bounds.fRight - inset, bounds.fBottom - inset);
    552             (*verts)->fColor = color;
    553             (*verts)->fOffset = SkPoint::Make(0, 0);
    554             (*verts)->fDistanceCorrection = distanceCorrection;
    555             (*verts)->fClampValue = clampValue;
    556             (*verts)++;
    557         }
    558 
    559     }
    560 
    561     void onPrepareDraws(Target* target) const override {
    562         // Setup geometry processor
    563         sk_sp<GrGeometryProcessor> gp = GrRRectShadowGeoProc::Make();
    564 
    565         int instanceCount = fGeoData.count();
    566         size_t vertexStride = gp->getVertexStride();
    567         SkASSERT(sizeof(CircleVertex) == vertexStride);
    568 
    569         const GrBuffer* vertexBuffer;
    570         int firstVertex;
    571         CircleVertex* verts = (CircleVertex*)target->makeVertexSpace(vertexStride, fVertCount,
    572                                                                      &vertexBuffer, &firstVertex);
    573         if (!verts) {
    574             SkDebugf("Could not allocate vertices\n");
    575             return;
    576         }
    577 
    578         const GrBuffer* indexBuffer = nullptr;
    579         int firstIndex = 0;
    580         uint16_t* indices = target->makeIndexSpace(fIndexCount, &indexBuffer, &firstIndex);
    581         if (!indices) {
    582             SkDebugf("Could not allocate indices\n");
    583             return;
    584         }
    585 
    586         int currStartVertex = 0;
    587         for (int i = 0; i < instanceCount; i++) {
    588             const Geometry& args = fGeoData[i];
    589 
    590             if (args.fIsCircle) {
    591                 bool isStroked = SkToBool(kStroke_RRectType == args.fType);
    592                 this->fillInCircleVerts(args, isStroked, &verts);
    593 
    594                 const uint16_t* primIndices = circle_type_to_indices(isStroked);
    595                 const int primIndexCount = circle_type_to_index_count(isStroked);
    596                 for (int i = 0; i < primIndexCount; ++i) {
    597                     *indices++ = primIndices[i] + currStartVertex;
    598                 }
    599 
    600                 currStartVertex += circle_type_to_vert_count(isStroked);
    601 
    602             } else {
    603                 this->fillInRRectVerts(args, &verts);
    604 
    605                 const uint16_t* primIndices = rrect_type_to_indices(args.fType);
    606                 const int primIndexCount = rrect_type_to_index_count(args.fType);
    607                 for (int i = 0; i < primIndexCount; ++i) {
    608                     *indices++ = primIndices[i] + currStartVertex;
    609                 }
    610 
    611                 currStartVertex += rrect_type_to_vert_count(args.fType);
    612             }
    613         }
    614 
    615         static const uint32_t kPipelineFlags = 0;
    616         const GrPipeline* pipeline =
    617                 target->makePipeline(kPipelineFlags, &GrProcessorSet::EmptySet());
    618 
    619         GrMesh mesh(GrPrimitiveType::kTriangles);
    620         mesh.setIndexed(indexBuffer, fIndexCount, firstIndex, 0, fVertCount - 1);
    621         mesh.setVertexData(vertexBuffer, firstVertex);
    622         target->draw(gp.get(), pipeline, mesh);
    623     }
    624 
    625     bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
    626         ShadowCircularRRectOp* that = t->cast<ShadowCircularRRectOp>();
    627         fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin());
    628         this->joinBounds(*that);
    629         fVertCount += that->fVertCount;
    630         fIndexCount += that->fIndexCount;
    631         return true;
    632     }
    633 
    634     SkSTArray<1, Geometry, true> fGeoData;
    635     int fVertCount;
    636     int fIndexCount;
    637 
    638     typedef GrMeshDrawOp INHERITED;
    639 };
    640 
    641 }  // anonymous namespace
    642 
    643 ///////////////////////////////////////////////////////////////////////////////
    644 
    645 namespace GrShadowRRectOp {
    646 std::unique_ptr<GrDrawOp> Make(GrColor color,
    647                                const SkMatrix& viewMatrix,
    648                                const SkRRect& rrect,
    649                                SkScalar blurWidth,
    650                                SkScalar insetWidth,
    651                                SkScalar blurClamp) {
    652     // Shadow rrect ops only handle simple circular rrects.
    653     SkASSERT(viewMatrix.isSimilarity() &&
    654              (rrect.isSimpleCircular() || rrect.isRect() || rrect.isCircle()));
    655 
    656     // Do any matrix crunching before we reset the draw state for device coords.
    657     const SkRect& rrectBounds = rrect.getBounds();
    658     SkRect bounds;
    659     viewMatrix.mapRect(&bounds, rrectBounds);
    660 
    661     // Map radius and inset. As the matrix is a similarity matrix, this should be isotropic.
    662     SkScalar radius = rrect.getSimpleRadii().fX;
    663     SkScalar matrixFactor = viewMatrix[SkMatrix::kMScaleX] + viewMatrix[SkMatrix::kMSkewX];
    664     SkScalar scaledRadius = SkScalarAbs(radius*matrixFactor);
    665     SkScalar scaledInsetWidth = SkScalarAbs(insetWidth*matrixFactor);
    666 
    667     return std::unique_ptr<GrDrawOp>(new ShadowCircularRRectOp(color, bounds,
    668                                                                scaledRadius,
    669                                                                rrect.isOval(),
    670                                                                blurWidth,
    671                                                                scaledInsetWidth,
    672                                                                blurClamp));
    673 }
    674 }
    675 
    676 ///////////////////////////////////////////////////////////////////////////////
    677 
    678 #if GR_TEST_UTILS
    679 
    680 GR_DRAW_OP_TEST_DEFINE(ShadowRRectOp) {
    681     // create a similarity matrix
    682     SkScalar rotate = random->nextSScalar1() * 360.f;
    683     SkScalar translateX = random->nextSScalar1() * 1000.f;
    684     SkScalar translateY = random->nextSScalar1() * 1000.f;
    685     SkScalar scale = random->nextSScalar1() * 100.f;
    686     SkMatrix viewMatrix;
    687     viewMatrix.setRotate(rotate);
    688     viewMatrix.postTranslate(translateX, translateY);
    689     viewMatrix.postScale(scale, scale);
    690     SkScalar insetWidth = random->nextSScalar1() * 72.f;
    691     SkScalar blurWidth = random->nextSScalar1() * 72.f;
    692     SkScalar blurClamp = random->nextSScalar1();
    693     bool isCircle = random->nextBool();
    694     // This op doesn't use a full GrPaint, just a color.
    695     GrColor color = paint.getColor();
    696     if (isCircle) {
    697         SkRect circle = GrTest::TestSquare(random);
    698         SkRRect rrect = SkRRect::MakeOval(circle);
    699         return GrShadowRRectOp::Make(color, viewMatrix, rrect, blurWidth, insetWidth, blurClamp);
    700     } else {
    701         SkRRect rrect;
    702         do {
    703             // This may return a rrect with elliptical corners, which we don't support.
    704             rrect = GrTest::TestRRectSimple(random);
    705         } while (!rrect.isSimpleCircular());
    706         return GrShadowRRectOp::Make(color, viewMatrix, rrect, blurWidth, insetWidth, blurClamp);
    707     }
    708 }
    709 
    710 #endif
    711