1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2012 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "include/core/SkPaint.h"
9cb93a386Sopenharmony_ci#include "include/core/SkPath.h"
10cb93a386Sopenharmony_ci#include "include/core/SkRect.h"
11cb93a386Sopenharmony_ci#include "include/core/SkStrokeRec.h"
12cb93a386Sopenharmony_ci#include "src/core/SkPathPriv.h"
13cb93a386Sopenharmony_ci#include "src/core/SkStroke.h"
14cb93a386Sopenharmony_ci#include "tests/Test.h"
15cb93a386Sopenharmony_ci
16cb93a386Sopenharmony_cistatic bool equal(const SkRect& a, const SkRect& b) {
17cb93a386Sopenharmony_ci    return  SkScalarNearlyEqual(a.left(), b.left()) &&
18cb93a386Sopenharmony_ci            SkScalarNearlyEqual(a.top(), b.top()) &&
19cb93a386Sopenharmony_ci            SkScalarNearlyEqual(a.right(), b.right()) &&
20cb93a386Sopenharmony_ci            SkScalarNearlyEqual(a.bottom(), b.bottom());
21cb93a386Sopenharmony_ci}
22cb93a386Sopenharmony_ci
23cb93a386Sopenharmony_cistatic void test_strokecubic(skiatest::Reporter* reporter) {
24cb93a386Sopenharmony_ci    uint32_t hexCubicVals[] = {
25cb93a386Sopenharmony_ci        0x424c1086, 0x44bcf0cb,  // fX=51.0161362 fY=1511.52478
26cb93a386Sopenharmony_ci        0x424c107c, 0x44bcf0cb,  // fX=51.0160980 fY=1511.52478
27cb93a386Sopenharmony_ci        0x424c10c2, 0x44bcf0cb,  // fX=51.0163651 fY=1511.52478
28cb93a386Sopenharmony_ci        0x424c1119, 0x44bcf0ca,  // fX=51.0166969 fY=1511.52466
29cb93a386Sopenharmony_ci    };
30cb93a386Sopenharmony_ci    SkPoint cubicVals[] = {
31cb93a386Sopenharmony_ci        {51.0161362f, 1511.52478f },
32cb93a386Sopenharmony_ci        {51.0160980f, 1511.52478f },
33cb93a386Sopenharmony_ci        {51.0163651f, 1511.52478f },
34cb93a386Sopenharmony_ci        {51.0166969f, 1511.52466f },
35cb93a386Sopenharmony_ci    };
36cb93a386Sopenharmony_ci    SkPaint paint;
37cb93a386Sopenharmony_ci
38cb93a386Sopenharmony_ci    paint.setStyle(SkPaint::kStroke_Style);
39cb93a386Sopenharmony_ci    paint.setStrokeWidth(0.394537568f);
40cb93a386Sopenharmony_ci    SkPath path, fillPath;
41cb93a386Sopenharmony_ci    path.moveTo(cubicVals[0]);
42cb93a386Sopenharmony_ci    path.cubicTo(cubicVals[1], cubicVals[2], cubicVals[3]);
43cb93a386Sopenharmony_ci    paint.getFillPath(path, &fillPath);
44cb93a386Sopenharmony_ci    path.reset();
45cb93a386Sopenharmony_ci    path.moveTo(SkBits2Float(hexCubicVals[0]), SkBits2Float(hexCubicVals[1]));
46cb93a386Sopenharmony_ci    path.cubicTo(SkBits2Float(hexCubicVals[2]), SkBits2Float(hexCubicVals[3]),
47cb93a386Sopenharmony_ci            SkBits2Float(hexCubicVals[4]), SkBits2Float(hexCubicVals[5]),
48cb93a386Sopenharmony_ci            SkBits2Float(hexCubicVals[6]), SkBits2Float(hexCubicVals[7]));
49cb93a386Sopenharmony_ci    paint.getFillPath(path, &fillPath);
50cb93a386Sopenharmony_ci}
51cb93a386Sopenharmony_ci
52cb93a386Sopenharmony_cistatic void test_strokerect(skiatest::Reporter* reporter) {
53cb93a386Sopenharmony_ci    const SkScalar width = SkIntToScalar(10);
54cb93a386Sopenharmony_ci    SkPaint paint;
55cb93a386Sopenharmony_ci
56cb93a386Sopenharmony_ci    paint.setStyle(SkPaint::kStroke_Style);
57cb93a386Sopenharmony_ci    paint.setStrokeWidth(width);
58cb93a386Sopenharmony_ci
59cb93a386Sopenharmony_ci    SkRect r = { 0, 0, SkIntToScalar(200), SkIntToScalar(100) };
60cb93a386Sopenharmony_ci
61cb93a386Sopenharmony_ci    SkRect outer(r);
62cb93a386Sopenharmony_ci    outer.outset(width/2, width/2);
63cb93a386Sopenharmony_ci
64cb93a386Sopenharmony_ci    static const SkPaint::Join joins[] = {
65cb93a386Sopenharmony_ci        SkPaint::kMiter_Join, SkPaint::kRound_Join, SkPaint::kBevel_Join
66cb93a386Sopenharmony_ci    };
67cb93a386Sopenharmony_ci
68cb93a386Sopenharmony_ci    for (size_t i = 0; i < SK_ARRAY_COUNT(joins); ++i) {
69cb93a386Sopenharmony_ci        paint.setStrokeJoin(joins[i]);
70cb93a386Sopenharmony_ci
71cb93a386Sopenharmony_ci        SkPath path, fillPath;
72cb93a386Sopenharmony_ci        path.addRect(r);
73cb93a386Sopenharmony_ci        paint.getFillPath(path, &fillPath);
74cb93a386Sopenharmony_ci
75cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, equal(outer, fillPath.getBounds()));
76cb93a386Sopenharmony_ci
77cb93a386Sopenharmony_ci        bool isMiter = SkPaint::kMiter_Join == joins[i];
78cb93a386Sopenharmony_ci        SkRect nested[2];
79cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, SkPathPriv::IsNestedFillRects(fillPath, nested) == isMiter);
80cb93a386Sopenharmony_ci        if (isMiter) {
81cb93a386Sopenharmony_ci            SkRect inner(r);
82cb93a386Sopenharmony_ci            inner.inset(width/2, width/2);
83cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, equal(nested[0], outer));
84cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, equal(nested[1], inner));
85cb93a386Sopenharmony_ci        }
86cb93a386Sopenharmony_ci    }
87cb93a386Sopenharmony_ci}
88cb93a386Sopenharmony_ci
89cb93a386Sopenharmony_cistatic void test_strokerec_equality(skiatest::Reporter* reporter) {
90cb93a386Sopenharmony_ci    {
91cb93a386Sopenharmony_ci        SkStrokeRec s1(SkStrokeRec::kFill_InitStyle);
92cb93a386Sopenharmony_ci        SkStrokeRec s2(SkStrokeRec::kFill_InitStyle);
93cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
94cb93a386Sopenharmony_ci
95cb93a386Sopenharmony_ci        // Test that style mismatch is detected.
96cb93a386Sopenharmony_ci        s2.setHairlineStyle();
97cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, !s1.hasEqualEffect(s2));
98cb93a386Sopenharmony_ci
99cb93a386Sopenharmony_ci        s1.setHairlineStyle();
100cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
101cb93a386Sopenharmony_ci
102cb93a386Sopenharmony_ci        // ResScale is not part of equality.
103cb93a386Sopenharmony_ci        s1.setResScale(2.1f);
104cb93a386Sopenharmony_ci        s2.setResScale(1.2f);
105cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
106cb93a386Sopenharmony_ci        s1.setFillStyle();
107cb93a386Sopenharmony_ci        s2.setFillStyle();
108cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
109cb93a386Sopenharmony_ci        s1.setStrokeStyle(1.0f, false);
110cb93a386Sopenharmony_ci        s2.setStrokeStyle(1.0f, false);
111cb93a386Sopenharmony_ci        s1.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kRound_Join, 2.9f);
112cb93a386Sopenharmony_ci        s2.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kRound_Join, 2.9f);
113cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
114cb93a386Sopenharmony_ci    }
115cb93a386Sopenharmony_ci
116cb93a386Sopenharmony_ci    // Stroke parameters on fill or hairline style are not part of equality.
117cb93a386Sopenharmony_ci    {
118cb93a386Sopenharmony_ci        SkStrokeRec s1(SkStrokeRec::kFill_InitStyle);
119cb93a386Sopenharmony_ci        SkStrokeRec s2(SkStrokeRec::kFill_InitStyle);
120cb93a386Sopenharmony_ci        for (int i = 0; i < 2; ++i) {
121cb93a386Sopenharmony_ci            s1.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kRound_Join, 2.9f);
122cb93a386Sopenharmony_ci            s2.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kRound_Join, 2.1f);
123cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
124cb93a386Sopenharmony_ci            s2.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kBevel_Join, 2.9f);
125cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
126cb93a386Sopenharmony_ci            s2.setStrokeParams(SkPaint::kRound_Cap, SkPaint::kRound_Join, 2.9f);
127cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
128cb93a386Sopenharmony_ci            s1.setHairlineStyle();
129cb93a386Sopenharmony_ci            s2.setHairlineStyle();
130cb93a386Sopenharmony_ci        }
131cb93a386Sopenharmony_ci    }
132cb93a386Sopenharmony_ci
133cb93a386Sopenharmony_ci    // Stroke parameters on stroke style are part of equality.
134cb93a386Sopenharmony_ci    {
135cb93a386Sopenharmony_ci        SkStrokeRec s1(SkStrokeRec::kFill_InitStyle);
136cb93a386Sopenharmony_ci        SkStrokeRec s2(SkStrokeRec::kFill_InitStyle);
137cb93a386Sopenharmony_ci        s1.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kRound_Join, 2.9f);
138cb93a386Sopenharmony_ci        s2.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kRound_Join, 2.9f);
139cb93a386Sopenharmony_ci        s1.setStrokeStyle(1.0f, false);
140cb93a386Sopenharmony_ci
141cb93a386Sopenharmony_ci        s2.setStrokeStyle(1.0f, true);
142cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, !s1.hasEqualEffect(s2));
143cb93a386Sopenharmony_ci
144cb93a386Sopenharmony_ci        s2.setStrokeStyle(2.1f, false);
145cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, !s1.hasEqualEffect(s2));
146cb93a386Sopenharmony_ci
147cb93a386Sopenharmony_ci        s2.setStrokeStyle(1.0f, false);
148cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
149cb93a386Sopenharmony_ci
150cb93a386Sopenharmony_ci        s2.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kRound_Join, 2.1f);
151cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));  // Miter limit not relevant to butt caps.
152cb93a386Sopenharmony_ci        s2.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kBevel_Join, 2.9f);
153cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, !s1.hasEqualEffect(s2));
154cb93a386Sopenharmony_ci        s2.setStrokeParams(SkPaint::kRound_Cap, SkPaint::kRound_Join, 2.9f);
155cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, !s1.hasEqualEffect(s2));
156cb93a386Sopenharmony_ci
157cb93a386Sopenharmony_ci        // Sets fill.
158cb93a386Sopenharmony_ci        s1.setStrokeStyle(0.0f, true);
159cb93a386Sopenharmony_ci        s2.setStrokeStyle(0.0f, true);
160cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
161cb93a386Sopenharmony_ci    }
162cb93a386Sopenharmony_ci}
163cb93a386Sopenharmony_ci
164cb93a386Sopenharmony_ci// From skbug.com/6491. The large stroke width can cause numerical instabilities.
165cb93a386Sopenharmony_cistatic void test_big_stroke(skiatest::Reporter* reporter) {
166cb93a386Sopenharmony_ci    SkPaint paint;
167cb93a386Sopenharmony_ci    paint.setStyle(SkPaint::kStrokeAndFill_Style);
168cb93a386Sopenharmony_ci    paint.setStrokeWidth(1.49679073e+10f);
169cb93a386Sopenharmony_ci
170cb93a386Sopenharmony_ci    SkPath path;
171cb93a386Sopenharmony_ci    path.moveTo(SkBits2Float(0x46380000), SkBits2Float(0xc6380000));  // 11776, -11776
172cb93a386Sopenharmony_ci    path.lineTo(SkBits2Float(0x46a00000), SkBits2Float(0xc6a00000));  // 20480, -20480
173cb93a386Sopenharmony_ci    path.lineTo(SkBits2Float(0x468c0000), SkBits2Float(0xc68c0000));  // 17920, -17920
174cb93a386Sopenharmony_ci    path.lineTo(SkBits2Float(0x46100000), SkBits2Float(0xc6100000));  // 9216, -9216
175cb93a386Sopenharmony_ci    path.lineTo(SkBits2Float(0x46380000), SkBits2Float(0xc6380000));  // 11776, -11776
176cb93a386Sopenharmony_ci    path.close();
177cb93a386Sopenharmony_ci
178cb93a386Sopenharmony_ci    SkPath strokeAndFillPath;
179cb93a386Sopenharmony_ci    paint.getFillPath(path, &strokeAndFillPath);
180cb93a386Sopenharmony_ci}
181cb93a386Sopenharmony_ci
182cb93a386Sopenharmony_ciDEF_TEST(Stroke, reporter) {
183cb93a386Sopenharmony_ci    test_strokecubic(reporter);
184cb93a386Sopenharmony_ci    test_strokerect(reporter);
185cb93a386Sopenharmony_ci    test_strokerec_equality(reporter);
186cb93a386Sopenharmony_ci    test_big_stroke(reporter);
187cb93a386Sopenharmony_ci}
188