1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2011 Google Inc.
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */
75755a2a9ab531192fd26b523960ae0c551c7b24cturk@google.com
85546ef2dd9edad601383b85907f677118f857332reed@google.com#include "SkCanvas.h"
90650c6ca12e026201091f3e9ea9cbf0fed2b6da1reed@android.com#include "SkCubicClipper.h"
105755a2a9ab531192fd26b523960ae0c551c7b24cturk@google.com#include "SkGeometry.h"
118f6884aab8aecd7657cf3f9cdbc682f0deca29c5tfarina@chromium.org#include "SkPaint.h"
128f6884aab8aecd7657cf3f9cdbc682f0deca29c5tfarina@chromium.org#include "Test.h"
135755a2a9ab531192fd26b523960ae0c551c7b24cturk@google.com
145546ef2dd9edad601383b85907f677118f857332reed@google.com// Currently the supersampler blitter uses int16_t for its index into an array
155546ef2dd9edad601383b85907f677118f857332reed@google.com// the width of the clip. Test that we don't crash/assert if we try to draw
165546ef2dd9edad601383b85907f677118f857332reed@google.com// with a device/clip that is larger.
175546ef2dd9edad601383b85907f677118f857332reed@google.comstatic void test_giantClip() {
185546ef2dd9edad601383b85907f677118f857332reed@google.com    SkBitmap bm;
19fa9e5fa42a555712fb7a29d08d2ae2bdef0ed68ecommit-bot@chromium.org    bm.allocN32Pixels(64919, 1);
205546ef2dd9edad601383b85907f677118f857332reed@google.com    SkCanvas canvas(bm);
21dbfac8a72393eaf01670aeb3244de0e18d8faf98junov@google.com    canvas.clear(SK_ColorTRANSPARENT);
22d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
235546ef2dd9edad601383b85907f677118f857332reed@google.com    SkPath path;
245546ef2dd9edad601383b85907f677118f857332reed@google.com    path.moveTo(0, 0); path.lineTo(1, 0); path.lineTo(33, 1);
255546ef2dd9edad601383b85907f677118f857332reed@google.com    SkPaint paint;
265546ef2dd9edad601383b85907f677118f857332reed@google.com    paint.setAntiAlias(true);
275546ef2dd9edad601383b85907f677118f857332reed@google.com    canvas.drawPath(path, paint);
285546ef2dd9edad601383b85907f677118f857332reed@google.com}
295755a2a9ab531192fd26b523960ae0c551c7b24cturk@google.com
305755a2a9ab531192fd26b523960ae0c551c7b24cturk@google.comstatic void PrintCurve(const char *name, const SkPoint crv[4]) {
31fab44db294846ff05d837b9cf0bf97a073891da7bungeman@google.com    SkDebugf("%s: %.10g, %.10g, %.10g, %.10g, %.10g, %.10g, %.10g, %.10g\n",
325755a2a9ab531192fd26b523960ae0c551c7b24cturk@google.com            name,
33d41344553163085bfcfaf7d5882c6028934f8e3breed@android.com            (float)crv[0].fX, (float)crv[0].fY,
34d41344553163085bfcfaf7d5882c6028934f8e3breed@android.com            (float)crv[1].fX, (float)crv[1].fY,
35d41344553163085bfcfaf7d5882c6028934f8e3breed@android.com            (float)crv[2].fX, (float)crv[2].fY,
36d41344553163085bfcfaf7d5882c6028934f8e3breed@android.com            (float)crv[3].fX, (float)crv[3].fY);
377d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com
385755a2a9ab531192fd26b523960ae0c551c7b24cturk@google.com}
395755a2a9ab531192fd26b523960ae0c551c7b24cturk@google.com
405755a2a9ab531192fd26b523960ae0c551c7b24cturk@google.com
417d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.comstatic bool CurvesAreEqual(const SkPoint c0[4],
427d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com                           const SkPoint c1[4],
437d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com                           float tol) {
447d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    for (int i = 0; i < 4; i++) {
454b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org        if (SkScalarAbs(c0[i].fX - c1[i].fX) > tol ||
464b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org            SkScalarAbs(c0[i].fY - c1[i].fY) > tol
477d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com        ) {
487d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com            PrintCurve("c0", c0);
497d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com            PrintCurve("c1", c1);
507d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com            return false;
517d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com        }
527d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    }
537d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    return true;
545755a2a9ab531192fd26b523960ae0c551c7b24cturk@google.com}
555755a2a9ab531192fd26b523960ae0c551c7b24cturk@google.com
565755a2a9ab531192fd26b523960ae0c551c7b24cturk@google.com
577d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.comstatic SkPoint* SetCurve(float x0, float y0,
587d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com                         float x1, float y1,
597d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com                         float x2, float y2,
607d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com                         float x3, float y3,
617d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com                         SkPoint crv[4]) {
624b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org    crv[0].fX = x0;   crv[0].fY = y0;
634b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org    crv[1].fX = x1;   crv[1].fY = y1;
644b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org    crv[2].fX = x2;   crv[2].fY = y2;
654b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org    crv[3].fX = x3;   crv[3].fY = y3;
665755a2a9ab531192fd26b523960ae0c551c7b24cturk@google.com    return crv;
675755a2a9ab531192fd26b523960ae0c551c7b24cturk@google.com}
687d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com
695755a2a9ab531192fd26b523960ae0c551c7b24cturk@google.com
70e4fafb146e85cdfcf9d5418597b6818aa0754adatfarina@chromium.orgDEF_TEST(ClipCubic, reporter) {
717d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    static SkPoint crv[4] = {
72d41344553163085bfcfaf7d5882c6028934f8e3breed@android.com        { SkIntToScalar(0), SkIntToScalar(0)  },
73d41344553163085bfcfaf7d5882c6028934f8e3breed@android.com        { SkIntToScalar(2), SkIntToScalar(3)  },
74d41344553163085bfcfaf7d5882c6028934f8e3breed@android.com        { SkIntToScalar(1), SkIntToScalar(10) },
75d41344553163085bfcfaf7d5882c6028934f8e3breed@android.com        { SkIntToScalar(4), SkIntToScalar(12) }
767d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    };
777d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com
787d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    SkCubicClipper clipper;
797d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    SkPoint clipped[4], shouldbe[4];
807d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    SkIRect clipRect;
817d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    bool success;
824b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org    const float tol = 1e-4f;
837d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com
847d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    // Test no clip, with plenty of room.
857d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    clipRect.set(-2, -2, 6, 14);
867d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    clipper.setClip(clipRect);
877d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    success = clipper.clipCubic(crv, clipped);
887d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    REPORTER_ASSERT(reporter, success == true);
897d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
907d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com        0, 0, 2, 3, 1, 10, 4, 12, shouldbe), tol));
917d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com
927d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    // Test no clip, touching first point.
937d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    clipRect.set(-2, 0, 6, 14);
947d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    clipper.setClip(clipRect);
957d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    success = clipper.clipCubic(crv, clipped);
967d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    REPORTER_ASSERT(reporter, success == true);
977d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
987d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com        0, 0, 2, 3, 1, 10, 4, 12, shouldbe), tol));
997d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com
1007d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    // Test no clip, touching last point.
1017d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    clipRect.set(-2, -2, 6, 12);
1027d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    clipper.setClip(clipRect);
1037d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    success = clipper.clipCubic(crv, clipped);
1047d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    REPORTER_ASSERT(reporter, success == true);
1057d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
1067d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com        0, 0, 2, 3, 1, 10, 4, 12, shouldbe), tol));
1077d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com
1087d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    // Test all clip.
1097d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    clipRect.set(-2, 14, 6, 20);
1107d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    clipper.setClip(clipRect);
1117d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    success = clipper.clipCubic(crv, clipped);
1127d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    REPORTER_ASSERT(reporter, success == false);
1137d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com
1147d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    // Test clip at 1.
1157d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    clipRect.set(-2, 1, 6, 14);
1167d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    clipper.setClip(clipRect);
1177d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    success = clipper.clipCubic(crv, clipped);
1187d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    REPORTER_ASSERT(reporter, success == true);
1197d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
1206853e808a464ca75ff1328338d1eb55ff27c4337robertphillips@google.com        0.5126125216f, 1,
1216853e808a464ca75ff1328338d1eb55ff27c4337robertphillips@google.com        1.841195941f,  4.337081432f,
1226853e808a464ca75ff1328338d1eb55ff27c4337robertphillips@google.com        1.297019958f,  10.19801331f,
1237d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com        4,            12,
1247d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com        shouldbe), tol));
1257d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com
1267d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    // Test clip at 2.
1277d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    clipRect.set(-2, 2, 6, 14);
1287d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    clipper.setClip(clipRect);
1297d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    success = clipper.clipCubic(crv, clipped);
1307d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    REPORTER_ASSERT(reporter, success == true);
1317d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
1326853e808a464ca75ff1328338d1eb55ff27c4337robertphillips@google.com        00.8412352204f, 2,
1336853e808a464ca75ff1328338d1eb55ff27c4337robertphillips@google.com        1.767683744f,   5.400758266f,
1346853e808a464ca75ff1328338d1eb55ff27c4337robertphillips@google.com        1.55052948f,    10.36701965f,
1357d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com        4,             12,
1367d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com        shouldbe), tol));
1377d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com
1387d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    // Test clip at 11.
1397d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    clipRect.set(-2, -2, 6, 11);
1407d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    clipper.setClip(clipRect);
1417d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    success = clipper.clipCubic(crv, clipped);
1427d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    REPORTER_ASSERT(reporter, success == true);
1437d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
1447d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com        0,           0,
1456853e808a464ca75ff1328338d1eb55ff27c4337robertphillips@google.com        1.742904663f, 2.614356995f,
1466853e808a464ca75ff1328338d1eb55ff27c4337robertphillips@google.com        1.207521796f, 8.266430855f,
1476853e808a464ca75ff1328338d1eb55ff27c4337robertphillips@google.com        3.026495695f, 11,
1487d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com        shouldbe), tol));
1497d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com
1507d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    // Test clip at 10.
1517d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    clipRect.set(-2, -2, 6, 10);
1527d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    clipper.setClip(clipRect);
1537d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    success = clipper.clipCubic(crv, clipped);
1547d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    REPORTER_ASSERT(reporter, success == true);
1557d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com    REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
1567d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com        0,           0,
1576853e808a464ca75ff1328338d1eb55ff27c4337robertphillips@google.com        1.551193237f, 2.326789856f,
1586853e808a464ca75ff1328338d1eb55ff27c4337robertphillips@google.com        1.297736168f, 7.059780121f,
1596853e808a464ca75ff1328338d1eb55ff27c4337robertphillips@google.com        2.505550385f, 10,
1607d3a58a5e442e0aba239616a4e996e64866ffbd0turk@google.com        shouldbe), tol));
1615546ef2dd9edad601383b85907f677118f857332reed@google.com
1625546ef2dd9edad601383b85907f677118f857332reed@google.com    test_giantClip();
1635755a2a9ab531192fd26b523960ae0c551c7b24cturk@google.com}
164