aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Hal Canary <halcanary@google.com>2018-06-19 09:53:26 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-06-19 20:11:33 +0000
commitc9b6dda8042dcdd478a3218474fcd1656bb87076 (patch)
treed94bef982979972b2675c06e8d6ffaebb57c7f5c
parent3425e22b9e9781570db306dfa70a47e34824be9e (diff)
SkUtils: safe SkUTF16_NextUnichar
Change-Id: Ief70f3055d9612c8934ede967c1048dd7fcb102a Reviewed-on: https://skia-review.googlesource.com/135705 Commit-Queue: Hal Canary <halcanary@google.com> Auto-Submit: Hal Canary <halcanary@google.com> Reviewed-by: Herb Derby <herb@google.com>
-rw-r--r--src/core/SkDevice.cpp47
-rw-r--r--src/core/SkUtils.cpp52
-rw-r--r--src/core/SkUtils.h2
3 files changed, 64 insertions, 37 deletions
diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp
index 23560986bc..46404b2887 100644
--- a/src/core/SkDevice.cpp
+++ b/src/core/SkDevice.cpp
@@ -483,33 +483,11 @@ void SkBaseDevice::drawTextOnPath(const void* text, size_t byteLength,
}
#include "SkUtils.h"
-typedef int (*CountTextProc)(const char* text);
-static int count_utf16(const char* text) {
- const uint16_t* prev = (uint16_t*)text;
- (void)SkUTF16_NextUnichar(&prev);
- return SkToInt((const char*)prev - text);
-}
-static int return_4(const char* text) { return 4; }
-static int return_2(const char* text) { return 2; }
void SkBaseDevice::drawTextRSXform(const void* text, size_t len,
const SkRSXform xform[], const SkPaint& paint) {
- CountTextProc proc = nullptr;
- switch (paint.getTextEncoding()) {
- case SkPaint::kUTF8_TextEncoding:
- proc = SkUTF8_CountUTF8Bytes;
- break;
- case SkPaint::kUTF16_TextEncoding:
- proc = count_utf16;
- break;
- case SkPaint::kUTF32_TextEncoding:
- proc = return_4;
- break;
- case SkPaint::kGlyphID_TextEncoding:
- proc = return_2;
- break;
- }
-
+ SkPaint::TextEncoding textEncoding = paint.getTextEncoding();
+ const char* end = (const char*)text + len;
SkPaint localPaint(paint);
SkShader* shader = paint.getShader();
SkScalar pos[2] = {0.0f, 0.0f};
@@ -533,8 +511,25 @@ void SkBaseDevice::drawTextRSXform(const void* text, size_t len,
localPaint.setShader(nullptr); // can't handle this xform
}
}
-
- int subLen = proc((const char*)text);
+ int subLen = 0;
+ switch (textEncoding) {
+ case SkPaint::kUTF8_TextEncoding:
+ subLen = SkUTF8_CountUTF8Bytes((const char*)text);
+ break;
+ case SkPaint::kUTF16_TextEncoding:
+ {
+ const uint16_t* ptr = (const uint16_t*)text;
+ (void)SkUTF16_NextUnichar(&ptr, (const uint16_t*)end);
+ subLen = SkToInt((const char*)ptr - (const char*)text);
+ };
+ break;
+ case SkPaint::kUTF32_TextEncoding:
+ subLen = 4;
+ break;
+ case SkPaint::kGlyphID_TextEncoding:
+ subLen = 2;
+ break;
+ }
this->drawPosText(text, subLen, pos, 2, origin, localPaint);
text = (const char*)text + subLen;
}
diff --git a/src/core/SkUtils.cpp b/src/core/SkUtils.cpp
index e6fafa0b07..c12bac50ff 100644
--- a/src/core/SkUtils.cpp
+++ b/src/core/SkUtils.cpp
@@ -289,22 +289,52 @@ int SkUTF16_CountUnichars(const void* text, size_t byteLength) {
return count;
}
-SkUnichar SkUTF16_NextUnichar(const uint16_t** srcPtr) {
- SkASSERT(srcPtr && *srcPtr);
-
+SkUnichar SkUTF16_NextUnichar(const uint16_t** srcPtr, const uint16_t* endPtr) {
+ if (!srcPtr || !endPtr) {
+ return -1;
+ }
const uint16_t* src = *srcPtr;
- SkUnichar c = *src++;
+ if (src >= endPtr) {
+ return -1;
+ }
+ uint16_t c = *src++;
+ SkUnichar result = c;
- SkASSERT(!SkUTF16_IsLowSurrogate(c));
+ if (SkUTF16_IsLowSurrogate(c)) {
+ return -1; // srcPtr should never point at low surrogate.
+ }
if (SkUTF16_IsHighSurrogate(c)) {
- unsigned c2 = *src++;
- SkASSERT(SkUTF16_IsLowSurrogate(c2));
-
- // c = ((c & 0x3FF) << 10) + (c2 & 0x3FF) + 0x10000
- // c = (((c & 0x3FF) + 64) << 10) + (c2 & 0x3FF)
- c = (c << 10) + c2 + (0x10000 - (0xD800 << 10) - 0xDC00);
+ 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);
+ if (c == -1) {
+ SkASSERT(false);
+ ++(*srcPtr);
+ return 0xFFFD; // REPLACEMENT CHARACTER.
+ }
return c;
}
diff --git a/src/core/SkUtils.h b/src/core/SkUtils.h
index 6037b60c3c..795b47a0c4 100644
--- a/src/core/SkUtils.h
+++ b/src/core/SkUtils.h
@@ -84,6 +84,8 @@ size_t SkUTF8_FromUnichar(SkUnichar uni, char utf8[] = nullptr);
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);