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/SkScalar.h" 9cb93a386Sopenharmony_ci#include "src/core/SkMathPriv.h" 10cb93a386Sopenharmony_ci#include "src/core/SkPointPriv.h" 11cb93a386Sopenharmony_ci#include "tests/Test.h" 12cb93a386Sopenharmony_ci 13cb93a386Sopenharmony_ci/* 14cb93a386Sopenharmony_ci Duplicates lots of code from gpu/src/GrPathUtils.cpp 15cb93a386Sopenharmony_ci It'd be nice not to do so, but that code's set up currently to only have 16cb93a386Sopenharmony_ci a single implementation. 17cb93a386Sopenharmony_ci*/ 18cb93a386Sopenharmony_ci 19cb93a386Sopenharmony_ci// Sk uses 6, Gr (implicitly) used 10, both apparently arbitrarily. 20cb93a386Sopenharmony_ci#define MAX_COEFF_SHIFT 6 21cb93a386Sopenharmony_cistatic const uint32_t MAX_POINTS_PER_CURVE = 1 << MAX_COEFF_SHIFT; 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_ci// max + 0.5 min has error [0.0, 0.12] 24cb93a386Sopenharmony_ci// max + 0.375 min has error [-.03, 0.07] 25cb93a386Sopenharmony_ci// 0.96043387 max + 0.397824735 min has error [-.06, +.05] 26cb93a386Sopenharmony_ci// For determining the maximum possible number of points to use in 27cb93a386Sopenharmony_ci// drawing a quadratic, we want to err on the high side. 28cb93a386Sopenharmony_cistatic inline int cheap_distance(SkScalar dx, SkScalar dy) { 29cb93a386Sopenharmony_ci int idx = SkAbs32(SkScalarRoundToInt(dx)); 30cb93a386Sopenharmony_ci int idy = SkAbs32(SkScalarRoundToInt(dy)); 31cb93a386Sopenharmony_ci if (idx > idy) { 32cb93a386Sopenharmony_ci idx += idy >> 1; 33cb93a386Sopenharmony_ci } else { 34cb93a386Sopenharmony_ci idx = idy + (idx >> 1); 35cb93a386Sopenharmony_ci } 36cb93a386Sopenharmony_ci return idx; 37cb93a386Sopenharmony_ci} 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_cistatic inline int estimate_distance(const SkPoint points[]) { 40cb93a386Sopenharmony_ci return cheap_distance(points[1].fX * 2 - points[2].fX - points[0].fX, 41cb93a386Sopenharmony_ci points[1].fY * 2 - points[2].fY - points[0].fY); 42cb93a386Sopenharmony_ci} 43cb93a386Sopenharmony_ci 44cb93a386Sopenharmony_cistatic inline SkScalar compute_distance(const SkPoint points[]) { 45cb93a386Sopenharmony_ci return SkPointPriv::DistanceToLineSegmentBetween(points[1], points[0], points[2]); 46cb93a386Sopenharmony_ci} 47cb93a386Sopenharmony_ci 48cb93a386Sopenharmony_cistatic inline uint32_t estimate_pointCount(int distance) { 49cb93a386Sopenharmony_ci // Includes -2 bias because this estimator runs 4x high? 50cb93a386Sopenharmony_ci int shift = 30 - SkCLZ(distance); 51cb93a386Sopenharmony_ci // Clamp to zero if above subtraction went negative. 52cb93a386Sopenharmony_ci shift &= ~(shift>>31); 53cb93a386Sopenharmony_ci if (shift > MAX_COEFF_SHIFT) { 54cb93a386Sopenharmony_ci shift = MAX_COEFF_SHIFT; 55cb93a386Sopenharmony_ci } 56cb93a386Sopenharmony_ci return 1 << shift; 57cb93a386Sopenharmony_ci} 58cb93a386Sopenharmony_ci 59cb93a386Sopenharmony_cistatic inline uint32_t compute_pointCount(SkScalar d, SkScalar tol) { 60cb93a386Sopenharmony_ci if (d < tol) { 61cb93a386Sopenharmony_ci return 1; 62cb93a386Sopenharmony_ci } else { 63cb93a386Sopenharmony_ci int temp = SkScalarCeilToInt(SkScalarSqrt(d / tol)); 64cb93a386Sopenharmony_ci uint32_t count = std::min<uint32_t>(SkNextPow2(temp), MAX_POINTS_PER_CURVE); 65cb93a386Sopenharmony_ci return count; 66cb93a386Sopenharmony_ci } 67cb93a386Sopenharmony_ci} 68cb93a386Sopenharmony_ci 69cb93a386Sopenharmony_cistatic uint32_t quadraticPointCount_EE(const SkPoint points[]) { 70cb93a386Sopenharmony_ci int distance = estimate_distance(points); 71cb93a386Sopenharmony_ci return estimate_pointCount(distance); 72cb93a386Sopenharmony_ci} 73cb93a386Sopenharmony_ci 74cb93a386Sopenharmony_cistatic uint32_t quadraticPointCount_EC(const SkPoint points[], SkScalar tol) { 75cb93a386Sopenharmony_ci int distance = estimate_distance(points); 76cb93a386Sopenharmony_ci return compute_pointCount(SkIntToScalar(distance), tol); 77cb93a386Sopenharmony_ci} 78cb93a386Sopenharmony_ci 79cb93a386Sopenharmony_cistatic uint32_t quadraticPointCount_CE(const SkPoint points[]) { 80cb93a386Sopenharmony_ci SkScalar distance = compute_distance(points); 81cb93a386Sopenharmony_ci return estimate_pointCount(SkScalarRoundToInt(distance)); 82cb93a386Sopenharmony_ci} 83cb93a386Sopenharmony_ci 84cb93a386Sopenharmony_cistatic uint32_t quadraticPointCount_CC(const SkPoint points[], SkScalar tol) { 85cb93a386Sopenharmony_ci SkScalar distance = compute_distance(points); 86cb93a386Sopenharmony_ci return compute_pointCount(distance, tol); 87cb93a386Sopenharmony_ci} 88cb93a386Sopenharmony_ci 89cb93a386Sopenharmony_ci// Curve from samplecode/SampleSlides.cpp 90cb93a386Sopenharmony_cistatic const int gXY[] = { 91cb93a386Sopenharmony_ci 4, 0, 0, -4, 8, -4, 12, 0, 8, 4, 0, 4 92cb93a386Sopenharmony_ci}; 93cb93a386Sopenharmony_ci 94cb93a386Sopenharmony_cistatic const int gSawtooth[] = { 95cb93a386Sopenharmony_ci 0, 0, 10, 10, 20, 20, 30, 10, 40, 0, 50, -10, 60, -20, 70, -10, 80, 0 96cb93a386Sopenharmony_ci}; 97cb93a386Sopenharmony_ci 98cb93a386Sopenharmony_cistatic const int gOvalish[] = { 99cb93a386Sopenharmony_ci 0, 0, 5, 15, 20, 20, 35, 15, 40, 0 100cb93a386Sopenharmony_ci}; 101cb93a386Sopenharmony_ci 102cb93a386Sopenharmony_cistatic const int gSharpSawtooth[] = { 103cb93a386Sopenharmony_ci 0, 0, 1, 10, 2, 0, 3, -10, 4, 0 104cb93a386Sopenharmony_ci}; 105cb93a386Sopenharmony_ci 106cb93a386Sopenharmony_ci// Curve crosses back over itself around 0,10 107cb93a386Sopenharmony_cistatic const int gRibbon[] = { 108cb93a386Sopenharmony_ci -4, 0, 4, 20, 0, 25, -4, 20, 4, 0 109cb93a386Sopenharmony_ci}; 110cb93a386Sopenharmony_ci 111cb93a386Sopenharmony_cistatic bool one_d_pe(const int* array, const unsigned int count, 112cb93a386Sopenharmony_ci skiatest::Reporter* reporter) { 113cb93a386Sopenharmony_ci SkPoint path [3]; 114cb93a386Sopenharmony_ci path[1] = SkPoint::Make(SkIntToScalar(array[0]), SkIntToScalar(array[1])); 115cb93a386Sopenharmony_ci path[2] = SkPoint::Make(SkIntToScalar(array[2]), SkIntToScalar(array[3])); 116cb93a386Sopenharmony_ci int numErrors = 0; 117cb93a386Sopenharmony_ci for (unsigned i = 4; i < count; i += 2) { 118cb93a386Sopenharmony_ci path[0] = path[1]; 119cb93a386Sopenharmony_ci path[1] = path[2]; 120cb93a386Sopenharmony_ci path[2] = SkPoint::Make(SkIntToScalar(array[i]), 121cb93a386Sopenharmony_ci SkIntToScalar(array[i+1])); 122cb93a386Sopenharmony_ci uint32_t computedCount = 123cb93a386Sopenharmony_ci quadraticPointCount_CC(path, SkIntToScalar(1)); 124cb93a386Sopenharmony_ci uint32_t estimatedCount = 125cb93a386Sopenharmony_ci quadraticPointCount_EE(path); 126cb93a386Sopenharmony_ci 127cb93a386Sopenharmony_ci if (false) { // avoid bit rot, suppress warning 128cb93a386Sopenharmony_ci computedCount = 129cb93a386Sopenharmony_ci quadraticPointCount_EC(path, SkIntToScalar(1)); 130cb93a386Sopenharmony_ci estimatedCount = 131cb93a386Sopenharmony_ci quadraticPointCount_CE(path); 132cb93a386Sopenharmony_ci } 133cb93a386Sopenharmony_ci // Allow estimated to be high by a factor of two, but no less than 134cb93a386Sopenharmony_ci // the computed value. 135cb93a386Sopenharmony_ci bool isAccurate = (estimatedCount >= computedCount) && 136cb93a386Sopenharmony_ci (estimatedCount <= 2 * computedCount); 137cb93a386Sopenharmony_ci 138cb93a386Sopenharmony_ci if (!isAccurate) { 139cb93a386Sopenharmony_ci ERRORF(reporter, "Curve from %.2f %.2f through %.2f %.2f to " 140cb93a386Sopenharmony_ci "%.2f %.2f computes %d, estimates %d\n", 141cb93a386Sopenharmony_ci path[0].fX, path[0].fY, path[1].fX, path[1].fY, 142cb93a386Sopenharmony_ci path[2].fX, path[2].fY, computedCount, estimatedCount); 143cb93a386Sopenharmony_ci numErrors++; 144cb93a386Sopenharmony_ci } 145cb93a386Sopenharmony_ci } 146cb93a386Sopenharmony_ci 147cb93a386Sopenharmony_ci return (numErrors == 0); 148cb93a386Sopenharmony_ci} 149cb93a386Sopenharmony_ci 150cb93a386Sopenharmony_ci 151cb93a386Sopenharmony_ci 152cb93a386Sopenharmony_cistatic void TestQuadPointCount(skiatest::Reporter* reporter) { 153cb93a386Sopenharmony_ci one_d_pe(gXY, SK_ARRAY_COUNT(gXY), reporter); 154cb93a386Sopenharmony_ci one_d_pe(gSawtooth, SK_ARRAY_COUNT(gSawtooth), reporter); 155cb93a386Sopenharmony_ci one_d_pe(gOvalish, SK_ARRAY_COUNT(gOvalish), reporter); 156cb93a386Sopenharmony_ci one_d_pe(gSharpSawtooth, SK_ARRAY_COUNT(gSharpSawtooth), reporter); 157cb93a386Sopenharmony_ci one_d_pe(gRibbon, SK_ARRAY_COUNT(gRibbon), reporter); 158cb93a386Sopenharmony_ci} 159cb93a386Sopenharmony_ci 160cb93a386Sopenharmony_ciDEF_TEST(PathCoverage, reporter) { 161cb93a386Sopenharmony_ci TestQuadPointCount(reporter); 162cb93a386Sopenharmony_ci 163cb93a386Sopenharmony_ci} 164