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:
parent
3425e22b9e
commit
c9b6dda804
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user