1b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar
2b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar/*
3b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar * Copyright 2006 The Android Open Source Project
4b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar *
5b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar * Use of this source code is governed by a BSD-style license that can be
6b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar * found in the LICENSE file.
7b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar */
8b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar
9b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar
10b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar#include "SkUtils.h"
1156ac85c4fd18ee4af27c81b0ce11b2191461a0a5Daniel Dunbar
1256ac85c4fd18ee4af27c81b0ce11b2191461a0a5Daniel Dunbar#if 0
13389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis#define assign_16_longs(dst, value)             \
1456ac85c4fd18ee4af27c81b0ce11b2191461a0a5Daniel Dunbar    do {                                        \
1556ac85c4fd18ee4af27c81b0ce11b2191461a0a5Daniel Dunbar        (dst)[0] = value;   (dst)[1] = value;   \
1656ac85c4fd18ee4af27c81b0ce11b2191461a0a5Daniel Dunbar        (dst)[2] = value;   (dst)[3] = value;   \
1756ac85c4fd18ee4af27c81b0ce11b2191461a0a5Daniel Dunbar        (dst)[4] = value;   (dst)[5] = value;   \
1856ac85c4fd18ee4af27c81b0ce11b2191461a0a5Daniel Dunbar        (dst)[6] = value;   (dst)[7] = value;   \
1956ac85c4fd18ee4af27c81b0ce11b2191461a0a5Daniel Dunbar        (dst)[8] = value;   (dst)[9] = value;   \
2056ac85c4fd18ee4af27c81b0ce11b2191461a0a5Daniel Dunbar        (dst)[10] = value;  (dst)[11] = value;  \
2156ac85c4fd18ee4af27c81b0ce11b2191461a0a5Daniel Dunbar        (dst)[12] = value;  (dst)[13] = value;  \
226ab7cd853e9c15cf986a8a7c3db1f8d20e275409Sebastian Redl        (dst)[14] = value;  (dst)[15] = value;  \
2356ac85c4fd18ee4af27c81b0ce11b2191461a0a5Daniel Dunbar    } while (0)
2456ac85c4fd18ee4af27c81b0ce11b2191461a0a5Daniel Dunbar#else
25b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar#define assign_16_longs(dst, value)             \
2656ac85c4fd18ee4af27c81b0ce11b2191461a0a5Daniel Dunbar    do {                                        \
272dc14532b641bae011a374e2c6c393d2196c1411Duncan Sands        *(dst)++ = value;   *(dst)++ = value;   \
28b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        *(dst)++ = value;   *(dst)++ = value;   \
2903013fa9a0bf1ef4b907f5fec006c8f4000fdd21Michael J. Spencer        *(dst)++ = value;   *(dst)++ = value;   \
3003013fa9a0bf1ef4b907f5fec006c8f4000fdd21Michael J. Spencer        *(dst)++ = value;   *(dst)++ = value;   \
31b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        *(dst)++ = value;   *(dst)++ = value;   \
32b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        *(dst)++ = value;   *(dst)++ = value;   \
33b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        *(dst)++ = value;   *(dst)++ = value;   \
34b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        *(dst)++ = value;   *(dst)++ = value;   \
35b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    } while (0)
369f61aa9e280adea9fbf3365f0e4f6ed568c9885aJeffrey Yasskin#endif
37b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar
38b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar///////////////////////////////////////////////////////////////////////////////
39b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar
40b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbarvoid sk_memset16_portable(uint16_t dst[], uint16_t value, int count) {
41b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    SkASSERT(dst != NULL && count >= 0);
42b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar
43b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    if (count <= 0) {
44b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        return;
45b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    }
469f61aa9e280adea9fbf3365f0e4f6ed568c9885aJeffrey Yasskin
47b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    // not sure if this helps to short-circuit on small values of count
48b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    if (count < 8) {
49b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        do {
50b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar            *dst++ = (uint16_t)value;
51b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        } while (--count != 0);
52b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        return;
53b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    }
54b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar
55b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    // ensure we're on a long boundary
569f61aa9e280adea9fbf3365f0e4f6ed568c9885aJeffrey Yasskin    if ((size_t)dst & 2) {
57b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        *dst++ = (uint16_t)value;
58b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        count -= 1;
59b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    }
60b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar
61b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    uint32_t value32 = ((uint32_t)value << 16) | value;
62b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar
63d30952838421ddfb9f7e346b2ba8213889a5f789Anna Zaks    // handle the bulk with our unrolled macro
64d30952838421ddfb9f7e346b2ba8213889a5f789Anna Zaks    {
65d30952838421ddfb9f7e346b2ba8213889a5f789Anna Zaks        int sixteenlongs = count >> 5;
66d30952838421ddfb9f7e346b2ba8213889a5f789Anna Zaks        if (sixteenlongs) {
67d30952838421ddfb9f7e346b2ba8213889a5f789Anna Zaks            uint32_t* dst32 = (uint32_t*)dst;
68d30952838421ddfb9f7e346b2ba8213889a5f789Anna Zaks            do {
69d30952838421ddfb9f7e346b2ba8213889a5f789Anna Zaks                assign_16_longs(dst32, value32);
70d30952838421ddfb9f7e346b2ba8213889a5f789Anna Zaks            } while (--sixteenlongs != 0);
71d30952838421ddfb9f7e346b2ba8213889a5f789Anna Zaks            dst = (uint16_t*)dst32;
72d30952838421ddfb9f7e346b2ba8213889a5f789Anna Zaks            count &= 31;
7356ac85c4fd18ee4af27c81b0ce11b2191461a0a5Daniel Dunbar        }
7456ac85c4fd18ee4af27c81b0ce11b2191461a0a5Daniel Dunbar    }
7556ac85c4fd18ee4af27c81b0ce11b2191461a0a5Daniel Dunbar
7656ac85c4fd18ee4af27c81b0ce11b2191461a0a5Daniel Dunbar    // handle (most) of the rest
77b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    {
78b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        int longs = count >> 1;
79116f3640daee424dfcdbe55e80be5a67476be4b0Argyrios Kyrtzidis        if (longs) {
80116f3640daee424dfcdbe55e80be5a67476be4b0Argyrios Kyrtzidis            do {
81a4c7a4314ffbe402091695874e93d9b0a79c8099Ted Kremenek                *(uint32_t*)dst = value32;
82b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar                dst += 2;
83b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar            } while (--longs != 0);
84b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        }
85b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    }
86b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar
87b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    // cleanup a possible trailing short
88b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    if (count & 1) {
89b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        *dst = (uint16_t)value;
90b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    }
91b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar}
92b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar
93d30952838421ddfb9f7e346b2ba8213889a5f789Anna Zaksvoid sk_memset32_portable(uint32_t dst[], uint32_t value, int count) {
94d30952838421ddfb9f7e346b2ba8213889a5f789Anna Zaks    SkASSERT(dst != NULL && count >= 0);
95d30952838421ddfb9f7e346b2ba8213889a5f789Anna Zaks
96d30952838421ddfb9f7e346b2ba8213889a5f789Anna Zaks    int sixteenlongs = count >> 4;
97b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    if (sixteenlongs) {
98b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        do {
99b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar            assign_16_longs(dst, value);
100b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        } while (--sixteenlongs != 0);
101b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        count &= 15;
102b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    }
103b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar
104b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    if (count) {
105fc576514d06c46a7cac49500169411d82f38d04bTed Kremenek        do {
106fc576514d06c46a7cac49500169411d82f38d04bTed Kremenek            *dst++ = value;
107b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        } while (--count != 0);
108b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    }
109b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar}
110b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar
111b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbarstatic void sk_memset16_stub(uint16_t dst[], uint16_t value, int count) {
112b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    SkMemset16Proc proc = SkMemset16GetPlatformProc();
1131040c227efc6821cd39795206c178894470a1a48Sandeep Patel    sk_memset16 = proc ? proc : sk_memset16_portable;
114b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    sk_memset16(dst, value, count);
11543dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis}
11643dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis
11743dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios KyrtzidisSkMemset16Proc sk_memset16 = sk_memset16_stub;
11843dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis
11943dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidisstatic void sk_memset32_stub(uint32_t dst[], uint32_t value, int count) {
12043dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis    SkMemset32Proc proc = SkMemset32GetPlatformProc();
12143dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis    sk_memset32 = proc ? proc : sk_memset32_portable;
12243dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis    sk_memset32(dst, value, count);
12343dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis}
124b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar
125b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel DunbarSkMemset32Proc sk_memset32 = sk_memset32_stub;
126b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar
127b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar///////////////////////////////////////////////////////////////////////////////
128b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar
129b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar/*  0xxxxxxx    1 total
130b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    10xxxxxx    // never a leading byte
131b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    110xxxxx    2 total
132b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    1110xxxx    3 total
133b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    11110xxx    4 total
1347c4fd9121f5885096fd3258d20a984e3f08f8603Nick Lewycky
1357c4fd9121f5885096fd3258d20a984e3f08f8603Nick Lewycky    11 10 01 01 xx xx xx xx 0...
1367c4fd9121f5885096fd3258d20a984e3f08f8603Nick Lewycky    0xE5XX0000
1377c4fd9121f5885096fd3258d20a984e3f08f8603Nick Lewycky    0xE5 << 24
138f2d8b9f967a1ab53ee9fdbcc3ac0a4ee0a83a26eDaniel Dunbar*/
139f2d8b9f967a1ab53ee9fdbcc3ac0a4ee0a83a26eDaniel Dunbar
140f2d8b9f967a1ab53ee9fdbcc3ac0a4ee0a83a26eDaniel Dunbar#ifdef SK_DEBUG
141f2d8b9f967a1ab53ee9fdbcc3ac0a4ee0a83a26eDaniel Dunbar    static void assert_utf8_leadingbyte(unsigned c) {
1429f084a3166b684573ba49df28fc5792bc37d92e1John McCall        SkASSERT(c <= 0xF7);    // otherwise leading byte is too big (more than 4 bytes)
1439f084a3166b684573ba49df28fc5792bc37d92e1John McCall        SkASSERT((c & 0xC0) != 0x80);   // can't begin with a middle char
144256a76e0b0e0c9e65a3122917d553ef10bc84d29John McCall    }
145256a76e0b0e0c9e65a3122917d553ef10bc84d29John McCall
146e8ba8d78a258ec992d3521eebdae8324db777b14Nick Lewycky    int SkUTF8_LeadByteToCount(unsigned c) {
147e8ba8d78a258ec992d3521eebdae8324db777b14Nick Lewycky        assert_utf8_leadingbyte(c);
148e8ba8d78a258ec992d3521eebdae8324db777b14Nick Lewycky        return (((0xE5 << 24) >> (c >> 4 << 1)) & 3) + 1;
149e8ba8d78a258ec992d3521eebdae8324db777b14Nick Lewycky    }
150b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar#else
151b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    #define assert_utf8_leadingbyte(c)
15250a4487683a7e09fb93e8b506181e034241a0ffeDaniel Dunbar#endif
15350a4487683a7e09fb93e8b506181e034241a0ffeDaniel Dunbar
15432096695c76033a6b0b1747c439f7378a11e8312John McCallint SkUTF8_CountUnichars(const char utf8[]) {
15532096695c76033a6b0b1747c439f7378a11e8312John McCall    SkASSERT(utf8);
156e26bdb91b7e3912ffe895b78a446db94471a59ddDaniel Dunbar
157e26bdb91b7e3912ffe895b78a446db94471a59ddDaniel Dunbar    int count = 0;
158b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar
159b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    for (;;) {
1601ad6648cce57bd187f1853f58fef26cd9bf4934fDaniel Dunbar        int c = *(const uint8_t*)utf8;
1611ad6648cce57bd187f1853f58fef26cd9bf4934fDaniel Dunbar        if (c == 0) {
162b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar            break;
163b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        }
164a0fa203f04235cb6d05eeb8cea3392a01aa7571bBob Wilson        utf8 += SkUTF8_LeadByteToCount(c);
1651be3b3bd5c983e3fc5b78db155632d2d2d6aa968Daniel Dunbar        count += 1;
1661be3b3bd5c983e3fc5b78db155632d2d2d6aa968Daniel Dunbar    }
1677d065d0f21b35f445cee13730398bc2bec6edff2Daniel Dunbar    return count;
1687d065d0f21b35f445cee13730398bc2bec6edff2Daniel Dunbar}
1697d065d0f21b35f445cee13730398bc2bec6edff2Daniel Dunbar
1707d065d0f21b35f445cee13730398bc2bec6edff2Daniel Dunbarint SkUTF8_CountUnichars(const char utf8[], size_t byteLength) {
171b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    SkASSERT(NULL != utf8 || 0 == byteLength);
172b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar
173b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    int         count = 0;
174b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    const char* stop = utf8 + byteLength;
17520249a1af2e462dcafdd6a350f1c7967b264ff25Michael J. Spencer
176f84d409903dd4107c8cef5a08fcfce6e5c21d4deEric Christopher    while (utf8 < stop) {
177f84d409903dd4107c8cef5a08fcfce6e5c21d4deEric Christopher        utf8 += SkUTF8_LeadByteToCount(*(const uint8_t*)utf8);
178f84d409903dd4107c8cef5a08fcfce6e5c21d4deEric Christopher        count += 1;
179f84d409903dd4107c8cef5a08fcfce6e5c21d4deEric Christopher    }
180bbea7168326d810eff18dfb8bc43c7790fd55010Chris Lattner    return count;
181bbea7168326d810eff18dfb8bc43c7790fd55010Chris Lattner}
182bbea7168326d810eff18dfb8bc43c7790fd55010Chris Lattner
183bbea7168326d810eff18dfb8bc43c7790fd55010Chris LattnerSkUnichar SkUTF8_ToUnichar(const char utf8[]) {
184f219e7c1529fac29e34483667f740b452e5ef9ccDaniel Dunbar    SkASSERT(NULL != utf8);
185f219e7c1529fac29e34483667f740b452e5ef9ccDaniel Dunbar
186f219e7c1529fac29e34483667f740b452e5ef9ccDaniel Dunbar    const uint8_t*  p = (const uint8_t*)utf8;
187f219e7c1529fac29e34483667f740b452e5ef9ccDaniel Dunbar    int             c = *p;
188f219e7c1529fac29e34483667f740b452e5ef9ccDaniel Dunbar    int             hic = c << 24;
189f219e7c1529fac29e34483667f740b452e5ef9ccDaniel Dunbar
190d51e43af0b3a6897b971f316c4de2035ec82d1f2Peter Collingbourne    assert_utf8_leadingbyte(c);
191d51e43af0b3a6897b971f316c4de2035ec82d1f2Peter Collingbourne
192efb0fa9e11f75af51744a6159530ef7cc8efa24aDaniel Dunbar    if (hic < 0) {
193efb0fa9e11f75af51744a6159530ef7cc8efa24aDaniel Dunbar        uint32_t mask = (uint32_t)~0x3F;
194efb0fa9e11f75af51744a6159530ef7cc8efa24aDaniel Dunbar        hic <<= 1;
195efb0fa9e11f75af51744a6159530ef7cc8efa24aDaniel Dunbar        do {
196f85e193739c953358c865005855253af4f68a497John McCall            c = (c << 6) | (*++p & 0x3F);
197f85e193739c953358c865005855253af4f68a497John McCall            mask <<= 5;
198f219e7c1529fac29e34483667f740b452e5ef9ccDaniel Dunbar        } while ((hic <<= 1) < 0);
199f219e7c1529fac29e34483667f740b452e5ef9ccDaniel Dunbar        c &= ~mask;
200f219e7c1529fac29e34483667f740b452e5ef9ccDaniel Dunbar    }
201f219e7c1529fac29e34483667f740b452e5ef9ccDaniel Dunbar    return c;
202f219e7c1529fac29e34483667f740b452e5ef9ccDaniel Dunbar}
203f219e7c1529fac29e34483667f740b452e5ef9ccDaniel Dunbar
2043b315264d1a6fa303e20fe0caec306ccafc090deDaniel DunbarSkUnichar SkUTF8_NextUnichar(const char** ptr) {
2053b315264d1a6fa303e20fe0caec306ccafc090deDaniel Dunbar    SkASSERT(NULL != ptr && NULL != *ptr);
2063b315264d1a6fa303e20fe0caec306ccafc090deDaniel Dunbar
2073b315264d1a6fa303e20fe0caec306ccafc090deDaniel Dunbar    const uint8_t*  p = (const uint8_t*)*ptr;
208f219e7c1529fac29e34483667f740b452e5ef9ccDaniel Dunbar    int             c = *p;
209f219e7c1529fac29e34483667f740b452e5ef9ccDaniel Dunbar    int             hic = c << 24;
210f219e7c1529fac29e34483667f740b452e5ef9ccDaniel Dunbar
211f219e7c1529fac29e34483667f740b452e5ef9ccDaniel Dunbar    assert_utf8_leadingbyte(c);
212f219e7c1529fac29e34483667f740b452e5ef9ccDaniel Dunbar
213f219e7c1529fac29e34483667f740b452e5ef9ccDaniel Dunbar    if (hic < 0) {
214f643b9b338b797a824447207d7eab5f1187f4f34Daniel Dunbar        uint32_t mask = (uint32_t)~0x3F;
215f643b9b338b797a824447207d7eab5f1187f4f34Daniel Dunbar        hic <<= 1;
216f643b9b338b797a824447207d7eab5f1187f4f34Daniel Dunbar        do {
217f643b9b338b797a824447207d7eab5f1187f4f34Daniel Dunbar            c = (c << 6) | (*++p & 0x3F);
218f643b9b338b797a824447207d7eab5f1187f4f34Daniel Dunbar            mask <<= 5;
219f643b9b338b797a824447207d7eab5f1187f4f34Daniel Dunbar        } while ((hic <<= 1) < 0);
220f643b9b338b797a824447207d7eab5f1187f4f34Daniel Dunbar        c &= ~mask;
221f643b9b338b797a824447207d7eab5f1187f4f34Daniel Dunbar    }
222f643b9b338b797a824447207d7eab5f1187f4f34Daniel Dunbar    *ptr = (char*)p + 1;
223f643b9b338b797a824447207d7eab5f1187f4f34Daniel Dunbar    return c;
22417d3fea677753e6e3e82ffe2cbdeccbf5f2e7497Daniel Dunbar}
22517d3fea677753e6e3e82ffe2cbdeccbf5f2e7497Daniel Dunbar
22617d3fea677753e6e3e82ffe2cbdeccbf5f2e7497Daniel DunbarSkUnichar SkUTF8_PrevUnichar(const char** ptr) {
22717d3fea677753e6e3e82ffe2cbdeccbf5f2e7497Daniel Dunbar    SkASSERT(NULL != ptr && NULL != *ptr);
2281b9060553221720152e12981109549e0a1d8e3a1Chad Rosier
2291b9060553221720152e12981109549e0a1d8e3a1Chad Rosier    const char* p = *ptr;
230c3b9014c7236a15cf467662264b243a22c420312Nick Lewycky
231c3b9014c7236a15cf467662264b243a22c420312Nick Lewycky    if (*--p & 0x80) {
2324ecc9b73b3716775ed4e09091e300796a9a72378Daniel Dunbar        while (*--p & 0x40) {
2334ecc9b73b3716775ed4e09091e300796a9a72378Daniel Dunbar            ;
234969323239f16589329d091a2b8ef200fcfe7c9e9Daniel Dunbar        }
235969323239f16589329d091a2b8ef200fcfe7c9e9Daniel Dunbar    }
236f24a151d645abc89f94aa58ad59f3131502041b1Rafael Espindola
237f24a151d645abc89f94aa58ad59f3131502041b1Rafael Espindola    *ptr = (char*)p;
238ea523d73a6de06f828952a02f5ff86e4cc631695Nick Lewycky    return SkUTF8_NextUnichar(&p);
239ea523d73a6de06f828952a02f5ff86e4cc631695Nick Lewycky}
2403b315264d1a6fa303e20fe0caec306ccafc090deDaniel Dunbar
2413b315264d1a6fa303e20fe0caec306ccafc090deDaniel Dunbarsize_t SkUTF8_FromUnichar(SkUnichar uni, char utf8[]) {
242f219e7c1529fac29e34483667f740b452e5ef9ccDaniel Dunbar    if ((uint32_t)uni > 0x10FFFF) {
243f219e7c1529fac29e34483667f740b452e5ef9ccDaniel Dunbar        SkDEBUGFAIL("bad unichar");
244f219e7c1529fac29e34483667f740b452e5ef9ccDaniel Dunbar        return 0;
245f219e7c1529fac29e34483667f740b452e5ef9ccDaniel Dunbar    }
246f219e7c1529fac29e34483667f740b452e5ef9ccDaniel Dunbar
247f219e7c1529fac29e34483667f740b452e5ef9ccDaniel Dunbar    if (uni <= 127) {
248b689afb75049012a431d483432114ad5e75d4a92John McCall        if (utf8) {
249b689afb75049012a431d483432114ad5e75d4a92John McCall            *utf8 = (char)uni;
2503c66d30d513106bb794990c5e4ba36a31ac19f15Daniel Dunbar        }
2513c66d30d513106bb794990c5e4ba36a31ac19f15Daniel Dunbar        return 1;
2523c66d30d513106bb794990c5e4ba36a31ac19f15Daniel Dunbar    }
2533c66d30d513106bb794990c5e4ba36a31ac19f15Daniel Dunbar
254b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    char    tmp[4];
255b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    char*   p = tmp;
256b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    size_t  count = 1;
257b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar
258b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    SkDEBUGCODE(SkUnichar orig = uni;)
259b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar
260eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar    while (uni > 0x7F >> count) {
261eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar        *p++ = (char)(0x80 | (uni & 0x3F));
262b34d69b9292534c1c574f168f0ac10aea652adcaDaniel Dunbar        uni >>= 6;
263b34d69b9292534c1c574f168f0ac10aea652adcaDaniel Dunbar        count += 1;
264b34d69b9292534c1c574f168f0ac10aea652adcaDaniel Dunbar    }
265b34d69b9292534c1c574f168f0ac10aea652adcaDaniel Dunbar
266b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    if (utf8) {
267b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        p = tmp;
268b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        utf8 += count;
269b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        while (p < tmp + count - 1) {
270b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar            *--utf8 = *p++;
271b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        }
272b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        *--utf8 = (char)(~(0xFF >> count) | uni);
273b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    }
274b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar
275b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    SkASSERT(utf8 == NULL || orig == SkUTF8_ToUnichar(utf8));
276b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    return count;
277b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar}
278b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar
279b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar///////////////////////////////////////////////////////////////////////////////
280b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar
281b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbarint SkUTF16_CountUnichars(const uint16_t src[]) {
282b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    SkASSERT(src);
283b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar
284b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    int count = 0;
285b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    unsigned c;
286b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    while ((c = *src++) != 0) {
287b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        SkASSERT(!SkUTF16_IsLowSurrogate(c));
288b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        if (SkUTF16_IsHighSurrogate(c)) {
289b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar            c = *src++;
290b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar            SkASSERT(SkUTF16_IsLowSurrogate(c));
291b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        }
292b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        count += 1;
293b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    }
294b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    return count;
295b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar}
296b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar
297b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbarint SkUTF16_CountUnichars(const uint16_t src[], int numberOf16BitValues) {
2984786c15f4977c7cee98fde3ebdee213dba23848bDouglas Gregor    SkASSERT(src);
2994786c15f4977c7cee98fde3ebdee213dba23848bDouglas Gregor
300b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    const uint16_t* stop = src + numberOf16BitValues;
301b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    int count = 0;
302b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    while (src < stop) {
303b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        unsigned c = *src++;
3047d2b8c1fcc2b707be78b09930a7767477822462fDouglas Gregor        SkASSERT(!SkUTF16_IsLowSurrogate(c));
3057d2b8c1fcc2b707be78b09930a7767477822462fDouglas Gregor        if (SkUTF16_IsHighSurrogate(c)) {
306b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar            SkASSERT(src < stop);
307b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar            c = *src++;
3086fbe8398ba1680ffc5daa7395850ff8765b7905bChris Lattner            SkASSERT(SkUTF16_IsLowSurrogate(c));
3096fbe8398ba1680ffc5daa7395850ff8765b7905bChris Lattner        }
3106fbe8398ba1680ffc5daa7395850ff8765b7905bChris Lattner        count += 1;
3116fbe8398ba1680ffc5daa7395850ff8765b7905bChris Lattner    }
312c9471b0ff1815ed0149dbfcad0f385ed8648eeb0Douglas Gregor    return count;
313c9471b0ff1815ed0149dbfcad0f385ed8648eeb0Douglas Gregor}
314c9471b0ff1815ed0149dbfcad0f385ed8648eeb0Douglas Gregor
315c9471b0ff1815ed0149dbfcad0f385ed8648eeb0Douglas GregorSkUnichar SkUTF16_NextUnichar(const uint16_t** srcPtr) {
316c9471b0ff1815ed0149dbfcad0f385ed8648eeb0Douglas Gregor    SkASSERT(srcPtr && *srcPtr);
317c9471b0ff1815ed0149dbfcad0f385ed8648eeb0Douglas Gregor
318c9471b0ff1815ed0149dbfcad0f385ed8648eeb0Douglas Gregor    const uint16_t* src = *srcPtr;
319c9471b0ff1815ed0149dbfcad0f385ed8648eeb0Douglas Gregor    SkUnichar       c = *src++;
320c100214fdc41a7ea215f75d433eb1cb829fd4330Chris Lattner
321c100214fdc41a7ea215f75d433eb1cb829fd4330Chris Lattner    SkASSERT(!SkUTF16_IsLowSurrogate(c));
322c100214fdc41a7ea215f75d433eb1cb829fd4330Chris Lattner    if (SkUTF16_IsHighSurrogate(c)) {
323c100214fdc41a7ea215f75d433eb1cb829fd4330Chris Lattner        unsigned c2 = *src++;
32408c6695f6018fb6cb1a7c7d311a851aa5c233bc0Daniel Dunbar        SkASSERT(SkUTF16_IsLowSurrogate(c2));
32508c6695f6018fb6cb1a7c7d311a851aa5c233bc0Daniel Dunbar
32608c6695f6018fb6cb1a7c7d311a851aa5c233bc0Daniel Dunbar        // c = ((c & 0x3FF) << 10) + (c2 & 0x3FF) + 0x10000
32708c6695f6018fb6cb1a7c7d311a851aa5c233bc0Daniel Dunbar        // c = (((c & 0x3FF) + 64) << 10) + (c2 & 0x3FF)
3286c1cb9916e9988dcdd65b9266dbe24afd173427aDouglas Gregor        c = (c << 10) + c2 + (0x10000 - (0xD800 << 10) - 0xDC00);
3296c1cb9916e9988dcdd65b9266dbe24afd173427aDouglas Gregor    }
3306c1cb9916e9988dcdd65b9266dbe24afd173427aDouglas Gregor    *srcPtr = src;
3316c1cb9916e9988dcdd65b9266dbe24afd173427aDouglas Gregor    return c;
3326c1cb9916e9988dcdd65b9266dbe24afd173427aDouglas Gregor}
3336c1cb9916e9988dcdd65b9266dbe24afd173427aDouglas Gregor
3346c1cb9916e9988dcdd65b9266dbe24afd173427aDouglas GregorSkUnichar SkUTF16_PrevUnichar(const uint16_t** srcPtr) {
335575cf3791216c33770ba950430493cdd43099f8fDouglas Gregor    SkASSERT(srcPtr && *srcPtr);
336575cf3791216c33770ba950430493cdd43099f8fDouglas Gregor
337575cf3791216c33770ba950430493cdd43099f8fDouglas Gregor    const uint16_t* src = *srcPtr;
338575cf3791216c33770ba950430493cdd43099f8fDouglas Gregor    SkUnichar       c = *--src;
33952388f9aefba585475a38081272ce582d033c883Chris Lattner
340124fca533d9fef2e3f6359283909bd342b5f5f26Chris Lattner    SkASSERT(!SkUTF16_IsHighSurrogate(c));
341124fca533d9fef2e3f6359283909bd342b5f5f26Chris Lattner    if (SkUTF16_IsLowSurrogate(c)) {
342124fca533d9fef2e3f6359283909bd342b5f5f26Chris Lattner        unsigned c2 = *--src;
343b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        SkASSERT(SkUTF16_IsHighSurrogate(c2));
344b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        c = (c2 << 10) + c + (0x10000 - (0xD800 << 10) - 0xDC00);
345b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    }
346b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    *srcPtr = src;
347b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    return c;
348b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar}
349b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar
350b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbarsize_t SkUTF16_FromUnichar(SkUnichar uni, uint16_t dst[]) {
351b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    SkASSERT((unsigned)uni <= 0x10FFFF);
352b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar
353b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    int extra = (uni > 0xFFFF);
354b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar
355c34ce3fa613d5e4a283e53615fceafd17390445bDaniel Dunbar    if (dst) {
356b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        if (extra) {
357c34ce3fa613d5e4a283e53615fceafd17390445bDaniel Dunbar            // dst[0] = SkToU16(0xD800 | ((uni - 0x10000) >> 10));
358c34ce3fa613d5e4a283e53615fceafd17390445bDaniel Dunbar            // dst[0] = SkToU16(0xD800 | ((uni >> 10) - 64));
359c34ce3fa613d5e4a283e53615fceafd17390445bDaniel Dunbar            dst[0] = SkToU16((0xD800 - 64) + (uni >> 10));
360c34ce3fa613d5e4a283e53615fceafd17390445bDaniel Dunbar            dst[1] = SkToU16(0xDC00 | (uni & 0x3FF));
361c34ce3fa613d5e4a283e53615fceafd17390445bDaniel Dunbar
362faddc3e53a95c68f2c3a966e0f1e6eba110dafd6Daniel Dunbar            SkASSERT(SkUTF16_IsHighSurrogate(dst[0]));
363c34ce3fa613d5e4a283e53615fceafd17390445bDaniel Dunbar            SkASSERT(SkUTF16_IsLowSurrogate(dst[1]));
364c34ce3fa613d5e4a283e53615fceafd17390445bDaniel Dunbar        } else {
365c34ce3fa613d5e4a283e53615fceafd17390445bDaniel Dunbar            dst[0] = SkToU16(uni);
366895fcca55a6d52a71639f2472a6623ab2dd9f628Peter Collingbourne            SkASSERT(!SkUTF16_IsHighSurrogate(dst[0]));
367c34ce3fa613d5e4a283e53615fceafd17390445bDaniel Dunbar            SkASSERT(!SkUTF16_IsLowSurrogate(dst[0]));
368c34ce3fa613d5e4a283e53615fceafd17390445bDaniel Dunbar        }
369c34ce3fa613d5e4a283e53615fceafd17390445bDaniel Dunbar    }
370c34ce3fa613d5e4a283e53615fceafd17390445bDaniel Dunbar    return 1 + extra;
371b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar}
372b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar
3739f61aa9e280adea9fbf3365f0e4f6ed568c9885aJeffrey Yasskinsize_t SkUTF16_ToUTF8(const uint16_t utf16[], int numberOf16BitValues,
374b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar                      char utf8[]) {
375b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    SkASSERT(numberOf16BitValues >= 0);
376b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    if (numberOf16BitValues <= 0) {
377b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        return 0;
378b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    }
379b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar
3809f61aa9e280adea9fbf3365f0e4f6ed568c9885aJeffrey Yasskin    SkASSERT(utf16 != NULL);
381b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar
382b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    const uint16_t* stop = utf16 + numberOf16BitValues;
383f35142413974e9dfe2c5f202084db4bd1c2073e9John McCall    size_t          size = 0;
384b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar
385b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    if (utf8 == NULL) {    // just count
386b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        while (utf16 < stop) {
387b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar            size += SkUTF8_FromUnichar(SkUTF16_NextUnichar(&utf16), NULL);
388b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        }
389b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    } else {
390b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        char* start = utf8;
391b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar        while (utf16 < stop) {
392b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar            utf8 += SkUTF8_FromUnichar(SkUTF16_NextUnichar(&utf16), utf8);
39332148cef25570a4fbe3ad0ec497ce3ae2cf1b774Daniel Dunbar        }
394da1573f95902a42aa4d11e8f45ab98ec7e27bc28Daniel Dunbar        size = utf8 - start;
395b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar    }
396467dc88512b4ba4bb16e274ea3771dc1415d31daDouglas Gregor    return size;
397b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar}
398b3375cba7938e01895bb504e7e48ad94a2e07dd1Daniel Dunbar