aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core
diff options
context:
space:
mode:
authorGravatar Florin Malita <fmalita@chromium.org>2017-02-16 22:12:41 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-02-17 03:45:02 +0000
commitf614ba2ddc7e0805616bd40e104021695ff7d767 (patch)
treeaa12721ce9cb3624524be7b70e09cce7bcbd43fe /src/core
parent1d2aed03983c068433387c37a0ba54c909921e07 (diff)
Fix drawVertices() texture mapping in the presence of a local matrix
Change-Id: I6379f2e7c030d7d1e0fcb2bd6ecc7d81c8a4eec5 Reviewed-on: https://skia-review.googlesource.com/8502 Commit-Queue: Florin Malita <fmalita@chromium.org> Reviewed-by: Mike Reed <reed@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
Diffstat (limited to 'src/core')
-rw-r--r--src/core/SkDraw.cpp60
1 files changed, 57 insertions, 3 deletions
diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp
index 4ec48952eb..4182ef3a72 100644
--- a/src/core/SkDraw.cpp
+++ b/src/core/SkDraw.cpp
@@ -1855,7 +1855,56 @@ void SkTriColorShader::toString(SkString* str) const {
}
#endif
-static sk_sp<SkShader> MakeTextureShader(const VertState& state, const SkPoint verts[],
+namespace {
+
+// Similar to SkLocalMatrixShader, but composes the local matrix with the CTM (instead
+// of composing with the inherited local matrix):
+//
+// rec' = {rec.ctm x localMatrix, rec.localMatrix}
+//
+// (as opposed to rec' = {rec.ctm, rec.localMatrix x localMatrix})
+//
+class SkLocalInnerMatrixShader final : public SkShader {
+public:
+ SkLocalInnerMatrixShader(sk_sp<SkShader> proxy, const SkMatrix& localMatrix)
+ : INHERITED(&localMatrix)
+ , fProxyShader(std::move(proxy)) {}
+
+ Factory getFactory() const override {
+ SkASSERT(false);
+ return nullptr;
+ }
+
+protected:
+ void flatten(SkWriteBuffer&) const override {
+ SkASSERT(false);
+ }
+
+ Context* onMakeContext(const ContextRec& rec, SkArenaAlloc* alloc) const override {
+ SkMatrix adjustedCTM = SkMatrix::Concat(*rec.fMatrix, this->getLocalMatrix());
+ ContextRec newRec(rec);
+ newRec.fMatrix = &adjustedCTM;
+ return fProxyShader->makeContext(newRec, alloc);
+ }
+
+ bool onAppendStages(SkRasterPipeline* p, SkColorSpace* cs, SkArenaAlloc* alloc,
+ const SkMatrix& ctm, const SkPaint& paint,
+ const SkMatrix* localM) const override {
+ // We control the shader graph ancestors, so we know there's no local matrix being
+ // injected before this.
+ SkASSERT(!localM);
+
+ SkMatrix adjustedCTM = SkMatrix::Concat(ctm, this->getLocalMatrix());
+ return fProxyShader->appendStages(p, cs, alloc, adjustedCTM, paint);
+ }
+
+private:
+ sk_sp<SkShader> fProxyShader;
+
+ typedef SkShader INHERITED;
+};
+
+sk_sp<SkShader> MakeTextureShader(const VertState& state, const SkPoint verts[],
const SkPoint texs[], const SkPaint& paint,
SkColorSpace* dstColorSpace,
SkArenaAlloc* alloc) {
@@ -1868,9 +1917,12 @@ static sk_sp<SkShader> MakeTextureShader(const VertState& state, const SkPoint v
if (p0 != p1 || p0 != p2) {
// Common case (non-collapsed texture coordinates).
// Map the texture to vertices using a local transform.
+
+ // We cannot use a plain SkLocalMatrix shader, because we need the texture matrix
+ // to compose next to the CTM.
SkMatrix localMatrix;
return texture_to_matrix(state, verts, texs, &localMatrix)
- ? alloc->makeSkSp<SkLocalMatrixShader>(paint.refShader(), localMatrix)
+ ? alloc->makeSkSp<SkLocalInnerMatrixShader>(paint.refShader(), localMatrix)
: nullptr;
}
@@ -1901,6 +1953,8 @@ static sk_sp<SkShader> MakeTextureShader(const VertState& state, const SkPoint v
return alloc->makeSkSp<SkColorShader>(SkUnPreMultiply::PMColorToColor(pmColor));
}
+} // anonymous ns
+
void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count,
const SkPoint vertices[], const SkPoint textures[],
const SkColor colors[], SkBlendMode bmode,
@@ -1978,7 +2032,7 @@ void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count,
//
static constexpr size_t kAllocSize =
sizeof(SkAutoBlitterChoose) + sizeof(SkComposeShader) +
- SkTMax(sizeof(SkLocalMatrixShader), sizeof(SkColorShader));
+ SkTMax(sizeof(SkLocalInnerMatrixShader), sizeof(SkColorShader));
char allocBuffer[kAllocSize];
SkArenaAlloc alloc(allocBuffer);