1561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes/*
2561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes * Copyright 2014 Google Inc.
3561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes *
4561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes * Use of this source code is governed by a BSD-style license that can be
5561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes * found in the LICENSE file.
6561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes */
7561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
8561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "gl/builders/GrGLProgramBuilder.h"
9561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "GrRRectEffect.h"
10561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
11561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "gl/GrGLProcessor.h"
12561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "gl/GrGLSL.h"
13561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "GrConvexPolyEffect.h"
14561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "GrOvalEffect.h"
15561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "GrTBackendProcessorFactory.h"
16561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
17561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "SkRRect.h"
18561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
198d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath// The effects defined here only handle rrect radii >= kRadiusMin.
208d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamathstatic const SkScalar kRadiusMin = SK_ScalarHalf;
21561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
22561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes//////////////////////////////////////////////////////////////////////////////
23561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
24561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesclass GLCircularRRectEffect;
25561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
26561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesclass CircularRRectEffect : public GrFragmentProcessor {
27561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughespublic:
28561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
29561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    enum CornerFlags {
30561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes        kTopLeft_CornerFlag     = (1 << SkRRect::kUpperLeft_Corner),
31561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes        kTopRight_CornerFlag    = (1 << SkRRect::kUpperRight_Corner),
32561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes        kBottomRight_CornerFlag = (1 << SkRRect::kLowerRight_Corner),
33561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes        kBottomLeft_CornerFlag  = (1 << SkRRect::kLowerLeft_Corner),
34561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
35561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes        kLeft_CornerFlags   = kTopLeft_CornerFlag    | kBottomLeft_CornerFlag,
36561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes        kTop_CornerFlags    = kTopLeft_CornerFlag    | kTopRight_CornerFlag,
37561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes        kRight_CornerFlags  = kTopRight_CornerFlag   | kBottomRight_CornerFlag,
388d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath        kBottom_CornerFlags = kBottomLeft_CornerFlag | kBottomRight_CornerFlag,
39561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
40561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes        kAll_CornerFlags = kTopLeft_CornerFlag    | kTopRight_CornerFlag |
41561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                           kBottomLeft_CornerFlag | kBottomRight_CornerFlag,
42561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
43561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes        kNone_CornerFlags = 0
44561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    };
45561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
46561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    // The flags are used to indicate which corners are circluar (unflagged corners are assumed to
47561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    // be square).
48561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    static GrFragmentProcessor* Create(GrPrimitiveEdgeType, uint32_t circularCornerFlags,
49561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                                       const SkRRect&);
50561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
51561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    virtual ~CircularRRectEffect() {};
52561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    static const char* Name() { return "CircularRRect"; }
53561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
548d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    const SkRRect& getRRect() const { return fRRect; }
55561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
56561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    uint32_t getCircularCornerFlags() const { return fCircularCornerFlags; }
57561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
58561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
59561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
60561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    typedef GLCircularRRectEffect GLProcessor;
61561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
62561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
63561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
64561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE;
65561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
66561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesprivate:
67561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    CircularRRectEffect(GrPrimitiveEdgeType, uint32_t circularCornerFlags, const SkRRect&);
68561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
69561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    virtual bool onIsEqual(const GrProcessor& other) const SK_OVERRIDE;
708d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath
718d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    SkRRect                fRRect;
72561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    GrPrimitiveEdgeType    fEdgeType;
73561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    uint32_t               fCircularCornerFlags;
74561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
75561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
76561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
778d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    typedef GrFragmentProcessor INHERITED;
78561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes};
79561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
808d8858e39800de641b50f6e8e864af9cf68bedeaNarayan KamathGrFragmentProcessor* CircularRRectEffect::Create(GrPrimitiveEdgeType edgeType,
81561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                                                 uint32_t circularCornerFlags,
82561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                                                 const SkRRect& rrect) {
83561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    if (kFillAA_GrProcessorEdgeType != edgeType && kInverseFillAA_GrProcessorEdgeType != edgeType) {
84561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes        return NULL;
85561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    }
86561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    return SkNEW_ARGS(CircularRRectEffect, (edgeType, circularCornerFlags, rrect));
87561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes}
88561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
89561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesvoid CircularRRectEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
90561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    *validFlags = 0;
91561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes}
92561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
93561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesconst GrBackendFragmentProcessorFactory& CircularRRectEffect::getFactory() const {
94561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    return GrTBackendFragmentProcessorFactory<CircularRRectEffect>::getInstance();
95561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes}
96561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
97561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott HughesCircularRRectEffect::CircularRRectEffect(GrPrimitiveEdgeType edgeType, uint32_t circularCornerFlags,
98561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                                         const SkRRect& rrect)
998d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    : fRRect(rrect)
100561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    , fEdgeType(edgeType)
101561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    , fCircularCornerFlags(circularCornerFlags) {
102561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    this->setWillReadFragmentPosition();
103561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes}
104561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
105561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesbool CircularRRectEffect::onIsEqual(const GrProcessor& other) const {
106561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    const CircularRRectEffect& crre = other.cast<CircularRRectEffect>();
107561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    // The corner flags are derived from fRRect, so no need to check them.
108561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    return fEdgeType == crre.fEdgeType && fRRect == crre.fRRect;
109561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes}
110561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
111561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes//////////////////////////////////////////////////////////////////////////////
112561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
113561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott HughesGR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircularRRectEffect);
114561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
1158d8858e39800de641b50f6e8e864af9cf68bedeaNarayan KamathGrFragmentProcessor* CircularRRectEffect::TestCreate(SkRandom* random,
1168d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                                                     GrContext*,
1178d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                                                     const GrDrawTargetCaps& caps,
1188d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                                                     GrTexture*[]) {
1198d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    SkScalar w = random->nextRangeScalar(20.f, 1000.f);
1208d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    SkScalar h = random->nextRangeScalar(20.f, 1000.f);
1218d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    SkScalar r = random->nextRangeF(kRadiusMin, 9.f);
1228d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    SkRRect rrect;
1238d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    rrect.setRectXY(SkRect::MakeWH(w, h), r, r);
1248d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    GrFragmentProcessor* fp;
125561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    do {
126561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes        GrPrimitiveEdgeType et =
127561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                (GrPrimitiveEdgeType)random->nextULessThan(kGrProcessorEdgeTypeCnt);
1288d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath        fp = GrRRectEffect::Create(et, rrect);
129561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    } while (NULL == fp);
130561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    return fp;
1318d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath}
132561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
133561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes//////////////////////////////////////////////////////////////////////////////
134561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
1358d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamathclass GLCircularRRectEffect : public GrGLFragmentProcessor {
136561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughespublic:
137561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    GLCircularRRectEffect(const GrBackendProcessorFactory&, const GrProcessor&);
138561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
139561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    virtual void emitCode(GrGLProgramBuilder* builder,
1408d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                          const GrFragmentProcessor& fp,
141561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                          const GrProcessorKey& key,
142561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                          const char* outputColor,
143561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                          const char* inputColor,
144561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                          const TransformedCoordsArray&,
145561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                          const TextureSamplerArray&) SK_OVERRIDE;
1468d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath
147561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    static inline void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder*);
148561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
149561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE;
150561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
151561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesprivate:
152561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    GrGLProgramDataManager::UniformHandle fInnerRectUniform;
153561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    GrGLProgramDataManager::UniformHandle fRadiusPlusHalfUniform;
154561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    SkRRect                               fPrevRRect;
155561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    typedef GrGLFragmentProcessor INHERITED;
156561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes};
157561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
158561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott HughesGLCircularRRectEffect::GLCircularRRectEffect(const GrBackendProcessorFactory& factory,
159561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                                             const GrProcessor& )
160561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    : INHERITED (factory) {
161561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    fPrevRRect.setEmpty();
162561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes}
1638d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath
1648d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamathvoid GLCircularRRectEffect::emitCode(GrGLProgramBuilder* builder,
1658d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                             const GrFragmentProcessor& fp,
1668d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                             const GrProcessorKey& key,
1678d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                             const char* outputColor,
1688d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                             const char* inputColor,
1698d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                             const TransformedCoordsArray&,
1708d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                             const TextureSamplerArray& samplers) {
1718d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    const CircularRRectEffect& crre = fp.cast<CircularRRectEffect>();
1728d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    const char *rectName;
1738d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    const char *radiusPlusHalfName;
1748d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    // The inner rect is the rrect bounds inset by the radius. Its left, top, right, and bottom
1758d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    // edges correspond to components x, y, z, and w, respectively. When a side of the rrect has
1768d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    // only rectangular corners, that side's value corresponds to the rect edge's value outset by
1778d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    // half a pixel.
1788d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    fInnerRectUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1798d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                                            kVec4f_GrSLType,
1808d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                                            "innerRect",
1818d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                                            &rectName);
1828d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    fRadiusPlusHalfUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1838d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                                                 kFloat_GrSLType,
1848d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                                                 "radiusPlusHalf",
1858d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                                                 &radiusPlusHalfName);
1868d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath
1878d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
1888d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    const char* fragmentPos = fsBuilder->fragmentPosition();
1898d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    // At each quarter-circle corner we compute a vector that is the offset of the fragment position
1908d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    // from the circle center. The vector is pinned in x and y to be in the quarter-plane relevant
1918d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    // to that corner. This means that points near the interior near the rrect top edge will have
1928d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    // a vector that points straight up for both the TL left and TR corners. Computing an
1938d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    // alpha from this vector at either the TR or TL corner will give the correct result. Similarly,
1948d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    // fragments near the other three edges will get the correct AA. Fragments in the interior of
1958d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    // the rrect will have a (0,0) vector at all four corners. So long as the radius > 0.5 they will
1968d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    // correctly produce an alpha value of 1 at all four corners. We take the min of all the alphas.
1978d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    // The code below is a simplified version of the above that performs maxs on the vector
1988d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    // components before computing distances and alpha values so that only one distance computation
1998d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    // need be computed to determine the min alpha.
2008d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    //
2018d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    // For the cases where one half of the rrect is rectangular we drop one of the x or y
2028d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    // computations, compute a separate rect edge alpha for the rect side, and mul the two computed
2038d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    // alphas together.
2048d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    switch (crre.getCircularCornerFlags()) {
2058d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath        case CircularRRectEffect::kAll_CornerFlags:
2068d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath            fsBuilder->codeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
2078d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath            fsBuilder->codeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
2088d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath            fsBuilder->codeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n");
2098d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath            fsBuilder->codeAppendf("\t\tfloat alpha = clamp(%s - length(dxy), 0.0, 1.0);\n",
2108d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                                   radiusPlusHalfName);
2118d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath            break;
2128d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath        case CircularRRectEffect::kTopLeft_CornerFlag:
2138d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath            fsBuilder->codeAppendf("\t\tvec2 dxy = max(%s.xy - %s.xy, 0.0);\n",
2148d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                                   rectName, fragmentPos);
2158d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath            fsBuilder->codeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n",
2168d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                                    rectName, fragmentPos);
2178d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath            fsBuilder->codeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n",
2188d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                                    rectName, fragmentPos);
2198d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath            fsBuilder->codeAppendf("\t\tfloat alpha = bottomAlpha * rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
2208d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                                   radiusPlusHalfName);
2218d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath            break;
2228d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath        case CircularRRectEffect::kTopRight_CornerFlag:
2238d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath            fsBuilder->codeAppendf("\t\tvec2 dxy = max(vec2(%s.x - %s.z, %s.y - %s.y), 0.0);\n",
2248d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                                   fragmentPos, rectName, rectName, fragmentPos);
2258d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath            fsBuilder->codeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n",
2268d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                                   fragmentPos, rectName);
2278d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath            fsBuilder->codeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n",
2288d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                                    rectName, fragmentPos);
2298d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath            fsBuilder->codeAppendf("\t\tfloat alpha = bottomAlpha * leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
2308d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                                   radiusPlusHalfName);
2318d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath            break;
2328d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath        case CircularRRectEffect::kBottomRight_CornerFlag:
2338d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath            fsBuilder->codeAppendf("\t\tvec2 dxy = max(%s.xy - %s.zw, 0.0);\n",
2348d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                                   fragmentPos, rectName);
2358d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath            fsBuilder->codeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n",
2368d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                                   fragmentPos, rectName);
2378d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath            fsBuilder->codeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n",
2388d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                                   fragmentPos, rectName);
2398d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath            fsBuilder->codeAppendf("\t\tfloat alpha = topAlpha * leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
2408d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                                   radiusPlusHalfName);
2418d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath            break;
2428d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath        case CircularRRectEffect::kBottomLeft_CornerFlag:
243561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes            fsBuilder->codeAppendf("\t\tvec2 dxy = max(vec2(%s.x - %s.x, %s.y - %s.w), 0.0);\n",
244561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                                   rectName, fragmentPos, fragmentPos, rectName);
245561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes            fsBuilder->codeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n",
2468d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                                    rectName, fragmentPos);
247561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes            fsBuilder->codeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n",
248561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                                   fragmentPos, rectName);
2498d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath            fsBuilder->codeAppendf("\t\tfloat alpha = topAlpha * rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
250561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                                   radiusPlusHalfName);
251561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes            break;
2528d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath        case CircularRRectEffect::kLeft_CornerFlags:
253561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes            fsBuilder->codeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
2548d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath            fsBuilder->codeAppendf("\t\tfloat dy1 = %s.y - %s.w;\n", fragmentPos, rectName);
255561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes            fsBuilder->codeAppend("\t\tvec2 dxy = max(vec2(dxy0.x, max(dxy0.y, dy1)), 0.0);\n");
2568d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath            fsBuilder->codeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n",
257561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                                    rectName, fragmentPos);
258561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes            fsBuilder->codeAppendf("\t\tfloat alpha = rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
259561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                                   radiusPlusHalfName);
2608d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath            break;
261561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes        case CircularRRectEffect::kTop_CornerFlags:
262561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes            fsBuilder->codeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
263561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes            fsBuilder->codeAppendf("\t\tfloat dx1 = %s.x - %s.z;\n", fragmentPos, rectName);
264561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes            fsBuilder->codeAppend("\t\tvec2 dxy = max(vec2(max(dxy0.x, dx1), dxy0.y), 0.0);\n");
2658d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath            fsBuilder->codeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n",
266561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                                   rectName, fragmentPos);
267561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes            fsBuilder->codeAppendf("\t\tfloat alpha = bottomAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
268561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                                   radiusPlusHalfName);
269561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes            break;
270561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes        case CircularRRectEffect::kRight_CornerFlags:
2718d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath            fsBuilder->codeAppendf("\t\tfloat dy0 = %s.y - %s.y;\n", rectName, fragmentPos);
272561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes            fsBuilder->codeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
273561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes            fsBuilder->codeAppend("\t\tvec2 dxy = max(vec2(dxy1.x, max(dy0, dxy1.y)), 0.0);\n");
274561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes            fsBuilder->codeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n",
275561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                                   fragmentPos, rectName);
276561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes            fsBuilder->codeAppendf("\t\tfloat alpha = leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
277561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                                   radiusPlusHalfName);
278561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes            break;
279561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes        case CircularRRectEffect::kBottom_CornerFlags:
280561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes            fsBuilder->codeAppendf("\t\tfloat dx0 = %s.x - %s.x;\n", rectName, fragmentPos);
281561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes            fsBuilder->codeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
282561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes            fsBuilder->codeAppend("\t\tvec2 dxy = max(vec2(max(dx0, dxy1.x), dxy1.y), 0.0);\n");
283561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes            fsBuilder->codeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n",
284561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                                   fragmentPos, rectName);
2858d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath            fsBuilder->codeAppendf("\t\tfloat alpha = topAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
286561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                                   radiusPlusHalfName);
2878d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath            break;
288561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    }
289561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
290561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    if (kInverseFillAA_GrProcessorEdgeType == crre.getEdgeType()) {
291561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes        fsBuilder->codeAppend("\t\talpha = 1.0 - alpha;\n");
292561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    }
2938d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath
2948d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    fsBuilder->codeAppendf("\t\t%s = %s;\n", outputColor,
2958d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                           (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str());
2968d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath}
2978d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath
2988d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamathvoid GLCircularRRectEffect::GenKey(const GrProcessor& processor, const GrGLCaps&,
2998d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                                   GrProcessorKeyBuilder* b) {
300561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    const CircularRRectEffect& crre = processor.cast<CircularRRectEffect>();
301561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    GR_STATIC_ASSERT(kGrProcessorEdgeTypeCnt <= 8);
302561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    b->add32((crre.getCircularCornerFlags() << 3) | crre.getEdgeType());
303561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes}
3048d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath
305561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesvoid GLCircularRRectEffect::setData(const GrGLProgramDataManager& pdman,
3068d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                                    const GrProcessor& processor) {
307561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    const CircularRRectEffect& crre = processor.cast<CircularRRectEffect>();
308561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    const SkRRect& rrect = crre.getRRect();
3098d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    if (rrect != fPrevRRect) {
310561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes        SkRect rect = rrect.getBounds();
311561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes        SkScalar radius = 0;
3128d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath        switch (crre.getCircularCornerFlags()) {
3138d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath            case CircularRRectEffect::kAll_CornerFlags:
3148d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                SkASSERT(rrect.isSimpleCircular());
3158d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                radius = rrect.getSimpleRadii().fX;
3168d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                SkASSERT(radius >= kRadiusMin);
3178d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                rect.inset(radius, radius);
3188d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                break;
319561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes            case CircularRRectEffect::kTopLeft_CornerFlag:
320561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX;
321561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                rect.fLeft += radius;
322561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                rect.fTop += radius;
3238d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                rect.fRight += 0.5f;
324561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                rect.fBottom += 0.5f;
3258d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                break;
326561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes            case CircularRRectEffect::kTopRight_CornerFlag:
327561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                radius = rrect.radii(SkRRect::kUpperRight_Corner).fX;
328561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                rect.fLeft -= 0.5f;
3298d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                rect.fTop += radius;
330561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                rect.fRight -= radius;
331561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                rect.fBottom += 0.5f;
332561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                break;
333561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes            case CircularRRectEffect::kBottomRight_CornerFlag:
3348d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                radius = rrect.radii(SkRRect::kLowerRight_Corner).fX;
335561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                rect.fLeft -= 0.5f;
3368d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                rect.fTop -= 0.5f;
337561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                rect.fRight -= radius;
338561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                rect.fBottom -= radius;
3398d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                break;
3408d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath            case CircularRRectEffect::kBottomLeft_CornerFlag:
341561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                radius = rrect.radii(SkRRect::kLowerLeft_Corner).fX;
342561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                rect.fLeft += radius;
343561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                rect.fTop -= 0.5f;
344561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                rect.fRight += 0.5f;
3458d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                rect.fBottom -= radius;
346561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                break;
3478d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath            case CircularRRectEffect::kLeft_CornerFlags:
348561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX;
349561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                rect.fLeft += radius;
3508d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                rect.fTop += radius;
3518d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                rect.fRight += 0.5f;
3528d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                rect.fBottom -= radius;
3538d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                break;
354561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes            case CircularRRectEffect::kTop_CornerFlags:
355561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX;
356561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                rect.fLeft += radius;
357561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                rect.fTop += radius;
3588d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                rect.fRight -= radius;
3598d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                rect.fBottom += 0.5f;
360561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                break;
361561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes            case CircularRRectEffect::kRight_CornerFlags:
3628d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                radius = rrect.radii(SkRRect::kUpperRight_Corner).fX;
363561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                rect.fLeft -= 0.5f;
364561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                rect.fTop += radius;
365561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                rect.fRight -= radius;
366561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                rect.fBottom -= radius;
367561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                break;
3688d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath            case CircularRRectEffect::kBottom_CornerFlags:
3698d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                radius = rrect.radii(SkRRect::kLowerLeft_Corner).fX;
370561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                rect.fLeft += radius;
371561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                rect.fTop -= 0.5f;
372561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                rect.fRight -= radius;
373561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                rect.fBottom -= radius;
374561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                break;
375561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes            default:
376561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                SkFAIL("Should have been one of the above cases.");
3778d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath        }
378561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes        pdman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
3798d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath        pdman.set1f(fRadiusPlusHalfUniform, radius + 0.5f);
380561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes        fPrevRRect = rrect;
381561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    }
3828d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath}
3838d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath
3848d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath//////////////////////////////////////////////////////////////////////////////
385561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
386561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesclass GLEllipticalRRectEffect;
387561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
388561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesclass EllipticalRRectEffect : public GrFragmentProcessor {
3898d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamathpublic:
390561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    static GrFragmentProcessor* Create(GrPrimitiveEdgeType, const SkRRect&);
3918d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath
392561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    virtual ~EllipticalRRectEffect() {};
393561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    static const char* Name() { return "EllipticalRRect"; }
3948d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath
395561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    const SkRRect& getRRect() const { return fRRect; }
396561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
3978d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath
398561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
399561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
400561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    typedef GLEllipticalRRectEffect GLProcessor;
401561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
402561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
4038d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath
4048d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE;
405561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
406561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesprivate:
407561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    EllipticalRRectEffect(GrPrimitiveEdgeType, const SkRRect&);
408561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
409561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    virtual bool onIsEqual(const GrProcessor& other) const SK_OVERRIDE;
4108d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath
411561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    SkRRect             fRRect;
412561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    GrPrimitiveEdgeType    fEdgeType;
413561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
414561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
415561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
4168d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    typedef GrFragmentProcessor INHERITED;
417561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes};
418561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
419561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott HughesGrFragmentProcessor*
420561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott HughesEllipticalRRectEffect::Create(GrPrimitiveEdgeType edgeType, const SkRRect& rrect) {
421561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    if (kFillAA_GrProcessorEdgeType != edgeType && kInverseFillAA_GrProcessorEdgeType != edgeType) {
422561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes        return NULL;
423561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    }
424561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    return SkNEW_ARGS(EllipticalRRectEffect, (edgeType, rrect));
4258d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath}
426561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
427561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesvoid EllipticalRRectEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
428561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    *validFlags = 0;
429561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes}
430561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
431561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesconst GrBackendFragmentProcessorFactory& EllipticalRRectEffect::getFactory() const {
432561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    return GrTBackendFragmentProcessorFactory<EllipticalRRectEffect>::getInstance();
433561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes}
4348d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath
435561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott HughesEllipticalRRectEffect::EllipticalRRectEffect(GrPrimitiveEdgeType edgeType, const SkRRect& rrect)
436561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    : fRRect(rrect)
437561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    , fEdgeType(edgeType){
438561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    this->setWillReadFragmentPosition();
439561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes}
440561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
441561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesbool EllipticalRRectEffect::onIsEqual(const GrProcessor& other) const {
442561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    const EllipticalRRectEffect& erre = other.cast<EllipticalRRectEffect>();
4438d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    return fEdgeType == erre.fEdgeType && fRRect == erre.fRRect;
444561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes}
445561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
446561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes//////////////////////////////////////////////////////////////////////////////
447561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
448561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott HughesGR_DEFINE_FRAGMENT_PROCESSOR_TEST(EllipticalRRectEffect);
449561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
450561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott HughesGrFragmentProcessor* EllipticalRRectEffect::TestCreate(SkRandom* random,
451561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                                                       GrContext*,
4528d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                                                       const GrDrawTargetCaps& caps,
453561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                                                       GrTexture*[]) {
454561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    SkScalar w = random->nextRangeScalar(20.f, 1000.f);
455561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    SkScalar h = random->nextRangeScalar(20.f, 1000.f);
4568d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    SkVector r[4];
457561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    r[SkRRect::kUpperLeft_Corner].fX = random->nextRangeF(kRadiusMin, 9.f);
458561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    // ensure at least one corner really is elliptical
4598d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    do {
460561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes        r[SkRRect::kUpperLeft_Corner].fY = random->nextRangeF(kRadiusMin, 9.f);
461561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    } while (r[SkRRect::kUpperLeft_Corner].fY == r[SkRRect::kUpperLeft_Corner].fX);
462561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
463561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    SkRRect rrect;
464561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    if (random->nextBool()) {
465561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes        // half the time create a four-radii rrect.
4668d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath        r[SkRRect::kLowerRight_Corner].fX = random->nextRangeF(kRadiusMin, 9.f);
467561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes        r[SkRRect::kLowerRight_Corner].fY = random->nextRangeF(kRadiusMin, 9.f);
468561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
469561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes        r[SkRRect::kUpperRight_Corner].fX = r[SkRRect::kLowerRight_Corner].fX;
470561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes        r[SkRRect::kUpperRight_Corner].fY = r[SkRRect::kUpperLeft_Corner].fY;
471561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
472561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes        r[SkRRect::kLowerLeft_Corner].fX = r[SkRRect::kUpperLeft_Corner].fX;
473561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes        r[SkRRect::kLowerLeft_Corner].fY = r[SkRRect::kLowerRight_Corner].fY;
474561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
4758d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath        rrect.setRectRadii(SkRect::MakeWH(w, h), r);
476561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    } else {
477561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes        rrect.setRectXY(SkRect::MakeWH(w, h), r[SkRRect::kUpperLeft_Corner].fX,
478561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                                              r[SkRRect::kUpperLeft_Corner].fY);
4798d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    }
480561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    GrFragmentProcessor* fp;
481561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    do {
482561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes        GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)random->nextULessThan(kGrProcessorEdgeTypeCnt);
483561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes        fp = GrRRectEffect::Create(et, rrect);
484561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    } while (NULL == fp);
485561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    return fp;
4868d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath}
487561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
488561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes//////////////////////////////////////////////////////////////////////////////
489561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
490561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesclass GLEllipticalRRectEffect : public GrGLFragmentProcessor {
4918d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamathpublic:
492561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    GLEllipticalRRectEffect(const GrBackendProcessorFactory&, const GrProcessor&);
493561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
494561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    virtual void emitCode(GrGLProgramBuilder* builder,
495561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                          const GrFragmentProcessor& effect,
496561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                          const GrProcessorKey& key,
4978d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath                          const char* outputColor,
498561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                          const char* inputColor,
499561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                          const TransformedCoordsArray&,
500561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                          const TextureSamplerArray&) SK_OVERRIDE;
501561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
502561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    static inline void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder*);
503561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
504561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE;
505561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
506561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesprivate:
507561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    GrGLProgramDataManager::UniformHandle fInnerRectUniform;
508561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    GrGLProgramDataManager::UniformHandle fInvRadiiSqdUniform;
509561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    SkRRect                               fPrevRRect;
5108d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    typedef GrGLFragmentProcessor INHERITED;
511561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes};
512561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
513561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott HughesGLEllipticalRRectEffect::GLEllipticalRRectEffect(const GrBackendProcessorFactory& factory,
514561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                             const GrProcessor& effect)
515561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    : INHERITED (factory) {
516561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    fPrevRRect.setEmpty();
517561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes}
5188d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath
519561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesvoid GLEllipticalRRectEffect::emitCode(GrGLProgramBuilder* builder,
520561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                                       const GrFragmentProcessor& effect,
521561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                                       const GrProcessorKey& key,
522561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                                       const char* outputColor,
523561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                                       const char* inputColor,
524561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                                       const TransformedCoordsArray&,
525561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                                       const TextureSamplerArray& samplers) {
526561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    const EllipticalRRectEffect& erre = effect.cast<EllipticalRRectEffect>();
527561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    const char *rectName;
5288d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    // The inner rect is the rrect bounds inset by the x/y radii
529561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    fInnerRectUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
530561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                                            kVec4f_GrSLType,
531561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                                            "innerRect",
532561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                                            &rectName);
533561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
534561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
535561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    const char* fragmentPos = fsBuilder->fragmentPosition();
5368d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath    // At each quarter-ellipse corner we compute a vector that is the offset of the fragment pos
537561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    // to the ellipse center. The vector is pinned in x and y to be in the quarter-plane relevant
538561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    // to that corner. This means that points near the interior near the rrect top edge will have
539561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    // a vector that points straight up for both the TL left and TR corners. Computing an
540    // alpha from this vector at either the TR or TL corner will give the correct result. Similarly,
541    // fragments near the other three edges will get the correct AA. Fragments in the interior of
542    // the rrect will have a (0,0) vector at all four corners. So long as the radii > 0.5 they will
543    // correctly produce an alpha value of 1 at all four corners. We take the min of all the alphas.
544    // The code below is a simplified version of the above that performs maxs on the vector
545    // components before computing distances and alpha values so that only one distance computation
546    // need be computed to determine the min alpha.
547    fsBuilder->codeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
548    fsBuilder->codeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
549    switch (erre.getRRect().getType()) {
550        case SkRRect::kSimple_Type: {
551            const char *invRadiiXYSqdName;
552            fInvRadiiSqdUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
553                                                      kVec2f_GrSLType,
554                                                      "invRadiiXY",
555                                                      &invRadiiXYSqdName);
556            fsBuilder->codeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n");
557            // Z is the x/y offsets divided by squared radii.
558            fsBuilder->codeAppendf("\t\tvec2 Z = dxy * %s;\n", invRadiiXYSqdName);
559            break;
560        }
561        case SkRRect::kNinePatch_Type: {
562            const char *invRadiiLTRBSqdName;
563            fInvRadiiSqdUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
564                                                      kVec4f_GrSLType,
565                                                      "invRadiiLTRB",
566                                                      &invRadiiLTRBSqdName);
567            fsBuilder->codeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n");
568            // Z is the x/y offsets divided by squared radii. We only care about the (at most) one
569            // corner where both the x and y offsets are positive, hence the maxes. (The inverse
570            // squared radii will always be positive.)
571            fsBuilder->codeAppendf("\t\tvec2 Z = max(max(dxy0 * %s.xy, dxy1 * %s.zw), 0.0);\n",
572                                   invRadiiLTRBSqdName, invRadiiLTRBSqdName);
573            break;
574        }
575        default:
576            SkFAIL("RRect should always be simple or nine-patch.");
577    }
578    // implicit is the evaluation of (x/a)^2 + (y/b)^2 - 1.
579    fsBuilder->codeAppend("\t\tfloat implicit = dot(Z, dxy) - 1.0;\n");
580    // grad_dot is the squared length of the gradient of the implicit.
581    fsBuilder->codeAppendf("\t\tfloat grad_dot = 4.0 * dot(Z, Z);\n");
582    // avoid calling inversesqrt on zero.
583    fsBuilder->codeAppend("\t\tgrad_dot = max(grad_dot, 1.0e-4);\n");
584    fsBuilder->codeAppendf("\t\tfloat approx_dist = implicit * inversesqrt(grad_dot);\n");
585
586    if (kFillAA_GrProcessorEdgeType == erre.getEdgeType()) {
587        fsBuilder->codeAppend("\t\tfloat alpha = clamp(0.5 - approx_dist, 0.0, 1.0);\n");
588    } else {
589        fsBuilder->codeAppend("\t\tfloat alpha = clamp(0.5 + approx_dist, 0.0, 1.0);\n");
590    }
591
592    fsBuilder->codeAppendf("\t\t%s = %s;\n", outputColor,
593                           (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str());
594}
595
596void GLEllipticalRRectEffect::GenKey(const GrProcessor& effect, const GrGLCaps&,
597                                     GrProcessorKeyBuilder* b) {
598    const EllipticalRRectEffect& erre = effect.cast<EllipticalRRectEffect>();
599    GR_STATIC_ASSERT(kLast_GrProcessorEdgeType < (1 << 3));
600    b->add32(erre.getRRect().getType() | erre.getEdgeType() << 3);
601}
602
603void GLEllipticalRRectEffect::setData(const GrGLProgramDataManager& pdman,
604                                      const GrProcessor& effect) {
605    const EllipticalRRectEffect& erre = effect.cast<EllipticalRRectEffect>();
606    const SkRRect& rrect = erre.getRRect();
607    if (rrect != fPrevRRect) {
608        SkRect rect = rrect.getBounds();
609        const SkVector& r0 = rrect.radii(SkRRect::kUpperLeft_Corner);
610        SkASSERT(r0.fX >= kRadiusMin);
611        SkASSERT(r0.fY >= kRadiusMin);
612        switch (erre.getRRect().getType()) {
613            case SkRRect::kSimple_Type:
614                rect.inset(r0.fX, r0.fY);
615                pdman.set2f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX),
616                                                1.f / (r0.fY * r0.fY));
617                break;
618            case SkRRect::kNinePatch_Type: {
619                const SkVector& r1 = rrect.radii(SkRRect::kLowerRight_Corner);
620                SkASSERT(r1.fX >= kRadiusMin);
621                SkASSERT(r1.fY >= kRadiusMin);
622                rect.fLeft += r0.fX;
623                rect.fTop += r0.fY;
624                rect.fRight -= r1.fX;
625                rect.fBottom -= r1.fY;
626                pdman.set4f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX),
627                                                1.f / (r0.fY * r0.fY),
628                                                1.f / (r1.fX * r1.fX),
629                                                1.f / (r1.fY * r1.fY));
630                break;
631            }
632        default:
633            SkFAIL("RRect should always be simple or nine-patch.");
634        }
635        pdman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
636        fPrevRRect = rrect;
637    }
638}
639
640//////////////////////////////////////////////////////////////////////////////
641
642GrFragmentProcessor* GrRRectEffect::Create(GrPrimitiveEdgeType edgeType, const SkRRect& rrect) {
643    if (rrect.isRect()) {
644        return GrConvexPolyEffect::Create(edgeType, rrect.getBounds());
645    }
646
647    if (rrect.isOval()) {
648        return GrOvalEffect::Create(edgeType, rrect.getBounds());
649    }
650
651    if (rrect.isSimple()) {
652        if (rrect.getSimpleRadii().fX < kRadiusMin || rrect.getSimpleRadii().fY < kRadiusMin) {
653            // In this case the corners are extremely close to rectangular and we collapse the
654            // clip to a rectangular clip.
655            return GrConvexPolyEffect::Create(edgeType, rrect.getBounds());
656        }
657        if (rrect.getSimpleRadii().fX == rrect.getSimpleRadii().fY) {
658            return CircularRRectEffect::Create(edgeType, CircularRRectEffect::kAll_CornerFlags,
659                                               rrect);
660        } else {
661            return EllipticalRRectEffect::Create(edgeType, rrect);
662        }
663    }
664
665    if (rrect.isComplex() || rrect.isNinePatch()) {
666        // Check for the "tab" cases - two adjacent circular corners and two square corners.
667        SkScalar circularRadius = 0;
668        uint32_t cornerFlags  = 0;
669
670        SkVector radii[4];
671        bool squashedRadii = false;
672        for (int c = 0; c < 4; ++c) {
673            radii[c] = rrect.radii((SkRRect::Corner)c);
674            SkASSERT((0 == radii[c].fX) == (0 == radii[c].fY));
675            if (0 == radii[c].fX) {
676                // The corner is square, so no need to squash or flag as circular.
677                continue;
678            }
679            if (radii[c].fX < kRadiusMin || radii[c].fY < kRadiusMin) {
680                radii[c].set(0, 0);
681                squashedRadii = true;
682                continue;
683            }
684            if (radii[c].fX != radii[c].fY) {
685                cornerFlags = ~0U;
686                break;
687            }
688            if (!cornerFlags) {
689                circularRadius = radii[c].fX;
690                cornerFlags = 1 << c;
691            } else {
692                if (radii[c].fX != circularRadius) {
693                   cornerFlags = ~0U;
694                   break;
695                }
696                cornerFlags |= 1 << c;
697            }
698        }
699
700        switch (cornerFlags) {
701            case CircularRRectEffect::kAll_CornerFlags:
702                // This rrect should have been caught in the simple case above. Though, it would
703                // be correctly handled in the fallthrough code.
704                SkASSERT(false);
705            case CircularRRectEffect::kTopLeft_CornerFlag:
706            case CircularRRectEffect::kTopRight_CornerFlag:
707            case CircularRRectEffect::kBottomRight_CornerFlag:
708            case CircularRRectEffect::kBottomLeft_CornerFlag:
709            case CircularRRectEffect::kLeft_CornerFlags:
710            case CircularRRectEffect::kTop_CornerFlags:
711            case CircularRRectEffect::kRight_CornerFlags:
712            case CircularRRectEffect::kBottom_CornerFlags: {
713                SkTCopyOnFirstWrite<SkRRect> rr(rrect);
714                if (squashedRadii) {
715                    rr.writable()->setRectRadii(rrect.getBounds(), radii);
716                }
717                return CircularRRectEffect::Create(edgeType, cornerFlags, *rr);
718            }
719            case CircularRRectEffect::kNone_CornerFlags:
720                return GrConvexPolyEffect::Create(edgeType, rrect.getBounds());
721            default: {
722                if (squashedRadii) {
723                    // If we got here then we squashed some but not all the radii to zero. (If all
724                    // had been squashed cornerFlags would be 0.) The elliptical effect doesn't
725                    // support some rounded and some square corners.
726                    return NULL;
727                }
728                if (rrect.isNinePatch()) {
729                    return EllipticalRRectEffect::Create(edgeType, rrect);
730                }
731                return NULL;
732            }
733        }
734    }
735
736    return NULL;
737}
738