aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core
diff options
context:
space:
mode:
authorGravatar Hal Canary <halcanary@google.com>2018-07-25 16:52:48 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-07-31 20:11:19 +0000
commitf107a2fd014cd39c489060f2cd1b99cd49c7d0be (patch)
tree5c324821344901869203bbe055be8d3f69f696cb /src/core
parent1935aa3d27cd4ed4aef2dc04360f247a541d4b00 (diff)
SkUTF
Create new header and namespace, `SkUTF` where we are putting all of our robust, well documented UTF-8, UTF-16, and UTF-32 functions: `SkUTF::{Count,Next,To}UTF{8,16,32}()`. SkUTF.h and SkUTF.cpp do not depend on the rest of Skia and are suitable for re-use in other modules. Some of the old UTF-{8,16} functions still live in SkUtils.h; their use will be phased out in future CLs. Also added more unit testing and cleaned up old tests. Removed functions that were unused outside of tests or used only once. Change-Id: Iaa59b8705abccf9c4ba082f855da368a0bad8380 Reviewed-on: https://skia-review.googlesource.com/143306 Reviewed-by: Ben Wagner <bungeman@google.com> Commit-Queue: Hal Canary <halcanary@google.com>
Diffstat (limited to 'src/core')
-rw-r--r--src/core/SkFindAndPlaceGlyph.h24
-rw-r--r--src/core/SkFont.cpp4
-rw-r--r--src/core/SkOverdrawCanvas.cpp6
-rw-r--r--src/core/SkPaint.cpp104
-rw-r--r--src/core/SkPaintPriv.cpp6
-rw-r--r--src/core/SkString.cpp4
-rw-r--r--src/core/SkStringUtils.cpp6
-rw-r--r--src/core/SkUtils.cpp428
-rw-r--r--src/core/SkUtils.h98
9 files changed, 94 insertions, 586 deletions
diff --git a/src/core/SkFindAndPlaceGlyph.h b/src/core/SkFindAndPlaceGlyph.h
index f602e8d931..74fa516910 100644
--- a/src/core/SkFindAndPlaceGlyph.h
+++ b/src/core/SkFindAndPlaceGlyph.h
@@ -147,7 +147,7 @@ private:
private:
SkUnichar nextUnichar(const char** text, const char* stop) override {
- return SkUTF8_NextUnichar(text, stop);
+ return SkUTF::NextUTF8(text, stop);
}
};
@@ -157,7 +157,7 @@ private:
private:
SkUnichar nextUnichar(const char** text, const char* stop) override {
- return SkUTF16_NextUnichar((const uint16_t**)text, (const uint16_t*)stop);
+ return SkUTF::NextUTF16((const uint16_t**)text, (const uint16_t*)stop);
}
};
@@ -167,10 +167,7 @@ private:
private:
SkUnichar nextUnichar(const char** text, const char* stop) override {
- const int32_t* ptr = *(const int32_t**)text;
- SkUnichar uni = *ptr++;
- *text = (const char*)ptr;
- return uni;
+ return SkUTF::NextUTF32((const int32_t**)text, (const int32_t*)stop);
}
};
@@ -181,19 +178,24 @@ private:
SkASSERT(cache != nullptr);
}
- const SkGlyph& lookupGlyph(const char** text, const char*) override {
- return fCache->getGlyphIDMetrics(nextGlyphId(text));
+ const SkGlyph& lookupGlyph(const char** text, const char* stop) override {
+ return fCache->getGlyphIDMetrics(nextGlyphId(text, stop));
}
- const SkGlyph& lookupGlyphXY(const char** text, const char*,
+ const SkGlyph& lookupGlyphXY(const char** text, const char* stop,
SkFixed x, SkFixed y) override {
- return fCache->getGlyphIDMetrics(nextGlyphId(text), x, y);
+ return fCache->getGlyphIDMetrics(nextGlyphId(text, stop), x, y);
}
private:
- uint16_t nextGlyphId(const char** text) {
+ uint16_t nextGlyphId(const char** text, const char* stop) {
SkASSERT(text != nullptr);
const uint16_t* ptr = *(const uint16_t**)text;
+ SkASSERT(ptr);
+ if (ptr + 1 > (const uint16_t*)stop) {
+ *text = stop;
+ return 0;
+ }
uint16_t glyphID = *ptr;
ptr += 1;
*text = (const char*)ptr;
diff --git a/src/core/SkFont.cpp b/src/core/SkFont.cpp
index bde8c4c80b..081469f900 100644
--- a/src/core/SkFont.cpp
+++ b/src/core/SkFont.cpp
@@ -68,10 +68,10 @@ int SkFont::textToGlyphs(const void* text, size_t byteLength, SkTextEncoding enc
switch (encoding) {
case kUTF8_SkTextEncoding:
- count = SkUTF8_CountUnichars((const char*)text, byteLength);
+ count = SkUTF::CountUTF8((const char*)text, byteLength);
break;
case kUTF16_SkTextEncoding:
- count = SkUTF16_CountUnichars((const uint16_t*)text, byteLength);
+ count = SkUTF::CountUTF16((const uint16_t*)text, byteLength);
break;
case kUTF32_SkTextEncoding:
count = SkToInt(byteLength >> 2);
diff --git a/src/core/SkOverdrawCanvas.cpp b/src/core/SkOverdrawCanvas.cpp
index 249723e494..0e20878793 100644
--- a/src/core/SkOverdrawCanvas.cpp
+++ b/src/core/SkOverdrawCanvas.cpp
@@ -98,13 +98,15 @@ void SkOverdrawCanvas::onDrawTextOnPath(const void* text, size_t byteLength, con
typedef int (*CountTextProc)(const char* text, const char* stop);
static int count_utf16(const char* text, const char* stop) {
const uint16_t* prev = (const uint16_t*)text;
- (void)SkUTF16_NextUnichar(&prev, (const uint16_t*)stop);
+ (void)SkUTF::NextUTF16(&prev, (const uint16_t*)stop);
return SkToInt((const char*)prev - text);
}
static int return_4(const char* text, const char* stop) { return 4; }
static int return_2(const char* text, const char* stop) { return 2; }
static int count_utf8(const char* text, const char* stop) {
- return SkUTF8_LeadByteToCount(*(const uint8_t*)text);
+ const char* ptr = text;
+ (void)SkUTF::NextUTF8(&ptr, stop);
+ return SkToInt(ptr - text);
}
void SkOverdrawCanvas::onDrawTextRSXform(const void* text, size_t byteLength,
diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp
index 9b8431e591..15aa44eebc 100644
--- a/src/core/SkPaint.cpp
+++ b/src/core/SkPaint.cpp
@@ -399,9 +399,9 @@ int SkPaint::countText(const void* text, size_t byteLength) const {
SkASSERT(text != nullptr);
switch (this->getTextEncoding()) {
case kUTF8_TextEncoding:
- return SkUTF8_CountUnichars(text, byteLength);
+ return SkUTF::CountUTF8((const char*)text, byteLength);
case kUTF16_TextEncoding:
- return SkUTF16_CountUnichars(text, byteLength);
+ return SkUTF::CountUTF16((const uint16_t*)text, byteLength);
case kUTF32_TextEncoding:
return SkToInt(byteLength >> 2);
case kGlyphID_TextEncoding:
@@ -413,6 +413,13 @@ int SkPaint::countText(const void* text, size_t byteLength) const {
return 0;
}
+static SkTypeface::Encoding to_encoding(SkPaint::TextEncoding e) {
+ static_assert((int)SkTypeface::kUTF8_Encoding == (int)SkPaint::kUTF8_TextEncoding, "");
+ static_assert((int)SkTypeface::kUTF16_Encoding == (int)SkPaint::kUTF16_TextEncoding, "");
+ static_assert((int)SkTypeface::kUTF32_Encoding == (int)SkPaint::kUTF32_TextEncoding, "");
+ return (SkTypeface::Encoding)e;
+}
+
int SkPaint::textToGlyphs(const void* textData, size_t byteLength, uint16_t glyphs[]) const {
SkASSERT(textData != nullptr);
@@ -431,38 +438,16 @@ int SkPaint::textToGlyphs(const void* textData, size_t byteLength, uint16_t glyp
auto cache = SkStrikeCache::FindOrCreateStrikeExclusive(*this);
- const char* text = (const char*)textData;
- const char* stop = text + byteLength;
+ const void* stop = (const char*)textData + byteLength;
uint16_t* gptr = glyphs;
+ const SkTypeface::Encoding encoding = to_encoding(this->getTextEncoding());
- switch (this->getTextEncoding()) {
- case SkPaint::kUTF8_TextEncoding:
- while (text < stop) {
- SkUnichar u = SkUTF8_NextUnicharWithError(&text, stop);
- if (u < 0) {
- return 0; // bad UTF-8 sequence
- }
- *gptr++ = cache->unicharToGlyph(u);
- }
- break;
- case SkPaint::kUTF16_TextEncoding: {
- const uint16_t* text16 = (const uint16_t*)text;
- const uint16_t* stop16 = (const uint16_t*)stop;
- while (text16 < stop16) {
- *gptr++ = cache->unicharToGlyph(SkUTF16_NextUnichar(&text16, stop16));
- }
- break;
- }
- case kUTF32_TextEncoding: {
- const int32_t* text32 = (const int32_t*)text;
- const int32_t* stop32 = (const int32_t*)stop;
- while (text32 < stop32) {
- *gptr++ = cache->unicharToGlyph(*text32++);
- }
- break;
+ while (textData < stop) {
+ SkUnichar unichar = SkUTFN_Next(encoding, &textData, stop);
+ if (unichar < 0) {
+ return 0; // bad UTF-N sequence
}
- default:
- SkDEBUGFAIL("unknown text encoding");
+ *gptr++ = cache->unicharToGlyph(unichar);
}
return SkToInt(gptr - glyphs);
}
@@ -487,41 +472,12 @@ bool SkPaint::containsText(const void* textData, size_t byteLength) const {
}
auto cache = SkStrikeCache::FindOrCreateStrikeExclusive(*this);
-
- switch (this->getTextEncoding()) {
- case SkPaint::kUTF8_TextEncoding: {
- const char* text = static_cast<const char*>(textData);
- const char* stop = text + byteLength;
- while (text < stop) {
- if (0 == cache->unicharToGlyph(SkUTF8_NextUnichar(&text, stop))) {
- return false;
- }
- }
- break;
- }
- case SkPaint::kUTF16_TextEncoding: {
- const uint16_t* text = static_cast<const uint16_t*>(textData);
- const uint16_t* stop = text + (byteLength >> 1);
- while (text < stop) {
- if (0 == cache->unicharToGlyph(SkUTF16_NextUnichar(&text, stop))) {
- return false;
- }
- }
- break;
- }
- case SkPaint::kUTF32_TextEncoding: {
- const int32_t* text = static_cast<const int32_t*>(textData);
- const int32_t* stop = text + (byteLength >> 2);
- while (text < stop) {
- if (0 == cache->unicharToGlyph(*text++)) {
- return false;
- }
- }
- break;
- }
- default:
- SkDEBUGFAIL("unknown text encoding");
+ const void* stop = (const char*)textData + byteLength;
+ const SkTypeface::Encoding encoding = to_encoding(this->getTextEncoding());
+ while (textData < stop) {
+ if (0 == cache->unicharToGlyph(SkUTFN_Next(encoding, &textData, stop))) {
return false;
+ }
}
return true;
}
@@ -551,7 +507,7 @@ static const SkGlyph& sk_getMetrics_utf8_next(SkGlyphCache* cache,
SkASSERT(cache != nullptr);
SkASSERT(text != nullptr);
- return cache->getUnicharMetrics(SkUTF8_NextUnichar(text, stop));
+ return cache->getUnicharMetrics(SkUTF::NextUTF8(text, stop));
}
static const SkGlyph& sk_getMetrics_utf16_next(SkGlyphCache* cache,
@@ -561,7 +517,7 @@ static const SkGlyph& sk_getMetrics_utf16_next(SkGlyphCache* cache,
SkASSERT(text != nullptr);
return cache->getUnicharMetrics(
- SkUTF16_NextUnichar((const uint16_t**)text, (const uint16_t*)stop));
+ SkUTF::NextUTF16((const uint16_t**)text, (const uint16_t*)stop));
}
static const SkGlyph& sk_getMetrics_utf32_next(SkGlyphCache* cache,
@@ -570,10 +526,7 @@ static const SkGlyph& sk_getMetrics_utf32_next(SkGlyphCache* cache,
SkASSERT(cache != nullptr);
SkASSERT(text != nullptr);
- const int32_t* ptr = *(const int32_t**)text;
- SkUnichar uni = *ptr++;
- *text = (const char*)ptr;
- return cache->getUnicharMetrics(uni);
+ return cache->getUnicharMetrics(SkUTF::NextUTF32((const int32_t**)text, (const int32_t*)stop));
}
static const SkGlyph& sk_getMetrics_glyph_next(SkGlyphCache* cache,
@@ -595,7 +548,7 @@ static const SkGlyph& sk_getAdvance_utf8_next(SkGlyphCache* cache,
SkASSERT(cache != nullptr);
SkASSERT(text != nullptr);
- return cache->getUnicharAdvance(SkUTF8_NextUnichar(text, stop));
+ return cache->getUnicharAdvance(SkUTF::NextUTF8(text, stop));
}
static const SkGlyph& sk_getAdvance_utf16_next(SkGlyphCache* cache,
@@ -605,7 +558,7 @@ static const SkGlyph& sk_getAdvance_utf16_next(SkGlyphCache* cache,
SkASSERT(text != nullptr);
return cache->getUnicharAdvance(
- SkUTF16_NextUnichar((const uint16_t**)text, (const uint16_t*)stop));
+ SkUTF::NextUTF16((const uint16_t**)text, (const uint16_t*)stop));
}
static const SkGlyph& sk_getAdvance_utf32_next(SkGlyphCache* cache,
@@ -614,10 +567,7 @@ static const SkGlyph& sk_getAdvance_utf32_next(SkGlyphCache* cache,
SkASSERT(cache != nullptr);
SkASSERT(text != nullptr);
- const int32_t* ptr = *(const int32_t**)text;
- SkUnichar uni = *ptr++;
- *text = (const char*)ptr;
- return cache->getUnicharAdvance(uni);
+ return cache->getUnicharAdvance(SkUTF::NextUTF32((const int32_t**)text, (const int32_t*)stop));
}
static const SkGlyph& sk_getAdvance_glyph_next(SkGlyphCache* cache,
diff --git a/src/core/SkPaintPriv.cpp b/src/core/SkPaintPriv.cpp
index 3be1ebeafa..309d244951 100644
--- a/src/core/SkPaintPriv.cpp
+++ b/src/core/SkPaintPriv.cpp
@@ -92,9 +92,9 @@ bool SkPaintPriv::ShouldDither(const SkPaint& p, SkColorType dstCT) {
int SkPaintPriv::ValidCountText(const void* text, size_t length, SkPaint::TextEncoding encoding) {
switch (encoding) {
- case SkPaint::kUTF8_TextEncoding: return SkUTF8_CountUnichars(text, length);
- case SkPaint::kUTF16_TextEncoding: return SkUTF16_CountUnichars(text, length);
- case SkPaint::kUTF32_TextEncoding: return SkUTF32_CountUnichars(text, length);
+ case SkPaint::kUTF8_TextEncoding: return SkUTF::CountUTF8((const char*)text, length);
+ case SkPaint::kUTF16_TextEncoding: return SkUTF::CountUTF16((const uint16_t*)text, length);
+ case SkPaint::kUTF32_TextEncoding: return SkUTF::CountUTF32((const int32_t*)text, length);
case SkPaint::kGlyphID_TextEncoding:
if (!SkIsAlign2(intptr_t(text)) || !SkIsAlign2(length)) {
return -1;
diff --git a/src/core/SkString.cpp b/src/core/SkString.cpp
index 65dae1b753..6f7d80dfd7 100644
--- a/src/core/SkString.cpp
+++ b/src/core/SkString.cpp
@@ -446,8 +446,8 @@ void SkString::insert(size_t offset, const char text[], size_t len) {
}
void SkString::insertUnichar(size_t offset, SkUnichar uni) {
- char buffer[kMaxBytesInUTF8Sequence];
- size_t len = SkUTF8_FromUnichar(uni, buffer);
+ char buffer[SkUTF::kMaxBytesInUTF8Sequence];
+ size_t len = SkUTF::ToUTF8(uni, buffer);
if (len) {
this->insert(offset, buffer, len);
diff --git a/src/core/SkStringUtils.cpp b/src/core/SkStringUtils.cpp
index 500478585f..1743d0d26c 100644
--- a/src/core/SkStringUtils.cpp
+++ b/src/core/SkStringUtils.cpp
@@ -62,8 +62,8 @@ SkString SkStringFromUTF16(const uint16_t* src, size_t count) {
const uint16_t* end = src + count;
for (const uint16_t* ptr = src; ptr < end;) {
const uint16_t* last = ptr;
- SkUnichar u = SkUTF16_NextUnichar(&ptr, stop);
- size_t s = SkUTF8_FromUnichar(u);
+ SkUnichar u = SkUTF::NextUTF16(&ptr, stop);
+ size_t s = SkUTF::ToUTF8(u);
if (n > UINT32_MAX - s) {
end = last; // truncate input string
break;
@@ -73,7 +73,7 @@ SkString SkStringFromUTF16(const uint16_t* src, size_t count) {
ret = SkString(n);
char* out = ret.writable_str();
for (const uint16_t* ptr = src; ptr < end;) {
- out += SkUTF8_FromUnichar(SkUTF16_NextUnichar(&ptr, stop), out);
+ out += SkUTF::ToUTF8(SkUTF::NextUTF16(&ptr, stop), out);
}
SkASSERT(out == ret.writable_str() + n);
}
diff --git a/src/core/SkUtils.cpp b/src/core/SkUtils.cpp
index f0c1f60a09..9754da662c 100644
--- a/src/core/SkUtils.cpp
+++ b/src/core/SkUtils.cpp
@@ -7,431 +7,27 @@
#include "SkUtils.h"
-#include "SkTo.h"
-
-/* 0xxxxxxx 1 total
- 10xxxxxx // never a leading byte
- 110xxxxx 2 total
- 1110xxxx 3 total
- 11110xxx 4 total
-
- 11 10 01 01 xx xx xx xx 0...
- 0xE5XX0000
- 0xE5 << 24
-*/
-
-static bool utf8_byte_is_valid(uint8_t c) {
- return c < 0xF5 && (c & 0xFE) != 0xC0;
-}
-static bool utf8_byte_is_continuation(uint8_t c) {
- return (c & 0xC0) == 0x80;
-}
-static bool utf8_byte_is_leading_byte(uint8_t c) {
- return utf8_byte_is_valid(c) && !utf8_byte_is_continuation(c);
-}
-
-#ifdef SK_DEBUG
- static void assert_utf8_leadingbyte(unsigned c) {
- SkASSERT(utf8_byte_is_leading_byte(SkToU8(c)));
- }
-
- int SkUTF8_LeadByteToCount(unsigned c) {
- assert_utf8_leadingbyte(c);
- return (((0xE5 << 24) >> (c >> 4 << 1)) & 3) + 1;
- }
-#else
- #define assert_utf8_leadingbyte(c)
-#endif
-
-/**
- * @returns -1 iff invalid UTF8 byte,
- * 0 iff UTF8 continuation byte,
- * 1 iff ASCII byte,
- * 2 iff leading byte of 2-byte sequence,
- * 3 iff leading byte of 3-byte sequence, and
- * 4 iff leading byte of 4-byte sequence.
- *
- * I.e.: if return value > 0, then gives length of sequence.
-*/
-static int utf8_byte_type(uint8_t c) {
- if (c < 0x80) {
- return 1;
- } else if (c < 0xC0) {
- return 0;
- } else if (c < 0xF5 && (c & 0xFE) != 0xC0) { // "octet values C0, C1, F5 to FF never appear"
- return (((0xE5 << 24) >> ((unsigned)c >> 4 << 1)) & 3) + 1;
- } else {
- return -1;
- }
-}
-static bool utf8_type_is_valid_leading_byte(int type) { return type > 0; }
-
-int SkUTF8_CountUnichars(const char utf8[]) {
- SkASSERT(utf8);
-
- int count = 0;
-
- for (;;) {
- int c = *(const uint8_t*)utf8;
- if (c == 0) {
- break;
- }
- utf8 += SkUTF8_LeadByteToCount(c);
- count += 1;
- }
- return count;
-}
-
-// SAFE: returns -1 if invalid UTF-8
-int SkUTF8_CountUnichars(const void* text, size_t byteLength) {
- SkASSERT(text);
- const char* utf8 = static_cast<const char*>(text);
- int count = 0;
- const char* stop = utf8 + byteLength;
-
- while (utf8 < stop) {
- int type = utf8_byte_type(*(const uint8_t*)utf8);
- SkASSERT(type >= -1 && type <= 4);
- if (!utf8_type_is_valid_leading_byte(type) || utf8 + type > stop) {
- // Sequence extends beyond end.
- return -1;
- }
- while(type-- > 1) {
- ++utf8;
- if (!utf8_byte_is_continuation(*(const uint8_t*)utf8)) {
- return -1;
- }
- }
- ++utf8;
- ++count;
- }
- return count;
-}
-
-SkUnichar SkUTF8_ToUnichar(const char utf8[]) {
- SkASSERT(utf8);
-
- const uint8_t* p = (const uint8_t*)utf8;
- int c = *p;
- int hic = c << 24;
-
- assert_utf8_leadingbyte(c);
-
- if (hic < 0) {
- uint32_t mask = (uint32_t)~0x3F;
- hic = SkLeftShift(hic, 1);
- do {
- c = (c << 6) | (*++p & 0x3F);
- mask <<= 5;
- } while ((hic = SkLeftShift(hic, 1)) < 0);
- c &= ~mask;
- }
- return c;
-}
-
-// SAFE: returns -1 on invalid UTF-8 sequence.
-SkUnichar SkUTF8_NextUnicharWithError(const char** ptr, const char* end) {
- SkASSERT(ptr && *ptr);
- SkASSERT(*ptr < end);
- const uint8_t* p = (const uint8_t*)*ptr;
- int c = *p;
- int hic = c << 24;
-
- if (!utf8_byte_is_leading_byte(c)) {
- return -1;
- }
- if (hic < 0) {
- uint32_t mask = (uint32_t)~0x3F;
- hic = SkLeftShift(hic, 1);
- do {
- ++p;
- if (p >= (const uint8_t*)end) {
- return -1;
- }
- // check before reading off end of array.
- uint8_t nextByte = *p;
- if (!utf8_byte_is_continuation(nextByte)) {
- return -1;
- }
- c = (c << 6) | (nextByte & 0x3F);
- mask <<= 5;
- } while ((hic = SkLeftShift(hic, 1)) < 0);
- c &= ~mask;
- }
- *ptr = (char*)p + 1;
- return c;
-}
-
-SkUnichar SkUTF8_NextUnichar(const char** ptr) {
- SkASSERT(ptr && *ptr);
-
- const uint8_t* p = (const uint8_t*)*ptr;
- int c = *p;
- int hic = c << 24;
-
- assert_utf8_leadingbyte(c);
-
- if (hic < 0) {
- uint32_t mask = (uint32_t)~0x3F;
- hic = SkLeftShift(hic, 1);
- do {
- c = (c << 6) | (*++p & 0x3F);
- mask <<= 5;
- } while ((hic = SkLeftShift(hic, 1)) < 0);
- c &= ~mask;
- }
- *ptr = (char*)p + 1;
- return c;
-}
-
-SkUnichar SkUTF8_PrevUnichar(const char** ptr) {
- SkASSERT(ptr && *ptr);
-
- const char* p = *ptr;
-
- if (*--p & 0x80) {
- while (*--p & 0x40) {
- ;
- }
- }
-
- *ptr = (char*)p;
- return SkUTF8_NextUnichar(&p);
-}
-
-size_t SkUTF8_FromUnichar(SkUnichar uni, char utf8[]) {
- if ((uint32_t)uni > 0x10FFFF) {
- SkDEBUGFAIL("bad unichar");
- return 0;
- }
-
- if (uni <= 127) {
- if (utf8) {
- *utf8 = (char)uni;
- }
- return 1;
- }
-
- char tmp[4];
- char* p = tmp;
- size_t count = 1;
-
- SkDEBUGCODE(SkUnichar orig = uni;)
-
- while (uni > 0x7F >> count) {
- *p++ = (char)(0x80 | (uni & 0x3F));
- uni >>= 6;
- count += 1;
- }
-
- if (utf8) {
- p = tmp;
- utf8 += count;
- while (p < tmp + count - 1) {
- *--utf8 = *p++;
- }
- *--utf8 = (char)(~(0xFF >> count) | uni);
- }
-
- SkASSERT(utf8 == nullptr || orig == SkUTF8_ToUnichar(utf8));
- return count;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-int SkUTF16_CountUnichars(const uint16_t src[]) {
- SkASSERT(src);
-
- int count = 0;
- unsigned c;
- while ((c = *src++) != 0) {
- SkASSERT(!SkUTF16_IsLowSurrogate(c));
- if (SkUTF16_IsHighSurrogate(c)) {
- c = *src++;
- SkASSERT(SkUTF16_IsLowSurrogate(c));
- }
- count += 1;
- }
- return count;
-}
-
-// returns -1 on error
-int SkUTF16_CountUnichars(const void* text, size_t byteLength) {
- SkASSERT(text);
- if (!SkIsAlign2(intptr_t(text)) || !SkIsAlign2(byteLength)) {
- return -1;
- }
-
- const uint16_t* src = static_cast<const uint16_t*>(text);
- const uint16_t* stop = src + (byteLength >> 1);
- int count = 0;
- while (src < stop) {
- unsigned c = *src++;
- if (SkUTF16_IsLowSurrogate(c)) {
- return -1;
- }
- if (SkUTF16_IsHighSurrogate(c)) {
- if (src >= stop) {
- return -1;
- }
- c = *src++;
- if (!SkUTF16_IsLowSurrogate(c)) {
- return -1;
- }
- }
- count += 1;
- }
- return count;
-}
-
-SkUnichar SkUTF16_NextUnichar(const uint16_t** srcPtr, const uint16_t* endPtr) {
- if (!srcPtr || !endPtr) {
- return -1;
- }
- const uint16_t* src = *srcPtr;
- if (src >= endPtr) {
- return -1;
- }
- uint16_t c = *src++;
- SkUnichar result = c;
-
- if (SkUTF16_IsLowSurrogate(c)) {
- return -1; // srcPtr should never point at low surrogate.
- }
- if (SkUTF16_IsHighSurrogate(c)) {
- if (src == endPtr) {
- return -1; // Truncated string.
- }
- uint16_t low = *src++;
- if (!SkUTF16_IsLowSurrogate(low)) {
- return -1;
- }
- /*
- [paraphrased from wikipedia]
- Take the high surrogate and subtract 0xD800, then multiply by 0x400.
- Take the low surrogate and subtract 0xDC00. Add these two results
- together, and finally add 0x10000 to get the final decoded codepoint.
-
- unicode = (high - 0xD800) * 0x400 + low - 0xDC00 + 0x10000
- unicode = (high * 0x400) - (0xD800 * 0x400) + low - 0xDC00 + 0x10000
- unicode = (high << 10) - (0xD800 << 10) + low - 0xDC00 + 0x10000
- unicode = (high << 10) + low - ((0xD800 << 10) + 0xDC00 - 0x10000)
- */
- result = (result << 10) + (SkUnichar)low - ((0xD800 << 10) + 0xDC00 - 0x10000);
- }
- *srcPtr = src;
- return result;
-}
-
-SkUnichar SkUTF16_NextUnichar(const uint16_t** srcPtr) {
- SkUnichar c = SkUTF16_NextUnichar(srcPtr, *srcPtr + 2);
+template <typename T>
+static SkUnichar next(const T** srcPtr, unsigned N, SkUnichar (*fn)(const T**, const T*)) {
+ SkASSERT(srcPtr);
+ const T* ptr = *srcPtr;
+ SkUnichar c = fn(&ptr, ptr + N);
if (c == -1) {
SkASSERT(false);
++(*srcPtr);
- return 0xFFFD; // REPLACEMENT CHARACTER.
- }
- return c;
-}
-
-SkUnichar SkUTF16_PrevUnichar(const uint16_t** srcPtr) {
- SkASSERT(srcPtr && *srcPtr);
-
- const uint16_t* src = *srcPtr;
- SkUnichar c = *--src;
-
- SkASSERT(!SkUTF16_IsHighSurrogate(c));
- if (SkUTF16_IsLowSurrogate(c)) {
- unsigned c2 = *--src;
- SkASSERT(SkUTF16_IsHighSurrogate(c2));
- c = (c2 << 10) + c + (0x10000 - (0xD800 << 10) - 0xDC00);
+ return 0xFFFD; // REPLACEMENT CHARACTER
}
- *srcPtr = src;
+ *srcPtr = ptr;
return c;
}
-
-size_t SkUTF16_FromUnichar(SkUnichar uni, uint16_t dst[]) {
- SkASSERT((unsigned)uni <= 0x10FFFF);
-
- int extra = (uni > 0xFFFF);
-
- if (dst) {
- if (extra) {
- // dst[0] = SkToU16(0xD800 | ((uni - 0x10000) >> 10));
- // dst[0] = SkToU16(0xD800 | ((uni >> 10) - 64));
- dst[0] = SkToU16((0xD800 - 64) + (uni >> 10));
- dst[1] = SkToU16(0xDC00 | (uni & 0x3FF));
-
- SkASSERT(SkUTF16_IsHighSurrogate(dst[0]));
- SkASSERT(SkUTF16_IsLowSurrogate(dst[1]));
- } else {
- dst[0] = SkToU16(uni);
- SkASSERT(!SkUTF16_IsHighSurrogate(dst[0]));
- SkASSERT(!SkUTF16_IsLowSurrogate(dst[0]));
- }
- }
- return 1 + extra;
-}
-
-size_t SkUTF16_ToUTF8(const uint16_t utf16[], int numberOf16BitValues,
- char utf8[]) {
- SkASSERT(numberOf16BitValues >= 0);
- if (numberOf16BitValues <= 0) {
- return 0;
- }
-
- SkASSERT(utf16 != nullptr);
-
- const uint16_t* stop = utf16 + numberOf16BitValues;
- size_t size = 0;
-
- if (utf8 == nullptr) { // just count
- while (utf16 < stop) {
- size += SkUTF8_FromUnichar(SkUTF16_NextUnichar(&utf16), nullptr);
- }
- } else {
- char* start = utf8;
- while (utf16 < stop) {
- utf8 += SkUTF8_FromUnichar(SkUTF16_NextUnichar(&utf16), utf8);
- }
- size = utf8 - start;
- }
- return size;
+SkUnichar SkUTF8_NextUnichar(const char** p) {
+ return next<char>(p, SkUTF::kMaxBytesInUTF8Sequence, SkUTF::NextUTF8);
}
-
-// returns -1 on error
-int SkUTF32_CountUnichars(const void* text, size_t byteLength) {
- if (!SkIsAlign4(intptr_t(text)) || !SkIsAlign4(byteLength)) {
- return -1;
- }
- const uint32_t kInvalidUnicharMask = 0xFF000000; // unichar fits in 24 bits
- const uint32_t* ptr = static_cast<const uint32_t*>(text);
- const uint32_t* stop = ptr + (byteLength >> 2);
- while (ptr < stop) {
- if (*ptr & kInvalidUnicharMask) {
- return -1;
- }
- ptr += 1;
- }
- return SkToInt(byteLength >> 2);
+SkUnichar SkUTF16_NextUnichar(const uint16_t** p) {
+ return next<uint16_t>(p, 2, SkUTF::NextUTF16);
}
-// returns -1 on error
-int SkUTFN_CountUnichars(
- SkTypeface::Encoding encoding, const void* utfN, size_t byteLength) {
- SkASSERT(utfN != nullptr);
- switch (encoding) {
- case SkTypeface::kUTF8_Encoding:
- return SkUTF8_CountUnichars(utfN, byteLength);
- case SkTypeface::kUTF16_Encoding:
- return SkUTF16_CountUnichars(utfN, byteLength);
- case SkTypeface::kUTF32_Encoding:
- return SkUTF32_CountUnichars(utfN, byteLength);
- default:
- SkDEBUGFAIL("unknown text encoding");
- }
-
- return -1;
-}
+///////////////////////////////////////////////////////////////////////////////
const char SkHexadecimalDigits::gUpper[16] =
{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
diff --git a/src/core/SkUtils.h b/src/core/SkUtils.h
index 795b47a0c4..e18934d6b8 100644
--- a/src/core/SkUtils.h
+++ b/src/core/SkUtils.h
@@ -8,10 +8,9 @@
#ifndef SkUtils_DEFINED
#define SkUtils_DEFINED
-#include "SkTypes.h"
-#include "SkMath.h"
#include "SkOpts.h"
#include "SkTypeface.h"
+#include "../utils/SkUTF.h"
/** Similar to memset(), but it assigns a 16, 32, or 64-bit value into the buffer.
@param buffer The memory to have value copied into it
@@ -27,87 +26,46 @@ static inline void sk_memset32(uint32_t buffer[], uint32_t value, int count) {
static inline void sk_memset64(uint64_t buffer[], uint64_t value, int count) {
SkOpts::memset64(buffer, value, count);
}
-///////////////////////////////////////////////////////////////////////////////
-#define kMaxBytesInUTF8Sequence 4
+///////////////////////////////////////////////////////////////////////////////
-#ifdef SK_DEBUG
- int SkUTF8_LeadByteToCount(unsigned c);
-#else
- #define SkUTF8_LeadByteToCount(c) ((((0xE5 << 24) >> ((unsigned)c >> 4 << 1)) & 3) + 1)
-#endif
+// Unlike the functions in SkUTF.h, these two functions do not take an array
+// length parameter. When possible, use SkUTF::NextUTF{8,16} instead.
+SkUnichar SkUTF8_NextUnichar(const char**);
+SkUnichar SkUTF16_NextUnichar(const uint16_t**);
-inline int SkUTF8_CountUTF8Bytes(const char utf8[]) {
- SkASSERT(utf8);
- return SkUTF8_LeadByteToCount(*(const uint8_t*)utf8);
-}
+///////////////////////////////////////////////////////////////////////////////
-int SkUTF8_CountUnichars(const char utf8[]);
+static inline bool SkUTF16_IsHighSurrogate(uint16_t c) { return ((c) & 0xFC00) == 0xD800; }
-/** These functions are safe: invalid sequences will return -1; */
-int SkUTF8_CountUnichars(const void* utf8, size_t byteLength);
-int SkUTF16_CountUnichars(const void* utf16, size_t byteLength);
-int SkUTF32_CountUnichars(const void* utf32, size_t byteLength);
-int SkUTFN_CountUnichars(SkTypeface::Encoding encoding, const void* utfN, size_t byteLength);
+static inline bool SkUTF16_IsLowSurrogate (uint16_t c) { return ((c) & 0xFC00) == 0xDC00; }
-/** This function is safe: invalid UTF8 sequences will return -1
- * When -1 is returned, ptr is unchanged.
- * Precondition: *ptr < end;
- */
-SkUnichar SkUTF8_NextUnicharWithError(const char** ptr, const char* end);
+///////////////////////////////////////////////////////////////////////////////
-/** this version replaces invalid utf-8 sequences with code point U+FFFD. */
-inline SkUnichar SkUTF8_NextUnichar(const char** ptr, const char* end) {
- SkUnichar val = SkUTF8_NextUnicharWithError(ptr, end);
- if (val < 0) {
- *ptr = end;
- return 0xFFFD; // REPLACEMENT CHARACTER
+static inline int SkUTFN_CountUnichars(SkTypeface::Encoding enc, const void* utfN, size_t bytes) {
+ switch (enc) {
+ case SkTypeface::kUTF8_Encoding: return SkUTF::CountUTF8((const char*)utfN, bytes);
+ case SkTypeface::kUTF16_Encoding: return SkUTF::CountUTF16((const uint16_t*)utfN, bytes);
+ case SkTypeface::kUTF32_Encoding: return SkUTF::CountUTF32((const int32_t*)utfN, bytes);
+ default: SkDEBUGFAIL("unknown text encoding"); return -1;
}
- return val;
}
-SkUnichar SkUTF8_ToUnichar(const char utf8[]);
-SkUnichar SkUTF8_NextUnichar(const char**);
-SkUnichar SkUTF8_PrevUnichar(const char**);
-
-/** Return the number of bytes need to convert a unichar
- into a utf8 sequence. Will be 1..kMaxBytesInUTF8Sequence,
- or 0 if uni is illegal.
-*/
-size_t SkUTF8_FromUnichar(SkUnichar uni, char utf8[] = nullptr);
-
-///////////////////////////////////////////////////////////////////////////////
-
-#define SkUTF16_IsHighSurrogate(c) (((c) & 0xFC00) == 0xD800)
-#define SkUTF16_IsLowSurrogate(c) (((c) & 0xFC00) == 0xDC00)
-
-int SkUTF16_CountUnichars(const uint16_t utf16[]);
-// returns the current unichar and then moves past it (*p++)
-SkUnichar SkUTF16_NextUnichar(const uint16_t**);
-SkUnichar SkUTF16_NextUnichar(const uint16_t** srcPtr, const uint16_t* end);
-
-// this guy backs up to the previus unichar value, and returns it (*--p)
-SkUnichar SkUTF16_PrevUnichar(const uint16_t**);
-size_t SkUTF16_FromUnichar(SkUnichar uni, uint16_t utf16[] = nullptr);
-
-size_t SkUTF16_ToUTF8(const uint16_t utf16[], int numberOf16BitValues,
- char utf8[] = nullptr);
-
-inline bool SkUnichar_IsVariationSelector(SkUnichar uni) {
-/* The 'true' ranges are:
- * 0x180B <= uni <= 0x180D
- * 0xFE00 <= uni <= 0xFE0F
- * 0xE0100 <= uni <= 0xE01EF
- */
- if (uni < 0x180B || uni > 0xE01EF) {
- return false;
- }
- if ((uni > 0x180D && uni < 0xFE00) || (uni > 0xFE0F && uni < 0xE0100)) {
- return false;
+static inline SkUnichar SkUTFN_Next(SkTypeface::Encoding enc,
+ const void** ptr, const void* stop) {
+ switch (enc) {
+ case SkTypeface::kUTF8_Encoding:
+ return SkUTF::NextUTF8((const char**)ptr, (const char*)stop);
+ case SkTypeface::kUTF16_Encoding:
+ return SkUTF::NextUTF16((const uint16_t**)ptr, (const uint16_t*)stop);
+ case SkTypeface::kUTF32_Encoding:
+ return SkUTF::NextUTF32((const int32_t**)ptr, (const int32_t*)stop);
+ default: SkDEBUGFAIL("unknown text encoding"); return -1;
}
- return true;
}
+///////////////////////////////////////////////////////////////////////////////
+
namespace SkHexadecimalDigits {
extern const char gUpper[16]; // 0-9A-F
extern const char gLower[16]; // 0-9a-f