aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core
diff options
context:
space:
mode:
authorGravatar Florin Malita <fmalita@chromium.org>2017-02-14 16:19:49 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-02-14 22:54:56 +0000
commit4b66512a6384d32c1a89396bd4a229c03cce67a0 (patch)
tree67a9805e72b020cfb8252ceea3224c1dc9dd2c38 /src/core
parent70c60638be6eba5f5b54e0056bc0fd716f086eb0 (diff)
Handle collapsed drawVertices() texture coords gracefully
Detect collapsed coords and implement using a solid color shader. Replace SkTLazy objects with a stack-based SkArenaAllocator. Change-Id: I5d867648d551ea30558fd8ae0c99b9292bc92961 Reviewed-on: https://skia-review.googlesource.com/8451 Reviewed-by: Mike Reed <reed@google.com> Commit-Queue: Florin Malita <fmalita@chromium.org>
Diffstat (limited to 'src/core')
-rw-r--r--src/core/SkDraw.cpp74
1 files changed, 66 insertions, 8 deletions
diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp
index eb5af7ab06..4ec48952eb 100644
--- a/src/core/SkDraw.cpp
+++ b/src/core/SkDraw.cpp
@@ -13,6 +13,7 @@
#include "SkBlitter.h"
#include "SkCanvas.h"
#include "SkColorPriv.h"
+#include "SkColorShader.h"
#include "SkDevice.h"
#include "SkDeviceLooper.h"
#include "SkFindAndPlaceGlyph.h"
@@ -33,6 +34,7 @@
#include "SkTemplates.h"
#include "SkTextMapStateProc.h"
#include "SkTLazy.h"
+#include "SkUnPreMultiply.h"
#include "SkUtils.h"
#include "SkVertState.h"
@@ -1853,6 +1855,52 @@ void SkTriColorShader::toString(SkString* str) const {
}
#endif
+static sk_sp<SkShader> MakeTextureShader(const VertState& state, const SkPoint verts[],
+ const SkPoint texs[], const SkPaint& paint,
+ SkColorSpace* dstColorSpace,
+ SkArenaAlloc* alloc) {
+ SkASSERT(paint.getShader());
+
+ const auto& p0 = texs[state.f0],
+ p1 = texs[state.f1],
+ p2 = texs[state.f2];
+
+ if (p0 != p1 || p0 != p2) {
+ // Common case (non-collapsed texture coordinates).
+ // Map the texture to vertices using a local transform.
+ SkMatrix localMatrix;
+ return texture_to_matrix(state, verts, texs, &localMatrix)
+ ? alloc->makeSkSp<SkLocalMatrixShader>(paint.refShader(), localMatrix)
+ : nullptr;
+ }
+
+ // Collapsed texture coordinates special case.
+ // The texture is a solid color, sampled at the given point.
+ SkMatrix shaderInvLocalMatrix;
+ SkAssertResult(paint.getShader()->getLocalMatrix().invert(&shaderInvLocalMatrix));
+
+ const auto sample = SkPoint::Make(0.5f, 0.5f);
+ const auto mappedSample = shaderInvLocalMatrix.mapXY(sample.x(), sample.y()),
+ mappedPoint = shaderInvLocalMatrix.mapXY(p0.x(), p0.y());
+ const auto localMatrix = SkMatrix::MakeTrans(mappedSample.x() - mappedPoint.x(),
+ mappedSample.y() - mappedPoint.y());
+
+ SkShader::ContextRec rec(paint, SkMatrix::I(), &localMatrix,
+ SkShader::ContextRec::kPMColor_DstType, dstColorSpace);
+ auto* ctx = paint.getShader()->makeContext(rec, alloc);
+ if (!ctx) {
+ return nullptr;
+ }
+
+ SkPMColor pmColor;
+ ctx->shadeSpan(SkScalarFloorToInt(sample.x()), SkScalarFloorToInt(sample.y()), &pmColor, 1);
+
+ // no need to keep this temp context around.
+ alloc->reset();
+
+ return alloc->makeSkSp<SkColorShader>(SkUnPreMultiply::PMColorToColor(pmColor));
+}
+
void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count,
const SkPoint vertices[], const SkPoint textures[],
const SkColor colors[], SkBlendMode bmode,
@@ -1922,18 +1970,28 @@ void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count,
while (vertProc(&state)) {
auto* blitterPtr = blitter.get();
- SkTLazy<SkLocalMatrixShader> localShader;
- SkTLazy<SkAutoBlitterChoose> localBlitter;
+ // We're going to allocate at most
+ //
+ // * one SkLocalMatrixShader OR one SkColorShader
+ // * one SkComposeShader
+ // * one SkAutoBlitterChoose
+ //
+ static constexpr size_t kAllocSize =
+ sizeof(SkAutoBlitterChoose) + sizeof(SkComposeShader) +
+ SkTMax(sizeof(SkLocalMatrixShader), sizeof(SkColorShader));
+ char allocBuffer[kAllocSize];
+ SkArenaAlloc alloc(allocBuffer);
if (textures) {
- SkMatrix tempM;
- if (texture_to_matrix(state, vertices, textures, &tempM)) {
- localShader.init(p.refShader(), tempM);
-
+ sk_sp<SkShader> texShader = MakeTextureShader(state, vertices, textures, paint,
+ fDst.colorSpace(), &alloc);
+ if (texShader) {
SkPaint localPaint(p);
- localPaint.setShader(sk_ref_sp(localShader.get()));
+ localPaint.setShader(colors
+ ? alloc.makeSkSp<SkComposeShader>(triShader, std::move(texShader), bmode)
+ : std::move(texShader));
- blitterPtr = localBlitter.init(fDst, *fMatrix, localPaint)->get();
+ blitterPtr = alloc.make<SkAutoBlitterChoose>(fDst, *fMatrix, localPaint)->get();
if (blitterPtr->isNullBlitter()) {
continue;
}