1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/*
2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2012 Google Inc.
3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *
4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be
5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file.
6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */
7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkTwoPointConicalGradient.h"
9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkRasterPipeline.h"
11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkReadBuffer.h"
12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkWriteBuffer.h"
13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "../../jumper/SkJumper.h"
14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Please see https://skia.org/dev/design/conical for how our shader works.
16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkTwoPointConicalGradient::FocalData::set(SkScalar r0, SkScalar r1, SkMatrix& matrix) {
18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fIsSwapped = false;
19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fFocalX = r0 / (r0 - r1);
20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (SkScalarNearlyZero(fFocalX - 1)) {
21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // swap r0, r1
22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        matrix.postTranslate(-1, 0);
23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        matrix.postScale(-1, 1);
24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        std::swap(r0, r1);
25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fFocalX = 0; // because r0 is now 0
26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fIsSwapped = true;
27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Map {focal point, (1, 0)} to {(0, 0), (1, 0)}
30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkPoint from[2]   = { {fFocalX, 0}, {1, 0} };
31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkPoint to[2]     = { {0, 0}, {1, 0} };
32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkMatrix focalMatrix;
33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!focalMatrix.setPolyToPoly(from, to, 2)) {
34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDEBUGFAILF("Mapping focal point failed unexpectedly for focalX = %f.\n", fFocalX);
35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // We won't be able to draw the gradient; at least make sure that we initialize the
36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // memory to prevent security issues.
37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        focalMatrix = SkMatrix::MakeScale(1, 1);
38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    matrix.postConcat(focalMatrix);
40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fR1 = r1 / SkScalarAbs(1 - fFocalX); // focalMatrix has a scale of 1/(1-f)
41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // The following transformations are just to accelerate the shader computation by saving
43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // some arithmatic operations.
44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (this->isFocalOnCircle()) {
45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        matrix.postScale(0.5, 0.5);
46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        matrix.postScale(fR1 / (fR1 * fR1 - 1), 1 / sqrt(SkScalarAbs(fR1 * fR1 - 1)));
48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    matrix.postScale(SkScalarAbs(1 - fFocalX), SkScalarAbs(1 - fFocalX)); // scale |1 - f|
50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotsk_sp<SkShader> SkTwoPointConicalGradient::Create(const SkPoint& c0, SkScalar r0,
53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                  const SkPoint& c1, SkScalar r1,
54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                  const Descriptor& desc) {
55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkMatrix gradientMatrix;
56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    Type     gradientType;
57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (SkScalarNearlyZero((c0 - c1).length())) {
59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Concentric case: we can pretend we're radial (with a tiny twist).
60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkScalar scale = 1.0f / SkTMax(r0, r1);
61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        gradientMatrix = SkMatrix::MakeTrans(-c1.x(), -c1.y());
62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        gradientMatrix.postScale(scale, scale);
63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        gradientType = Type::kRadial;
65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkPoint centers[2] = { c0    , c1     };
67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkPoint unitvec[2] = { {0, 0}, {1, 0} };
68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!gradientMatrix.setPolyToPoly(centers, unitvec, 2)) {
70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // Degenerate case.
71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return nullptr;
72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        gradientType = SkScalarNearlyZero(r1 - r0) ? Type::kStrip : Type::kFocal;
75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    FocalData focalData;
78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (gradientType == Type::kFocal) {
79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const auto dCenter = (c0 - c1).length();
80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        focalData.set(r0 / dCenter, r1 / dCenter, gradientMatrix); // this may change gradientMatrix
81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return sk_sp<SkShader>(new SkTwoPointConicalGradient(c0, r0, c1, r1, desc,
83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                         gradientType, gradientMatrix, focalData));
84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkTwoPointConicalGradient::SkTwoPointConicalGradient(
87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkPoint& start, SkScalar startRadius,
88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkPoint& end, SkScalar endRadius,
89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const Descriptor& desc, Type type, const SkMatrix& gradientMatrix, const FocalData& data)
90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    : SkGradientShaderBase(desc, gradientMatrix)
91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fCenter1(start)
92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fCenter2(end)
93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fRadius1(startRadius)
94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fRadius2(endRadius)
95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fType(type)
96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot{
97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // this is degenerate, and should be caught by our caller
98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(fCenter1 != fCenter2 || fRadius1 != fRadius2);
99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (type == Type::kFocal) {
100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fFocalData = data;
101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkTwoPointConicalGradient::isOpaque() const {
105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Because areas outside the cone are left untouched, we cannot treat the
106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // shader as opaque even if the gradient itself is opaque.
107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // TODO(junov): Compute whether the cone fills the plane crbug.com/222380
108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return false;
109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Returns the original non-sorted version of the gradient
112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkShader::GradientType SkTwoPointConicalGradient::asAGradient(GradientInfo* info) const {
113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (info) {
114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        commonAsAGradient(info);
115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        info->fPoint[0] = fCenter1;
116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        info->fPoint[1] = fCenter2;
117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        info->fRadius[0] = fRadius1;
118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        info->fRadius[1] = fRadius2;
119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return kConical_GradientType;
121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotsk_sp<SkFlattenable> SkTwoPointConicalGradient::CreateProc(SkReadBuffer& buffer) {
124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    DescriptorScope desc;
125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!desc.unflatten(buffer)) {
126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return nullptr;
127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPoint c1 = buffer.readPoint();
129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPoint c2 = buffer.readPoint();
130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkScalar r1 = buffer.readScalar();
131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkScalar r2 = buffer.readScalar();
132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (buffer.isVersionLT(SkReadBuffer::k2PtConicalNoFlip_Version) && buffer.readBool()) {
134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // legacy flipped gradient
135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkTSwap(c1, c2);
136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkTSwap(r1, r2);
137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkColor4f* colors = desc.mutableColors();
139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkScalar* pos = desc.mutablePos();
140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const int last = desc.fCount - 1;
141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const int half = desc.fCount >> 1;
142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (int i = 0; i < half; ++i) {
143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkTSwap(colors[i], colors[last - i]);
144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (pos) {
145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkScalar tmp = pos[i];
146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                pos[i] = SK_Scalar1 - pos[last - i];
147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                pos[last - i] = SK_Scalar1 - tmp;
148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (pos) {
151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (desc.fCount & 1) {
152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                pos[half] = SK_Scalar1 - pos[half];
153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return SkGradientShader::MakeTwoPointConical(c1, r1, c2, r2, desc.fColors,
158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                 std::move(desc.fColorSpace), desc.fPos,
159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                 desc.fCount, desc.fTileMode, desc.fGradFlags,
160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                 desc.fLocalMatrix);
161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkTwoPointConicalGradient::flatten(SkWriteBuffer& buffer) const {
164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->INHERITED::flatten(buffer);
165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    buffer.writePoint(fCenter1);
166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    buffer.writePoint(fCenter2);
167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    buffer.writeScalar(fRadius1);
168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    buffer.writeScalar(fRadius2);
169fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
170fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
171fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if SK_SUPPORT_GPU
172fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
173fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkGr.h"
174fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkTwoPointConicalGradient_gpu.h"
175fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
176fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstd::unique_ptr<GrFragmentProcessor> SkTwoPointConicalGradient::asFragmentProcessor(
177fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const GrFPArgs& args) const {
178fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(args.fContext);
179fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return Gr2PtConicalGradientEffect::Make(
180fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            GrGradientEffect::CreateArgs(args.fContext, this, args.fLocalMatrix, fTileMode,
181fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                         args.fDstColorSpaceInfo->colorSpace()));
182fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
183fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
184fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
185fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
186fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotsk_sp<SkShader> SkTwoPointConicalGradient::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
187fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const AutoXformColors xformedColors(*this, xformer);
188fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return SkGradientShader::MakeTwoPointConical(fCenter1, fRadius1, fCenter2, fRadius2,
189fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                 xformedColors.fColors.get(), fOrigPos, fColorCount,
190fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                 fTileMode, fGradFlags, &this->getLocalMatrix());
191fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
192fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
193fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
194fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifndef SK_IGNORE_TO_STRING
195fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkTwoPointConicalGradient::toString(SkString* str) const {
196fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    str->append("SkTwoPointConicalGradient: (");
197fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
198fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    str->append("center1: (");
199fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    str->appendScalar(fCenter1.fX);
200fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    str->append(", ");
201fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    str->appendScalar(fCenter1.fY);
202fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    str->append(") radius1: ");
203fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    str->appendScalar(fRadius1);
204fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    str->append(" ");
205fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
206fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    str->append("center2: (");
207fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    str->appendScalar(fCenter2.fX);
208fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    str->append(", ");
209fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    str->appendScalar(fCenter2.fY);
210fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    str->append(") radius2: ");
211fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    str->appendScalar(fRadius2);
212fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    str->append(" ");
213fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
214fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->INHERITED::toString(str);
215fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
216fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    str->append(")");
217fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
218fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
219fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
220fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkTwoPointConicalGradient::appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* p,
221fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                     SkRasterPipeline* postPipeline) const {
222fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const auto dRadius = fRadius2 - fRadius1;
223fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
224fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fType == Type::kRadial) {
225fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        p->append(SkRasterPipeline::xy_to_radius);
226fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
227fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Tiny twist: radial computes a t for [0, r2], but we want a t for [r1, r2].
228fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        auto scale =  SkTMax(fRadius1, fRadius2) / dRadius;
229fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        auto bias  = -fRadius1 / dRadius;
230fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
231fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        p->append_matrix(alloc, SkMatrix::Concat(SkMatrix::MakeTrans(bias, 0),
232fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                 SkMatrix::MakeScale(scale, 1)));
233fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
234fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
235fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
236fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fType == Type::kStrip) {
237fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        auto* ctx = alloc->make<SkJumper_2PtConicalCtx>();
238fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkScalar scaledR0 = fRadius1 / this->getCenterX1();
239fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ctx->fP0 = scaledR0 * scaledR0;
240fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        p->append(SkRasterPipeline::xy_to_2pt_conical_strip, ctx);
241fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        p->append(SkRasterPipeline::mask_2pt_conical_nan, ctx);
242fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        postPipeline->append(SkRasterPipeline::apply_vector_mask, &ctx->fMask);
243fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
244fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
245fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
246fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    auto* ctx = alloc->make<SkJumper_2PtConicalCtx>();
247fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    ctx->fP0 = 1/fFocalData.fR1;
248fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    ctx->fP1 = fFocalData.fFocalX;
249fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
250fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fFocalData.isFocalOnCircle()) {
251fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        p->append(SkRasterPipeline::xy_to_2pt_conical_focal_on_circle);
252fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else if (fFocalData.isWellBehaved()) {
253fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        p->append(SkRasterPipeline::xy_to_2pt_conical_well_behaved, ctx);
254fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else if (fFocalData.isSwapped() || 1 - fFocalData.fFocalX < 0) {
255fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        p->append(SkRasterPipeline::xy_to_2pt_conical_smaller, ctx);
256fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
257fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        p->append(SkRasterPipeline::xy_to_2pt_conical_greater, ctx);
258fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
259fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
260fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!fFocalData.isWellBehaved()) {
261fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        p->append(SkRasterPipeline::mask_2pt_conical_degenerates, ctx);
262fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
263fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (1 - fFocalData.fFocalX < 0) {
264fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        p->append(SkRasterPipeline::negate_x);
265fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
266fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!fFocalData.isNativelyFocal()) {
267fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        p->append(SkRasterPipeline::alter_2pt_conical_compensate_focal, ctx);
268fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
269fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fFocalData.isSwapped()) {
270fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        p->append(SkRasterPipeline::alter_2pt_conical_unswap);
271fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
272fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!fFocalData.isWellBehaved()) {
273fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        postPipeline->append(SkRasterPipeline::apply_vector_mask, &ctx->fMask);
274fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
275fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
276