1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2011 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/SkBitmap.h" 9cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 10cb93a386Sopenharmony_ci#include "include/core/SkColor.h" 11cb93a386Sopenharmony_ci#include "include/core/SkPaint.h" 12cb93a386Sopenharmony_ci#include "include/core/SkPoint.h" 13cb93a386Sopenharmony_ci#include "include/core/SkRect.h" 14cb93a386Sopenharmony_ci#include "include/core/SkScalar.h" 15cb93a386Sopenharmony_ci#include "include/core/SkTypes.h" 16cb93a386Sopenharmony_ci#include "src/core/SkEdgeClipper.h" 17cb93a386Sopenharmony_ci#include "src/core/SkLineClipper.h" 18cb93a386Sopenharmony_ci#include "tests/Test.h" 19cb93a386Sopenharmony_ci 20cb93a386Sopenharmony_ci#include <cstring> 21cb93a386Sopenharmony_ci 22cb93a386Sopenharmony_cistatic void test_hairclipping(skiatest::Reporter* reporter) { 23cb93a386Sopenharmony_ci SkBitmap bm; 24cb93a386Sopenharmony_ci bm.allocN32Pixels(4, 4); 25cb93a386Sopenharmony_ci bm.eraseColor(SK_ColorWHITE); 26cb93a386Sopenharmony_ci 27cb93a386Sopenharmony_ci SkPaint paint; 28cb93a386Sopenharmony_ci paint.setAntiAlias(true); 29cb93a386Sopenharmony_ci 30cb93a386Sopenharmony_ci SkCanvas canvas(bm); 31cb93a386Sopenharmony_ci canvas.clipRect(SkRect::MakeWH(SkIntToScalar(4), SkIntToScalar(2))); 32cb93a386Sopenharmony_ci canvas.drawLine(1.5f, 1.5f, 33cb93a386Sopenharmony_ci 3.5f, 3.5f, paint); 34cb93a386Sopenharmony_ci 35cb93a386Sopenharmony_ci /** 36cb93a386Sopenharmony_ci * We had a bug where we misinterpreted the bottom of the clip, and 37cb93a386Sopenharmony_ci * would draw another pixel (to the right in this case) on the same 38cb93a386Sopenharmony_ci * last scanline. i.e. we would draw to [2,1], even though this hairline 39cb93a386Sopenharmony_ci * should just draw to [1,1], [2,2], [3,3] modulo the clip. 40cb93a386Sopenharmony_ci * 41cb93a386Sopenharmony_ci * The result of this entire draw should be that we only draw to [1,1] 42cb93a386Sopenharmony_ci * 43cb93a386Sopenharmony_ci * Fixed in rev. 3366 44cb93a386Sopenharmony_ci */ 45cb93a386Sopenharmony_ci for (int y = 0; y < 4; ++y) { 46cb93a386Sopenharmony_ci for (int x = 0; x < 4; ++x) { 47cb93a386Sopenharmony_ci bool nonWhite = (1 == y) && (1 == x); 48cb93a386Sopenharmony_ci SkPMColor c = *bm.getAddr32(x, y); 49cb93a386Sopenharmony_ci if (nonWhite) { 50cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0xFFFFFFFF != c); 51cb93a386Sopenharmony_ci } else { 52cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0xFFFFFFFF == c); 53cb93a386Sopenharmony_ci } 54cb93a386Sopenharmony_ci } 55cb93a386Sopenharmony_ci } 56cb93a386Sopenharmony_ci} 57cb93a386Sopenharmony_ci 58cb93a386Sopenharmony_cistatic void test_edgeclipper() { 59cb93a386Sopenharmony_ci SkEdgeClipper clipper(false); 60cb93a386Sopenharmony_ci 61cb93a386Sopenharmony_ci const SkPoint pts[] = { 62cb93a386Sopenharmony_ci { 3.0995476e+010f, 42.929779f }, 63cb93a386Sopenharmony_ci { -3.0995163e+010f, 51.050385f }, 64cb93a386Sopenharmony_ci { -3.0995157e+010f, 51.050392f }, 65cb93a386Sopenharmony_ci { -3.0995134e+010f, 51.050400f }, 66cb93a386Sopenharmony_ci }; 67cb93a386Sopenharmony_ci 68cb93a386Sopenharmony_ci const SkRect clip = { 0, 0, SkIntToScalar(300), SkIntToScalar(200) }; 69cb93a386Sopenharmony_ci 70cb93a386Sopenharmony_ci // this should not assert, even though our choppers do a poor numerical 71cb93a386Sopenharmony_ci // job when computing their t values. 72cb93a386Sopenharmony_ci // http://code.google.com/p/skia/issues/detail?id=444 73cb93a386Sopenharmony_ci clipper.clipCubic(pts, clip); 74cb93a386Sopenharmony_ci} 75cb93a386Sopenharmony_ci 76cb93a386Sopenharmony_cistatic void test_intersectline(skiatest::Reporter* reporter) { 77cb93a386Sopenharmony_ci static const SkScalar L = 0; 78cb93a386Sopenharmony_ci static const SkScalar T = 0; 79cb93a386Sopenharmony_ci static const SkScalar R = SkIntToScalar(100); 80cb93a386Sopenharmony_ci static const SkScalar B = SkIntToScalar(100); 81cb93a386Sopenharmony_ci static const SkScalar CX = SkScalarHalf(L + R); 82cb93a386Sopenharmony_ci static const SkScalar CY = SkScalarHalf(T + B); 83cb93a386Sopenharmony_ci static const SkRect gR = { L, T, R, B }; 84cb93a386Sopenharmony_ci 85cb93a386Sopenharmony_ci size_t i; 86cb93a386Sopenharmony_ci SkPoint dst[2]; 87cb93a386Sopenharmony_ci 88cb93a386Sopenharmony_ci static const SkPoint gEmpty[] = { 89cb93a386Sopenharmony_ci // sides 90cb93a386Sopenharmony_ci { L, CY }, { L - 10, CY }, 91cb93a386Sopenharmony_ci { R, CY }, { R + 10, CY }, 92cb93a386Sopenharmony_ci { CX, T }, { CX, T - 10 }, 93cb93a386Sopenharmony_ci { CX, B }, { CX, B + 10 }, 94cb93a386Sopenharmony_ci // corners 95cb93a386Sopenharmony_ci { L, T }, { L - 10, T - 10 }, 96cb93a386Sopenharmony_ci { L, B }, { L - 10, B + 10 }, 97cb93a386Sopenharmony_ci { R, T }, { R + 10, T - 10 }, 98cb93a386Sopenharmony_ci { R, B }, { R + 10, B + 10 }, 99cb93a386Sopenharmony_ci }; 100cb93a386Sopenharmony_ci for (i = 0; i < SK_ARRAY_COUNT(gEmpty); i += 2) { 101cb93a386Sopenharmony_ci bool valid = SkLineClipper::IntersectLine(&gEmpty[i], gR, dst); 102cb93a386Sopenharmony_ci if (valid) { 103cb93a386Sopenharmony_ci SkDebugf("----- [%zu] %g %g -> %g %g\n", 104cb93a386Sopenharmony_ci i/2, dst[0].fX, dst[0].fY, dst[1].fX, dst[1].fY); 105cb93a386Sopenharmony_ci } 106cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !valid); 107cb93a386Sopenharmony_ci } 108cb93a386Sopenharmony_ci 109cb93a386Sopenharmony_ci static const SkPoint gFull[] = { 110cb93a386Sopenharmony_ci // diagonals, chords 111cb93a386Sopenharmony_ci { L, T }, { R, B }, 112cb93a386Sopenharmony_ci { L, B }, { R, T }, 113cb93a386Sopenharmony_ci { CX, T }, { CX, B }, 114cb93a386Sopenharmony_ci { L, CY }, { R, CY }, 115cb93a386Sopenharmony_ci { CX, T }, { R, CY }, 116cb93a386Sopenharmony_ci { CX, T }, { L, CY }, 117cb93a386Sopenharmony_ci { L, CY }, { CX, B }, 118cb93a386Sopenharmony_ci { R, CY }, { CX, B }, 119cb93a386Sopenharmony_ci // edges 120cb93a386Sopenharmony_ci { L, T }, { L, B }, 121cb93a386Sopenharmony_ci { R, T }, { R, B }, 122cb93a386Sopenharmony_ci { L, T }, { R, T }, 123cb93a386Sopenharmony_ci { L, B }, { R, B }, 124cb93a386Sopenharmony_ci }; 125cb93a386Sopenharmony_ci for (i = 0; i < SK_ARRAY_COUNT(gFull); i += 2) { 126cb93a386Sopenharmony_ci bool valid = SkLineClipper::IntersectLine(&gFull[i], gR, dst); 127cb93a386Sopenharmony_ci if (!valid || 0 != memcmp(&gFull[i], dst, sizeof(dst))) { 128cb93a386Sopenharmony_ci SkDebugf("++++ [%zu] %g %g -> %g %g\n", 129cb93a386Sopenharmony_ci i/2, dst[0].fX, dst[0].fY, dst[1].fX, dst[1].fY); 130cb93a386Sopenharmony_ci } 131cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, valid && !memcmp(&gFull[i], dst, sizeof(dst))); 132cb93a386Sopenharmony_ci } 133cb93a386Sopenharmony_ci 134cb93a386Sopenharmony_ci static const SkPoint gPartial[] = { 135cb93a386Sopenharmony_ci { L - 10, CY }, { CX, CY }, { L, CY }, { CX, CY }, 136cb93a386Sopenharmony_ci { CX, T - 10 }, { CX, CY }, { CX, T }, { CX, CY }, 137cb93a386Sopenharmony_ci { R + 10, CY }, { CX, CY }, { R, CY }, { CX, CY }, 138cb93a386Sopenharmony_ci { CX, B + 10 }, { CX, CY }, { CX, B }, { CX, CY }, 139cb93a386Sopenharmony_ci // extended edges 140cb93a386Sopenharmony_ci { L, T - 10 }, { L, B + 10 }, { L, T }, { L, B }, 141cb93a386Sopenharmony_ci { R, T - 10 }, { R, B + 10 }, { R, T }, { R, B }, 142cb93a386Sopenharmony_ci { L - 10, T }, { R + 10, T }, { L, T }, { R, T }, 143cb93a386Sopenharmony_ci { L - 10, B }, { R + 10, B }, { L, B }, { R, B }, 144cb93a386Sopenharmony_ci }; 145cb93a386Sopenharmony_ci for (i = 0; i < SK_ARRAY_COUNT(gPartial); i += 4) { 146cb93a386Sopenharmony_ci bool valid = SkLineClipper::IntersectLine(&gPartial[i], gR, dst); 147cb93a386Sopenharmony_ci if (!valid || 0 != memcmp(&gPartial[i+2], dst, sizeof(dst))) { 148cb93a386Sopenharmony_ci SkDebugf("++++ [%zu] %g %g -> %g %g\n", 149cb93a386Sopenharmony_ci i/2, dst[0].fX, dst[0].fY, dst[1].fX, dst[1].fY); 150cb93a386Sopenharmony_ci } 151cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, valid && 152cb93a386Sopenharmony_ci !memcmp(&gPartial[i+2], dst, sizeof(dst))); 153cb93a386Sopenharmony_ci } 154cb93a386Sopenharmony_ci 155cb93a386Sopenharmony_ci} 156cb93a386Sopenharmony_ci 157cb93a386Sopenharmony_ciDEF_TEST(Clipper, reporter) { 158cb93a386Sopenharmony_ci test_intersectline(reporter); 159cb93a386Sopenharmony_ci test_edgeclipper(); 160cb93a386Sopenharmony_ci test_hairclipping(reporter); 161cb93a386Sopenharmony_ci} 162cb93a386Sopenharmony_ci 163cb93a386Sopenharmony_ciDEF_TEST(LineClipper_skbug_7981, r) { 164cb93a386Sopenharmony_ci SkPoint src[] = {{ -5.77698802E+17f, -1.81758057E+23f}, {38127, 2}}; 165cb93a386Sopenharmony_ci SkPoint dst[2]; 166cb93a386Sopenharmony_ci SkRect clip = { -32767, -32767, 32767, 32767 }; 167cb93a386Sopenharmony_ci 168cb93a386Sopenharmony_ci SkLineClipper::IntersectLine(src, clip, dst); 169cb93a386Sopenharmony_ci} 170cb93a386Sopenharmony_ci 171