1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/*
2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2011 Google Inc.
3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *
4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be
5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file.
6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */
7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkPackBits.h"
8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotsize_t SkPackBits::ComputeMaxSize8(size_t srcSize) {
10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // worst case is the number of 8bit values + 1 byte per (up to) 128 entries.
11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return ((srcSize + 127) >> 7) + srcSize;
12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic uint8_t* flush_same8(uint8_t dst[], uint8_t value, size_t count) {
15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while (count > 0) {
16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        size_t n = count > 128 ? 128 : count;
17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        *dst++ = (uint8_t)(n - 1);
18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        *dst++ = (uint8_t)value;
19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        count -= n;
20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return dst;
22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic uint8_t* flush_diff8(uint8_t* SK_RESTRICT dst,
25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                            const uint8_t* SK_RESTRICT src, size_t count) {
26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while (count > 0) {
27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        size_t n = count > 128 ? 128 : count;
28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        *dst++ = (uint8_t)(n + 127);
29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        memcpy(dst, src, n);
30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        src += n;
31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        dst += n;
32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        count -= n;
33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return dst;
35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotsize_t SkPackBits::Pack8(const uint8_t* SK_RESTRICT src, size_t srcSize,
38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                         uint8_t* SK_RESTRICT dst, size_t dstSize) {
39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (dstSize < ComputeMaxSize8(srcSize)) {
40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return 0;
41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    uint8_t* const origDst = dst;
44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const uint8_t* stop = src + srcSize;
45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (intptr_t count = stop - src; count > 0; count = stop - src) {
47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (1 == count) {
48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            *dst++ = 0;
49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            *dst++ = *src;
50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        unsigned value = *src;
54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const uint8_t* s = src + 1;
55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (*s == value) { // accumulate same values...
57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            do {
58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                s++;
59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (s == stop) {
60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    break;
61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            } while (*s == value);
63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            dst = flush_same8(dst, value, SkToInt(s - src));
64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } else {    // accumulate diff values...
65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            do {
66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (++s == stop) {
67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    goto FLUSH_DIFF;
68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // only stop if we hit 3 in a row,
70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // otherwise we get bigger than compuatemax
71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            } while (*s != s[-1] || s[-1] != s[-2]);
72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            s -= 2; // back up so we don't grab the "same" values that follow
73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        FLUSH_DIFF:
74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            dst = flush_diff8(dst, src, SkToInt(s - src));
75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        src = s;
77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return dst - origDst;
79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotint SkPackBits::Unpack8(const uint8_t* SK_RESTRICT src, size_t srcSize,
82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        uint8_t* SK_RESTRICT dst, size_t dstSize) {
83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    uint8_t* const origDst = dst;
84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    uint8_t* const endDst = dst + dstSize;
85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const uint8_t* stop = src + srcSize;
86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while (src < stop) {
88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        unsigned n = *src++;
89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (n <= 127) {   // repeat count (n + 1)
90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            n += 1;
91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (dst > (endDst - n) || src >= stop) {
92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return 0;
93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            memset(dst, *src++, n);
95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } else {    // same count (n - 127)
96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            n -= 127;
97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (dst > (endDst - n) || src > (stop - n)) {
98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return 0;
99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            memcpy(dst, src, n);
101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            src += n;
102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        dst += n;
104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(src <= stop);
106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(dst <= endDst);
107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return SkToInt(dst - origDst);
108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
109