Flutter Engine
The Flutter Engine
bug12866.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2022 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "gm/gm.h"
10#include "include/core/SkPath.h"
13
14static SkPath get_path() {
16 path.setFillType(SkPathFillType::kWinding);
17 path.moveTo(SkBits2Float(0x45034ec4), SkBits2Float(0x42e7fb80)); // 2100.92f, 115.991f
18 path.quadTo(SkBits2Float(0x4500f46c),
19 SkBits2Float(0x43333300),
20 SkBits2Float(0x4500f46c),
21 SkBits2Float(0x431f0ec0)); // 2063.28f, 179.199f, 2063.28f, 159.058f
22 path.quadTo(SkBits2Float(0x4500f46c),
23 SkBits2Float(0x430ad7c0),
24 SkBits2Float(0x45019462),
25 SkBits2Float(0x42fed580)); // 2063.28f, 138.843f, 2073.27f, 127.417f
26 path.quadTo(SkBits2Float(0x45023458),
27 SkBits2Float(0x42e7fb80),
28 SkBits2Float(0x45034ec4),
29 SkBits2Float(0x42e7fb80)); // 2083.27f, 115.991f, 2100.92f, 115.991f
30 path.close();
31 return path;
32}
33
34// Reproduces the underlying problem from skbug.com/12866.
35// The path (part of a glyph) was being drawn stroked, and with a perspective matrix.
36// The perspective matrix forces a very large resScale when stroking the path.
37// The resulting filled path is incorrect. Note that stroking with a smaller resScale works fine.
38DEF_SIMPLE_GM(bug12866, canvas, 128, 64) {
39 SkPaint strokePaint;
40 strokePaint.setAntiAlias(true);
42 strokePaint.setStrokeWidth(3);
43
44 SkPaint fillPaint;
45 fillPaint.setAntiAlias(true);
46
48 SkPath fillPath;
49 skpathutils::FillPathWithPaint(strokePath, strokePaint, &fillPath, nullptr, 1200.0f);
50
51 SkRect strokeBounds = strokePath.getBounds();
52 SkRect fillBounds = fillPath.getBounds();
53
54 // Draw the stroked path. This (internally) uses a resScale of 1.0, and looks good.
55 canvas->save();
56 canvas->translate(10 - strokeBounds.fLeft, 10 - strokeBounds.fTop);
57 canvas->drawPath(strokePath, strokePaint);
58 canvas->restore();
59
60 // With a perspective CTM, it's possible for resScale to become large. Draw the filled
61 // path produced by the stroker in that situation, which ends up being incorrect.
62 canvas->save();
63 canvas->translate(74 - fillBounds.fLeft, 10 - fillBounds.fTop);
64 canvas->drawPath(fillPath, fillPaint);
65 canvas->restore();
66}
67
68// This is another example of the same underlying bug (recursion limit in the stroker),
69// but with cubics, rather than quads.
70DEF_SIMPLE_GM(bug40810065, canvas, 256, 512) {
71 canvas->scale(2.f, 2.f);
72
74 path1.moveTo(108.87f, 3.78f);
75 path1.cubicTo(201.1f, -128.61f, 34.21f, 82.54f, 134.14f, 126.01f);
77 path2.moveTo(108.87f, 3.78f);
78 path2.cubicTo(201.f, -128.61f, 34.21f, 82.54f, 134.14f, 126.f);
79
81 stroke.setColor(SK_ColorBLACK);
82 stroke.setAntiAlias(true);
84 stroke.setStrokeWidth(1.f);
85 stroke.setStrokeCap(SkPaint::kRound_Cap);
86
87 canvas->save();
88 canvas->translate(-75.f, 50.f);
89 canvas->drawPath(path1, stroke);
90 canvas->restore();
91
92 canvas->save();
93 canvas->translate(-20.f, 100.f);
94 canvas->drawPath(path2, stroke);
95 canvas->restore();
96}
97
98// Finally: A repro case that involves conics. This should draw NOTHING. When incorrect, it drew
99// a large black rectangle over half of the slide.
100DEF_SIMPLE_GM_BG(bug41422450, canvas, 863, 473, SK_ColorWHITE) {
101 SkM44 mat{1, -0.00000139566271f, 0, -2321738,
102 0.000113059919f, 0.0123444516f, 0, -353,
103 0, 0, 1, 0,
104 0, 0, 0, 1};
105 canvas->concat(mat);
106
108 SkRect circle = SkRect::MakeLTRB(-3299135.5f, -12312541.0f, 9897407.0f, 884000.812f);
109 strokePath.arcTo(circle, 59.9999962f, 59.9999962f, true);
110
111 SkPaint strokePaint;
112 strokePaint.setStyle(SkPaint::kStroke_Style);
113 strokePaint.setStrokeWidth(2);
114 canvas->drawPath(strokePath, strokePaint);
115}
static SkPath path1()
static SkPath path2()
constexpr SkColor SK_ColorBLACK
Definition: SkColor.h:103
constexpr SkColor SK_ColorWHITE
Definition: SkColor.h:122
static float SkBits2Float(uint32_t bits)
Definition: SkFloatBits.h:48
DEF_SIMPLE_GM_BG(bug41422450, canvas, 863, 473, SK_ColorWHITE)
Definition: bug12866.cpp:100
static SkPath get_path()
Definition: bug12866.cpp:14
DEF_SIMPLE_GM(bug12866, canvas, 128, 64)
Definition: bug12866.cpp:38
Definition: SkM44.h:150
@ kRound_Cap
adds circle
Definition: SkPaint.h:335
void setStyle(Style style)
Definition: SkPaint.cpp:105
void setAntiAlias(bool aa)
Definition: SkPaint.h:170
@ kStroke_Style
set to stroke geometry
Definition: SkPaint.h:194
void setStrokeWidth(SkScalar width)
Definition: SkPaint.cpp:159
Definition: SkPath.h:59
SkPath & moveTo(SkScalar x, SkScalar y)
Definition: SkPath.cpp:688
const SkRect & getBounds() const
Definition: SkPath.cpp:430
SkPath & cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar x3, SkScalar y3)
Definition: SkPath.cpp:799
static void strokePath(SkCanvas *canvas, const SkPath &path)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
SK_API bool FillPathWithPaint(const SkPath &src, const SkPaint &paint, SkPath *dst, const SkRect *cullRect, SkScalar resScale=1)
Definition: SkPathUtils.cpp:23
SkScalar fLeft
smaller x-axis bounds
Definition: extension.cpp:14
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)
Definition: SkRect.h:646
SkScalar fTop
smaller y-axis bounds
Definition: extension.cpp:15