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>
This commit is contained in:
Hal Canary 2018-06-19 09:53:26 -04:00 committed by Skia Commit-Bot
parent 3425e22b9e
commit c9b6dda804
3 changed files with 63 additions and 36 deletions

View File

@ -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;
}

View File

@ -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));
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.
// c = ((c & 0x3FF) << 10) + (c2 & 0x3FF) + 0x10000
// c = (((c & 0x3FF) + 64) << 10) + (c2 & 0x3FF)
c = (c << 10) + c2 + (0x10000 - (0xD800 << 10) - 0xDC00);
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;
}

View File

@ -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);