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#ifndef SkTwoPointConicalGradient_DEFINED
9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#define SkTwoPointConicalGradient_DEFINED
10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkColorSpaceXformer.h"
12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkGradientShaderPriv.h"
13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass SkTwoPointConicalGradient final : public SkGradientShaderBase {
15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotpublic:
16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // See https://skia.org/dev/design/conical for what focal data means and how our shader works.
17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // We make it public so the GPU shader can also use it.
18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    struct FocalData {
19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkScalar    fR1;        // r1 after mapping focal point to (0, 0)
20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkScalar    fFocalX;    // f
21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        bool        fIsSwapped; // whether we swapped r0, r1
22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // The input r0, r1 are the radii when we map centers to {(0, 0), (1, 0)}.
24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // We'll post concat matrix with our transformation matrix that maps focal point to (0, 0).
25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        void set(SkScalar r0, SkScalar r1, SkMatrix& matrix);
26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Whether the focal point (0, 0) is on the end circle with center (1, 0) and radius r1. If
28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // this is true, it's as if an aircraft is flying at Mach 1 and all circles (soundwaves)
29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // will go through the focal point (aircraft). In our previous implementations, this was
30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // known as the edge case where the inside circle touches the outside circle (on the focal
31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // point). If we were to solve for t bruteforcely using a quadratic equation, this case
32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // implies that the quadratic equation degenerates to a linear equation.
33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        bool isFocalOnCircle() const { return SkScalarNearlyZero(1 - fR1); }
34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        bool isSwapped() const { return fIsSwapped; }
36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        bool isWellBehaved() const { return !this->isFocalOnCircle() && fR1 > 1; }
37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        bool isNativelyFocal() const { return SkScalarNearlyZero(fFocalX); }
38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    };
39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    enum class Type {
41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        kRadial,
42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        kStrip,
43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        kFocal
44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    };
45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    static sk_sp<SkShader> Create(const SkPoint& start, SkScalar startRadius,
47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                  const SkPoint& end, SkScalar endRadius,
48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                  const Descriptor&);
49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkShader::GradientType asAGradient(GradientInfo* info) const  override;
51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if SK_SUPPORT_GPU
52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs&) const override;
53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool isOpaque() const override;
55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkScalar getCenterX1() const { return SkPoint::Distance(fCenter1, fCenter2); }
57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkScalar getStartRadius() const { return fRadius1; }
58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkScalar getDiffRadius() const { return fRadius2 - fRadius1; }
59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkPoint& getStartCenter() const { return fCenter1; }
60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkPoint& getEndCenter() const { return fCenter2; }
61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkScalar getEndRadius() const { return fRadius2; }
62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    Type getType() const { return fType; }
64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkMatrix& getGradientMatrix() const { return fPtsToUnit; }
65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const FocalData& getFocalData() const { return fFocalData; }
66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SK_TO_STRING_OVERRIDE()
68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTwoPointConicalGradient)
69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprotected:
71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void flatten(SkWriteBuffer& buffer) const override;
72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override;
73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* tPipeline,
75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                              SkRasterPipeline* postPipeline) const override;
76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool onIsRasterPipelineOnly(const SkMatrix&) const override { return true; }
78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprivate:
80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkTwoPointConicalGradient(const SkPoint& c0, SkScalar r0,
81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                              const SkPoint& c1, SkScalar r1,
82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                              const Descriptor&, Type, const SkMatrix&, const FocalData&);
83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPoint  fCenter1;
85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPoint  fCenter2;
86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkScalar fRadius1;
87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkScalar fRadius2;
88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    Type     fType;
89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    FocalData fFocalData;
91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    friend class SkGradientShader;
93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    typedef SkGradientShaderBase INHERITED;
94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
97