Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkString.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
9
15#include "src/base/SkSafeMath.h"
16#include "src/base/SkUTF.h"
17#include "src/base/SkUtils.h"
18
19#include <algorithm>
20#include <cstdio>
21#include <cstring>
22#include <new>
23#include <string_view>
24#include <utility>
25
26// number of bytes (on the stack) to receive the printf result
27static const size_t kBufferSize = 1024;
28
30 char* fText;
32};
33
34template <int SIZE>
35static StringBuffer apply_format_string(const char* format, va_list args, char (&stackBuffer)[SIZE],
36 SkString* heapBuffer) SK_PRINTF_LIKE(1, 0);
37
38template <int SIZE>
39static StringBuffer apply_format_string(const char* format, va_list args, char (&stackBuffer)[SIZE],
40 SkString* heapBuffer) {
41 // First, attempt to print directly to the stack buffer.
42 va_list argsCopy;
43 va_copy(argsCopy, args);
44 int outLength = std::vsnprintf(stackBuffer, SIZE, format, args);
45 if (outLength < 0) {
46 SkDebugf("SkString: vsnprintf reported error.");
47 va_end(argsCopy);
48 return {stackBuffer, 0};
49 }
50 if (outLength < SIZE) {
51 va_end(argsCopy);
52 return {stackBuffer, outLength};
53 }
54
55 // Our text was too long to fit on the stack! However, we now know how much space we need to
56 // format it. Format the string into our heap buffer. `set` automatically reserves an extra
57 // byte at the end of the buffer for a null terminator, so we don't need to add one here.
58 heapBuffer->set(nullptr, outLength);
59 char* heapBufferDest = heapBuffer->data();
60 SkDEBUGCODE(int checkLength =) std::vsnprintf(heapBufferDest, outLength + 1, format, argsCopy);
61 SkASSERT(checkLength == outLength);
62 va_end(argsCopy);
63 return {heapBufferDest, outLength};
64}
65
66///////////////////////////////////////////////////////////////////////////////
67
68bool SkStrEndsWith(const char string[], const char suffixStr[]) {
69 SkASSERT(string);
70 SkASSERT(suffixStr);
71 size_t strLen = strlen(string);
72 size_t suffixLen = strlen(suffixStr);
73 return strLen >= suffixLen &&
74 !strncmp(string + strLen - suffixLen, suffixStr, suffixLen);
75}
76
77bool SkStrEndsWith(const char string[], const char suffixChar) {
78 SkASSERT(string);
79 size_t strLen = strlen(string);
80 if (0 == strLen) {
81 return false;
82 } else {
83 return (suffixChar == string[strLen-1]);
84 }
85}
86
87int SkStrStartsWithOneOf(const char string[], const char prefixes[]) {
88 int index = 0;
89 do {
90 const char* limit = strchr(prefixes, '\0');
91 if (!strncmp(string, prefixes, limit - prefixes)) {
92 return index;
93 }
94 prefixes = limit + 1;
95 index++;
96 } while (prefixes[0]);
97 return -1;
98}
99
100char* SkStrAppendU32(char string[], uint32_t dec) {
101 SkDEBUGCODE(char* start = string;)
102
104 char* p = buffer + sizeof(buffer);
105
106 do {
107 *--p = SkToU8('0' + dec % 10);
108 dec /= 10;
109 } while (dec != 0);
110
111 SkASSERT(p >= buffer);
112 size_t cp_len = buffer + sizeof(buffer) - p;
113 memcpy(string, p, cp_len);
114 string += cp_len;
115
117 return string;
118}
119
120char* SkStrAppendS32(char string[], int32_t dec) {
121 uint32_t udec = dec;
122 if (dec < 0) {
123 *string++ = '-';
124 udec = ~udec + 1; // udec = -udec, but silences some warnings that are trying to be helpful
125 }
126 return SkStrAppendU32(string, udec);
127}
128
129char* SkStrAppendU64(char string[], uint64_t dec, int minDigits) {
130 SkDEBUGCODE(char* start = string;)
131
133 char* p = buffer + sizeof(buffer);
134
135 do {
136 *--p = SkToU8('0' + (int32_t) (dec % 10));
137 dec /= 10;
138 minDigits--;
139 } while (dec != 0);
140
141 while (minDigits > 0) {
142 *--p = '0';
143 minDigits--;
144 }
145
146 SkASSERT(p >= buffer);
147 size_t cp_len = buffer + sizeof(buffer) - p;
148 memcpy(string, p, cp_len);
149 string += cp_len;
150
152 return string;
153}
154
155char* SkStrAppendS64(char string[], int64_t dec, int minDigits) {
156 uint64_t udec = dec;
157 if (dec < 0) {
158 *string++ = '-';
159 udec = ~udec + 1; // udec = -udec, but silences some warnings that are trying to be helpful
160 }
161 return SkStrAppendU64(string, udec, minDigits);
162}
163
164char* SkStrAppendScalar(char string[], SkScalar value) {
165 // Handle infinity and NaN ourselves to ensure consistent cross-platform results.
166 // (e.g.: `inf` versus `1.#INF00`, `nan` versus `-nan` for high-bit-set NaNs)
167 if (SkIsNaN(value)) {
168 strcpy(string, "nan");
169 return string + 3;
170 }
171 if (!SkIsFinite(value)) {
172 if (value > 0) {
173 strcpy(string, "inf");
174 return string + 3;
175 } else {
176 strcpy(string, "-inf");
177 return string + 4;
178 }
179 }
180
181 // since floats have at most 8 significant digits, we limit our %g to that.
182 static const char gFormat[] = "%.8g";
183 // make it 1 larger for the terminating 0
185 int len = snprintf(buffer, sizeof(buffer), gFormat, value);
186 memcpy(string, buffer, len);
188 return string + len;
189}
190
191///////////////////////////////////////////////////////////////////////////////
192
193const SkString::Rec SkString::gEmptyRec(0, 0);
194
195#define SizeOfRec() (gEmptyRec.data() - (const char*)&gEmptyRec)
196
197static uint32_t trim_size_t_to_u32(size_t value) {
198 if (sizeof(size_t) > sizeof(uint32_t)) {
199 if (value > UINT32_MAX) {
200 value = UINT32_MAX;
201 }
202 }
203 return (uint32_t)value;
204}
205
206static size_t check_add32(size_t base, size_t extra) {
207 SkASSERT(base <= UINT32_MAX);
208 if (sizeof(size_t) > sizeof(uint32_t)) {
209 if (base + extra > UINT32_MAX) {
210 extra = UINT32_MAX - base;
211 }
212 }
213 return extra;
214}
215
216sk_sp<SkString::Rec> SkString::Rec::Make(const char text[], size_t len) {
217 if (0 == len) {
218 return sk_sp<SkString::Rec>(const_cast<Rec*>(&gEmptyRec));
219 }
220
221 SkSafeMath safe;
222 // We store a 32bit version of the length
223 uint32_t stringLen = safe.castTo<uint32_t>(len);
224 // Add SizeOfRec() for our overhead and 1 for null-termination
225 size_t allocationSize = safe.add(len, SizeOfRec() + sizeof(char));
226 // Align up to a multiple of 4
227 allocationSize = safe.alignUp(allocationSize, 4);
228
229 SkASSERT_RELEASE(safe.ok());
230
231 void* storage = ::operator new (allocationSize);
232 sk_sp<Rec> rec(new (storage) Rec(stringLen, 1));
233 if (text) {
234 memcpy(rec->data(), text, len);
235 }
236 rec->data()[len] = 0;
237 return rec;
238}
239
240void SkString::Rec::ref() const {
241 if (this == &SkString::gEmptyRec) {
242 return;
243 }
244 SkAssertResult(this->fRefCnt.fetch_add(+1, std::memory_order_relaxed));
245}
246
247void SkString::Rec::unref() const {
248 if (this == &SkString::gEmptyRec) {
249 return;
250 }
251 int32_t oldRefCnt = this->fRefCnt.fetch_add(-1, std::memory_order_acq_rel);
252 SkASSERT(oldRefCnt);
253 if (1 == oldRefCnt) {
254 delete this;
255 }
256}
257
258bool SkString::Rec::unique() const {
259 return fRefCnt.load(std::memory_order_acquire) == 1;
260}
261
262#ifdef SK_DEBUG
263int32_t SkString::Rec::getRefCnt() const {
264 return fRefCnt.load(std::memory_order_relaxed);
265}
266
267const SkString& SkString::validate() const {
268 // make sure no one has written over our global
269 SkASSERT(0 == gEmptyRec.fLength);
270 SkASSERT(0 == gEmptyRec.getRefCnt());
271 SkASSERT(0 == gEmptyRec.data()[0]);
272
273 if (fRec.get() != &gEmptyRec) {
274 SkASSERT(fRec->fLength > 0);
275 SkASSERT(fRec->getRefCnt() > 0);
276 SkASSERT(0 == fRec->data()[fRec->fLength]);
277 }
278 return *this;
279}
280
281SkString& SkString::validate() {
282 const_cast<const SkString*>(this)->validate();
283 return *this;
284}
285#endif
286
287///////////////////////////////////////////////////////////////////////////////
288
289SkString::SkString() : fRec(const_cast<Rec*>(&gEmptyRec)) {
290}
291
293 fRec = Rec::Make(nullptr, len);
294}
295
297 size_t len = text ? strlen(text) : 0;
298
299 fRec = Rec::Make(text, len);
300}
301
302SkString::SkString(const char text[], size_t len) {
303 fRec = Rec::Make(text, len);
304}
305
306SkString::SkString(const SkString& src) : fRec(src.validate().fRec) {}
307
308SkString::SkString(SkString&& src) : fRec(std::move(src.validate().fRec)) {
309 src.fRec.reset(const_cast<Rec*>(&gEmptyRec));
310}
311
312SkString::SkString(const std::string& src) {
313 fRec = Rec::Make(src.c_str(), src.size());
314}
315
316SkString::SkString(std::string_view src) {
317 fRec = Rec::Make(src.data(), src.length());
318}
319
321 this->validate();
322}
323
324bool SkString::equals(const SkString& src) const {
325 return fRec == src.fRec || this->equals(src.c_str(), src.size());
326}
327
328bool SkString::equals(const char text[]) const {
329 return this->equals(text, text ? strlen(text) : 0);
330}
331
332bool SkString::equals(const char text[], size_t len) const {
333 SkASSERT(len == 0 || text != nullptr);
334
335 return fRec->fLength == len && !sk_careful_memcmp(fRec->data(), text, len);
336}
337
339 this->validate();
340 fRec = src.fRec; // sk_sp<Rec>::operator=(const sk_sp<Ref>&) checks for self-assignment.
341 return *this;
342}
343
345 this->validate();
346
347 if (fRec != src.fRec) {
348 this->swap(src);
349 }
350 return *this;
351}
352
354 this->validate();
355 return *this = SkString(text);
356}
357
359 this->validate();
360 fRec.reset(const_cast<Rec*>(&gEmptyRec));
361}
362
364 this->validate();
365
366 if (fRec->fLength) {
367 if (!fRec->unique()) {
368 fRec = Rec::Make(fRec->data(), fRec->fLength);
369 }
370 }
371 return fRec->data();
372}
373
374void SkString::resize(size_t len) {
375 len = trim_size_t_to_u32(len);
376 if (0 == len) {
377 this->reset();
378 } else if (fRec->unique() && ((len >> 2) <= (fRec->fLength >> 2))) {
379 // Use less of the buffer we have without allocating a smaller one.
380 char* p = this->data();
381 p[len] = '\0';
382 fRec->fLength = SkToU32(len);
383 } else {
384 SkString newString(len);
385 char* dest = newString.data();
386 int copyLen = std::min<uint32_t>(len, this->size());
387 memcpy(dest, this->c_str(), copyLen);
388 dest[copyLen] = '\0';
389 this->swap(newString);
390 }
391}
392
393void SkString::set(const char text[]) {
394 this->set(text, text ? strlen(text) : 0);
395}
396
397void SkString::set(const char text[], size_t len) {
398 len = trim_size_t_to_u32(len);
399 if (0 == len) {
400 this->reset();
401 } else if (fRec->unique() && ((len >> 2) <= (fRec->fLength >> 2))) {
402 // Use less of the buffer we have without allocating a smaller one.
403 char* p = this->data();
404 if (text) {
405 memcpy(p, text, len);
406 }
407 p[len] = '\0';
408 fRec->fLength = SkToU32(len);
409 } else {
410 SkString tmp(text, len);
411 this->swap(tmp);
412 }
413}
414
415void SkString::insert(size_t offset, const char text[]) {
416 this->insert(offset, text, text ? strlen(text) : 0);
417}
418
419void SkString::insert(size_t offset, const char text[], size_t len) {
420 if (len) {
421 size_t length = fRec->fLength;
422 if (offset > length) {
423 offset = length;
424 }
425
426 // Check if length + len exceeds 32bits, we trim len
427 len = check_add32(length, len);
428 if (0 == len) {
429 return;
430 }
431
432 /* If we're the only owner, and we have room in our allocation for the insert,
433 do it in place, rather than allocating a new buffer.
434
435 To know we have room, compare the allocated sizes
436 beforeAlloc = SkAlign4(length + 1)
437 afterAlloc = SkAligh4(length + 1 + len)
438 but SkAlign4(x) is (x + 3) >> 2 << 2
439 which is equivalent for testing to (length + 1 + 3) >> 2 == (length + 1 + 3 + len) >> 2
440 and we can then eliminate the +1+3 since that doesn't affec the answer
441 */
442 if (fRec->unique() && (length >> 2) == ((length + len) >> 2)) {
443 char* dst = this->data();
444
445 if (offset < length) {
446 memmove(dst + offset + len, dst + offset, length - offset);
447 }
448 memcpy(dst + offset, text, len);
449
450 dst[length + len] = 0;
451 fRec->fLength = SkToU32(length + len);
452 } else {
453 /* Seems we should use realloc here, since that is safe if it fails
454 (we have the original data), and might be faster than alloc/copy/free.
455 */
456 SkString tmp(fRec->fLength + len);
457 char* dst = tmp.data();
458
459 if (offset > 0) {
460 memcpy(dst, fRec->data(), offset);
461 }
462 memcpy(dst + offset, text, len);
463 if (offset < fRec->fLength) {
464 memcpy(dst + offset + len, fRec->data() + offset,
465 fRec->fLength - offset);
466 }
467
468 this->swap(tmp);
469 }
470 }
471}
472
475 size_t len = SkUTF::ToUTF8(uni, buffer);
476
477 if (len) {
478 this->insert(offset, buffer, len);
479 }
480}
481
482void SkString::insertS32(size_t offset, int32_t dec) {
484 char* stop = SkStrAppendS32(buffer, dec);
485 this->insert(offset, buffer, stop - buffer);
486}
487
488void SkString::insertS64(size_t offset, int64_t dec, int minDigits) {
490 char* stop = SkStrAppendS64(buffer, dec, minDigits);
491 this->insert(offset, buffer, stop - buffer);
492}
493
494void SkString::insertU32(size_t offset, uint32_t dec) {
496 char* stop = SkStrAppendU32(buffer, dec);
497 this->insert(offset, buffer, stop - buffer);
498}
499
500void SkString::insertU64(size_t offset, uint64_t dec, int minDigits) {
502 char* stop = SkStrAppendU64(buffer, dec, minDigits);
503 this->insert(offset, buffer, stop - buffer);
504}
505
506void SkString::insertHex(size_t offset, uint32_t hex, int minDigits) {
507 minDigits = SkTPin(minDigits, 0, 8);
508
509 char buffer[8];
510 char* p = buffer + sizeof(buffer);
511
512 do {
513 *--p = SkHexadecimalDigits::gUpper[hex & 0xF];
514 hex >>= 4;
515 minDigits -= 1;
516 } while (hex != 0);
517
518 while (--minDigits >= 0) {
519 *--p = '0';
520 }
521
522 SkASSERT(p >= buffer);
523 this->insert(offset, p, buffer + sizeof(buffer) - p);
524}
525
528 char* stop = SkStrAppendScalar(buffer, value);
529 this->insert(offset, buffer, stop - buffer);
530}
531
532///////////////////////////////////////////////////////////////////////////////
533
534void SkString::printf(const char format[], ...) {
535 va_list args;
536 va_start(args, format);
537 this->printVAList(format, args);
538 va_end(args);
539}
540
541void SkString::printVAList(const char format[], va_list args) {
542 char stackBuffer[kBufferSize];
543 StringBuffer result = apply_format_string(format, args, stackBuffer, this);
544
545 if (result.fText == stackBuffer) {
546 this->set(result.fText, result.fLength);
547 }
548}
549
550void SkString::appendf(const char format[], ...) {
551 va_list args;
552 va_start(args, format);
553 this->appendVAList(format, args);
554 va_end(args);
555}
556
557void SkString::appendVAList(const char format[], va_list args) {
558 if (this->isEmpty()) {
559 this->printVAList(format, args);
560 return;
561 }
562
563 SkString overflow;
564 char stackBuffer[kBufferSize];
565 StringBuffer result = apply_format_string(format, args, stackBuffer, &overflow);
566
567 this->append(result.fText, result.fLength);
568}
569
570void SkString::prependf(const char format[], ...) {
571 va_list args;
572 va_start(args, format);
573 this->prependVAList(format, args);
574 va_end(args);
575}
576
577void SkString::prependVAList(const char format[], va_list args) {
578 if (this->isEmpty()) {
579 this->printVAList(format, args);
580 return;
581 }
582
583 SkString overflow;
584 char stackBuffer[kBufferSize];
585 StringBuffer result = apply_format_string(format, args, stackBuffer, &overflow);
586
587 this->prepend(result.fText, result.fLength);
588}
589
590///////////////////////////////////////////////////////////////////////////////
591
592void SkString::remove(size_t offset, size_t length) {
593 size_t size = this->size();
594
595 if (offset < size) {
596 if (length > size - offset) {
597 length = size - offset;
598 }
599 SkASSERT(length <= size);
601 if (length > 0) {
602 SkString tmp(size - length);
603 char* dst = tmp.data();
604 const char* src = this->c_str();
605
606 if (offset) {
607 memcpy(dst, src, offset);
608 }
609 size_t tail = size - (offset + length);
610 if (tail) {
611 memcpy(dst + offset, src + (offset + length), tail);
612 }
613 SkASSERT(dst[tmp.size()] == 0);
614 this->swap(tmp);
615 }
616 }
617}
618
620 this->validate();
621 other.validate();
622
623 using std::swap;
624 swap(fRec, other.fRec);
625}
626
627///////////////////////////////////////////////////////////////////////////////
628
629SkString SkStringPrintf(const char* format, ...) {
630 SkString formattedOutput;
631 va_list args;
632 va_start(args, format);
633 formattedOutput.printVAList(format, args);
634 va_end(args);
635 return formattedOutput;
636}
#define SkAssertResult(cond)
Definition SkAssert.h:123
#define SkASSERT_RELEASE(cond)
Definition SkAssert.h:100
#define SkASSERT(cond)
Definition SkAssert.h:116
#define SK_PRINTF_LIKE(A, B)
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
#define SkDEBUGCODE(...)
Definition SkDebug.h:23
static bool SkIsFinite(T x, Pack... values)
static bool SkIsNaN(T x)
static int sk_careful_memcmp(const void *a, const void *b, size_t len)
Definition SkMalloc.h:143
static size_t check_add32(size_t base, size_t extra)
Definition SkString.cpp:206
char * SkStrAppendScalar(char string[], SkScalar value)
Definition SkString.cpp:164
char * SkStrAppendU32(char string[], uint32_t dec)
Definition SkString.cpp:100
char * SkStrAppendS64(char string[], int64_t dec, int minDigits)
Definition SkString.cpp:155
static const size_t kBufferSize
Definition SkString.cpp:27
char * SkStrAppendS32(char string[], int32_t dec)
Definition SkString.cpp:120
bool SkStrEndsWith(const char string[], const char suffixStr[])
Definition SkString.cpp:68
char * SkStrAppendU64(char string[], uint64_t dec, int minDigits)
Definition SkString.cpp:129
#define SizeOfRec()
Definition SkString.cpp:195
static uint32_t trim_size_t_to_u32(size_t value)
Definition SkString.cpp:197
static StringBuffer apply_format_string(const char *format, va_list args, char(&stackBuffer)[SIZE], SkString *heapBuffer) SK_PRINTF_LIKE(1
int SkStrStartsWithOneOf(const char string[], const char prefixes[])
Definition SkString.cpp:87
static constexpr int kSkStrAppendS32_MaxSize
Definition SkString.h:89
char * SkStrAppendU64(char buffer[], uint64_t, int minDigits)
Definition SkString.cpp:129
static constexpr int kSkStrAppendS64_MaxSize
Definition SkString.h:91
static constexpr int kSkStrAppendU32_MaxSize
Definition SkString.h:84
char * SkStrAppendScalar(char buffer[], SkScalar)
Definition SkString.cpp:164
SK_API SkString static SkString SkStringPrintf()
Definition SkString.h:287
char * SkStrAppendS64(char buffer[], int64_t, int minDigits)
Definition SkString.cpp:155
static constexpr int kSkStrAppendScalar_MaxSize
Definition SkString.h:101
static constexpr int kSkStrAppendU64_MaxSize
Definition SkString.h:86
char * SkStrAppendU32(char buffer[], uint32_t)
Definition SkString.cpp:100
char * SkStrAppendS32(char buffer[], int32_t)
Definition SkString.cpp:120
static constexpr const T & SkTPin(const T &x, const T &lo, const T &hi)
Definition SkTPin.h:19
constexpr uint8_t SkToU8(S x)
Definition SkTo.h:22
constexpr uint32_t SkToU32(S x)
Definition SkTo.h:26
int32_t SkUnichar
Definition SkTypes.h:175
size_t add(size_t x, size_t y)
Definition SkSafeMath.h:33
size_t alignUp(size_t x, size_t alignment)
Definition SkSafeMath.h:54
T castTo(size_t value)
Definition SkSafeMath.h:59
bool ok() const
Definition SkSafeMath.h:26
void insertScalar(size_t offset, SkScalar)
Definition SkString.cpp:526
void insertUnichar(size_t offset, SkUnichar)
Definition SkString.cpp:473
void printf(const char format[],...) SK_PRINTF_LIKE(2
Definition SkString.cpp:534
void void void void void void void remove(size_t offset, size_t length)
Definition SkString.cpp:592
void insertU64(size_t offset, uint64_t value, int minDigits=0)
Definition SkString.cpp:500
void void void void appendVAList(const char format[], va_list) SK_PRINTF_LIKE(2
Definition SkString.cpp:557
size_t size() const
Definition SkString.h:131
void void printVAList(const char format[], va_list) SK_PRINTF_LIKE(2
Definition SkString.cpp:541
void void void void void void prependVAList(const char format[], va_list) SK_PRINTF_LIKE(2
Definition SkString.cpp:577
void insertU32(size_t offset, uint32_t value)
Definition SkString.cpp:494
const char * data() const
Definition SkString.h:132
void insertS32(size_t offset, int32_t value)
Definition SkString.cpp:482
void set(const SkString &src)
Definition SkString.h:186
bool equals(const SkString &) const
Definition SkString.cpp:324
bool isEmpty() const
Definition SkString.h:130
void append(const char text[])
Definition SkString.h:203
void swap(SkString &other)
Definition SkString.cpp:619
void resize(size_t len)
Definition SkString.cpp:374
void insert(size_t offset, const char text[])
Definition SkString.cpp:415
SkString & operator=(const SkString &)
Definition SkString.cpp:338
void reset()
Definition SkString.cpp:358
void prepend(const char text[])
Definition SkString.h:215
const char * c_str() const
Definition SkString.h:133
void insertS64(size_t offset, int64_t value, int minDigits=0)
Definition SkString.cpp:488
void void void void void prependf(const char format[],...) SK_PRINTF_LIKE(2
Definition SkString.cpp:570
void insertHex(size_t offset, uint32_t value, int minDigits=0)
Definition SkString.cpp:506
void void void appendf(const char format[],...) SK_PRINTF_LIKE(2
Definition SkString.cpp:550
T * get() const
Definition SkRefCnt.h:303
void reset(T *ptr=nullptr)
Definition SkRefCnt.h:310
float SkScalar
Definition extension.cpp:12
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
static const uint8_t buffer[]
uint8_t value
GAsyncResult * result
uint32_t uint32_t * format
size_t length
std::u16string text
const char gUpper[16]
Definition SkUtils.cpp:10
SK_SPI size_t ToUTF8(SkUnichar uni, char utf8[kMaxBytesInUTF8Sequence]=nullptr)
constexpr unsigned kMaxBytesInUTF8Sequence
Definition SkUTF.h:59
Definition ref_ptr.h:256
#define SIZE
Point offset
char * fText
Definition SkString.cpp:30