3695bdb587
There was only one virtual method, so switch that to a bool stored in the base class. The derived types exist as hints for the reader, and an easy way to adjust how the new localToDevice is constructed. With this change, we don't need SkSimpleMatrixProvider. SkMatrixProvider is concrete, so we can use it directly. SkOverrideDeviceMatrixProvider no longer needs the original provider for anything, so remove that parameter. It now exists solely to inhibit the hitsPixelCenters flag. Fix a few spots (SkParticleBinding, some sites in SkRuntimeEffect) where we used SkSimpleMatrixProvider, even though the local coordinates being passed did not obey the hits-pixel-centers constraints. Most importantly, document how localToDeviceHitsPixelCenters works. Change-Id: Ibe9060bac0822d0edf52a507d390bd198d8e6dbd Reviewed-on: https://skia-review.googlesource.com/c/skia/+/482176 Reviewed-by: John Stiles <johnstiles@google.com> Commit-Queue: Brian Osman <brianosman@google.com>
249 lines
9.3 KiB
C++
249 lines
9.3 KiB
C++
/*
|
|
* 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/gm.h"
|
|
#include "include/core/SkBlendMode.h"
|
|
#include "include/core/SkCanvas.h"
|
|
#include "include/core/SkColor.h"
|
|
#include "include/core/SkFont.h"
|
|
#include "include/core/SkMatrix.h"
|
|
#include "include/core/SkPaint.h"
|
|
#include "include/core/SkPoint.h"
|
|
#include "include/core/SkRect.h"
|
|
#include "include/core/SkScalar.h"
|
|
#include "include/core/SkShader.h"
|
|
#include "include/core/SkSize.h"
|
|
#include "include/core/SkString.h"
|
|
#include "include/core/SkTileMode.h"
|
|
#include "include/core/SkTypeface.h"
|
|
#include "include/core/SkTypes.h"
|
|
#include "include/effects/SkGradientShader.h"
|
|
#include "include/gpu/GrRecordingContext.h"
|
|
#include "include/private/GrTypesPriv.h"
|
|
#include "src/core/SkCanvasPriv.h"
|
|
#include "src/core/SkMatrixProvider.h"
|
|
#include "src/gpu/GrPaint.h"
|
|
#include "src/gpu/SkGr.h"
|
|
#include "src/gpu/v1/SurfaceDrawContext_v1.h"
|
|
#include "tools/ToolUtils.h"
|
|
|
|
#include <utility>
|
|
|
|
static constexpr SkScalar kTileWidth = 40;
|
|
static constexpr SkScalar kTileHeight = 30;
|
|
|
|
static constexpr int kRowCount = 4;
|
|
static constexpr int kColCount = 3;
|
|
|
|
static void draw_text(SkCanvas* canvas, const char* text) {
|
|
SkFont font(ToolUtils::create_portable_typeface(), 12);
|
|
canvas->drawString(text, 0, 0, font, SkPaint());
|
|
}
|
|
|
|
static void draw_gradient_tiles(SkCanvas* canvas, bool alignGradients) {
|
|
// Always draw the same gradient
|
|
static constexpr SkPoint pts[] = { {0.f, 0.f}, {0.25f * kTileWidth, 0.25f * kTileHeight} };
|
|
static constexpr SkColor colors[] = { SK_ColorBLUE, SK_ColorWHITE };
|
|
|
|
auto sdc = SkCanvasPriv::TopDeviceSurfaceDrawContext(canvas);
|
|
|
|
auto rContext = canvas->recordingContext();
|
|
|
|
auto gradient = SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kMirror);
|
|
SkPaint paint;
|
|
paint.setShader(gradient);
|
|
|
|
for (int i = 0; i < kRowCount; ++i) {
|
|
for (int j = 0; j < kColCount; ++j) {
|
|
SkRect tile = SkRect::MakeWH(kTileWidth, kTileHeight);
|
|
if (alignGradients) {
|
|
tile.offset(j * kTileWidth, i * kTileHeight);
|
|
} else {
|
|
canvas->save();
|
|
canvas->translate(j * kTileWidth, i * kTileHeight);
|
|
}
|
|
|
|
unsigned aa = SkCanvas::kNone_QuadAAFlags;
|
|
if (i == 0) {
|
|
aa |= SkCanvas::kTop_QuadAAFlag;
|
|
}
|
|
if (i == kRowCount - 1) {
|
|
aa |= SkCanvas::kBottom_QuadAAFlag;
|
|
}
|
|
if (j == 0) {
|
|
aa |= SkCanvas::kLeft_QuadAAFlag;
|
|
}
|
|
if (j == kColCount - 1) {
|
|
aa |= SkCanvas::kRight_QuadAAFlag;
|
|
}
|
|
|
|
if (sdc) {
|
|
// Use non-public API to leverage general GrPaint capabilities
|
|
SkMatrix view = canvas->getTotalMatrix();
|
|
SkMatrixProvider matrixProvider(view);
|
|
GrPaint grPaint;
|
|
SkPaintToGrPaint(rContext, sdc->colorInfo(), paint, matrixProvider, &grPaint);
|
|
sdc->fillRectWithEdgeAA(nullptr, std::move(grPaint), GrAA::kYes,
|
|
static_cast<GrQuadAAFlags>(aa), view, tile);
|
|
} else {
|
|
// Fallback to solid color on raster backend since the public API only has color
|
|
SkColor color = alignGradients ? SK_ColorBLUE
|
|
: (i * kColCount + j) % 2 == 0 ? SK_ColorBLUE
|
|
: SK_ColorWHITE;
|
|
canvas->experimental_DrawEdgeAAQuad(
|
|
tile, nullptr, static_cast<SkCanvas::QuadAAFlags>(aa), color,
|
|
SkBlendMode::kSrcOver);
|
|
}
|
|
|
|
if (!alignGradients) {
|
|
// Pop off the matrix translation when drawing unaligned
|
|
canvas->restore();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void draw_color_tiles(SkCanvas* canvas, bool multicolor) {
|
|
for (int i = 0; i < kRowCount; ++i) {
|
|
for (int j = 0; j < kColCount; ++j) {
|
|
SkRect tile = SkRect::MakeXYWH(j * kTileWidth, i * kTileHeight, kTileWidth, kTileHeight);
|
|
|
|
SkColor4f color;
|
|
if (multicolor) {
|
|
color = {(i + 1.f) / kRowCount, (j + 1.f) / kColCount, .4f, 1.f};
|
|
} else {
|
|
color = {.2f, .8f, .3f, 1.f};
|
|
}
|
|
|
|
unsigned aa = SkCanvas::kNone_QuadAAFlags;
|
|
if (i == 0) {
|
|
aa |= SkCanvas::kTop_QuadAAFlag;
|
|
}
|
|
if (i == kRowCount - 1) {
|
|
aa |= SkCanvas::kBottom_QuadAAFlag;
|
|
}
|
|
if (j == 0) {
|
|
aa |= SkCanvas::kLeft_QuadAAFlag;
|
|
}
|
|
if (j == kColCount - 1) {
|
|
aa |= SkCanvas::kRight_QuadAAFlag;
|
|
}
|
|
|
|
canvas->experimental_DrawEdgeAAQuad(
|
|
tile, nullptr, static_cast<SkCanvas::QuadAAFlags>(aa), color.toSkColor(),
|
|
SkBlendMode::kSrcOver);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void draw_tile_boundaries(SkCanvas* canvas, const SkMatrix& local) {
|
|
// Draw grid of red lines at interior tile boundaries.
|
|
static constexpr SkScalar kLineOutset = 10.f;
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
paint.setColor(SK_ColorRED);
|
|
paint.setStyle(SkPaint::kStroke_Style);
|
|
paint.setStrokeWidth(0.f);
|
|
for (int x = 1; x < kColCount; ++x) {
|
|
SkPoint pts[] = {{x * kTileWidth, 0}, {x * kTileWidth, kRowCount * kTileHeight}};
|
|
local.mapPoints(pts, 2);
|
|
SkVector v = pts[1] - pts[0];
|
|
v.setLength(v.length() + kLineOutset);
|
|
canvas->drawLine(pts[1] - v, pts[0] + v, paint);
|
|
}
|
|
for (int y = 1; y < kRowCount; ++y) {
|
|
SkPoint pts[] = {{0, y * kTileHeight}, {kTileWidth * kColCount, y * kTileHeight}};
|
|
local.mapPoints(pts, 2);
|
|
SkVector v = pts[1] - pts[0];
|
|
v.setLength(v.length() + kLineOutset);
|
|
canvas->drawLine(pts[1] - v, pts[0] + v, paint);
|
|
}
|
|
}
|
|
|
|
// Tile renderers (column variation)
|
|
typedef void (*TileRenderer)(SkCanvas*);
|
|
static TileRenderer kTileSets[] = {
|
|
[](SkCanvas* canvas) { draw_gradient_tiles(canvas, /* aligned */ false); },
|
|
[](SkCanvas* canvas) { draw_gradient_tiles(canvas, /* aligned */ true); },
|
|
[](SkCanvas* canvas) { draw_color_tiles(canvas, /* multicolor */ false); },
|
|
[](SkCanvas* canvas) { draw_color_tiles(canvas, /* multicolor */true); },
|
|
};
|
|
static const char* kTileSetNames[] = { "Local", "Aligned", "Green", "Multicolor" };
|
|
static_assert(SK_ARRAY_COUNT(kTileSets) == SK_ARRAY_COUNT(kTileSetNames), "Count mismatch");
|
|
|
|
namespace skiagm {
|
|
|
|
class DrawQuadSetGM : public GM {
|
|
private:
|
|
SkString onShortName() override { return SkString("draw_quad_set"); }
|
|
SkISize onISize() override { return SkISize::Make(800, 800); }
|
|
|
|
void onDraw(SkCanvas* canvas) override {
|
|
SkMatrix rowMatrices[5];
|
|
// Identity
|
|
rowMatrices[0].setIdentity();
|
|
// Translate/scale
|
|
rowMatrices[1].setTranslate(5.5f, 20.25f);
|
|
rowMatrices[1].postScale(.9f, .7f);
|
|
// Rotation
|
|
rowMatrices[2].setRotate(20.0f);
|
|
rowMatrices[2].preTranslate(15.f, -20.f);
|
|
// Skew
|
|
rowMatrices[3].setSkew(.5f, .25f);
|
|
rowMatrices[3].preTranslate(-30.f, 0.f);
|
|
// Perspective
|
|
SkPoint src[4];
|
|
SkRect::MakeWH(kColCount * kTileWidth, kRowCount * kTileHeight).toQuad(src);
|
|
SkPoint dst[4] = {{0, 0},
|
|
{kColCount * kTileWidth + 10.f, 15.f},
|
|
{kColCount * kTileWidth - 28.f, kRowCount * kTileHeight + 40.f},
|
|
{25.f, kRowCount * kTileHeight - 15.f}};
|
|
SkAssertResult(rowMatrices[4].setPolyToPoly(src, dst, 4));
|
|
rowMatrices[4].preTranslate(0.f, +10.f);
|
|
static const char* matrixNames[] = { "Identity", "T+S", "Rotate", "Skew", "Perspective" };
|
|
static_assert(SK_ARRAY_COUNT(matrixNames) == SK_ARRAY_COUNT(rowMatrices), "Count mismatch");
|
|
|
|
// Print a column header
|
|
canvas->save();
|
|
canvas->translate(110.f, 20.f);
|
|
for (size_t j = 0; j < SK_ARRAY_COUNT(kTileSetNames); ++j) {
|
|
draw_text(canvas, kTileSetNames[j]);
|
|
canvas->translate(kColCount * kTileWidth + 30.f, 0.f);
|
|
}
|
|
canvas->restore();
|
|
canvas->translate(0.f, 40.f);
|
|
|
|
// Render all tile variations
|
|
for (size_t i = 0; i < SK_ARRAY_COUNT(rowMatrices); ++i) {
|
|
canvas->save();
|
|
canvas->translate(10.f, 0.5f * kRowCount * kTileHeight);
|
|
draw_text(canvas, matrixNames[i]);
|
|
|
|
canvas->translate(100.f, -0.5f * kRowCount * kTileHeight);
|
|
for (size_t j = 0; j < SK_ARRAY_COUNT(kTileSets); ++j) {
|
|
canvas->save();
|
|
draw_tile_boundaries(canvas, rowMatrices[i]);
|
|
|
|
canvas->concat(rowMatrices[i]);
|
|
kTileSets[j](canvas);
|
|
// Undo the local transformation
|
|
canvas->restore();
|
|
// And advance to the next column
|
|
canvas->translate(kColCount * kTileWidth + 30.f, 0.f);
|
|
}
|
|
// Reset back to the left edge
|
|
canvas->restore();
|
|
// And advance to the next row
|
|
canvas->translate(0.f, kRowCount * kTileHeight + 20.f);
|
|
}
|
|
}
|
|
};
|
|
|
|
DEF_GM(return new DrawQuadSetGM();)
|
|
|
|
} // namespace skiagm
|