aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Florin Malita <fmalita@chromium.org>2018-04-04 14:17:30 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-04-04 18:54:28 +0000
commit325ea327ff6106f5f35df437a2bbb88f566bb3c4 (patch)
tree7d28868b905eb60d3e9fd3a020df1475d4bd0608
parent1efe3224735046db153ffff6691b1f741f371794 (diff)
Fix SkLocalMatrixShader nesting semantics
Inherited/outer local matrices are supposed to compose to the right of (preconcat) other/nested local matrices. BUG=skia:7781 Change-Id: Icd3c24f226845427be849a8be3d78293aef176b3 Reviewed-on: https://skia-review.googlesource.com/118344 Commit-Queue: Florin Malita <fmalita@chromium.org> Reviewed-by: Mike Reed <reed@google.com>
-rw-r--r--gm/localmatrixshader.cpp101
-rw-r--r--gn/gm.gni1
-rw-r--r--src/shaders/SkLocalMatrixShader.cpp20
3 files changed, 113 insertions, 9 deletions
diff --git a/gm/localmatrixshader.cpp b/gm/localmatrixshader.cpp
new file mode 100644
index 0000000000..bbd2775b7c
--- /dev/null
+++ b/gm/localmatrixshader.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm.h"
+#include "SkCanvas.h"
+#include "SkShader.h"
+#include "SkSurface.h"
+#include "sk_tool_utils.h"
+
+static sk_sp<SkImage> make_image(SkCanvas* rootCanvas) {
+ static constexpr SkScalar kSize = 50;
+ SkImageInfo info = SkImageInfo::MakeN32Premul(kSize, kSize);
+ auto surface = sk_tool_utils::makeSurface(rootCanvas, info);
+
+ SkPaint p;
+ p.setAntiAlias(true);
+ p.setColor(SK_ColorGREEN);
+
+ surface->getCanvas()->drawCircle(kSize / 2, kSize / 2, kSize / 2, p);
+
+ p.setStyle(SkPaint::kStroke_Style);
+ p.setColor(SK_ColorRED);
+ surface->getCanvas()->drawLine(kSize * .25f, kSize * .50f, kSize * .75f, kSize * .50f, p);
+ surface->getCanvas()->drawLine(kSize * .50f, kSize * .25f, kSize * .50f, kSize * .75f, p);
+
+ return surface->makeImageSnapshot();
+}
+
+DEF_SIMPLE_GM(localmatrixshader_nested, canvas, 450, 1200) {
+ auto image = make_image(canvas);
+
+ using FactoryT = sk_sp<SkShader> (*)(const sk_sp<SkImage>&,
+ const SkMatrix& inner,
+ const SkMatrix& outer);
+ static const FactoryT gFactories[] = {
+ // SkLocalMatrixShader(SkImageShader(inner), outer)
+ [](const sk_sp<SkImage>& img, const SkMatrix& inner, const SkMatrix& outer) {
+ return img->makeShader(&inner)->makeWithLocalMatrix(outer);
+ },
+
+ // SkLocalMatrixShader(SkLocalMatrixShader(SkImageShader(I), inner), outer)
+ [](const sk_sp<SkImage>& img, const SkMatrix& inner, const SkMatrix& outer) {
+ return img->makeShader()->makeWithLocalMatrix(inner)->makeWithLocalMatrix(outer);
+ },
+
+ // SkLocalMatrixShader(SkComposeShader(SkImageShader(inner)), outer)
+ [](const sk_sp<SkImage>& img, const SkMatrix& inner, const SkMatrix& outer) {
+ return SkShader::MakeCompose(SkShader::MakeColorShader(SK_ColorTRANSPARENT),
+ img->makeShader(&inner),
+ SkBlendMode::kSrcOver)
+ ->makeWithLocalMatrix(outer);
+ },
+
+ // SkLocalMatrixShader(SkComposeShader(SkLocalMatrixShader(SkImageShader(I), inner)), outer)
+ [](const sk_sp<SkImage>& img, const SkMatrix& inner, const SkMatrix& outer) {
+ return SkShader::MakeCompose(SkShader::MakeColorShader(SK_ColorTRANSPARENT),
+ img->makeShader()->makeWithLocalMatrix(inner),
+ SkBlendMode::kSrcOver)
+ ->makeWithLocalMatrix(outer);
+ },
+ };
+
+ static const auto inner = SkMatrix::MakeScale(2, 2),
+ outer = SkMatrix::MakeTrans(20, 20);
+
+ SkPaint border;
+ border.setAntiAlias(true);
+ border.setStyle(SkPaint::kStroke_Style);
+
+ auto rect = SkRect::Make(image->bounds());
+ SkAssertResult(SkMatrix::Concat(inner, outer).mapRect(&rect));
+
+ const auto drawColumn = [&]() {
+ SkAutoCanvasRestore acr(canvas, true);
+ for (const auto& f : gFactories) {
+ SkPaint p;
+ p.setShader(f(image, inner, outer));
+
+ canvas->drawRect(rect, p);
+ canvas->drawRect(rect, border);
+
+ canvas->translate(0, rect.height() * 1.5f);
+ }
+ };
+
+ drawColumn();
+
+ {
+ SkAutoCanvasRestore acr(canvas, true);
+ canvas->translate(0, rect.height() * SK_ARRAY_COUNT(gFactories) * 1.5f);
+ drawColumn();
+ }
+
+ canvas->translate(rect.width() * 1.5f, 0);
+ canvas->scale(2, 2);
+ drawColumn();
+}
diff --git a/gn/gm.gni b/gn/gm.gni
index 1558881e06..b1f5135068 100644
--- a/gn/gm.gni
+++ b/gn/gm.gni
@@ -201,6 +201,7 @@ gm_sources = [
"$_gm/linepaths.cpp",
"$_gm/localmatriximagefilter.cpp",
"$_gm/localmatriximageshader.cpp",
+ "$_gm/localmatrixshader.cpp",
"$_gm/lumafilter.cpp",
"$_gm/makecolorspace.cpp",
"$_gm/makeRasterImage.cpp",
diff --git a/src/shaders/SkLocalMatrixShader.cpp b/src/shaders/SkLocalMatrixShader.cpp
index a08fea14a5..e352d31299 100644
--- a/src/shaders/SkLocalMatrixShader.cpp
+++ b/src/shaders/SkLocalMatrixShader.cpp
@@ -6,6 +6,7 @@
*/
#include "SkLocalMatrixShader.h"
+#include "SkTLazy.h"
#if SK_SUPPORT_GPU
#include "GrFragmentProcessor.h"
@@ -42,14 +43,14 @@ void SkLocalMatrixShader::flatten(SkWriteBuffer& buffer) const {
SkShaderBase::Context* SkLocalMatrixShader::onMakeContext(
const ContextRec& rec, SkArenaAlloc* alloc) const
{
- ContextRec newRec(rec);
- SkMatrix tmp;
+ SkTCopyOnFirstWrite<SkMatrix> lm(this->getLocalMatrix());
if (rec.fLocalMatrix) {
- tmp.setConcat(*rec.fLocalMatrix, this->getLocalMatrix());
- newRec.fLocalMatrix = &tmp;
- } else {
- newRec.fLocalMatrix = &this->getLocalMatrix();
+ lm.writable()->preConcat(*rec.fLocalMatrix);
}
+
+ ContextRec newRec(rec);
+ newRec.fLocalMatrix = lm;
+
return as_SB(fProxyShader)->makeContext(newRec, alloc);
}
@@ -65,12 +66,13 @@ SkImage* SkLocalMatrixShader::onIsAImage(SkMatrix* outMatrix, enum TileMode* mod
}
bool SkLocalMatrixShader::onAppendStages(const StageRec& rec) const {
- SkMatrix tmp;
+ SkTCopyOnFirstWrite<SkMatrix> lm(this->getLocalMatrix());
if (rec.fLocalM) {
- tmp.setConcat(*rec.fLocalM, this->getLocalMatrix());
+ lm.writable()->preConcat(*rec.fLocalM);
}
+
StageRec newRec = rec;
- newRec.fLocalM = rec.fLocalM ? &tmp : &this->getLocalMatrix();
+ newRec.fLocalM = lm;
return as_SB(fProxyShader)->appendStages(newRec);
}