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