drawGlyphRunRSXform: post-compose shader local matrix adjustments

Bug: skia:11113
Change-Id: Ic34a0c80b44031d77d361d35e64301297b3f3189
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/347047
Commit-Queue: Florin Malita <fmalita@chromium.org>
Commit-Queue: Florin Malita <fmalita@google.com>
Reviewed-by: Mike Reed <reed@google.com>
This commit is contained in:
Florin Malita 2020-12-29 15:34:33 -05:00 committed by Skia Commit-Bot
parent 6e9bf51dd8
commit ff49f92e26
2 changed files with 41 additions and 11 deletions

View File

@ -31,7 +31,7 @@ private:
SkFontStyle::kNormal_Width,
SkFontStyle::kUpright_Slant);
SkFont font(ToolUtils::create_portable_typeface(nullptr, style), kFontSZ);
font.setEdging(SkFont::Edging::kAlias);
font.setEdging(SkFont::Edging::kAntiAlias);
static constexpr char txt[] = "TEST";
SkGlyphID glyphs[16];
@ -95,7 +95,8 @@ private:
->drawRect({0, 0, kTileSize.width()*0.9f, kTileSize.height()*0.9f}, p);
return surface->makeImageSnapshot()
->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, SkSamplingOptions(), &lm)
->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat,
SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone), &lm)
->makeWithLocalMatrix(outer_lm);
}

View File

@ -395,6 +395,43 @@ bool SkBaseDevice::peekPixels(SkPixmap* pmap) {
#include "src/core/SkUtils.h"
// TODO: This does not work for arbitrary shader DAGs (when there is no single leaf local matrix).
// What we really need is proper post-LM plumbing for shaders.
static sk_sp<SkShader> make_post_inverse_lm(const SkShader* shader, const SkMatrix& m) {
SkMatrix inverse;
if (!shader || !m.invert(&inverse)) {
return nullptr;
}
// Normal LMs pre-compose. In order to push a post local matrix, we shoot for
// something along these lines (where all new components are pre-composed):
//
// new_lm X current_lm == current_lm X inv(current_lm) X new_lm X current_lm
//
// We also have two sources of local matrices:
// - the actual shader lm
// - outer lms applied via SkLocalMatrixShader
SkMatrix outer_lm;
const auto nested_shader = as_SB(shader)->makeAsALocalMatrixShader(&outer_lm);
if (nested_shader) {
// unfurl the shader
shader = nested_shader.get();
} else {
outer_lm.reset();
}
const auto lm = *as_SB(shader)->totalLocalMatrix(nullptr);
SkMatrix lm_inv;
if (!lm.invert(&lm_inv)) {
return nullptr;
}
// Note: since we unfurled the shader above, we don't need to apply an outer_lm inverse
return shader->makeWithLocalMatrix(lm_inv * inverse * lm * outer_lm);
}
void SkBaseDevice::drawGlyphRunRSXform(const SkFont& font, const SkGlyphID glyphs[],
const SkRSXform xform[], int count, SkPoint origin,
const SkPaint& paint) {
@ -426,15 +463,7 @@ void SkBaseDevice::drawGlyphRunRSXform(const SkFont& font, const SkGlyphID glyph
// (i.e. the shader that cares about the ctm) so we have to undo our little ctm trick
// with a localmatrixshader so that the shader draws as if there was no change to the ctm.
SkPaint transformingPaint{paint};
auto shader = transformingPaint.getShader();
if (shader) {
SkMatrix inverse;
if (glyphToDevice.invert(&inverse)) {
transformingPaint.setShader(shader->makeWithLocalMatrix(inverse));
} else {
transformingPaint.setShader(nullptr); // can't handle this xform
}
}
transformingPaint.setShader(make_post_inverse_lm(paint.getShader(), glyphToDevice));
this->setLocalToDevice(originalLocalToDevice * SkM44(glyphToDevice));