blob: a9e61c4f2b6fdd36ef7c58c20b12d91b32585794 [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"
Hal Canaryc640d0d2018-06-13 09:59:02 -04009#include "SkTo.h"
10
Ben Wagner29f2eaf2018-06-15 13:58:41 -040011#include <cstring>
12
bungemanccb74b82016-02-23 12:55:20 -080013size_t SkPackBits::ComputeMaxSize8(size_t srcSize) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000014 // worst case is the number of 8bit values + 1 byte per (up to) 128 entries.
bungemanccb74b82016-02-23 12:55:20 -080015 return ((srcSize + 127) >> 7) + srcSize;
reed@android.com8a1c16f2008-12-17 15:59:43 +000016}
17
jschuh699b8522015-06-04 15:10:37 -070018static uint8_t* flush_same8(uint8_t dst[], uint8_t value, size_t count) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000019 while (count > 0) {
bungemanccb74b82016-02-23 12:55:20 -080020 size_t n = count > 128 ? 128 : count;
reed@android.com8a1c16f2008-12-17 15:59:43 +000021 *dst++ = (uint8_t)(n - 1);
22 *dst++ = (uint8_t)value;
23 count -= n;
24 }
25 return dst;
26}
27
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +000028static uint8_t* flush_diff8(uint8_t* SK_RESTRICT dst,
jschuh699b8522015-06-04 15:10:37 -070029 const uint8_t* SK_RESTRICT src, size_t count) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000030 while (count > 0) {
bungemanccb74b82016-02-23 12:55:20 -080031 size_t n = count > 128 ? 128 : count;
reed@android.com8a1c16f2008-12-17 15:59:43 +000032 *dst++ = (uint8_t)(n + 127);
jschuh699b8522015-06-04 15:10:37 -070033 memcpy(dst, src, n);
reed@android.com8a1c16f2008-12-17 15:59:43 +000034 src += n;
35 dst += n;
36 count -= n;
37 }
38 return dst;
39}
40
jschuh699b8522015-06-04 15:10:37 -070041size_t SkPackBits::Pack8(const uint8_t* SK_RESTRICT src, size_t srcSize,
42 uint8_t* SK_RESTRICT dst, size_t dstSize) {
43 if (dstSize < ComputeMaxSize8(srcSize)) {
44 return 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +000045 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000046
jschuh699b8522015-06-04 15:10:37 -070047 uint8_t* const origDst = dst;
48 const uint8_t* stop = src + srcSize;
reed@android.com8a1c16f2008-12-17 15:59:43 +000049
jschuh699b8522015-06-04 15:10:37 -070050 for (intptr_t count = stop - src; count > 0; count = stop - src) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000051 if (1 == count) {
52 *dst++ = 0;
53 *dst++ = *src;
jschuh699b8522015-06-04 15:10:37 -070054 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +000055 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +000056
reed@android.com8a1c16f2008-12-17 15:59:43 +000057 unsigned value = *src;
58 const uint8_t* s = src + 1;
rmistry@google.comfbfcd562012-08-23 18:09:54 +000059
reed@android.com8a1c16f2008-12-17 15:59:43 +000060 if (*s == value) { // accumulate same values...
61 do {
62 s++;
63 if (s == stop) {
64 break;
65 }
66 } while (*s == value);
commit-bot@chromium.org2cfa3202014-04-19 22:00:40 +000067 dst = flush_same8(dst, value, SkToInt(s - src));
reed@android.com8a1c16f2008-12-17 15:59:43 +000068 } else { // accumulate diff values...
69 do {
70 if (++s == stop) {
71 goto FLUSH_DIFF;
72 }
73 // only stop if we hit 3 in a row,
74 // otherwise we get bigger than compuatemax
75 } while (*s != s[-1] || s[-1] != s[-2]);
76 s -= 2; // back up so we don't grab the "same" values that follow
77 FLUSH_DIFF:
commit-bot@chromium.org2cfa3202014-04-19 22:00:40 +000078 dst = flush_diff8(dst, src, SkToInt(s - src));
reed@android.com8a1c16f2008-12-17 15:59:43 +000079 }
80 src = s;
81 }
jschuh699b8522015-06-04 15:10:37 -070082 return dst - origDst;
reed@android.com8a1c16f2008-12-17 15:59:43 +000083}
84
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +000085int SkPackBits::Unpack8(const uint8_t* SK_RESTRICT src, size_t srcSize,
jschuh699b8522015-06-04 15:10:37 -070086 uint8_t* SK_RESTRICT dst, size_t dstSize) {
87 uint8_t* const origDst = dst;
88 uint8_t* const endDst = dst + dstSize;
reed@android.com8a1c16f2008-12-17 15:59:43 +000089 const uint8_t* stop = src + srcSize;
rmistry@google.comfbfcd562012-08-23 18:09:54 +000090
reed@android.com8a1c16f2008-12-17 15:59:43 +000091 while (src < stop) {
92 unsigned n = *src++;
93 if (n <= 127) { // repeat count (n + 1)
94 n += 1;
Mike Reedfca3d0a2018-01-09 15:13:59 -050095 if (dst > (endDst - n) || src >= stop) {
jschuh699b8522015-06-04 15:10:37 -070096 return 0;
97 }
98 memset(dst, *src++, n);
reed@android.com8a1c16f2008-12-17 15:59:43 +000099 } else { // same count (n - 127)
100 n -= 127;
Mike Reedfca3d0a2018-01-09 15:13:59 -0500101 if (dst > (endDst - n) || src > (stop - n)) {
jschuh699b8522015-06-04 15:10:37 -0700102 return 0;
103 }
104 memcpy(dst, src, n);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000105 src += n;
106 }
107 dst += n;
108 }
jschuh699b8522015-06-04 15:10:37 -0700109 SkASSERT(src <= stop);
Mike Reedfca3d0a2018-01-09 15:13:59 -0500110 SkASSERT(dst <= endDst);
commit-bot@chromium.org2cfa3202014-04-19 22:00:40 +0000111 return SkToInt(dst - origDst);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000112}