xref: /aosp_15_r20/external/skia/gm/bug12866.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkPath.h"
11 #include "include/core/SkPathUtils.h"
12 #include "src/base/SkFloatBits.h"
13 
get_path()14 static SkPath get_path() {
15     SkPath 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.
38 DEF_SIMPLE_GM(bug12866, canvas, 128, 64) {
39     SkPaint strokePaint;
40     strokePaint.setAntiAlias(true);
41     strokePaint.setStyle(SkPaint::kStroke_Style);
42     strokePaint.setStrokeWidth(3);
43 
44     SkPaint fillPaint;
45     fillPaint.setAntiAlias(true);
46 
47     SkPath strokePath = get_path();
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.
70 DEF_SIMPLE_GM(bug40810065, canvas, 256, 512) {
71     canvas->scale(2.f, 2.f);
72 
73     SkPath path1;
74     path1.moveTo(108.87f, 3.78f);
75     path1.cubicTo(201.1f, -128.61f, 34.21f, 82.54f, 134.14f, 126.01f);
76     SkPath path2;
77     path2.moveTo(108.87f, 3.78f);
78     path2.cubicTo(201.f, -128.61f, 34.21f, 82.54f, 134.14f, 126.f);
79 
80     SkPaint stroke;
81     stroke.setColor(SK_ColorBLACK);
82     stroke.setAntiAlias(true);
83     stroke.setStyle(SkPaint::kStroke_Style);
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.
100 DEF_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 
107     SkPath strokePath;
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 }
116