blob: 352fd2b2dc87c1d70deb721cc42beea379f2de78 [file] [log] [blame]
// 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
#include "experimental/sorttoy/sorttypes.h"
#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 <memory>
#include <vector>
class Cmd;
class ClipCmd;
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() {}
void addClip(sk_sp<ClipCmd> clipCmd);
void translate(SkIPoint trans) {
fTrans += trans;
fCached = nullptr;
}
SkIPoint getTrans() const { return fTrans; }
bool operator==(const MCState& other) const;
const std::vector<sk_sp<ClipCmd>>& cmds() const { return fCmds; }
sk_sp<FakeMCBlob> getCached() const {
return fCached;
}
void setCached(sk_sp<FakeMCBlob> cached) {
fCached = cached;
}
void aboutToBePopped(PaintersOrder paintersOrderWhenPopped);
protected:
friend class FakeMCBlob;
SkIPoint fTrans { 0, 0 };
// 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.
std::vector<sk_sp<ClipCmd>> fCmds;
sk_sp<FakeMCBlob> fCached;
};
FakeMCBlob(const std::vector<MCState>& stack);
int count() const { return fStack.size(); }
int id() const { return fID; }
SkIPoint ctm() const { return fCTM; }
const std::vector<MCState>& mcStates() const { return fStack; }
const MCState& operator[](int index) const { return fStack[index]; }
SkIRect scissor() const { return fScissor; }
private:
static int NextID() {
static int sID = 1;
return sID++;
}
const int fID;
SkIPoint fCTM { 0, 0 };
SkIRect fScissor;
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());
}
void clip(sk_sp<ClipCmd> clipCmd) {
fStack.back().addClip(std::move(clipCmd));
}
// 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);
}
void pop(PaintersOrder paintersOrderWhenPopped) {
SkASSERT(fStack.size() > 0);
fStack.back().aboutToBePopped(paintersOrderWhenPopped);
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() {}
FakePaint(SkColor c)
: fType(Type::kNormal)
, fColor0(c)
, fColor1(SK_ColorUNUSED) {
}
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
int toID() const;
SkColor evalColor(int x, int y) const;
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();
void drawShape(ID, PaintersOrder, Shape, SkIRect, FakePaint);
void clipShape(ID, PaintersOrder, Shape, SkIRect);
void translate(SkIPoint trans) {
fTracker.translate(trans);
}
void restore(PaintersOrder paintersOrderWhenPopped);
void finalize();
void getOrder(std::vector<ID>*) const;
sk_sp<FakeMCBlob> snapState() { return fTracker.snapState(); }
protected:
private:
void sort();
bool fFinalized = false;
std::vector<sk_sp<Cmd>> fSortedCmds;
FakeStateTracker fTracker;
SkBitmap fBM;
uint32_t fZBuffer[256][256];
};
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();
}
void drawShape(ID, Shape, SkIRect, FakePaint);
void clipShape(ID, Shape, SkIRect);
void translate(SkIPoint trans) {
SkASSERT(!fFinalized);
fDeviceStack.back()->translate(trans);
}
void restore() {
SkASSERT(!fFinalized);
fDeviceStack.back()->restore(this->peekPaintersOrder());
}
void finalize();
std::vector<ID> getOrder() const;
sk_sp<FakeMCBlob> snapState() {
return fDeviceStack.back()->snapState();
}
protected:
private:
PaintersOrder nextPaintersOrder() {
return PaintersOrder(fNextPaintersOrder++);
}
PaintersOrder peekPaintersOrder() const {
return PaintersOrder(fNextPaintersOrder);
}
uint32_t fNextPaintersOrder = 1;
bool fFinalized = false;
std::vector<std::unique_ptr<FakeDevice>> fDeviceStack;
};
#endif // Fake_DEFINED