blob: e46590956c764b8f6ebd9c5ea2731423b5777fc3 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
Hal Canaryc640d0d2018-06-13 09:59:02 -04007
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SkPackBits.h"
9
Hal Canaryc640d0d2018-06-13 09:59:02 -040010#include "SkTo.h"
11
bungemanccb74b82016-02-23 12:55:20 -080012size_t SkPackBits::ComputeMaxSize8(size_t srcSize) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000013 // worst case is the number of 8bit values + 1 byte per (up to) 128 entries.
bungemanccb74b82016-02-23 12:55:20 -080014 return ((srcSize + 127) >> 7) + srcSize;
reed@android.com8a1c16f2008-12-17 15:59:43 +000015}
16
jschuh699b8522015-06-04 15:10:37 -070017static uint8_t* flush_same8(uint8_t dst[], uint8_t value, size_t count) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000018 while (count > 0) {
bungemanccb74b82016-02-23 12:55:20 -080019 size_t n = count > 128 ? 128 : count;
reed@android.com8a1c16f2008-12-17 15:59:43 +000020 *dst++ = (uint8_t)(n - 1);
21 *dst++ = (uint8_t)value;
22 count -= n;
23 }
24 return dst;
25}
26
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +000027static uint8_t* flush_diff8(uint8_t* SK_RESTRICT dst,
jschuh699b8522015-06-04 15:10:37 -070028 const uint8_t* SK_RESTRICT src, size_t count) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000029 while (count > 0) {
bungemanccb74b82016-02-23 12:55:20 -080030 size_t n = count > 128 ? 128 : count;
reed@android.com8a1c16f2008-12-17 15:59:43 +000031 *dst++ = (uint8_t)(n + 127);
jschuh699b8522015-06-04 15:10:37 -070032 memcpy(dst, src, n);
reed@android.com8a1c16f2008-12-17 15:59:43 +000033 src += n;
34 dst += n;
35 count -= n;
36 }
37 return dst;
38}
39
jschuh699b8522015-06-04 15:10:37 -070040size_t SkPackBits::Pack8(const uint8_t* SK_RESTRICT src, size_t srcSize,
41 uint8_t* SK_RESTRICT dst, size_t dstSize) {
42 if (dstSize < ComputeMaxSize8(srcSize)) {
43 return 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +000044 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000045
jschuh699b8522015-06-04 15:10:37 -070046 uint8_t* const origDst = dst;
47 const uint8_t* stop = src + srcSize;
reed@android.com8a1c16f2008-12-17 15:59:43 +000048
jschuh699b8522015-06-04 15:10:37 -070049 for (intptr_t count = stop - src; count > 0; count = stop - src) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000050 if (1 == count) {
51 *dst++ = 0;
52 *dst++ = *src;
jschuh699b8522015-06-04 15:10:37 -070053 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +000054 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +000055
reed@android.com8a1c16f2008-12-17 15:59:43 +000056 unsigned value = *src;
57 const uint8_t* s = src + 1;
rmistry@google.comfbfcd562012-08-23 18:09:54 +000058
reed@android.com8a1c16f2008-12-17 15:59:43 +000059 if (*s == value) { // accumulate same values...
60 do {
61 s++;
62 if (s == stop) {
63 break;
64 }
65 } while (*s == value);
commit-bot@chromium.org2cfa3202014-04-19 22:00:40 +000066 dst = flush_same8(dst, value, SkToInt(s - src));
reed@android.com8a1c16f2008-12-17 15:59:43 +000067 } else { // accumulate diff values...
68 do {
69 if (++s == stop) {
70 goto FLUSH_DIFF;
71 }
72 // only stop if we hit 3 in a row,
73 // otherwise we get bigger than compuatemax
74 } while (*s != s[-1] || s[-1] != s[-2]);
75 s -= 2; // back up so we don't grab the "same" values that follow
76 FLUSH_DIFF:
commit-bot@chromium.org2cfa3202014-04-19 22:00:40 +000077 dst = flush_diff8(dst, src, SkToInt(s - src));
reed@android.com8a1c16f2008-12-17 15:59:43 +000078 }
79 src = s;
80 }
jschuh699b8522015-06-04 15:10:37 -070081 return dst - origDst;
reed@android.com8a1c16f2008-12-17 15:59:43 +000082}
83
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +000084int SkPackBits::Unpack8(const uint8_t* SK_RESTRICT src, size_t srcSize,
jschuh699b8522015-06-04 15:10:37 -070085 uint8_t* SK_RESTRICT dst, size_t dstSize) {
86 uint8_t* const origDst = dst;
87 uint8_t* const endDst = dst + dstSize;
reed@android.com8a1c16f2008-12-17 15:59:43 +000088 const uint8_t* stop = src + srcSize;
rmistry@google.comfbfcd562012-08-23 18:09:54 +000089
reed@android.com8a1c16f2008-12-17 15:59:43 +000090 while (src < stop) {
91 unsigned n = *src++;
92 if (n <= 127) { // repeat count (n + 1)
93 n += 1;
Mike Reedfca3d0a2018-01-09 15:13:59 -050094 if (dst > (endDst - n) || src >= stop) {
jschuh699b8522015-06-04 15:10:37 -070095 return 0;
96 }
97 memset(dst, *src++, n);
reed@android.com8a1c16f2008-12-17 15:59:43 +000098 } else { // same count (n - 127)
99 n -= 127;
Mike Reedfca3d0a2018-01-09 15:13:59 -0500100 if (dst > (endDst - n) || src > (stop - n)) {
jschuh699b8522015-06-04 15:10:37 -0700101 return 0;
102 }
103 memcpy(dst, src, n);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000104 src += n;
105 }
106 dst += n;
107 }
jschuh699b8522015-06-04 15:10:37 -0700108 SkASSERT(src <= stop);
Mike Reedfca3d0a2018-01-09 15:13:59 -0500109 SkASSERT(dst <= endDst);
commit-bot@chromium.org2cfa3202014-04-19 22:00:40 +0000110 return SkToInt(dst - origDst);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000111}