blob: 63588e242de4be9a10d315781b981635b17585ce [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.
#include "experimental/ngatoy/Cmds.h"
#include "experimental/ngatoy/Fake.h"
#include "experimental/ngatoy/SortKey.h"
#include "include/core/SkBitmap.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkColor.h"
#include "include/core/SkPaint.h"
#include "include/effects/SkGradientShader.h"
//------------------------------------------------------------------------------------------------
RectCmd::RectCmd(ID id,
PaintersOrder paintersOrder,
SkIRect r,
const FakePaint& p,
sk_sp<FakeMCBlob> state)
: Cmd(id)
, fPaintersOrder(paintersOrder)
, fRect(r)
, fPaint(p)
, fMCState(std::move(state)) {
}
uint32_t RectCmd::getSortZ() const {
return fPaintersOrder.toUInt();
}
uint32_t RectCmd::getDrawZ() const {
return fPaintersOrder.toUInt();
}
SortKey RectCmd::getKey() {
return SortKey(fPaint.isTransparent(), fMCState->id(), this->getSortZ(), fPaint.toID());
}
static void apply_diff(FakeCanvas* c, const FakeMCBlob& desired, const FakeMCBlob* prior) {
int prefix = desired.determineSharedPrefix(prior);
if (prior) {
for (int j = prefix; j < prior->count(); ++j) {
c->restore();
}
}
for (int j = prefix; j < desired.count(); ++j) {
desired[j].apply(c);
}
}
void RectCmd::execute(FakeCanvas* c) const {
apply_diff(c, *fMCState, c->snapState().get());
c->drawRect(fID, fRect, fPaint);
}
static void apply_diff(SkCanvas* c, const FakeMCBlob& desired, const FakeMCBlob* prior) {
int prefix = desired.determineSharedPrefix(prior);
if (prior) {
for (int j = prefix; j < prior->count(); ++j) {
c->restore();
}
}
for (int j = prefix; j < desired.count(); ++j) {
desired[j].apply(c);
}
}
void RectCmd::execute(SkCanvas* c, const FakeMCBlob* priorState) const {
SkColor4f colors[2] = {
SkColor4f::FromColor(fPaint.c0()),
SkColor4f::FromColor(fPaint.c1())
};
SkPaint p;
if (fPaint.toID() == kSolidMat) {
p.setColor(fPaint.c0());
} else if (fPaint.toID() == kLinearMat) {
SkPoint pts[] = { { 0.0f, 0.0f, }, { 256.0f, 256.0f } };
p.setShader(SkGradientShader::MakeLinear(pts, colors, nullptr, nullptr, 2,
SkTileMode::kClamp));
} else {
SkASSERT(fPaint.toID() == kRadialMat);
auto shader = SkGradientShader::MakeRadial(SkPoint::Make(128.0f, 128.0f),
128.0f,
colors,
nullptr,
nullptr,
2,
SkTileMode::kRepeat);
p.setShader(std::move(shader));
}
apply_diff(c, *fMCState, priorState);
c->drawRect(SkRect::Make(fRect), p);
}
static bool is_opaque(SkColor c) {
return 0xFF == SkColorGetA(c);
}
void RectCmd::rasterize(uint32_t zBuffer[256][256], SkBitmap* dstBM) const {
uint32_t z = this->getDrawZ();
for (int y = fRect.fTop; y < fRect.fBottom; ++y) {
for (int x = fRect.fLeft; x < fRect.fRight; ++x) {
if (fMCState->clipped(x, y)) {
continue;
}
if (z > zBuffer[x][y]) {
zBuffer[x][y] = z;
SkColor c = fPaint.evalColor(x, y);
if (is_opaque(c)) {
*dstBM->getAddr32(x, y) = c;
} else {
SkColor4f bot = SkColor4f::FromColor(*dstBM->getAddr32(x, y));
SkColor4f top = SkColor4f::FromColor(c);
SkColor4f result = {
top.fA * top.fR + (1.0f - top.fA) * bot.fR,
top.fA * top.fG + (1.0f - top.fA) * bot.fG,
top.fA * top.fB + (1.0f - top.fA) * bot.fB,
top.fA + (1.0f - top.fA) * bot.fA
};
*dstBM->getAddr32(x, y) = result.toSkColor();
}
}
}
}
}