1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/* 3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project 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 */ 8ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkEdge.h" 118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkFDot6.h" 12889bd8bd7f604acae0a6303365bc82c06da1e6f3tomhudson@google.com#include "SkMath.h" 138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/* 158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com In setLine, setQuadratic, setCubic, the first thing we do is to convert 168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com the points into FDot6. This is modulated by the shift parameter, which 178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com will either be 0, or something like 2 for antialiasing. 188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com In the float case, we want to turn the float into .6 by saying pt * 64, 208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com or pt * 256 for antialiasing. This is implemented as 1 << (shift + 6). 218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com In the fixed case, we want to turn the fixed into .6 by saying pt >> 10, 238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com or pt >> 8 for antialiasing. This is implemented as pt >> (10 - shift). 248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/ 258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 26e2faf17bcc523557e44ef443b48a53f286886a53reed@google.comstatic inline SkFixed SkFDot6ToFixedDiv2(SkFDot6 value) { 27e2faf17bcc523557e44ef443b48a53f286886a53reed@google.com // we want to return SkFDot6ToFixed(value >> 1), but we don't want to throw 28e2faf17bcc523557e44ef443b48a53f286886a53reed@google.com // away data in value, so just perform a modify up-shift 29e2faf17bcc523557e44ef443b48a53f286886a53reed@google.com return value << (16 - 6 - 1); 30e2faf17bcc523557e44ef443b48a53f286886a53reed@google.com} 31e2faf17bcc523557e44ef443b48a53f286886a53reed@google.com 328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////// 338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint SkEdge::setLine(const SkPoint& p0, const SkPoint& p1, const SkIRect* clip, 358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int shift) { 368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFDot6 x0, y0, x1, y1; 378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com { 392f26528e59908856e36e88aa3be94d84014e9a58george#ifdef SK_RASTERIZE_EVEN_ROUNDING 402f26528e59908856e36e88aa3be94d84014e9a58george x0 = SkScalarRoundToFDot6(p0.fX, shift); 412f26528e59908856e36e88aa3be94d84014e9a58george y0 = SkScalarRoundToFDot6(p0.fY, shift); 422f26528e59908856e36e88aa3be94d84014e9a58george x1 = SkScalarRoundToFDot6(p1.fX, shift); 432f26528e59908856e36e88aa3be94d84014e9a58george y1 = SkScalarRoundToFDot6(p1.fY, shift); 442f26528e59908856e36e88aa3be94d84014e9a58george#else 458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com float scale = float(1 << (shift + 6)); 468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com x0 = int(p0.fX * scale); 478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com y0 = int(p0.fY * scale); 488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com x1 = int(p1.fX * scale); 498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com y1 = int(p1.fY * scale); 502f26528e59908856e36e88aa3be94d84014e9a58george#endif 518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int winding = 1; 548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (y0 > y1) { 568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkTSwap(x0, x1); 578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkTSwap(y0, y1); 588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com winding = -1; 598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int top = SkFDot6Round(y0); 628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int bot = SkFDot6Round(y1); 638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // are we a zero-height line? 658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (top == bot) { 668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return 0; 678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // are we completely above or below the clip? 6949f085dddff10473b6ebf832a974288300224e60bsalomon if (clip && (top >= clip->fBottom || bot <= clip->fTop)) { 708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return 0; 718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFixed slope = SkFDot6Div(x1 - x0, y1 - y0); 7409a029b687465190c828bde896173e23aa350c4creed@google.com const int dy = SkEdge_Compute_DY(top, y0); 758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 7609a029b687465190c828bde896173e23aa350c4creed@google.com fX = SkFDot6ToFixed(x0 + SkFixedMul(slope, dy)); // + SK_Fixed1/2 778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fDX = slope; 788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fFirstY = top; 798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fLastY = bot - 1; 808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fCurveCount = 0; 818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fWinding = SkToS8(winding); 828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fCurveShift = 0; 838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (clip) { 858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->chopLineWithClip(*clip); 868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return 1; 888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// called from a curve subclass 918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint SkEdge::updateLine(SkFixed x0, SkFixed y0, SkFixed x1, SkFixed y1) 928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(fWinding == 1 || fWinding == -1); 948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(fCurveCount != 0); 958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// SkASSERT(fCurveShift != 0); 968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com y0 >>= 10; 988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com y1 >>= 10; 998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(y0 <= y1); 1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int top = SkFDot6Round(y0); 1038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int bot = SkFDot6Round(y1); 1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// SkASSERT(top >= fFirstY); 1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // are we a zero-height line? 1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (top == bot) 1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return 0; 1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com x0 >>= 10; 1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com x1 >>= 10; 1138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFixed slope = SkFDot6Div(x1 - x0, y1 - y0); 11509a029b687465190c828bde896173e23aa350c4creed@google.com const int dy = SkEdge_Compute_DY(top, y0); 1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 11709a029b687465190c828bde896173e23aa350c4creed@google.com fX = SkFDot6ToFixed(x0 + SkFixedMul(slope, dy)); // + SK_Fixed1/2 1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fDX = slope; 1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fFirstY = top; 1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fLastY = bot - 1; 1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return 1; 1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkEdge::chopLineWithClip(const SkIRect& clip) 1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 1278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int top = fFirstY; 1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(top < clip.fBottom); 1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // clip the line to the top 1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (top < clip.fTop) 1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com { 1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(fLastY >= clip.fTop); 1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fX += fDX * (clip.fTop - top); 1368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fFirstY = clip.fTop; 1378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////// 1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/* We store 1<<shift in a (signed) byte, so its maximum value is 1<<6 == 64. 1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com Note that this limits the number of lines we use to approximate a curve. 1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com If we need to increase this, we need to store fCurveCount in something 1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com larger than int8_t. 1468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/ 1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define MAX_COEFF_SHIFT 6 1488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic inline SkFDot6 cheap_distance(SkFDot6 dx, SkFDot6 dy) 1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com dx = SkAbs32(dx); 1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com dy = SkAbs32(dy); 1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // return max + min/2 1548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (dx > dy) 1558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com dx += dy >> 1; 1568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com else 1578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com dx = dy + (dx >> 1); 1588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return dx; 1598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic inline int diff_to_shift(SkFDot6 dx, SkFDot6 dy) 1628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 1638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // cheap calc of distance from center of p0-p2 to the center of the curve 1648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFDot6 dist = cheap_distance(dx, dy); 1658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // shift down dist (it is currently in dot6) 1678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // down by 5 should give us 1/2 pixel accuracy (assuming our dist is accurate...) 1688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // this is chosen by heuristic: make it as big as possible (to minimize segments) 1698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // ... but small enough so that our curves still look smooth 1708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com dist = (dist + (1 << 4)) >> 5; 1718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // each subdivision (shift value) cuts this dist (error) by 1/4 1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return (32 - SkCLZ(dist)) >> 1; 1748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 176c07d23a6e220c0aff36e3e4e06c1b685a440108ereed@android.comint SkQuadraticEdge::setQuadratic(const SkPoint pts[3], int shift) 1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 1788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFDot6 x0, y0, x1, y1, x2, y2; 1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com { 1812f26528e59908856e36e88aa3be94d84014e9a58george#ifdef SK_RASTERIZE_EVEN_ROUNDING 1822f26528e59908856e36e88aa3be94d84014e9a58george x0 = SkScalarRoundToFDot6(pts[0].fX, shift); 1832f26528e59908856e36e88aa3be94d84014e9a58george y0 = SkScalarRoundToFDot6(pts[0].fY, shift); 1842f26528e59908856e36e88aa3be94d84014e9a58george x1 = SkScalarRoundToFDot6(pts[1].fX, shift); 1852f26528e59908856e36e88aa3be94d84014e9a58george y1 = SkScalarRoundToFDot6(pts[1].fY, shift); 1862f26528e59908856e36e88aa3be94d84014e9a58george x2 = SkScalarRoundToFDot6(pts[2].fX, shift); 1872f26528e59908856e36e88aa3be94d84014e9a58george y2 = SkScalarRoundToFDot6(pts[2].fY, shift); 1882f26528e59908856e36e88aa3be94d84014e9a58george#else 1898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com float scale = float(1 << (shift + 6)); 1908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com x0 = int(pts[0].fX * scale); 1918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com y0 = int(pts[0].fY * scale); 1928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com x1 = int(pts[1].fX * scale); 1938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com y1 = int(pts[1].fY * scale); 1948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com x2 = int(pts[2].fX * scale); 1958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com y2 = int(pts[2].fY * scale); 1962f26528e59908856e36e88aa3be94d84014e9a58george#endif 1978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int winding = 1; 2008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (y0 > y2) 2018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com { 2028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkTSwap(x0, x2); 2038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkTSwap(y0, y2); 2048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com winding = -1; 2058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(y0 <= y1 && y1 <= y2); 2078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int top = SkFDot6Round(y0); 2098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int bot = SkFDot6Round(y2); 2108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // are we a zero-height quad (line)? 2128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (top == bot) 2138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return 0; 2148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // compute number of steps needed (1 << shift) 2168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com { 2178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFDot6 dx = ((x1 << 1) - x0 - x2) >> 2; 2188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFDot6 dy = ((y1 << 1) - y0 - y2) >> 2; 2198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com shift = diff_to_shift(dx, dy); 2208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(shift >= 0); 2218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // need at least 1 subdivision for our bias trick 2238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (shift == 0) { 2248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com shift = 1; 2258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else if (shift > MAX_COEFF_SHIFT) { 2268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com shift = MAX_COEFF_SHIFT; 2278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 228fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 2298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fWinding = SkToS8(winding); 2308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com //fCubicDShift only set for cubics 2318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fCurveCount = SkToS8(1 << shift); 2328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 233e2faf17bcc523557e44ef443b48a53f286886a53reed@google.com /* 234e2faf17bcc523557e44ef443b48a53f286886a53reed@google.com * We want to reformulate into polynomial form, to make it clear how we 235e2faf17bcc523557e44ef443b48a53f286886a53reed@google.com * should forward-difference. 236e2faf17bcc523557e44ef443b48a53f286886a53reed@google.com * 237e2faf17bcc523557e44ef443b48a53f286886a53reed@google.com * p0 (1 - t)^2 + p1 t(1 - t) + p2 t^2 ==> At^2 + Bt + C 238e2faf17bcc523557e44ef443b48a53f286886a53reed@google.com * 239e2faf17bcc523557e44ef443b48a53f286886a53reed@google.com * A = p0 - 2p1 + p2 240e2faf17bcc523557e44ef443b48a53f286886a53reed@google.com * B = 2(p1 - p0) 241e2faf17bcc523557e44ef443b48a53f286886a53reed@google.com * C = p0 242e2faf17bcc523557e44ef443b48a53f286886a53reed@google.com * 243e2faf17bcc523557e44ef443b48a53f286886a53reed@google.com * Our caller must have constrained our inputs (p0..p2) to all fit into 244e2faf17bcc523557e44ef443b48a53f286886a53reed@google.com * 16.16. However, as seen above, we sometimes compute values that can be 245e2faf17bcc523557e44ef443b48a53f286886a53reed@google.com * larger (e.g. B = 2*(p1 - p0)). To guard against overflow, we will store 246e2faf17bcc523557e44ef443b48a53f286886a53reed@google.com * A and B at 1/2 of their actual value, and just apply a 2x scale during 247e2faf17bcc523557e44ef443b48a53f286886a53reed@google.com * application in updateQuadratic(). Hence we store (shift - 1) in 248e2faf17bcc523557e44ef443b48a53f286886a53reed@google.com * fCurveShift. 249e2faf17bcc523557e44ef443b48a53f286886a53reed@google.com */ 250e2faf17bcc523557e44ef443b48a53f286886a53reed@google.com 251e2faf17bcc523557e44ef443b48a53f286886a53reed@google.com fCurveShift = SkToU8(shift - 1); 252e2faf17bcc523557e44ef443b48a53f286886a53reed@google.com 253e2faf17bcc523557e44ef443b48a53f286886a53reed@google.com SkFixed A = SkFDot6ToFixedDiv2(x0 - x1 - x1 + x2); // 1/2 the real value 254e2faf17bcc523557e44ef443b48a53f286886a53reed@google.com SkFixed B = SkFDot6ToFixed(x1 - x0); // 1/2 the real value 2558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fQx = SkFDot6ToFixed(x0); 2578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fQDx = B + (A >> shift); // biased by shift 2588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fQDDx = A >> (shift - 1); // biased by shift 2598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 260e2faf17bcc523557e44ef443b48a53f286886a53reed@google.com A = SkFDot6ToFixedDiv2(y0 - y1 - y1 + y2); // 1/2 the real value 261e2faf17bcc523557e44ef443b48a53f286886a53reed@google.com B = SkFDot6ToFixed(y1 - y0); // 1/2 the real value 2628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fQy = SkFDot6ToFixed(y0); 2648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fQDy = B + (A >> shift); // biased by shift 2658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fQDDy = A >> (shift - 1); // biased by shift 2668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fQLastX = SkFDot6ToFixed(x2); 2688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fQLastY = SkFDot6ToFixed(y2); 2698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return this->updateQuadratic(); 2718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 2728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint SkQuadraticEdge::updateQuadratic() 2748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 2758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int success; 2768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int count = fCurveCount; 2778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFixed oldx = fQx; 2788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFixed oldy = fQy; 2798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFixed dx = fQDx; 2808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFixed dy = fQDy; 2818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFixed newx, newy; 2828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int shift = fCurveShift; 2838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(count > 0); 2858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com do { 2878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (--count > 0) 2888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com { 2898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com newx = oldx + (dx >> shift); 2908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com dx += fQDDx; 2918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com newy = oldy + (dy >> shift); 2928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com dy += fQDDy; 2938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com else // last segment 2958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com { 2968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com newx = fQLastX; 2978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com newy = fQLastY; 2988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com success = this->updateLine(oldx, oldy, newx, newy); 3008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com oldx = newx; 3018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com oldy = newy; 3028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } while (count > 0 && !success); 3038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fQx = newx; 3058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fQy = newy; 3068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fQDx = dx; 3078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fQDy = dy; 30863debae4c1020fa1e0ccd92ef3cbfdc8735acf8ereed@android.com fCurveCount = SkToS8(count); 3098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return success; 3108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 3118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////// 3138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic inline int SkFDot6UpShift(SkFDot6 x, int upShift) { 3158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT((x << upShift >> upShift) == x); 3168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return x << upShift; 3178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 3188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/* f(1/3) = (8a + 12b + 6c + d) / 27 3208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com f(2/3) = (a + 6b + 12c + 8d) / 27 3218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com f(1/3)-b = (8a - 15b + 6c + d) / 27 3238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com f(2/3)-c = (a + 6b - 15c + 8d) / 27 3248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com use 16/512 to approximate 1/27 3268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/ 3278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic SkFDot6 cubic_delta_from_line(SkFDot6 a, SkFDot6 b, SkFDot6 c, SkFDot6 d) 3288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 3298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFDot6 oneThird = ((a << 3) - ((b << 4) - b) + 6*c + d) * 19 >> 9; 3308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFDot6 twoThird = (a + 6*b - ((c << 4) - c) + (d << 3)) * 19 >> 9; 3318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return SkMax32(SkAbs32(oneThird), SkAbs32(twoThird)); 3338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 3348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint SkCubicEdge::setCubic(const SkPoint pts[4], const SkIRect* clip, int shift) 3368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 3378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFDot6 x0, y0, x1, y1, x2, y2, x3, y3; 3388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com { 3402f26528e59908856e36e88aa3be94d84014e9a58george#ifdef SK_RASTERIZE_EVEN_ROUNDING 3412f26528e59908856e36e88aa3be94d84014e9a58george x0 = SkScalarRoundToFDot6(pts[0].fX, shift); 3422f26528e59908856e36e88aa3be94d84014e9a58george y0 = SkScalarRoundToFDot6(pts[0].fY, shift); 3432f26528e59908856e36e88aa3be94d84014e9a58george x1 = SkScalarRoundToFDot6(pts[1].fX, shift); 3442f26528e59908856e36e88aa3be94d84014e9a58george y1 = SkScalarRoundToFDot6(pts[1].fY, shift); 3452f26528e59908856e36e88aa3be94d84014e9a58george x2 = SkScalarRoundToFDot6(pts[2].fX, shift); 3462f26528e59908856e36e88aa3be94d84014e9a58george y2 = SkScalarRoundToFDot6(pts[2].fY, shift); 3472f26528e59908856e36e88aa3be94d84014e9a58george x3 = SkScalarRoundToFDot6(pts[3].fX, shift); 3482f26528e59908856e36e88aa3be94d84014e9a58george y3 = SkScalarRoundToFDot6(pts[3].fY, shift); 3492f26528e59908856e36e88aa3be94d84014e9a58george#else 3508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com float scale = float(1 << (shift + 6)); 3518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com x0 = int(pts[0].fX * scale); 3528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com y0 = int(pts[0].fY * scale); 3538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com x1 = int(pts[1].fX * scale); 3548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com y1 = int(pts[1].fY * scale); 3558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com x2 = int(pts[2].fX * scale); 3568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com y2 = int(pts[2].fY * scale); 3578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com x3 = int(pts[3].fX * scale); 3588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com y3 = int(pts[3].fY * scale); 3592f26528e59908856e36e88aa3be94d84014e9a58george#endif 3608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 3618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int winding = 1; 3638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (y0 > y3) 3648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com { 3658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkTSwap(x0, x3); 3668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkTSwap(x1, x2); 3678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkTSwap(y0, y3); 3688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkTSwap(y1, y2); 3698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com winding = -1; 3708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 3718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int top = SkFDot6Round(y0); 3738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int bot = SkFDot6Round(y3); 3748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // are we a zero-height cubic (line)? 3768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (top == bot) 3778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return 0; 3788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // are we completely above or below the clip? 3808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (clip && (top >= clip->fBottom || bot <= clip->fTop)) 3818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return 0; 3828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // compute number of steps needed (1 << shift) 3848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com { 3858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // Can't use (center of curve - center of baseline), since center-of-curve 3868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // need not be the max delta from the baseline (it could even be coincident) 3878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // so we try just looking at the two off-curve points 3888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFDot6 dx = cubic_delta_from_line(x0, x1, x2, x3); 3898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFDot6 dy = cubic_delta_from_line(y0, y1, y2, y3); 3908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // add 1 (by observation) 3918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com shift = diff_to_shift(dx, dy) + 1; 3928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 3938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // need at least 1 subdivision for our bias trick 3948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(shift > 0); 3958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (shift > MAX_COEFF_SHIFT) { 3968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com shift = MAX_COEFF_SHIFT; 3978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 3988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com /* Since our in coming data is initially shifted down by 10 (or 8 in 4008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com antialias). That means the most we can shift up is 8. However, we 4018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com compute coefficients with a 3*, so the safest upshift is really 6 4028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com */ 4038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int upShift = 6; // largest safe value 4048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int downShift = shift + upShift - 10; 4058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (downShift < 0) { 4068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com downShift = 0; 4078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com upShift = 10 - shift; 4088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fWinding = SkToS8(winding); 4118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fCurveCount = SkToS8(-1 << shift); 4128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fCurveShift = SkToU8(shift); 4138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fCubicDShift = SkToU8(downShift); 4148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFixed B = SkFDot6UpShift(3 * (x1 - x0), upShift); 4168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFixed C = SkFDot6UpShift(3 * (x0 - x1 - x1 + x2), upShift); 4178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFixed D = SkFDot6UpShift(x3 + 3 * (x1 - x2) - x0, upShift); 4188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fCx = SkFDot6ToFixed(x0); 4208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fCDx = B + (C >> shift) + (D >> 2*shift); // biased by shift 4218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fCDDx = 2*C + (3*D >> (shift - 1)); // biased by 2*shift 4228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fCDDDx = 3*D >> (shift - 1); // biased by 2*shift 4238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com B = SkFDot6UpShift(3 * (y1 - y0), upShift); 4258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com C = SkFDot6UpShift(3 * (y0 - y1 - y1 + y2), upShift); 4268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com D = SkFDot6UpShift(y3 + 3 * (y1 - y2) - y0, upShift); 4278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fCy = SkFDot6ToFixed(y0); 4298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fCDy = B + (C >> shift) + (D >> 2*shift); // biased by shift 4308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fCDDy = 2*C + (3*D >> (shift - 1)); // biased by 2*shift 4318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fCDDDy = 3*D >> (shift - 1); // biased by 2*shift 4328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fCLastX = SkFDot6ToFixed(x3); 4348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fCLastY = SkFDot6ToFixed(y3); 4358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (clip) 4378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com { 4388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com do { 4399da1ae3f35a6f25adf4f58ae2589129ceec6d11breed@android.com if (!this->updateCubic()) { 4409da1ae3f35a6f25adf4f58ae2589129ceec6d11breed@android.com return 0; 4419da1ae3f35a6f25adf4f58ae2589129ceec6d11breed@android.com } 4428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } while (!this->intersectsClip(*clip)); 4438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->chopLineWithClip(*clip); 4448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return 1; 4458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return this->updateCubic(); 4478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 4488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint SkCubicEdge::updateCubic() 4508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 4518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int success; 4528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int count = fCurveCount; 4538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFixed oldx = fCx; 4548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFixed oldy = fCy; 4558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFixed newx, newy; 4568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const int ddshift = fCurveShift; 4578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const int dshift = fCubicDShift; 4588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(count < 0); 4608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com do { 4628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (++count < 0) 4638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com { 4648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com newx = oldx + (fCDx >> dshift); 4658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fCDx += fCDDx >> ddshift; 4668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fCDDx += fCDDDx; 4678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com newy = oldy + (fCDy >> dshift); 4698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fCDy += fCDDy >> ddshift; 4708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fCDDy += fCDDDy; 4718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com else // last segment 4738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com { 4748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // SkDebugf("LastX err=%d, LastY err=%d\n", (oldx + (fCDx >> shift) - fLastX), (oldy + (fCDy >> shift) - fLastY)); 4758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com newx = fCLastX; 4768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com newy = fCLastY; 4778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 478055c7c299cb47eebd360b809ad58a0006e2e55f7skia.committer@gmail.com 4798cae8358f78b81539f1006afe592a37f1604e67creed@google.com // we want to say SkASSERT(oldy <= newy), but our finite fixedpoint 4808cae8358f78b81539f1006afe592a37f1604e67creed@google.com // doesn't always achieve that, so we have to explicitly pin it here. 4818cae8358f78b81539f1006afe592a37f1604e67creed@google.com if (newy < oldy) { 4828cae8358f78b81539f1006afe592a37f1604e67creed@google.com newy = oldy; 4838cae8358f78b81539f1006afe592a37f1604e67creed@google.com } 4848cae8358f78b81539f1006afe592a37f1604e67creed@google.com 4858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com success = this->updateLine(oldx, oldy, newx, newy); 4868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com oldx = newx; 4878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com oldy = newy; 4888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } while (count < 0 && !success); 4898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fCx = newx; 4918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fCy = newy; 49263debae4c1020fa1e0ccd92ef3cbfdc8735acf8ereed@android.com fCurveCount = SkToS8(count); 4938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return success; 4948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 495