1/*
2 * Copyright 2011 Google Inc.
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 "SkCanvas.h"
9#include "SkCubicClipper.h"
10#include "SkGeometry.h"
11#include "SkPaint.h"
12#include "Test.h"
13
14// Currently the supersampler blitter uses int16_t for its index into an array
15// the width of the clip. Test that we don't crash/assert if we try to draw
16// with a device/clip that is larger.
17static void test_giantClip() {
18    SkBitmap bm;
19    bm.allocN32Pixels(64919, 1);
20    SkCanvas canvas(bm);
21    canvas.clear(SK_ColorTRANSPARENT);
22
23    SkPath path;
24    path.moveTo(0, 0); path.lineTo(1, 0); path.lineTo(33, 1);
25    SkPaint paint;
26    paint.setAntiAlias(true);
27    canvas.drawPath(path, paint);
28}
29
30static void PrintCurve(const char *name, const SkPoint crv[4]) {
31    SkDebugf("%s: %.10g, %.10g, %.10g, %.10g, %.10g, %.10g, %.10g, %.10g\n",
32            name,
33            (float)crv[0].fX, (float)crv[0].fY,
34            (float)crv[1].fX, (float)crv[1].fY,
35            (float)crv[2].fX, (float)crv[2].fY,
36            (float)crv[3].fX, (float)crv[3].fY);
37
38}
39
40
41static bool CurvesAreEqual(const SkPoint c0[4],
42                           const SkPoint c1[4],
43                           float tol) {
44    for (int i = 0; i < 4; i++) {
45        if (SkScalarAbs(c0[i].fX - c1[i].fX) > tol ||
46            SkScalarAbs(c0[i].fY - c1[i].fY) > tol
47        ) {
48            PrintCurve("c0", c0);
49            PrintCurve("c1", c1);
50            return false;
51        }
52    }
53    return true;
54}
55
56
57static SkPoint* SetCurve(float x0, float y0,
58                         float x1, float y1,
59                         float x2, float y2,
60                         float x3, float y3,
61                         SkPoint crv[4]) {
62    crv[0].fX = x0;   crv[0].fY = y0;
63    crv[1].fX = x1;   crv[1].fY = y1;
64    crv[2].fX = x2;   crv[2].fY = y2;
65    crv[3].fX = x3;   crv[3].fY = y3;
66    return crv;
67}
68
69
70DEF_TEST(ClipCubic, reporter) {
71    static SkPoint crv[4] = {
72        { SkIntToScalar(0), SkIntToScalar(0)  },
73        { SkIntToScalar(2), SkIntToScalar(3)  },
74        { SkIntToScalar(1), SkIntToScalar(10) },
75        { SkIntToScalar(4), SkIntToScalar(12) }
76    };
77
78    SkCubicClipper clipper;
79    SkPoint clipped[4], shouldbe[4];
80    SkIRect clipRect;
81    bool success;
82    const float tol = 1e-4f;
83
84    // Test no clip, with plenty of room.
85    clipRect.set(-2, -2, 6, 14);
86    clipper.setClip(clipRect);
87    success = clipper.clipCubic(crv, clipped);
88    REPORTER_ASSERT(reporter, success == true);
89    REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
90        0, 0, 2, 3, 1, 10, 4, 12, shouldbe), tol));
91
92    // Test no clip, touching first point.
93    clipRect.set(-2, 0, 6, 14);
94    clipper.setClip(clipRect);
95    success = clipper.clipCubic(crv, clipped);
96    REPORTER_ASSERT(reporter, success == true);
97    REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
98        0, 0, 2, 3, 1, 10, 4, 12, shouldbe), tol));
99
100    // Test no clip, touching last point.
101    clipRect.set(-2, -2, 6, 12);
102    clipper.setClip(clipRect);
103    success = clipper.clipCubic(crv, clipped);
104    REPORTER_ASSERT(reporter, success == true);
105    REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
106        0, 0, 2, 3, 1, 10, 4, 12, shouldbe), tol));
107
108    // Test all clip.
109    clipRect.set(-2, 14, 6, 20);
110    clipper.setClip(clipRect);
111    success = clipper.clipCubic(crv, clipped);
112    REPORTER_ASSERT(reporter, success == false);
113
114    // Test clip at 1.
115    clipRect.set(-2, 1, 6, 14);
116    clipper.setClip(clipRect);
117    success = clipper.clipCubic(crv, clipped);
118    REPORTER_ASSERT(reporter, success == true);
119    REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
120        0.5126125216f, 1,
121        1.841195941f,  4.337081432f,
122        1.297019958f,  10.19801331f,
123        4,            12,
124        shouldbe), tol));
125
126    // Test clip at 2.
127    clipRect.set(-2, 2, 6, 14);
128    clipper.setClip(clipRect);
129    success = clipper.clipCubic(crv, clipped);
130    REPORTER_ASSERT(reporter, success == true);
131    REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
132        00.8412352204f, 2,
133        1.767683744f,   5.400758266f,
134        1.55052948f,    10.36701965f,
135        4,             12,
136        shouldbe), tol));
137
138    // Test clip at 11.
139    clipRect.set(-2, -2, 6, 11);
140    clipper.setClip(clipRect);
141    success = clipper.clipCubic(crv, clipped);
142    REPORTER_ASSERT(reporter, success == true);
143    REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
144        0,           0,
145        1.742904663f, 2.614356995f,
146        1.207521796f, 8.266430855f,
147        3.026495695f, 11,
148        shouldbe), tol));
149
150    // Test clip at 10.
151    clipRect.set(-2, -2, 6, 10);
152    clipper.setClip(clipRect);
153    success = clipper.clipCubic(crv, clipped);
154    REPORTER_ASSERT(reporter, success == true);
155    REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
156        0,           0,
157        1.551193237f, 2.326789856f,
158        1.297736168f, 7.059780121f,
159        2.505550385f, 10,
160        shouldbe), tol));
161
162    test_giantClip();
163}
164