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