2021-05-20 13:45:10 +00:00
|
|
|
// Copyright 2021 Google LLC.
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
#ifndef Fake_DEFINED
|
|
|
|
#define Fake_DEFINED
|
|
|
|
|
2021-07-01 17:27:16 +00:00
|
|
|
#include "experimental/sorttoy/sorttypes.h"
|
2021-06-17 19:34:15 +00:00
|
|
|
|
2021-05-20 13:45:10 +00:00
|
|
|
#include "include/core/SkBitmap.h"
|
|
|
|
#include "include/core/SkColor.h"
|
|
|
|
#include "include/core/SkMatrix.h"
|
|
|
|
#include "include/core/SkRefCnt.h"
|
|
|
|
#include "include/core/SkTypes.h"
|
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
class Cmd;
|
2021-06-17 19:34:15 +00:00
|
|
|
class ClipCmd;
|
2021-05-20 13:45:10 +00:00
|
|
|
class FakeCanvas;
|
|
|
|
class SkBitmap;
|
|
|
|
class SkCanvas;
|
|
|
|
|
|
|
|
constexpr SkColor SK_ColorUNUSED = SkColorSetARGB(0x00, 0xFF, 0xFF, 0xFF);
|
|
|
|
|
|
|
|
// This is roughly equivalent to a moment in time of an SkClipStack. It is snapped off of a
|
|
|
|
// FakeStateTracker.
|
|
|
|
class FakeMCBlob : public SkRefCnt {
|
|
|
|
public:
|
|
|
|
class MCState {
|
|
|
|
public:
|
|
|
|
MCState() {}
|
|
|
|
|
2021-06-22 18:12:14 +00:00
|
|
|
void addClip(sk_sp<ClipCmd> clipCmd);
|
2021-05-20 13:45:10 +00:00
|
|
|
|
|
|
|
void translate(SkIPoint trans) {
|
|
|
|
fTrans += trans;
|
|
|
|
fCached = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
SkIPoint getTrans() const { return fTrans; }
|
|
|
|
|
2021-06-22 18:12:14 +00:00
|
|
|
bool operator==(const MCState& other) const;
|
2021-05-20 13:45:10 +00:00
|
|
|
|
2021-06-17 20:32:51 +00:00
|
|
|
const std::vector<sk_sp<ClipCmd>>& cmds() const { return fCmds; }
|
2021-05-20 13:45:10 +00:00
|
|
|
|
|
|
|
sk_sp<FakeMCBlob> getCached() const {
|
|
|
|
return fCached;
|
|
|
|
}
|
|
|
|
void setCached(sk_sp<FakeMCBlob> cached) {
|
|
|
|
fCached = cached;
|
|
|
|
}
|
|
|
|
|
2021-06-22 16:44:16 +00:00
|
|
|
void aboutToBePopped(PaintersOrder paintersOrderWhenPopped);
|
|
|
|
|
2021-05-20 13:45:10 +00:00
|
|
|
protected:
|
|
|
|
friend class FakeMCBlob;
|
|
|
|
|
2021-06-17 19:34:15 +00:00
|
|
|
SkIPoint fTrans { 0, 0 };
|
2021-06-22 18:12:14 +00:00
|
|
|
// The clip rects in the ClipCmds have been transformed into the 'parent' space of this
|
|
|
|
// MCState (i.e., in the coordinate frame of the MCState prior to this one in 'fStack').
|
|
|
|
// Alternatively, the 'fTrans' in effect when they were added has already been applied.
|
2021-06-17 20:32:51 +00:00
|
|
|
std::vector<sk_sp<ClipCmd>> fCmds;
|
|
|
|
sk_sp<FakeMCBlob> fCached;
|
2021-05-20 13:45:10 +00:00
|
|
|
};
|
|
|
|
|
2021-06-22 18:12:14 +00:00
|
|
|
FakeMCBlob(const std::vector<MCState>& stack);
|
2021-05-20 13:45:10 +00:00
|
|
|
|
|
|
|
int count() const { return fStack.size(); }
|
2021-05-24 18:41:24 +00:00
|
|
|
int id() const { return fID; }
|
2021-05-20 13:45:10 +00:00
|
|
|
SkIPoint ctm() const { return fCTM; }
|
|
|
|
const std::vector<MCState>& mcStates() const { return fStack; }
|
|
|
|
const MCState& operator[](int index) const { return fStack[index]; }
|
2021-06-17 19:34:15 +00:00
|
|
|
SkIRect scissor() const { return fScissor; }
|
2021-05-20 13:45:10 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
static int NextID() {
|
|
|
|
static int sID = 1;
|
|
|
|
return sID++;
|
|
|
|
}
|
|
|
|
|
|
|
|
const int fID;
|
|
|
|
SkIPoint fCTM { 0, 0 };
|
2021-06-17 19:34:15 +00:00
|
|
|
SkIRect fScissor;
|
2021-05-20 13:45:10 +00:00
|
|
|
std::vector<MCState> fStack;
|
|
|
|
};
|
|
|
|
|
|
|
|
class FakeStateTracker {
|
|
|
|
public:
|
|
|
|
FakeStateTracker() {
|
|
|
|
fStack.push_back(FakeMCBlob::MCState());
|
|
|
|
}
|
|
|
|
|
|
|
|
sk_sp<FakeMCBlob> snapState() {
|
|
|
|
sk_sp<FakeMCBlob> tmp = fStack.back().getCached();
|
|
|
|
if (tmp) {
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = sk_make_sp<FakeMCBlob>(fStack);
|
|
|
|
fStack.back().setCached(tmp);
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
void push() {
|
|
|
|
fStack.push_back(FakeMCBlob::MCState());
|
|
|
|
}
|
|
|
|
|
2021-06-23 13:10:14 +00:00
|
|
|
void clip(sk_sp<ClipCmd> clipCmd) {
|
2021-06-22 18:12:14 +00:00
|
|
|
fStack.back().addClip(std::move(clipCmd));
|
2021-05-20 13:45:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// For now we only store translates - in the full Skia this would be the whole 4x4 matrix
|
|
|
|
void translate(SkIPoint trans) {
|
|
|
|
fStack.back().translate(trans);
|
|
|
|
}
|
|
|
|
|
2021-06-22 16:44:16 +00:00
|
|
|
void pop(PaintersOrder paintersOrderWhenPopped) {
|
2021-05-20 13:45:10 +00:00
|
|
|
SkASSERT(fStack.size() > 0);
|
2021-06-22 16:44:16 +00:00
|
|
|
fStack.back().aboutToBePopped(paintersOrderWhenPopped);
|
2021-05-20 13:45:10 +00:00
|
|
|
fStack.pop_back();
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::vector<FakeMCBlob::MCState> fStack;
|
|
|
|
};
|
|
|
|
|
|
|
|
// The FakePaint simulates two aspects of the SkPaint:
|
|
|
|
//
|
|
|
|
// Batching based on FP context changes:
|
|
|
|
// There are three types of paint (solid color, linear gradient and radial gradient) and,
|
|
|
|
// ideally, they would all be batched together
|
|
|
|
//
|
|
|
|
// Transparency:
|
|
|
|
// The transparent objects need to be draw back to front.
|
|
|
|
class FakePaint {
|
|
|
|
public:
|
|
|
|
FakePaint() {}
|
2021-06-03 18:36:08 +00:00
|
|
|
FakePaint(SkColor c)
|
|
|
|
: fType(Type::kNormal)
|
|
|
|
, fColor0(c)
|
|
|
|
, fColor1(SK_ColorUNUSED) {
|
|
|
|
}
|
2021-05-20 13:45:10 +00:00
|
|
|
|
|
|
|
void setColor(SkColor c) {
|
|
|
|
fType = Type::kNormal;
|
|
|
|
fColor0 = c;
|
|
|
|
fColor1 = SK_ColorUNUSED;
|
|
|
|
}
|
|
|
|
SkColor getColor() const {
|
|
|
|
SkASSERT(fType == Type::kNormal);
|
|
|
|
return fColor0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setLinear(SkColor c0, SkColor c1) {
|
|
|
|
fType = Type::kLinear;
|
|
|
|
fColor0 = c0;
|
|
|
|
fColor1 = c1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setRadial(SkColor c0, SkColor c1) {
|
|
|
|
fType = Type::kRadial;
|
|
|
|
fColor0 = c0;
|
|
|
|
fColor1 = c1;
|
|
|
|
}
|
|
|
|
|
|
|
|
SkColor c0() const { return fColor0; }
|
|
|
|
SkColor c1() const { return fColor1; }
|
|
|
|
|
|
|
|
bool isTransparent() const {
|
|
|
|
if (fType == Type::kNormal) {
|
|
|
|
return 0xFF != SkColorGetA(fColor0);
|
|
|
|
} else {
|
|
|
|
return 0xFF != SkColorGetA(fColor0) && 0xFF != SkColorGetA(fColor1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get a material id for this paint that should be jammed into the sort key
|
2021-06-17 20:32:51 +00:00
|
|
|
int toID() const;
|
2021-05-20 13:45:10 +00:00
|
|
|
|
2021-06-03 18:36:08 +00:00
|
|
|
SkColor evalColor(int x, int y) const;
|
|
|
|
|
2021-05-20 13:45:10 +00:00
|
|
|
protected:
|
|
|
|
|
|
|
|
private:
|
|
|
|
enum class Type {
|
|
|
|
kNormal,
|
|
|
|
kLinear,
|
|
|
|
kRadial
|
|
|
|
};
|
|
|
|
|
|
|
|
Type fType = Type::kNormal;
|
|
|
|
SkColor fColor0 = SK_ColorBLACK;
|
|
|
|
SkColor fColor1 = SK_ColorBLACK;
|
|
|
|
};
|
|
|
|
|
|
|
|
class FakeDevice {
|
|
|
|
public:
|
|
|
|
FakeDevice(SkBitmap bm) : fBM(bm) {
|
|
|
|
SkASSERT(bm.width() == 256 && bm.height() == 256);
|
|
|
|
|
|
|
|
memset(fZBuffer, 0, sizeof(fZBuffer));
|
|
|
|
}
|
|
|
|
|
|
|
|
~FakeDevice() {}
|
|
|
|
|
|
|
|
void save();
|
2021-06-23 13:10:14 +00:00
|
|
|
void drawShape(ID, PaintersOrder, Shape, SkIRect, FakePaint);
|
|
|
|
void clipShape(ID, PaintersOrder, Shape, SkIRect);
|
2021-05-20 13:45:10 +00:00
|
|
|
void translate(SkIPoint trans) {
|
|
|
|
fTracker.translate(trans);
|
|
|
|
}
|
|
|
|
|
2021-06-22 16:44:16 +00:00
|
|
|
void restore(PaintersOrder paintersOrderWhenPopped);
|
2021-05-20 13:45:10 +00:00
|
|
|
|
|
|
|
void finalize();
|
|
|
|
|
2021-06-09 18:11:00 +00:00
|
|
|
void getOrder(std::vector<ID>*) const;
|
2021-05-20 13:45:10 +00:00
|
|
|
sk_sp<FakeMCBlob> snapState() { return fTracker.snapState(); }
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
|
|
private:
|
2021-06-04 14:07:25 +00:00
|
|
|
void sort();
|
2021-05-20 13:45:10 +00:00
|
|
|
|
2021-06-17 20:32:51 +00:00
|
|
|
bool fFinalized = false;
|
|
|
|
std::vector<sk_sp<Cmd>> fSortedCmds;
|
2021-05-20 13:45:10 +00:00
|
|
|
|
2021-06-17 20:32:51 +00:00
|
|
|
FakeStateTracker fTracker;
|
|
|
|
SkBitmap fBM;
|
|
|
|
uint32_t fZBuffer[256][256];
|
2021-05-20 13:45:10 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class FakeCanvas {
|
|
|
|
public:
|
|
|
|
FakeCanvas(SkBitmap& bm) {
|
|
|
|
fDeviceStack.push_back(std::make_unique<FakeDevice>(bm));
|
|
|
|
}
|
|
|
|
|
|
|
|
void saveLayer() {
|
|
|
|
SkASSERT(!fFinalized);
|
|
|
|
|
|
|
|
// TODO: implement
|
|
|
|
}
|
|
|
|
|
|
|
|
void save() {
|
|
|
|
SkASSERT(!fFinalized);
|
|
|
|
fDeviceStack.back()->save();
|
|
|
|
}
|
|
|
|
|
2021-06-23 13:10:14 +00:00
|
|
|
void drawShape(ID, Shape, SkIRect, FakePaint);
|
2021-05-20 13:45:10 +00:00
|
|
|
|
2021-06-23 13:10:14 +00:00
|
|
|
void clipShape(ID, Shape, SkIRect);
|
2021-05-20 13:45:10 +00:00
|
|
|
|
|
|
|
void translate(SkIPoint trans) {
|
|
|
|
SkASSERT(!fFinalized);
|
|
|
|
|
|
|
|
fDeviceStack.back()->translate(trans);
|
|
|
|
}
|
|
|
|
|
|
|
|
void restore() {
|
|
|
|
SkASSERT(!fFinalized);
|
2021-06-22 16:44:16 +00:00
|
|
|
fDeviceStack.back()->restore(this->peekPaintersOrder());
|
2021-05-20 13:45:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void finalize();
|
|
|
|
|
2021-06-09 18:11:00 +00:00
|
|
|
std::vector<ID> getOrder() const;
|
2021-05-20 13:45:10 +00:00
|
|
|
sk_sp<FakeMCBlob> snapState() {
|
|
|
|
return fDeviceStack.back()->snapState();
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
|
|
private:
|
2021-06-10 12:36:44 +00:00
|
|
|
PaintersOrder nextPaintersOrder() {
|
|
|
|
return PaintersOrder(fNextPaintersOrder++);
|
|
|
|
}
|
|
|
|
PaintersOrder peekPaintersOrder() const {
|
|
|
|
return PaintersOrder(fNextPaintersOrder);
|
2021-05-20 13:45:10 +00:00
|
|
|
}
|
|
|
|
|
2021-06-10 12:36:44 +00:00
|
|
|
uint32_t fNextPaintersOrder = 1;
|
2021-05-20 13:45:10 +00:00
|
|
|
bool fFinalized = false;
|
|
|
|
std::vector<std::unique_ptr<FakeDevice>> fDeviceStack;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
#endif // Fake_DEFINED
|