1cb93a386Sopenharmony_ci// Copyright 2021 Google LLC.
2cb93a386Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
3cb93a386Sopenharmony_ci
4cb93a386Sopenharmony_ci#include "experimental/sorttoy/Fake.h"
5cb93a386Sopenharmony_ci
6cb93a386Sopenharmony_ci#include "experimental/sorttoy/Cmds.h"
7cb93a386Sopenharmony_ci#include "experimental/sorttoy/SortKey.h"
8cb93a386Sopenharmony_ci
9cb93a386Sopenharmony_ci#include "include/core/SkBitmap.h"
10cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h"
11cb93a386Sopenharmony_ci
12cb93a386Sopenharmony_ci//-------------------------------------------------------------------------------------------------
13cb93a386Sopenharmony_civoid FakeMCBlob::MCState::addClip(sk_sp<ClipCmd> clipCmd) {
14cb93a386Sopenharmony_ci    clipCmd->mutate(fTrans);
15cb93a386Sopenharmony_ci    fCmds.push_back(std::move(clipCmd));
16cb93a386Sopenharmony_ci    fCached = nullptr;
17cb93a386Sopenharmony_ci}
18cb93a386Sopenharmony_ci
19cb93a386Sopenharmony_cibool FakeMCBlob::MCState::operator==(const MCState& other) const {
20cb93a386Sopenharmony_ci    if (fTrans != other.fTrans || fCmds.size() != other.fCmds.size()) {
21cb93a386Sopenharmony_ci        return false;
22cb93a386Sopenharmony_ci    }
23cb93a386Sopenharmony_ci
24cb93a386Sopenharmony_ci    for (size_t i = 0; i < fCmds.size(); ++i) {
25cb93a386Sopenharmony_ci        if (fCmds[i]->rect() != other.fCmds[i]->rect()) {
26cb93a386Sopenharmony_ci            return false;
27cb93a386Sopenharmony_ci        }
28cb93a386Sopenharmony_ci    }
29cb93a386Sopenharmony_ci
30cb93a386Sopenharmony_ci    return true;
31cb93a386Sopenharmony_ci}
32cb93a386Sopenharmony_ci
33cb93a386Sopenharmony_civoid FakeMCBlob::MCState::aboutToBePopped(PaintersOrder paintersOrderWhenPopped) {
34cb93a386Sopenharmony_ci    for (sk_sp<ClipCmd>& c : fCmds) {
35cb93a386Sopenharmony_ci        c->onAboutToBePopped(paintersOrderWhenPopped);
36cb93a386Sopenharmony_ci    }
37cb93a386Sopenharmony_ci}
38cb93a386Sopenharmony_ci
39cb93a386Sopenharmony_ci
40cb93a386Sopenharmony_ciFakeMCBlob::FakeMCBlob(const std::vector<MCState>& stack) : fID(NextID()), fStack(stack) {
41cb93a386Sopenharmony_ci    fScissor = SkIRect::MakeLTRB(-1000, -1000, 1000, 1000);
42cb93a386Sopenharmony_ci
43cb93a386Sopenharmony_ci    for (MCState& s : fStack) {
44cb93a386Sopenharmony_ci        // xform the clip rects into device space to compute the scissor
45cb93a386Sopenharmony_ci        for (const sk_sp<ClipCmd>& c : s.fCmds) {
46cb93a386Sopenharmony_ci            SkASSERT(c->hasBeenMutated());
47cb93a386Sopenharmony_ci            SkIRect r = c->rect();
48cb93a386Sopenharmony_ci            r.offset(fCTM);
49cb93a386Sopenharmony_ci            if (!fScissor.intersect(r)) {
50cb93a386Sopenharmony_ci                fScissor.setEmpty();
51cb93a386Sopenharmony_ci            }
52cb93a386Sopenharmony_ci        }
53cb93a386Sopenharmony_ci        fCTM += s.getTrans();
54cb93a386Sopenharmony_ci    }
55cb93a386Sopenharmony_ci}
56cb93a386Sopenharmony_ci
57cb93a386Sopenharmony_ci//-------------------------------------------------------------------------------------------------
58cb93a386Sopenharmony_ci// Linearly blend between c0 & c1:
59cb93a386Sopenharmony_ci//      (t == 0) -> c0
60cb93a386Sopenharmony_ci//      (t == 1) -> c1
61cb93a386Sopenharmony_cistatic SkColor blend(float t, SkColor c0, SkColor c1) {
62cb93a386Sopenharmony_ci    SkASSERT(t >= 0.0f && t <= 1.0f);
63cb93a386Sopenharmony_ci
64cb93a386Sopenharmony_ci    SkColor4f top = SkColor4f::FromColor(c0);
65cb93a386Sopenharmony_ci    SkColor4f bot = SkColor4f::FromColor(c1);
66cb93a386Sopenharmony_ci
67cb93a386Sopenharmony_ci    SkColor4f result = {
68cb93a386Sopenharmony_ci        t * bot.fR + (1.0f - t) * top.fR,
69cb93a386Sopenharmony_ci        t * bot.fG + (1.0f - t) * top.fG,
70cb93a386Sopenharmony_ci        t * bot.fB + (1.0f - t) * top.fB,
71cb93a386Sopenharmony_ci        t * bot.fA + (1.0f - t) * top.fA
72cb93a386Sopenharmony_ci    };
73cb93a386Sopenharmony_ci    return result.toSkColor();
74cb93a386Sopenharmony_ci}
75cb93a386Sopenharmony_ci
76cb93a386Sopenharmony_ciint FakePaint::toID() const {
77cb93a386Sopenharmony_ci    switch (fType) {
78cb93a386Sopenharmony_ci        case Type::kNormal: return kSolidMat;
79cb93a386Sopenharmony_ci        case Type::kLinear: return kLinearMat;
80cb93a386Sopenharmony_ci        case Type::kRadial: return kRadialMat;
81cb93a386Sopenharmony_ci    }
82cb93a386Sopenharmony_ci    SkUNREACHABLE;
83cb93a386Sopenharmony_ci}
84cb93a386Sopenharmony_ci
85cb93a386Sopenharmony_ciSkColor FakePaint::evalColor(int x, int y) const {
86cb93a386Sopenharmony_ci    switch (fType) {
87cb93a386Sopenharmony_ci        case Type::kNormal: return fColor0;
88cb93a386Sopenharmony_ci        case Type::kLinear: {
89cb93a386Sopenharmony_ci            float t = SK_ScalarRoot2Over2 * x + SK_ScalarRoot2Over2 * y;
90cb93a386Sopenharmony_ci            t /= SK_ScalarSqrt2 * 256.0f;
91cb93a386Sopenharmony_ci            return blend(t, fColor0, fColor1);
92cb93a386Sopenharmony_ci        }
93cb93a386Sopenharmony_ci        case Type::kRadial: {
94cb93a386Sopenharmony_ci            x -= 128;
95cb93a386Sopenharmony_ci            y -= 128;
96cb93a386Sopenharmony_ci            float dist = sqrt(x*x + y*y) / 128.0f;
97cb93a386Sopenharmony_ci            if (dist > 1.0f) {
98cb93a386Sopenharmony_ci                return fColor0;
99cb93a386Sopenharmony_ci            } else {
100cb93a386Sopenharmony_ci                return blend(dist, fColor0, fColor1);
101cb93a386Sopenharmony_ci            }
102cb93a386Sopenharmony_ci        }
103cb93a386Sopenharmony_ci    }
104cb93a386Sopenharmony_ci    SkUNREACHABLE;
105cb93a386Sopenharmony_ci}
106cb93a386Sopenharmony_ci
107cb93a386Sopenharmony_ci//-------------------------------------------------------------------------------------------------
108cb93a386Sopenharmony_civoid FakeDevice::save() {
109cb93a386Sopenharmony_ci    fTracker.push();
110cb93a386Sopenharmony_ci}
111cb93a386Sopenharmony_ci
112cb93a386Sopenharmony_civoid FakeDevice::drawShape(ID id, PaintersOrder paintersOrder, Shape shape, SkIRect r, FakePaint p) {
113cb93a386Sopenharmony_ci    sk_sp<FakeMCBlob> state = fTracker.snapState();
114cb93a386Sopenharmony_ci    SkASSERT(state);
115cb93a386Sopenharmony_ci
116cb93a386Sopenharmony_ci    sk_sp<Cmd> tmp = sk_make_sp<DrawCmd>(id, paintersOrder, shape, r, p, std::move(state));
117cb93a386Sopenharmony_ci
118cb93a386Sopenharmony_ci    fSortedCmds.push_back(std::move(tmp));
119cb93a386Sopenharmony_ci}
120cb93a386Sopenharmony_ci
121cb93a386Sopenharmony_civoid FakeDevice::clipShape(ID id, PaintersOrder paintersOrder, Shape shape, SkIRect r) {
122cb93a386Sopenharmony_ci    sk_sp<ClipCmd> tmp = sk_make_sp<ClipCmd>(id, paintersOrder, shape, r);
123cb93a386Sopenharmony_ci
124cb93a386Sopenharmony_ci    fTracker.clip(std::move(tmp));
125cb93a386Sopenharmony_ci}
126cb93a386Sopenharmony_ci
127cb93a386Sopenharmony_civoid FakeDevice::restore(PaintersOrder paintersOrderWhenPopped) {
128cb93a386Sopenharmony_ci    fTracker.pop(paintersOrderWhenPopped);
129cb93a386Sopenharmony_ci}
130cb93a386Sopenharmony_ci
131cb93a386Sopenharmony_civoid FakeDevice::finalize() {
132cb93a386Sopenharmony_ci    SkASSERT(!fFinalized);
133cb93a386Sopenharmony_ci    fFinalized = true;
134cb93a386Sopenharmony_ci
135cb93a386Sopenharmony_ci    this->sort();
136cb93a386Sopenharmony_ci    for (const sk_sp<Cmd>& c : fSortedCmds) {
137cb93a386Sopenharmony_ci        c->rasterize(fZBuffer, &fBM);
138cb93a386Sopenharmony_ci    }
139cb93a386Sopenharmony_ci}
140cb93a386Sopenharmony_ci
141cb93a386Sopenharmony_civoid FakeDevice::getOrder(std::vector<ID>* ops) const {
142cb93a386Sopenharmony_ci    SkASSERT(fFinalized);
143cb93a386Sopenharmony_ci
144cb93a386Sopenharmony_ci    for (const sk_sp<Cmd>& c : fSortedCmds) {
145cb93a386Sopenharmony_ci        ops->push_back(c->id());
146cb93a386Sopenharmony_ci    }
147cb93a386Sopenharmony_ci}
148cb93a386Sopenharmony_ci
149cb93a386Sopenharmony_civoid FakeDevice::sort() {
150cb93a386Sopenharmony_ci    // In general we want:
151cb93a386Sopenharmony_ci    //  opaque draws to occur front to back (i.e., in reverse painter's order) while minimizing
152cb93a386Sopenharmony_ci    //        state changes due to materials
153cb93a386Sopenharmony_ci    //  transparent draws to occur back to front (i.e., in painter's order)
154cb93a386Sopenharmony_ci    //
155cb93a386Sopenharmony_ci    // In both scenarios we would like to batch as much as possible.
156cb93a386Sopenharmony_ci    std::sort(fSortedCmds.begin(), fSortedCmds.end(),
157cb93a386Sopenharmony_ci              [](const sk_sp<Cmd>& a, const sk_sp<Cmd>& b) {
158cb93a386Sopenharmony_ci                    return a->getKey() < b->getKey();
159cb93a386Sopenharmony_ci                });
160cb93a386Sopenharmony_ci}
161cb93a386Sopenharmony_ci
162cb93a386Sopenharmony_ci//-------------------------------------------------------------------------------------------------
163cb93a386Sopenharmony_civoid FakeCanvas::drawShape(ID id, Shape shape, SkIRect r, FakePaint p) {
164cb93a386Sopenharmony_ci    SkASSERT(!fFinalized);
165cb93a386Sopenharmony_ci
166cb93a386Sopenharmony_ci    fDeviceStack.back()->drawShape(id, this->nextPaintersOrder(), shape, r, p);
167cb93a386Sopenharmony_ci}
168cb93a386Sopenharmony_ci
169cb93a386Sopenharmony_civoid FakeCanvas::clipShape(ID id, Shape shape, SkIRect r) {
170cb93a386Sopenharmony_ci    SkASSERT(!fFinalized);
171cb93a386Sopenharmony_ci
172cb93a386Sopenharmony_ci    fDeviceStack.back()->clipShape(id, this->nextPaintersOrder(), shape, r);
173cb93a386Sopenharmony_ci}
174cb93a386Sopenharmony_ci
175cb93a386Sopenharmony_civoid FakeCanvas::finalize() {
176cb93a386Sopenharmony_ci    SkASSERT(!fFinalized);
177cb93a386Sopenharmony_ci    fFinalized = true;
178cb93a386Sopenharmony_ci
179cb93a386Sopenharmony_ci    for (auto& d : fDeviceStack) {
180cb93a386Sopenharmony_ci        d->finalize();
181cb93a386Sopenharmony_ci    }
182cb93a386Sopenharmony_ci}
183cb93a386Sopenharmony_ci
184cb93a386Sopenharmony_cistd::vector<ID> FakeCanvas::getOrder() const {
185cb93a386Sopenharmony_ci    SkASSERT(fFinalized);
186cb93a386Sopenharmony_ci
187cb93a386Sopenharmony_ci    std::vector<ID> ops;
188cb93a386Sopenharmony_ci
189cb93a386Sopenharmony_ci    for (auto& d : fDeviceStack) {
190cb93a386Sopenharmony_ci        d->getOrder(&ops);
191cb93a386Sopenharmony_ci    }
192cb93a386Sopenharmony_ci
193cb93a386Sopenharmony_ci    return ops;
194cb93a386Sopenharmony_ci}
195