1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/* 3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2011 Google Inc. 4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * 5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be 6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file. 7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */ 81fd56dc6e189ea0e94b5df9af959c243573f8883epoger@google.com// Unit tests for src/core/SkPoint.cpp and its header 91fd56dc6e189ea0e94b5df9af959c243573f8883epoger@google.com 101fd56dc6e189ea0e94b5df9af959c243573f8883epoger@google.com#include "SkPoint.h" 11c7d0ea3cd328566958bfcb86b4488dcbb94dd5ecreed@google.com#include "SkRect.h" 121fd56dc6e189ea0e94b5df9af959c243573f8883epoger@google.com#include "Test.h" 131fd56dc6e189ea0e94b5df9af959c243573f8883epoger@google.com 14c7d0ea3cd328566958bfcb86b4488dcbb94dd5ecreed@google.comstatic void test_casts(skiatest::Reporter* reporter) { 15c7d0ea3cd328566958bfcb86b4488dcbb94dd5ecreed@google.com SkPoint p = { 0, 0 }; 16c7d0ea3cd328566958bfcb86b4488dcbb94dd5ecreed@google.com SkRect r = { 0, 0, 0, 0 }; 17c7d0ea3cd328566958bfcb86b4488dcbb94dd5ecreed@google.com 18c7d0ea3cd328566958bfcb86b4488dcbb94dd5ecreed@google.com const SkScalar* pPtr = SkTCast<const SkScalar*>(&p); 19c7d0ea3cd328566958bfcb86b4488dcbb94dd5ecreed@google.com const SkScalar* rPtr = SkTCast<const SkScalar*>(&r); 20c7d0ea3cd328566958bfcb86b4488dcbb94dd5ecreed@google.com 21c7d0ea3cd328566958bfcb86b4488dcbb94dd5ecreed@google.com REPORTER_ASSERT(reporter, p.asScalars() == pPtr); 22c7d0ea3cd328566958bfcb86b4488dcbb94dd5ecreed@google.com REPORTER_ASSERT(reporter, r.asScalars() == rPtr); 23c7d0ea3cd328566958bfcb86b4488dcbb94dd5ecreed@google.com} 24c7d0ea3cd328566958bfcb86b4488dcbb94dd5ecreed@google.com 255a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com// Tests SkPoint::Normalize() for this (x,y) 265a5fe58595e881965c1a395885165eaccf2d44c5reed@google.comstatic void test_Normalize(skiatest::Reporter* reporter, 275a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com SkScalar x, SkScalar y) { 285a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com SkPoint point; 295a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com point.set(x, y); 305a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com SkScalar oldLength = point.length(); 315a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com SkScalar returned = SkPoint::Normalize(&point); 325a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com SkScalar newLength = point.length(); 335a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com REPORTER_ASSERT(reporter, SkScalarNearlyEqual(returned, oldLength)); 345a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com REPORTER_ASSERT(reporter, SkScalarNearlyEqual(newLength, SK_Scalar1)); 355a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com} 365a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com 371fd56dc6e189ea0e94b5df9af959c243573f8883epoger@google.com// Tests that SkPoint::length() and SkPoint::Length() both return 381fd56dc6e189ea0e94b5df9af959c243573f8883epoger@google.com// approximately expectedLength for this (x,y). 391fd56dc6e189ea0e94b5df9af959c243573f8883epoger@google.comstatic void test_length(skiatest::Reporter* reporter, SkScalar x, SkScalar y, 401fd56dc6e189ea0e94b5df9af959c243573f8883epoger@google.com SkScalar expectedLength) { 411fd56dc6e189ea0e94b5df9af959c243573f8883epoger@google.com SkPoint point; 421fd56dc6e189ea0e94b5df9af959c243573f8883epoger@google.com point.set(x, y); 431fd56dc6e189ea0e94b5df9af959c243573f8883epoger@google.com SkScalar s1 = point.length(); 441fd56dc6e189ea0e94b5df9af959c243573f8883epoger@google.com SkScalar s2 = SkPoint::Length(x, y); 45b7b5d93359fdd3c5b2c48be7c5bbc4c978538af5bungeman@google.com //The following should be exactly the same, but need not be. 4698a9e1f958c4992bd73899d84a1a1f20eca2c80eborenet@google.com //See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=323 47b7b5d93359fdd3c5b2c48be7c5bbc4c978538af5bungeman@google.com REPORTER_ASSERT(reporter, SkScalarNearlyEqual(s1, s2)); 481fd56dc6e189ea0e94b5df9af959c243573f8883epoger@google.com REPORTER_ASSERT(reporter, SkScalarNearlyEqual(s1, expectedLength)); 49ecc9d28072142ab503a237726748ec2dc4ff842fskia.committer@gmail.com 505a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com test_Normalize(reporter, x, y); 511fd56dc6e189ea0e94b5df9af959c243573f8883epoger@google.com} 521fd56dc6e189ea0e94b5df9af959c243573f8883epoger@google.com 5325720b4d7e6f86043997c040315f2874aa2c8c9areed@google.com// Ugh. Windows compiler can dive into other .cpp files, and sometimes 5425720b4d7e6f86043997c040315f2874aa2c8c9areed@google.com// notices that I will generate an overflow... which is exactly the point 5525720b4d7e6f86043997c040315f2874aa2c8c9areed@google.com// of this test! 5625720b4d7e6f86043997c040315f2874aa2c8c9areed@google.com// 5725720b4d7e6f86043997c040315f2874aa2c8c9areed@google.com// To avoid this warning, I need to convince the compiler that I might not 5825720b4d7e6f86043997c040315f2874aa2c8c9areed@google.com// use that big value, hence this hacky helper function: reporter is 5925720b4d7e6f86043997c040315f2874aa2c8c9areed@google.com// ALWAYS non-null. (shhhhhh, don't tell the compiler that). 6025720b4d7e6f86043997c040315f2874aa2c8c9areed@google.comtemplate <typename T> T get_value(skiatest::Reporter* reporter, T value) { 6125720b4d7e6f86043997c040315f2874aa2c8c9areed@google.com return reporter ? value : 0; 6225720b4d7e6f86043997c040315f2874aa2c8c9areed@google.com} 6325720b4d7e6f86043997c040315f2874aa2c8c9areed@google.com 64fcc9ca09a56cd43015cc990898a55978bc2bf23dreed@google.com// On linux gcc, 32bit, we are seeing the compiler propagate up the value 65fcc9ca09a56cd43015cc990898a55978bc2bf23dreed@google.com// of SkPoint::length() as a double (which we use sometimes to avoid overflow 66fcc9ca09a56cd43015cc990898a55978bc2bf23dreed@google.com// during the computation), even though the signature says float (SkScalar). 67fcc9ca09a56cd43015cc990898a55978bc2bf23dreed@google.com// 68fcc9ca09a56cd43015cc990898a55978bc2bf23dreed@google.com// force_as_float is meant to capture our latest technique (horrible as 69fcc9ca09a56cd43015cc990898a55978bc2bf23dreed@google.com// it is) to force the value to be a float, so we can test whether it was 70fcc9ca09a56cd43015cc990898a55978bc2bf23dreed@google.com// finite or not. 71fcc9ca09a56cd43015cc990898a55978bc2bf23dreed@google.comstatic float force_as_float(skiatest::Reporter* reporter, float value) { 72fcc9ca09a56cd43015cc990898a55978bc2bf23dreed@google.com uint32_t storage; 73fcc9ca09a56cd43015cc990898a55978bc2bf23dreed@google.com memcpy(&storage, &value, 4); 74fcc9ca09a56cd43015cc990898a55978bc2bf23dreed@google.com // even the pair of memcpy calls are not sufficient, since those seem to 75fcc9ca09a56cd43015cc990898a55978bc2bf23dreed@google.com // be no-op'd, so we add a runtime tests (just like get_value) to force 76fcc9ca09a56cd43015cc990898a55978bc2bf23dreed@google.com // the compiler to give us an actual float. 77fcc9ca09a56cd43015cc990898a55978bc2bf23dreed@google.com if (NULL == reporter) { 78fcc9ca09a56cd43015cc990898a55978bc2bf23dreed@google.com storage = ~storage; 79fcc9ca09a56cd43015cc990898a55978bc2bf23dreed@google.com } 80fcc9ca09a56cd43015cc990898a55978bc2bf23dreed@google.com memcpy(&value, &storage, 4); 81fcc9ca09a56cd43015cc990898a55978bc2bf23dreed@google.com return value; 82fcc9ca09a56cd43015cc990898a55978bc2bf23dreed@google.com} 83fcc9ca09a56cd43015cc990898a55978bc2bf23dreed@google.com 845a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com// test that we handle very large values correctly. i.e. that we can 855a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com// successfully normalize something whose mag overflows a float. 865a5fe58595e881965c1a395885165eaccf2d44c5reed@google.comstatic void test_overflow(skiatest::Reporter* reporter) { 874b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org SkScalar bigFloat = get_value(reporter, 3.4e38f); 8825720b4d7e6f86043997c040315f2874aa2c8c9areed@google.com SkPoint pt = { bigFloat, bigFloat }; 89ecc9d28072142ab503a237726748ec2dc4ff842fskia.committer@gmail.com 905a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com SkScalar length = pt.length(); 91fcc9ca09a56cd43015cc990898a55978bc2bf23dreed@google.com length = force_as_float(reporter, length); 92fcc9ca09a56cd43015cc990898a55978bc2bf23dreed@google.com 93dc9cdf8d49ecfe174c408845b7f2de6f5a756b1dreed@google.com // expect this to be non-finite, but dump the results if not. 94dc9cdf8d49ecfe174c408845b7f2de6f5a756b1dreed@google.com if (SkScalarIsFinite(length)) { 95dc9cdf8d49ecfe174c408845b7f2de6f5a756b1dreed@google.com SkDebugf("length(%g, %g) == %g\n", pt.fX, pt.fY, length); 96dc9cdf8d49ecfe174c408845b7f2de6f5a756b1dreed@google.com REPORTER_ASSERT(reporter, !SkScalarIsFinite(length)); 97dc9cdf8d49ecfe174c408845b7f2de6f5a756b1dreed@google.com } 985a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com 995a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com // this should succeed, even though we can't represent length 1005a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com REPORTER_ASSERT(reporter, pt.setLength(SK_Scalar1)); 1015a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com 1025a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com // now that pt is normalized, we check its length 1035a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com length = pt.length(); 1045a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com REPORTER_ASSERT(reporter, SkScalarNearlyEqual(length, SK_Scalar1)); 1055a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com} 1065a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com 1075a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com// test that we handle very small values correctly. i.e. that we can 1085a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com// report failure if we try to normalize them. 1095a5fe58595e881965c1a395885165eaccf2d44c5reed@google.comstatic void test_underflow(skiatest::Reporter* reporter) { 1104b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org SkPoint pt = { 1.0e-37f, 1.0e-37f }; 1115a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com SkPoint copy = pt; 1125a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com 1135a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com REPORTER_ASSERT(reporter, 0 == SkPoint::Normalize(&pt)); 1145a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com REPORTER_ASSERT(reporter, pt == copy); // pt is unchanged 1155a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com 1165a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com REPORTER_ASSERT(reporter, !pt.setLength(SK_Scalar1)); 1175a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com REPORTER_ASSERT(reporter, pt == copy); // pt is unchanged 1181fd56dc6e189ea0e94b5df9af959c243573f8883epoger@google.com} 1191fd56dc6e189ea0e94b5df9af959c243573f8883epoger@google.com 12011e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.orgDEF_TEST(Point, reporter) { 121c7d0ea3cd328566958bfcb86b4488dcbb94dd5ecreed@google.com test_casts(reporter); 122c7d0ea3cd328566958bfcb86b4488dcbb94dd5ecreed@google.com 1235a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com static const struct { 1245a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com SkScalar fX; 1255a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com SkScalar fY; 1265a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com SkScalar fLength; 1275a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com } gRec[] = { 1285a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com { SkIntToScalar(3), SkIntToScalar(4), SkIntToScalar(5) }, 1294b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org { 0.6f, 0.8f, SK_Scalar1 }, 1305a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com }; 131ecc9d28072142ab503a237726748ec2dc4ff842fskia.committer@gmail.com 1325a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) { 1335a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com test_length(reporter, gRec[i].fX, gRec[i].fY, gRec[i].fLength); 1345a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com } 1355a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com 1365a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com test_underflow(reporter); 1375a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com test_overflow(reporter); 1381fd56dc6e189ea0e94b5df9af959c243573f8883epoger@google.com} 1391fd56dc6e189ea0e94b5df9af959c243573f8883epoger@google.com 14011e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.orgDEF_TEST(Point_setLengthFast, reporter) { 14111e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org // Scale a (1,1) point to a bunch of different lengths, 14211e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org // making sure the slow and fast paths are within 0.1%. 14311e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org const float tests[] = { 1.0f, 0.0f, 1.0e-37f, 3.4e38f, 42.0f, 0.00012f }; 14411e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org 14511e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org const SkPoint kOne = {1.0f, 1.0f}; 14611e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org for (unsigned i = 0; i < SK_ARRAY_COUNT(tests); i++) { 14711e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org SkPoint slow = kOne, fast = kOne; 14811e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org 14911e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org slow.setLength(tests[i]); 15011e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org fast.setLengthFast(tests[i]); 15111e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org 15211e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org if (slow.length() < FLT_MIN && fast.length() < FLT_MIN) continue; 15311e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org 15411e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org SkScalar ratio = slow.length() / fast.length(); 15511e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org REPORTER_ASSERT(reporter, ratio > 0.999f); 15611e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org REPORTER_ASSERT(reporter, ratio < 1.001f); 15711e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org } 15811e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org} 159