18a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/*
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2008 The Android Open Source Project
38a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
68a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com */
78a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
84b163ed2c22facbe8891616874ae07ba7827d9c9reed@google.com#include "SkMathPriv.h"
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkFloatBits.h"
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkFloatingPoint.h"
118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkScalar.h"
128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
138f4d2306fa866a26f9448048ff63f692b2ba43aareed@google.comconst uint32_t gIEEENotANumber = 0x7FFFFFFF;
148f4d2306fa866a26f9448048ff63f692b2ba43aareed@google.comconst uint32_t gIEEEInfinity = 0x7F800000;
158f4d2306fa866a26f9448048ff63f692b2ba43aareed@google.comconst uint32_t gIEEENegativeInfinity = 0xFF800000;
168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define sub_shift(zeros, x, n)  \
188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    zeros -= n;                 \
198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    x >>= n
20fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint SkCLZ_portable(uint32_t x) {
228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (x == 0) {
238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return 32;
248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int zeros = 31;
278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (x & 0xFFFF0000) {
288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        sub_shift(zeros, x, 16);
298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (x & 0xFF00) {
318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        sub_shift(zeros, x, 8);
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (x & 0xF0) {
348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        sub_shift(zeros, x, 4);
358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (x & 0xC) {
378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        sub_shift(zeros, x, 2);
388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (x & 0x2) {
408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        sub_shift(zeros, x, 1);
418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return zeros;
448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
460e6e8cc627242cc7e301401cfe112ba98a008101robertphillips@google.comSkFixed SkFixedMul_portable(SkFixed a, SkFixed b) {
471915fd09f3b60eb907f5ab155e8379b589e2bae1reed@google.com#if defined(SkLONGLONG)
4801c41a556e0ef0ae2338a1b5ae110a501e1ed0a8reed@google.com    return static_cast<SkFixed>((int64_t)a * b >> 16);
490e6e8cc627242cc7e301401cfe112ba98a008101robertphillips@google.com#else
500e6e8cc627242cc7e301401cfe112ba98a008101robertphillips@google.com    int sa = SkExtractSign(a);
510e6e8cc627242cc7e301401cfe112ba98a008101robertphillips@google.com    int sb = SkExtractSign(b);
520e6e8cc627242cc7e301401cfe112ba98a008101robertphillips@google.com    // now make them positive
530e6e8cc627242cc7e301401cfe112ba98a008101robertphillips@google.com    a = SkApplySign(a, sa);
540e6e8cc627242cc7e301401cfe112ba98a008101robertphillips@google.com    b = SkApplySign(b, sb);
550e6e8cc627242cc7e301401cfe112ba98a008101robertphillips@google.com
560e6e8cc627242cc7e301401cfe112ba98a008101robertphillips@google.com    uint32_t    ah = a >> 16;
570e6e8cc627242cc7e301401cfe112ba98a008101robertphillips@google.com    uint32_t    al = a & 0xFFFF;
580e6e8cc627242cc7e301401cfe112ba98a008101robertphillips@google.com    uint32_t bh = b >> 16;
590e6e8cc627242cc7e301401cfe112ba98a008101robertphillips@google.com    uint32_t bl = b & 0xFFFF;
600e6e8cc627242cc7e301401cfe112ba98a008101robertphillips@google.com
610e6e8cc627242cc7e301401cfe112ba98a008101robertphillips@google.com    uint32_t R = ah * b + al * bh + (al * bl >> 16);
620e6e8cc627242cc7e301401cfe112ba98a008101robertphillips@google.com
630e6e8cc627242cc7e301401cfe112ba98a008101robertphillips@google.com    return SkApplySign(R, sa ^ sb);
640e6e8cc627242cc7e301401cfe112ba98a008101robertphillips@google.com#endif
650e6e8cc627242cc7e301401cfe112ba98a008101robertphillips@google.com}
660e6e8cc627242cc7e301401cfe112ba98a008101robertphillips@google.com
678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define DIVBITS_ITER(n)                                 \
708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    case n:                                             \
718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if ((numer = (numer << 1) - denom) >= 0)        \
728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            result |= 1 << (n - 1); else numer += denom
73fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint32_t SkDivBits(int32_t numer, int32_t denom, int shift_bias) {
758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(denom != 0);
768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (numer == 0) {
778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return 0;
788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
79fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // make numer and denom positive, and sign hold the resulting sign
818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int32_t sign = SkExtractSign(numer ^ denom);
828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    numer = SkAbs32(numer);
838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    denom = SkAbs32(denom);
848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int nbits = SkCLZ(numer) - 1;
868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int dbits = SkCLZ(denom) - 1;
878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int bits = shift_bias - nbits + dbits;
888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (bits < 0) {  // answer will underflow
908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return 0;
918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (bits > 31) {  // answer will overflow
938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return SkApplySign(SK_MaxS32, sign);
948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    denom <<= dbits;
978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    numer <<= nbits;
98fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkFixed result = 0;
100fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // do the first one
1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if ((numer -= denom) >= 0) {
1038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        result = 1;
1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        numer += denom;
1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
107fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // Now fall into our switch statement if there are more bits to compute
1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (bits > 0) {
1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // make room for the rest of the answer bits
1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        result <<= bits;
1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        switch (bits) {
1138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            DIVBITS_ITER(31); DIVBITS_ITER(30); DIVBITS_ITER(29);
1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            DIVBITS_ITER(28); DIVBITS_ITER(27); DIVBITS_ITER(26);
1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            DIVBITS_ITER(25); DIVBITS_ITER(24); DIVBITS_ITER(23);
1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            DIVBITS_ITER(22); DIVBITS_ITER(21); DIVBITS_ITER(20);
1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            DIVBITS_ITER(19); DIVBITS_ITER(18); DIVBITS_ITER(17);
1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            DIVBITS_ITER(16); DIVBITS_ITER(15); DIVBITS_ITER(14);
1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            DIVBITS_ITER(13); DIVBITS_ITER(12); DIVBITS_ITER(11);
1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            DIVBITS_ITER(10); DIVBITS_ITER( 9); DIVBITS_ITER( 8);
1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            DIVBITS_ITER( 7); DIVBITS_ITER( 6); DIVBITS_ITER( 5);
1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            DIVBITS_ITER( 4); DIVBITS_ITER( 3); DIVBITS_ITER( 2);
1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            // we merge these last two together, makes GCC make better ARM
1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            default:
1258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            DIVBITS_ITER( 1);
1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (result < 0) {
1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        result = SK_MaxS32;
1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return SkApplySign(result, sign);
1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/* www.worldserver.com/turk/computergraphics/FixedSqrt.pdf
1368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/
1378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint32_t SkSqrtBits(int32_t x, int count) {
1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(x >= 0 && count > 0 && (unsigned)count <= 30);
1398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint32_t    root = 0;
1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint32_t    remHi = 0;
1428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint32_t    remLo = x;
1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    do {
1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        root <<= 1;
1468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        remHi = (remHi<<2) | (remLo>>30);
1488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        remLo <<= 2;
1498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        uint32_t testDiv = (root << 1) + 1;
1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (remHi >= testDiv) {
1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            remHi -= testDiv;
1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            root++;
1548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } while (--count >= 0);
1568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return root;
1588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
1618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comfloat SkScalarSinCos(float radians, float* cosValue) {
1638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    float sinValue = sk_float_sin(radians);
1648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (cosValue) {
1668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        *cosValue = sk_float_cos(radians);
1678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (SkScalarNearlyZero(*cosValue)) {
1688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            *cosValue = 0;
1698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (SkScalarNearlyZero(sinValue)) {
1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        sinValue = 0;
1748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return sinValue;
1768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define INTERP_SINTABLE
1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define BUILD_TABLE_AT_RUNTIMEx
1808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define kTableSize  256
1828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef BUILD_TABLE_AT_RUNTIME
1848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static uint16_t gSkSinTable[kTableSize];
1858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static void build_sintable(uint16_t table[]) {
1878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        for (int i = 0; i < kTableSize; i++) {
1888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            double  rad = i * 3.141592653589793 / (2*kTableSize);
1898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            double  val = sin(rad);
1908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            int     ival = (int)(val * SK_Fixed1);
1918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            table[i] = SkToU16(ival);
1928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#else
1958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    #include "SkSinTable.h"
1968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
1978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SK_Fract1024SizeOver2PI     0x28BE60    /* floatToFract(1024 / 2PI) */
1998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef INTERP_SINTABLE
2018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic SkFixed interp_table(const uint16_t table[], int index, int partial255) {
2028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT((unsigned)index < kTableSize);
2038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT((unsigned)partial255 <= 255);
2048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkFixed lower = table[index];
2068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkFixed upper = (index == kTableSize - 1) ? SK_Fixed1 : table[index + 1];
2078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(lower < upper);
2098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(lower >= 0);
2108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(upper <= SK_Fixed1);
2118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    partial255 += (partial255 >> 7);
2138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return lower + ((upper - lower) * partial255 >> 8);
2148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
2168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkFixed SkFixedSinCos(SkFixed radians, SkFixed* cosValuePtr) {
2188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(SK_ARRAY_COUNT(gSkSinTable) == kTableSize);
2198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef BUILD_TABLE_AT_RUNTIME
2218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static bool gFirstTime = true;
2228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (gFirstTime) {
2238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        build_sintable(gSinTable);
2248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        gFirstTime = false;
2258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
2278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // make radians positive
2298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkFixed sinValue, cosValue;
2308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int32_t cosSign = 0;
2318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int32_t sinSign = SkExtractSign(radians);
2328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    radians = SkApplySign(radians, sinSign);
2338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // scale it to 0...1023 ...
2348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef INTERP_SINTABLE
2368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    radians = SkMulDiv(radians, 2 * kTableSize * 256, SK_FixedPI);
2378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int findex = radians & (kTableSize * 256 - 1);
2388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int index = findex >> 8;
2398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int partial = findex & 255;
2408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    sinValue = interp_table(gSkSinTable, index, partial);
2418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    findex = kTableSize * 256 - findex - 1;
2438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    index = findex >> 8;
2448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    partial = findex & 255;
2458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    cosValue = interp_table(gSkSinTable, index, partial);
2468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int quad = ((unsigned)radians / (kTableSize * 256)) & 3;
2488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#else
2498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    radians = SkMulDiv(radians, 2 * kTableSize, SK_FixedPI);
2508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int     index = radians & (kTableSize - 1);
2518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (index == 0) {
2538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        sinValue = 0;
2548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        cosValue = SK_Fixed1;
2558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
2568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        sinValue = gSkSinTable[index];
2578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        cosValue = gSkSinTable[kTableSize - index];
2588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int quad = ((unsigned)radians / kTableSize) & 3;
2608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
2618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (quad & 1) {
2638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkTSwap<SkFixed>(sinValue, cosValue);
2648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (quad & 2) {
2668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        sinSign = ~sinSign;
2678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (((quad - 1) & 2) == 0) {
2698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        cosSign = ~cosSign;
2708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // restore the sign for negative angles
2738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    sinValue = SkApplySign(sinValue, sinSign);
2748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    cosValue = SkApplySign(cosValue, cosSign);
2758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG
2778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (1) {
2788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkFixed sin2 = SkFixedMul(sinValue, sinValue);
2798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkFixed cos2 = SkFixedMul(cosValue, cosValue);
2808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int diff = cos2 + sin2 - SK_Fixed1;
2818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(SkAbs32(diff) <= 7);
2828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
2848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (cosValuePtr) {
2868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        *cosValuePtr = cosValue;
2878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return sinValue;
2898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
290