1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 28a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/* 3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2008 The Android Open Source Project 48a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.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. 78a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com */ 88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 9ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkInterpolator.h" 118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkMath.h" 128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkTSearch.h" 138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkInterpolatorBase::SkInterpolatorBase() { 158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fStorage = NULL; 168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fTimes = NULL; 178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDEBUGCODE(fTimesArray = NULL;) 188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkInterpolatorBase::~SkInterpolatorBase() { 218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (fStorage) { 228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com sk_free(fStorage); 238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkInterpolatorBase::reset(int elemCount, int frameCount) { 278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fFlags = 0; 288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fElemCount = SkToU8(elemCount); 298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fFrameCount = SkToS16(frameCount); 308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fRepeat = SK_Scalar1; 318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (fStorage) { 328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com sk_free(fStorage); 338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fStorage = NULL; 348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fTimes = NULL; 358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDEBUGCODE(fTimesArray = NULL); 368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/* Each value[] run is formated as: 408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com <time (in msec)> 418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com <blend> 428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com <data[fElemCount]> 438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com Totaling fElemCount+2 entries per keyframe 458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/ 468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkInterpolatorBase::getDuration(SkMSec* startTime, SkMSec* endTime) const { 488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (fFrameCount == 0) { 498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return false; 508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (startTime) { 538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *startTime = fTimes[0].fTime; 548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (endTime) { 568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *endTime = fTimes[fFrameCount - 1].fTime; 578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return true; 598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkScalar SkInterpolatorBase::ComputeRelativeT(SkMSec time, SkMSec prevTime, 628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMSec nextTime, const SkScalar blend[4]) { 638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(time > prevTime && time < nextTime); 648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar t = SkScalarDiv((SkScalar)(time - prevTime), 668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com (SkScalar)(nextTime - prevTime)); 678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return blend ? 688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkUnitCubicInterp(t, blend[0], blend[1], blend[2], blend[3]) : t; 698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkInterpolatorBase::Result SkInterpolatorBase::timeToT(SkMSec time, SkScalar* T, 728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int* indexPtr, SkBool* exactPtr) const { 738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(fFrameCount > 0); 748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com Result result = kNormal_Result; 758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (fRepeat != SK_Scalar1) { 76f523e25da069e3e1af2cb73d37073a34f3bb9ea2reed@android.com SkMSec startTime = 0, endTime = 0; // initialize to avoid warning 778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->getDuration(&startTime, &endTime); 788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMSec totalTime = endTime - startTime; 798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMSec offsetTime = time - startTime; 808015cdd8fa5694e52b70e728bcdc6b35d739b819reed@google.com endTime = SkScalarFloorToInt(fRepeat * totalTime); 818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (offsetTime >= endTime) { 828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar fraction = SkScalarFraction(fRepeat); 838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com offsetTime = fraction == 0 && fRepeat > 0 ? totalTime : 848015cdd8fa5694e52b70e728bcdc6b35d739b819reed@google.com (SkMSec) SkScalarFloorToInt(fraction * totalTime); 858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com result = kFreezeEnd_Result; 868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int mirror = fFlags & kMirror; 888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com offsetTime = offsetTime % (totalTime << mirror); 898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (offsetTime > totalTime) { // can only be true if fMirror is true 908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com offsetTime = (totalTime << 1) - offsetTime; 918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com time = offsetTime + startTime; 948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int index = SkTSearch<SkMSec>(&fTimes[0].fTime, fFrameCount, time, 978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com sizeof(SkTimeCode)); 988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com bool exact = true; 1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (index < 0) { 1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com index = ~index; 1038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (index == 0) { 1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com result = kFreezeStart_Result; 1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else if (index == fFrameCount) { 1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (fFlags & kReset) { 1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com index = 0; 1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com index -= 1; 1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com result = kFreezeEnd_Result; 1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 1138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com exact = false; 1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(index < fFrameCount); 1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const SkTimeCode* nextTime = &fTimes[index]; 1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMSec nextT = nextTime[0].fTime; 1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (exact) { 1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *T = 0; 1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMSec prevT = nextTime[-1].fTime; 1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *T = ComputeRelativeT(time, prevT, nextT, nextTime[-1].fBlend); 1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *indexPtr = index; 1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *exactPtr = exact; 1278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return result; 1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkInterpolator::SkInterpolator() { 1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com INHERITED::reset(0, 0); 1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fValues = NULL; 1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDEBUGCODE(fScalarsArray = NULL;) 1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkInterpolator::SkInterpolator(int elemCount, int frameCount) { 1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(elemCount > 0); 1398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->reset(elemCount, frameCount); 1408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkInterpolator::reset(int elemCount, int frameCount) { 1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com INHERITED::reset(elemCount, frameCount); 1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fStorage = sk_malloc_throw((sizeof(SkScalar) * elemCount + 1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com sizeof(SkTimeCode)) * frameCount); 1468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fTimes = (SkTimeCode*) fStorage; 1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fValues = (SkScalar*) ((char*) fStorage + sizeof(SkTimeCode) * frameCount); 1488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG 1498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fTimesArray = (SkTimeCode(*)[10]) fTimes; 1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fScalarsArray = (SkScalar(*)[10]) fValues; 1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif 1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SK_Fixed1Third (SK_Fixed1/3) 1558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SK_Fixed2Third (SK_Fixed1*2/3) 1568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic const SkScalar gIdentityBlend[4] = { 1588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 0.33333333f, 0.33333333f, 0.66666667f, 0.66666667f 1598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}; 1608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkInterpolator::setKeyFrame(int index, SkMSec time, 1628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const SkScalar values[], const SkScalar blend[4]) { 1638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(values != NULL); 164d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com 1658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (blend == NULL) { 1668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com blend = gIdentityBlend; 1678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com bool success = ~index == SkTSearch<SkMSec>(&fTimes->fTime, index, time, 1708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com sizeof(SkTimeCode)); 1718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(success); 1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (success) { 1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkTimeCode* timeCode = &fTimes[index]; 1748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com timeCode->fTime = time; 1758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com memcpy(timeCode->fBlend, blend, sizeof(timeCode->fBlend)); 1768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar* dst = &fValues[fElemCount * index]; 1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com memcpy(dst, values, fElemCount * sizeof(SkScalar)); 1788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return success; 1808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkInterpolator::Result SkInterpolator::timeToValues(SkMSec time, 1838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar values[]) const { 1848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar T; 1858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int index; 1868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkBool exact; 1878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com Result result = timeToT(time, &T, &index, &exact); 1888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (values) { 1898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const SkScalar* nextSrc = &fValues[index * fElemCount]; 1908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (exact) { 1928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com memcpy(values, nextSrc, fElemCount * sizeof(SkScalar)); 1938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 1948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(index > 0); 1958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const SkScalar* prevSrc = nextSrc - fElemCount; 1978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (int i = fElemCount - 1; i >= 0; --i) { 1998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com values[i] = SkScalarInterp(prevSrc[i], nextSrc[i], T); 2008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return result; 2048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 2058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////// 2078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comtypedef int Dot14; 2098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define Dot14_ONE (1 << 14) 2108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define Dot14_HALF (1 << 13) 2118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define Dot14ToFloat(x) ((x) / 16384.f) 2138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic inline Dot14 Dot14Mul(Dot14 a, Dot14 b) { 2158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return (a * b + Dot14_HALF) >> 14; 2168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 2178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic inline Dot14 eval_cubic(Dot14 t, Dot14 A, Dot14 B, Dot14 C) { 2198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return Dot14Mul(Dot14Mul(Dot14Mul(C, t) + B, t) + A, t); 2208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 2218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic inline Dot14 pin_and_convert(SkScalar x) { 2238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (x <= 0) { 2248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return 0; 2258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (x >= SK_Scalar1) { 2278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return Dot14_ONE; 2288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return SkScalarToFixed(x) >> 2; 2308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 2318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkScalar SkUnitCubicInterp(SkScalar value, SkScalar bx, SkScalar by, 2338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar cx, SkScalar cy) { 2348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // pin to the unit-square, and convert to 2.14 2358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com Dot14 x = pin_and_convert(value); 236d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com 2378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (x == 0) return 0; 2388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (x == Dot14_ONE) return SK_Scalar1; 239d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com 2408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com Dot14 b = pin_and_convert(bx); 2418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com Dot14 c = pin_and_convert(cx); 242d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com 2438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // Now compute our coefficients from the control points 2448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // t -> 3b 2458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // t^2 -> 3c - 6b 2468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // t^3 -> 3b - 3c + 1 2478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com Dot14 A = 3*b; 2488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com Dot14 B = 3*(c - 2*b); 2498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com Dot14 C = 3*(b - c) + Dot14_ONE; 2508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // Now search for a t value given x 2528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com Dot14 t = Dot14_HALF; 2538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com Dot14 dt = Dot14_HALF; 2548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (int i = 0; i < 13; i++) { 2558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com dt >>= 1; 2568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com Dot14 guess = eval_cubic(t, A, B, C); 2578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (x < guess) { 2588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com t -= dt; 2598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 2608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com t += dt; 2618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 263d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com 2648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // Now we have t, so compute the coeff for Y and evaluate 2658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com b = pin_and_convert(by); 2668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com c = pin_and_convert(cy); 2678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com A = 3*b; 2688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com B = 3*(c - 2*b); 2698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com C = 3*(b - c) + Dot14_ONE; 2708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return SkFixedToScalar(eval_cubic(t, A, B, C) << 2); 2718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 272