c29810e882
Adding ovals reveals the clipping failure. The "actual" results with the oval clips are currently incorrect. Bug: skia:11837 Change-Id: I0789d5f758457425250ff6cecc0a5bb44f6e82ef Reviewed-on: https://skia-review.googlesource.com/c/skia/+/420637 Commit-Queue: Robert Phillips <robertphillips@google.com> Reviewed-by: Michael Ludwig <michaelludwig@google.com>
253 lines
7.3 KiB
C++
253 lines
7.3 KiB
C++
// 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/core/SkRRect.h"
|
|
#include "include/effects/SkGradientShader.h"
|
|
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
SortKey SaveCmd::getKey() {
|
|
SkASSERT(0);
|
|
return {};
|
|
}
|
|
|
|
void SaveCmd::execute(FakeCanvas* f) const {
|
|
f->save();
|
|
}
|
|
|
|
void SaveCmd::execute(SkCanvas* c) const {
|
|
c->save();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
SortKey RestoreCmd::getKey() {
|
|
SkASSERT(0);
|
|
return {};
|
|
}
|
|
|
|
void RestoreCmd::execute(FakeCanvas* f) const {
|
|
f->restore();
|
|
}
|
|
|
|
void RestoreCmd::execute(SkCanvas* c) const {
|
|
c->restore();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
DrawCmd::DrawCmd(ID id,
|
|
Shape shape,
|
|
SkIRect r,
|
|
const FakePaint& p)
|
|
: Cmd(id)
|
|
, fShape(shape)
|
|
, fRect(r)
|
|
, fPaint(p) {
|
|
}
|
|
|
|
DrawCmd::DrawCmd(ID id,
|
|
PaintersOrder paintersOrder,
|
|
Shape shape,
|
|
SkIRect r,
|
|
const FakePaint& p,
|
|
sk_sp<FakeMCBlob> state)
|
|
: Cmd(id)
|
|
, fPaintersOrder(paintersOrder)
|
|
, fShape(shape)
|
|
, fRect(r)
|
|
, fPaint(p)
|
|
, fMCState(std::move(state)) {
|
|
}
|
|
|
|
static bool shared_contains(int x, int y, Shape s, SkIRect r) {
|
|
if (s == Shape::kRect) {
|
|
return r.contains(x, y);
|
|
} else {
|
|
float a = r.width() / 2.0f; // horizontal radius
|
|
float b = r.height() / 2.0f; // vertical radius
|
|
float h = 0.5f * (r.fLeft + r.fRight); // center X
|
|
float k = 0.5f * (r.fTop + r.fBottom); // center Y
|
|
|
|
float xTerm = x + 0.5f - h;
|
|
float yTerm = y + 0.5f - k;
|
|
|
|
return (xTerm * xTerm) / (a * a) + (yTerm * yTerm) / (b * b) < 1.0f;
|
|
}
|
|
}
|
|
|
|
bool DrawCmd::contains(int x, int y) const {
|
|
return shared_contains(x, y, fShape, fRect);
|
|
}
|
|
|
|
uint32_t DrawCmd::getSortZ() const {
|
|
return fPaintersOrder.toUInt();
|
|
}
|
|
|
|
// Opaque and transparent draws both write their painter's index to the depth buffer
|
|
uint32_t DrawCmd::getDrawZ() const {
|
|
return fPaintersOrder.toUInt();
|
|
}
|
|
|
|
SortKey DrawCmd::getKey() {
|
|
return SortKey(fPaint.isTransparent(), this->getSortZ(), fPaint.toID());
|
|
}
|
|
|
|
void DrawCmd::execute(FakeCanvas* c) const {
|
|
c->drawShape(fID, fShape, fRect, fPaint);
|
|
}
|
|
|
|
void DrawCmd::execute(SkCanvas* c) 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));
|
|
}
|
|
|
|
if (fShape == Shape::kRect) {
|
|
c->drawRect(SkRect::Make(fRect), p);
|
|
} else {
|
|
c->drawOval(SkRect::Make(fRect), p);
|
|
}
|
|
}
|
|
|
|
static bool is_opaque(SkColor c) {
|
|
return 0xFF == SkColorGetA(c);
|
|
}
|
|
|
|
void DrawCmd::rasterize(uint32_t zBuffer[256][256], SkBitmap* dstBM) const {
|
|
|
|
uint32_t z = this->getDrawZ();
|
|
SkIRect scissor = fMCState->scissor();
|
|
|
|
for (int y = fRect.fTop; y < fRect.fBottom; ++y) {
|
|
for (int x = fRect.fLeft; x < fRect.fRight; ++x) {
|
|
if (!scissor.contains(x, y)) {
|
|
continue;
|
|
}
|
|
|
|
if (!this->contains(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();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
ClipCmd::ClipCmd(ID id, Shape shape, SkIRect r)
|
|
: Cmd(id)
|
|
, fShape(shape)
|
|
, fRect(r) {
|
|
}
|
|
|
|
ClipCmd::ClipCmd(ID id, PaintersOrder paintersOrderWhenAdded, Shape shape, SkIRect r)
|
|
: Cmd(id)
|
|
, fShape(shape)
|
|
, fRect(r)
|
|
, fPaintersOrderWhenAdded(paintersOrderWhenAdded) {
|
|
}
|
|
|
|
ClipCmd::~ClipCmd() {}
|
|
|
|
bool ClipCmd::contains(int x, int y) const {
|
|
return shared_contains(x, y, fShape, fRect);
|
|
}
|
|
|
|
uint32_t ClipCmd::getSortZ() const {
|
|
SkASSERT(fPaintersOrderWhenAdded.isValid());
|
|
|
|
return fPaintersOrderWhenAdded.toUInt();
|
|
}
|
|
|
|
// A clip writes the painter's index corresponding to when it's "popped" off the clip stack
|
|
uint32_t ClipCmd::getDrawZ() const {
|
|
SkASSERT(fPaintersOrderWhenPopped.isValid());
|
|
|
|
return fPaintersOrderWhenPopped.toUInt();
|
|
}
|
|
|
|
SortKey ClipCmd::getKey() {
|
|
return SortKey(false, this->getSortZ(), kInvalidMat);
|
|
}
|
|
|
|
void ClipCmd::onAboutToBePopped(PaintersOrder paintersOrderWhenPopped) {
|
|
SkASSERT(!fPaintersOrderWhenPopped.isValid() && paintersOrderWhenPopped.isValid());
|
|
fPaintersOrderWhenPopped = paintersOrderWhenPopped;
|
|
}
|
|
|
|
void ClipCmd::execute(FakeCanvas* c) const {
|
|
// This call is creating the 'real' ClipCmd for the "actual" case
|
|
SkASSERT(!fPaintersOrderWhenAdded.isValid() && !fPaintersOrderWhenPopped.isValid());
|
|
|
|
c->clipShape(fID, fShape, fRect);
|
|
}
|
|
|
|
void ClipCmd::execute(SkCanvas* c) const {
|
|
if (fShape == Shape::kRect) {
|
|
c->clipRect(SkRect::Make(fRect));
|
|
} else {
|
|
c->clipRRect(SkRRect::MakeOval(SkRect::Make(fRect)));
|
|
}
|
|
}
|
|
|
|
void ClipCmd::rasterize(uint32_t zBuffer[256][256], SkBitmap* /* dstBM */) const {
|
|
uint32_t drawZ = this->getDrawZ();
|
|
|
|
// TODO: limit this via the scissor!
|
|
for (int y = 0; y < 256; ++y) {
|
|
for (int x = 0; x < 256; ++x) {
|
|
if (!this->contains(x, y) && drawZ > zBuffer[x][y]) {
|
|
zBuffer[x][y] = drawZ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|