blob: 45e8568a47dbcfd4afd1743bb8716d0d5144d410 [file] [log] [blame]
/*
* Copyright 2022 Google LLC
*
* 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/SkCanvas.h"
#include "include/core/SkPath.h"
#include "include/core/SkPathUtils.h"
#include "src/base/SkFloatBits.h"
static SkPath get_path() {
SkPath path;
path.setFillType(SkPathFillType::kWinding);
path.moveTo(SkBits2Float(0x45034ec4), SkBits2Float(0x42e7fb80)); // 2100.92f, 115.991f
path.quadTo(SkBits2Float(0x4500f46c),
SkBits2Float(0x43333300),
SkBits2Float(0x4500f46c),
SkBits2Float(0x431f0ec0)); // 2063.28f, 179.199f, 2063.28f, 159.058f
path.quadTo(SkBits2Float(0x4500f46c),
SkBits2Float(0x430ad7c0),
SkBits2Float(0x45019462),
SkBits2Float(0x42fed580)); // 2063.28f, 138.843f, 2073.27f, 127.417f
path.quadTo(SkBits2Float(0x45023458),
SkBits2Float(0x42e7fb80),
SkBits2Float(0x45034ec4),
SkBits2Float(0x42e7fb80)); // 2083.27f, 115.991f, 2100.92f, 115.991f
path.close();
return path;
}
// Reproduces the underlying problem from skbug.com/12866.
// The path (part of a glyph) was being drawn stroked, and with a perspective matrix.
// The perspective matrix forces a very large resScale when stroking the path.
// The resulting filled path is incorrect. Note that stroking with a smaller resScale works fine.
DEF_SIMPLE_GM(bug12866, canvas, 128, 64) {
SkPaint strokePaint;
strokePaint.setAntiAlias(true);
strokePaint.setStyle(SkPaint::kStroke_Style);
strokePaint.setStrokeWidth(3);
SkPaint fillPaint;
fillPaint.setAntiAlias(true);
SkPath strokePath = get_path();
SkPath fillPath;
skpathutils::FillPathWithPaint(strokePath, strokePaint, &fillPath, nullptr, 1200.0f);
SkRect strokeBounds = strokePath.getBounds();
SkRect fillBounds = fillPath.getBounds();
// Draw the stroked path. This (internally) uses a resScale of 1.0, and looks good.
canvas->save();
canvas->translate(10 - strokeBounds.fLeft, 10 - strokeBounds.fTop);
canvas->drawPath(strokePath, strokePaint);
canvas->restore();
// With a perspective CTM, it's possible for resScale to become large. Draw the filled
// path produced by the stroker in that situation, which ends up being incorrect.
canvas->save();
canvas->translate(74 - fillBounds.fLeft, 10 - fillBounds.fTop);
canvas->drawPath(fillPath, fillPaint);
canvas->restore();
}
// This is another example of the same underlying bug (recursion limit in the stroker),
// but with cubics, rather than quads.
DEF_SIMPLE_GM(bug40810065, canvas, 256, 512) {
canvas->scale(2.f, 2.f);
SkPath path1;
path1.moveTo(108.87f, 3.78f);
path1.cubicTo(201.1f, -128.61f, 34.21f, 82.54f, 134.14f, 126.01f);
SkPath path2;
path2.moveTo(108.87f, 3.78f);
path2.cubicTo(201.f, -128.61f, 34.21f, 82.54f, 134.14f, 126.f);
SkPaint stroke;
stroke.setColor(SK_ColorBLACK);
stroke.setAntiAlias(true);
stroke.setStyle(SkPaint::kStroke_Style);
stroke.setStrokeWidth(1.f);
stroke.setStrokeCap(SkPaint::kRound_Cap);
canvas->save();
canvas->translate(-75.f, 50.f);
canvas->drawPath(path1, stroke);
canvas->restore();
canvas->save();
canvas->translate(-20.f, 100.f);
canvas->drawPath(path2, stroke);
canvas->restore();
}
// Finally: A repro case that involves conics. This should draw NOTHING. When incorrect, it drew
// a large black rectangle over half of the slide.
DEF_SIMPLE_GM_BG(bug41422450, canvas, 863, 473, SK_ColorWHITE) {
SkM44 mat{1, -0.00000139566271f, 0, -2321738,
0.000113059919f, 0.0123444516f, 0, -353,
0, 0, 1, 0,
0, 0, 0, 1};
canvas->concat(mat);
SkPath strokePath;
SkRect circle = SkRect::MakeLTRB(-3299135.5f, -12312541.0f, 9897407.0f, 884000.812f);
strokePath.arcTo(circle, 59.9999962f, 59.9999962f, true);
SkPaint strokePaint;
strokePaint.setStyle(SkPaint::kStroke_Style);
strokePaint.setStrokeWidth(2);
canvas->drawPath(strokePath, strokePaint);
}