Flutter Engine
The Flutter Engine
editor.cpp
Go to the documentation of this file.
1// Copyright 2019 Google LLC.
2// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
3
5
9#include "src/base/SkUTF.h"
10
12
13#include <algorithm>
14#include <cfloat>
15
16using namespace SkPlainTextEditor;
17
18static inline SkRect offset(SkRect r, SkIPoint p) {
19 return r.makeOffset((float)p.x(), (float)p.y());
20}
21
22static constexpr SkRect kUnsetRect{-FLT_MAX, -FLT_MAX, -FLT_MAX, -FLT_MAX};
23
24static bool valid_utf8(const char* ptr, size_t size) { return SkUTF::CountUTF8(ptr, size) >= 0; }
25
26// Kind of like Python's readlines(), but without any allocation.
27// Calls f() on each line.
28// F is [](const char*, size_t) -> void
29template <typename F>
30static void readlines(const void* data, size_t size, F f) {
31 const char* start = (const char*)data;
32 const char* end = start + size;
33 const char* ptr = start;
34 while (ptr < end) {
35 while (*ptr++ != '\n' && ptr < end) {}
36 size_t len = ptr - start;
37 SkASSERT(len > 0);
38 f(start, len);
39 start = ptr;
40 }
41}
42
43static StringSlice remove_newline(const char* str, size_t len) {
44 return SkASSERT((str != nullptr) || (len == 0)),
45 StringSlice(str, (len > 0 && str[len - 1] == '\n') ? len - 1 : len);
46}
47
48void Editor::markDirty(TextLine* line) {
49 line->fBlob = nullptr;
50 line->fShaped = false;
51 line->fWordBoundaries = std::vector<bool>();
52}
53
55 if (font != fFont) {
56 fFont = std::move(font);
57 fNeedsReshape = true;
58 for (auto& l : fLines) { this->markDirty(&l); }
59 }
60}
61
63 fFontMgr = fontMgr;
64 fNeedsReshape = true;
65 for (auto& l : fLines) { this->markDirty(&l); }
66}
67
69 if (fWidth != w) {
70 fWidth = w;
71 fNeedsReshape = true;
72 for (auto& l : fLines) { this->markDirty(&l); }
73 }
74}
75static SkPoint to_point(SkIPoint p) { return {(float)p.x(), (float)p.y()}; }
76
78 Editor::TextPosition approximatePosition;
79 this->reshapeAll();
80 for (size_t j = 0; j < fLines.size(); ++j) {
81 const TextLine& line = fLines[j];
82 SkIRect lineRect = {0,
83 line.fOrigin.y(),
84 fWidth,
85 j + 1 < fLines.size() ? fLines[j + 1].fOrigin.y() : INT_MAX};
86 if (const SkTextBlob* b = line.fBlob.get()) {
87 SkIRect r = b->bounds().roundOut();
88 r.offset(line.fOrigin);
89 lineRect.join(r);
90 }
91 if (!lineRect.contains(xy.x(), xy.y())) {
92 continue;
93 }
94 SkPoint pt = to_point(xy - line.fOrigin);
95 const std::vector<SkRect>& pos = line.fCursorPos;
96 for (size_t i = 0; i < pos.size(); ++i) {
97 if (pos[i] != kUnsetRect && pos[i].contains(pt.x(), pt.y())) {
98 return Editor::TextPosition{i, j};
99 }
100 }
101 approximatePosition = {xy.x() <= line.fOrigin.x() ? 0 : line.fText.size(), j};
102 }
103 return approximatePosition;
104}
105
106static inline bool is_utf8_continuation(char v) {
107 return ((unsigned char)v & 0b11000000) ==
108 0b10000000;
109}
110
111static const char* next_utf8(const char* p, const char* end) {
112 if (p < end) {
113 do {
114 ++p;
115 } while (p < end && is_utf8_continuation(*p));
116 }
117 return p;
118}
119
120static const char* align_utf8(const char* p, const char* begin) {
121 while (p > begin && is_utf8_continuation(*p)) {
122 --p;
123 }
124 return p;
125}
126
127static const char* prev_utf8(const char* p, const char* begin) {
128 return p > begin ? align_utf8(p - 1, begin) : begin;
129}
130
132 this->reshapeAll();
133 cursor = this->move(Editor::Movement::kNowhere, cursor);
134 if (fLines.size() > 0) {
135 const TextLine& cLine = fLines[cursor.fParagraphIndex];
136 SkRect pos = {0, 0, 0, 0};
137 if (cursor.fTextByteIndex < cLine.fCursorPos.size()) {
138 pos = cLine.fCursorPos[cursor.fTextByteIndex];
139 }
140 pos.fRight = pos.fLeft + 1;
141 pos.fLeft -= 1;
142 return offset(pos, cLine.fOrigin);
143 }
144 return SkRect{0, 0, 0, 0};
145}
146
147static size_t count_char(const StringSlice& string, char value) {
148 size_t count = 0;
149 for (char c : string) { if (c == value) { ++count; } }
150 return count;
151}
152
153Editor::TextPosition Editor::insert(TextPosition pos, const char* utf8Text, size_t byteLen) {
154 if (!valid_utf8(utf8Text, byteLen) || 0 == byteLen) {
155 return pos;
156 }
157 pos = this->move(Editor::Movement::kNowhere, pos);
158 fNeedsReshape = true;
159 if (pos.fParagraphIndex < fLines.size()) {
160 fLines[pos.fParagraphIndex].fText.insert(pos.fTextByteIndex, utf8Text, byteLen);
161 this->markDirty(&fLines[pos.fParagraphIndex]);
162 } else {
163 SkASSERT(pos.fParagraphIndex == fLines.size());
164 SkASSERT(pos.fTextByteIndex == 0);
165 fLines.push_back(Editor::TextLine(StringSlice(utf8Text, byteLen)));
166 }
167 pos = Editor::TextPosition{pos.fTextByteIndex + byteLen, pos.fParagraphIndex};
168 size_t newlinecount = count_char(fLines[pos.fParagraphIndex].fText, '\n');
169 if (newlinecount > 0) {
170 StringSlice src = std::move(fLines[pos.fParagraphIndex].fText);
171 std::vector<TextLine>::const_iterator next = fLines.begin() + pos.fParagraphIndex + 1;
172 fLines.insert(next, newlinecount, TextLine());
173 TextLine* line = &fLines[pos.fParagraphIndex];
174 readlines(src.begin(), src.size(), [&line](const char* str, size_t l) {
175 (line++)->fText = remove_newline(str, l);
176 });
177 }
178 return pos;
179}
180
182 pos1 = this->move(Editor::Movement::kNowhere, pos1);
183 pos2 = this->move(Editor::Movement::kNowhere, pos2);
184 auto cmp = [](const Editor::TextPosition& u, const Editor::TextPosition& v) { return u < v; };
185 Editor::TextPosition start = std::min(pos1, pos2, cmp);
186 Editor::TextPosition end = std::max(pos1, pos2, cmp);
187 if (start == end || start.fParagraphIndex == fLines.size()) {
188 return start;
189 }
190 fNeedsReshape = true;
191 if (start.fParagraphIndex == end.fParagraphIndex) {
192 SkASSERT(end.fTextByteIndex > start.fTextByteIndex);
193 fLines[start.fParagraphIndex].fText.remove(
194 start.fTextByteIndex, end.fTextByteIndex - start.fTextByteIndex);
195 this->markDirty(&fLines[start.fParagraphIndex]);
196 } else {
197 SkASSERT(end.fParagraphIndex < fLines.size());
198 auto& line = fLines[start.fParagraphIndex];
199 line.fText.remove(start.fTextByteIndex,
200 line.fText.size() - start.fTextByteIndex);
201 line.fText.insert(start.fTextByteIndex,
202 fLines[end.fParagraphIndex].fText.begin() + end.fTextByteIndex,
203 fLines[end.fParagraphIndex].fText.size() - end.fTextByteIndex);
204 this->markDirty(&line);
205 fLines.erase(fLines.begin() + start.fParagraphIndex + 1,
206 fLines.begin() + end.fParagraphIndex + 1);
207 }
208 return start;
209}
210
211static void append(char** dst, size_t* count, const char* src, size_t n) {
212 if (*dst) {
213 ::memcpy(*dst, src, n);
214 *dst += n;
215 }
216 *count += n;
217}
218
219size_t Editor::copy(TextPosition pos1, TextPosition pos2, char* dst) const {
220 size_t size = 0;
221 pos1 = this->move(Editor::Movement::kNowhere, pos1);
222 pos2 = this->move(Editor::Movement::kNowhere, pos2);
223 auto cmp = [](const Editor::TextPosition& u, const Editor::TextPosition& v) { return u < v; };
224 Editor::TextPosition start = std::min(pos1, pos2, cmp);
225 Editor::TextPosition end = std::max(pos1, pos2, cmp);
226 if (start == end || start.fParagraphIndex == fLines.size()) {
227 return size;
228 }
229 if (start.fParagraphIndex == end.fParagraphIndex) {
230 SkASSERT(end.fTextByteIndex > start.fTextByteIndex);
231 auto& str = fLines[start.fParagraphIndex].fText;
232 append(&dst, &size, str.begin() + start.fTextByteIndex,
233 end.fTextByteIndex - start.fTextByteIndex);
234 return size;
235 }
236 SkASSERT(end.fParagraphIndex < fLines.size());
237 const std::vector<TextLine>::const_iterator firstP = fLines.begin() + start.fParagraphIndex;
238 const std::vector<TextLine>::const_iterator lastP = fLines.begin() + end.fParagraphIndex;
239 const auto& first = firstP->fText;
240 const auto& last = lastP->fText;
241
242 append(&dst, &size, first.begin() + start.fTextByteIndex, first.size() - start.fTextByteIndex);
243 for (auto line = firstP + 1; line < lastP; ++line) {
244 append(&dst, &size, "\n", 1);
245 append(&dst, &size, line->fText.begin(), line->fText.size());
246 }
247 append(&dst, &size, "\n", 1);
248 append(&dst, &size, last.begin(), end.fTextByteIndex);
249 return size;
250}
251
252static inline const char* begin(const StringSlice& s) { return s.begin(); }
253
254static inline const char* end(const StringSlice& s) { return s.end(); }
255
256static size_t align_column(const StringSlice& str, size_t p) {
257 if (p >= str.size()) {
258 return str.size();
259 }
260 return align_utf8(begin(str) + p, begin(str)) - begin(str);
261}
262
263// returns smallest i such that list[i] > value. value > list[i-1]
264// Use a binary search since list is monotonic
265template <typename T>
266static size_t find_first_larger(const std::vector<T>& list, T value) {
267 return (size_t)(std::upper_bound(list.begin(), list.end(), value) - list.begin());
268}
269
270static size_t find_closest_x(const std::vector<SkRect>& bounds, float x, size_t b, size_t e) {
271 if (b >= e) {
272 return b;
273 }
274 SkASSERT(e <= bounds.size());
275 size_t best_index = b;
276 float best_diff = ::fabsf(bounds[best_index].x() - x);
277 for (size_t i = b + 1; i < e; ++i) {
278 float d = ::fabsf(bounds[i].x() - x);
279 if (d < best_diff) {
280 best_diff = d;
281 best_index = i;
282 }
283 }
284 return best_index;
285}
286
288 if (fLines.empty()) {
289 return {0, 0};
290 }
291 // First thing: fix possible bad input values.
292 if (pos.fParagraphIndex >= fLines.size()) {
293 pos.fParagraphIndex = fLines.size() - 1;
294 pos.fTextByteIndex = fLines[pos.fParagraphIndex].fText.size();
295 } else {
296 pos.fTextByteIndex = align_column(fLines[pos.fParagraphIndex].fText, pos.fTextByteIndex);
297 }
298
299 SkASSERT(pos.fParagraphIndex < fLines.size());
300 SkASSERT(pos.fTextByteIndex <= fLines[pos.fParagraphIndex].fText.size());
301
302 SkASSERT(pos.fTextByteIndex == fLines[pos.fParagraphIndex].fText.size() ||
303 !is_utf8_continuation(fLines[pos.fParagraphIndex].fText.begin()[pos.fTextByteIndex]));
304
305 switch (move) {
307 break;
309 if (0 == pos.fTextByteIndex) {
310 if (pos.fParagraphIndex > 0) {
311 --pos.fParagraphIndex;
312 pos.fTextByteIndex = fLines[pos.fParagraphIndex].fText.size();
313 }
314 } else {
315 const auto& str = fLines[pos.fParagraphIndex].fText;
316 pos.fTextByteIndex =
317 prev_utf8(begin(str) + pos.fTextByteIndex, begin(str)) - begin(str);
318 }
319 break;
321 if (fLines[pos.fParagraphIndex].fText.size() == pos.fTextByteIndex) {
322 if (pos.fParagraphIndex + 1 < fLines.size()) {
323 ++pos.fParagraphIndex;
324 pos.fTextByteIndex = 0;
325 }
326 } else {
327 const auto& str = fLines[pos.fParagraphIndex].fText;
328 pos.fTextByteIndex =
329 next_utf8(begin(str) + pos.fTextByteIndex, end(str)) - begin(str);
330 }
331 break;
333 {
334 const std::vector<size_t>& list = fLines[pos.fParagraphIndex].fLineEndOffsets;
335 size_t f = find_first_larger(list, pos.fTextByteIndex);
336 pos.fTextByteIndex = f > 0 ? list[f - 1] : 0;
337 }
338 break;
340 {
341 const std::vector<size_t>& list = fLines[pos.fParagraphIndex].fLineEndOffsets;
342 size_t f = find_first_larger(list, pos.fTextByteIndex);
343 if (f < list.size()) {
344 pos.fTextByteIndex = list[f] > 0 ? list[f] - 1 : 0;
345 } else {
346 pos.fTextByteIndex = fLines[pos.fParagraphIndex].fText.size();
347 }
348 }
349 break;
351 {
352 SkASSERT(pos.fTextByteIndex < fLines[pos.fParagraphIndex].fCursorPos.size());
353 float x = fLines[pos.fParagraphIndex].fCursorPos[pos.fTextByteIndex].left();
354 const std::vector<size_t>& list = fLines[pos.fParagraphIndex].fLineEndOffsets;
355 size_t f = find_first_larger(list, pos.fTextByteIndex);
356 // list[f] > value. value > list[f-1]
357 if (f > 0) {
358 // not the first line in paragraph.
359 pos.fTextByteIndex = find_closest_x(fLines[pos.fParagraphIndex].fCursorPos, x,
360 (f == 1) ? 0 : list[f - 2],
361 list[f - 1]);
362 } else if (pos.fParagraphIndex > 0) {
363 --pos.fParagraphIndex;
364 const auto& newLine = fLines[pos.fParagraphIndex];
365 size_t r = newLine.fLineEndOffsets.size();
366 if (r > 0) {
367 pos.fTextByteIndex = find_closest_x(newLine.fCursorPos, x,
368 newLine.fLineEndOffsets[r - 1],
369 newLine.fCursorPos.size());
370 } else {
371 pos.fTextByteIndex = find_closest_x(newLine.fCursorPos, x, 0,
372 newLine.fCursorPos.size());
373 }
374 }
375 pos.fTextByteIndex =
376 align_column(fLines[pos.fParagraphIndex].fText, pos.fTextByteIndex);
377 }
378 break;
380 {
381 const std::vector<size_t>& list = fLines[pos.fParagraphIndex].fLineEndOffsets;
382 float x = fLines[pos.fParagraphIndex].fCursorPos[pos.fTextByteIndex].left();
383
384 size_t f = find_first_larger(list, pos.fTextByteIndex);
385 if (f < list.size()) {
386 const auto& bounds = fLines[pos.fParagraphIndex].fCursorPos;
387 pos.fTextByteIndex = find_closest_x(bounds, x, list[f],
388 f + 1 < list.size() ? list[f + 1]
389 : bounds.size());
390 } else if (pos.fParagraphIndex + 1 < fLines.size()) {
391 ++pos.fParagraphIndex;
392 const auto& bounds = fLines[pos.fParagraphIndex].fCursorPos;
393 const std::vector<size_t>& l2 = fLines[pos.fParagraphIndex].fLineEndOffsets;
394 pos.fTextByteIndex = find_closest_x(bounds, x, 0,
395 l2.size() > 0 ? l2[0] : bounds.size());
396 } else {
397 pos.fTextByteIndex = fLines[pos.fParagraphIndex].fText.size();
398 }
399 pos.fTextByteIndex =
400 align_column(fLines[pos.fParagraphIndex].fText, pos.fTextByteIndex);
401 }
402 break;
404 {
405 if (pos.fTextByteIndex == 0) {
406 pos = this->move(Editor::Movement::kLeft, pos);
407 break;
408 }
409 const std::vector<bool>& words = fLines[pos.fParagraphIndex].fWordBoundaries;
410 SkASSERT(words.size() == fLines[pos.fParagraphIndex].fText.size());
411 do {
412 --pos.fTextByteIndex;
413 } while (pos.fTextByteIndex > 0 && !words[pos.fTextByteIndex]);
414 }
415 break;
417 {
418 const StringSlice& text = fLines[pos.fParagraphIndex].fText;
419 if (pos.fTextByteIndex == text.size()) {
420 pos = this->move(Editor::Movement::kRight, pos);
421 break;
422 }
423 const std::vector<bool>& words = fLines[pos.fParagraphIndex].fWordBoundaries;
424 SkASSERT(words.size() == text.size());
425 do {
426 ++pos.fTextByteIndex;
427 } while (pos.fTextByteIndex < text.size() && !words[pos.fTextByteIndex]);
428 }
429 break;
430
431 }
432 return pos;
433}
434
436 this->reshapeAll();
437 if (!c) {
438 return;
439 }
440
441 c->drawPaint(SkPaint(options.fBackgroundColor));
442
443 SkPaint selection = SkPaint(options.fSelectionColor);
444 auto cmp = [](const Editor::TextPosition& u, const Editor::TextPosition& v) { return u < v; };
445 for (TextPosition pos = std::min(options.fSelectionBegin, options.fSelectionEnd, cmp),
446 end = std::max(options.fSelectionBegin, options.fSelectionEnd, cmp);
447 pos < end;
449 {
450 SkASSERT(pos.fParagraphIndex < fLines.size());
451 const TextLine& l = fLines[pos.fParagraphIndex];
452 c->drawRect(offset(l.fCursorPos[pos.fTextByteIndex], l.fOrigin), selection);
453 }
454
455 if (fLines.size() > 0) {
456 c->drawRect(Editor::getLocation(options.fCursor), SkPaint(options.fCursorColor));
457 }
458
459 SkPaint foreground = SkPaint(options.fForegroundColor);
460 for (const TextLine& line : fLines) {
461 if (line.fBlob) {
462 c->drawTextBlob(line.fBlob.get(), line.fOrigin.x(), line.fOrigin.y(), foreground);
463 }
464 }
465}
466
467void Editor::reshapeAll() {
468 if (fNeedsReshape) {
469 if (fLines.empty()) {
470 fLines.push_back(TextLine());
471 }
472 float shape_width = (float)(fWidth);
473 #ifdef SK_EDITOR_GO_FAST
474 SkSemaphore semaphore;
475 std::unique_ptr<SkExecutor> executor = SkExecutor::MakeFIFOThreadPool(100);
476 int jobCount = 0;
477 for (TextLine& line : fLines) {
478 if (!line.fShaped) {
479 executor->add([&]() {
480 ShapeResult result = Shape(line.fText.begin(), line.fText.size(),
481 fFont, fLocale, shape_width);
482 line.fBlob = std::move(result.blob);
483 line.fLineEndOffsets = std::move(result.lineBreakOffsets);
484 line.fCursorPos = std::move(result.glyphBounds);
485 line.fWordBoundaries = std::move(result.wordBreaks);
486 line.fHeight = result.verticalAdvance;
487 line.fShaped = true;
488 semaphore.signal();
489 }
490 ++jobCount;
491 });
492 }
493 while (jobCount-- > 0) { semaphore.wait(); }
494 #else
495 for (TextLine& line : fLines) {
496 if (!line.fShaped) {
497 ShapeResult result = Shape(line.fText.begin(), line.fText.size(),
498 fFont, fFontMgr, fLocale, shape_width);
499 line.fBlob = std::move(result.blob);
500 line.fLineEndOffsets = std::move(result.lineBreakOffsets);
501 line.fCursorPos = std::move(result.glyphBounds);
502 line.fWordBoundaries = std::move(result.wordBreaks);
503 line.fHeight = result.verticalAdvance;
504 line.fShaped = true;
505 }
506 }
507 #endif
508 int y = 0;
509 for (TextLine& line : fLines) {
510 line.fOrigin = {0, y};
511 y += line.fHeight;
512 }
513 fHeight = y;
514 fNeedsReshape = false;
515 }
516}
517
const char * options
int count
Definition: FontMgrTest.cpp:50
SkPoint pos
static float next(float f)
#define SkASSERT(cond)
Definition: SkAssert.h:116
void drawRect(const SkRect &rect, const SkPaint &paint)
Definition: SkCanvas.cpp:1673
void drawPaint(const SkPaint &paint)
Definition: SkCanvas.cpp:1668
void drawTextBlob(const SkTextBlob *blob, SkScalar x, SkScalar y, const SkPaint &paint)
Definition: SkCanvas.cpp:2484
static std::unique_ptr< SkExecutor > MakeFIFOThreadPool(int threads=0, bool allowBorrowing=true)
Definition: SkExecutor.cpp:146
Definition: SkFont.h:35
void paint(SkCanvas *canvas, PaintOpts)
Definition: editor.cpp:435
SkRect getLocation(TextPosition)
Definition: editor.cpp:131
void setFont(SkFont font)
Definition: editor.cpp:54
Text text() const
Definition: editor.h:57
void setWidth(int w)
Definition: editor.cpp:68
StringView line(size_t i) const
Definition: editor.h:89
size_t copy(TextPosition pos1, TextPosition pos2, char *dst=nullptr) const
Definition: editor.cpp:219
void setFontMgr(sk_sp< SkFontMgr > fontMgr)
Definition: editor.cpp:62
TextPosition move(Editor::Movement move, Editor::TextPosition pos) const
Definition: editor.cpp:287
TextPosition insert(TextPosition, const char *utf8Text, size_t byteLen)
Definition: editor.cpp:153
TextPosition getPosition(SkIPoint)
Definition: editor.cpp:77
TextPosition remove(TextPosition, TextPosition)
Definition: editor.cpp:181
const SkFont & font() const
Definition: editor.h:36
std::size_t size() const
Definition: stringslice.h:27
void signal(int n=1)
Definition: SkSemaphore.h:56
void wait()
Definition: SkSemaphore.h:74
static const char * align_utf8(const char *p, const char *begin)
Definition: editor.cpp:120
static size_t find_first_larger(const std::vector< T > &list, T value)
Definition: editor.cpp:266
static const char * prev_utf8(const char *p, const char *begin)
Definition: editor.cpp:127
static const char * end(const StringSlice &s)
Definition: editor.cpp:254
static const char * begin(const StringSlice &s)
Definition: editor.cpp:252
static SkPoint to_point(SkIPoint p)
Definition: editor.cpp:75
static void readlines(const void *data, size_t size, F f)
Definition: editor.cpp:30
static constexpr SkRect kUnsetRect
Definition: editor.cpp:22
static size_t align_column(const StringSlice &str, size_t p)
Definition: editor.cpp:256
static const char * next_utf8(const char *p, const char *end)
Definition: editor.cpp:111
static bool valid_utf8(const char *ptr, size_t size)
Definition: editor.cpp:24
static bool is_utf8_continuation(char v)
Definition: editor.cpp:106
static void append(char **dst, size_t *count, const char *src, size_t n)
Definition: editor.cpp:211
static size_t count_char(const StringSlice &string, char value)
Definition: editor.cpp:147
static SkRect offset(SkRect r, SkIPoint p)
Definition: editor.cpp:18
static size_t find_closest_x(const std::vector< SkRect > &bounds, float x, size_t b, size_t e)
Definition: editor.cpp:270
static StringSlice remove_newline(const char *str, size_t len)
Definition: editor.cpp:43
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition: main.cc:19
sk_sp< SkFontMgr > fontMgr
Definition: examples.cpp:32
static bool b
struct MyStruct s
glong glong end
uint8_t value
GAsyncResult * result
static float max(float r, float g, float b)
Definition: hsl.cpp:49
static float min(float r, float g, float b)
Definition: hsl.cpp:48
double y
double x
ShapeResult Shape(const char *ut8text, size_t textByteLen, const SkFont &font, sk_sp< SkFontMgr > fontMgr, const char *locale, float width)
Definition: shape.cpp:301
Optional< SkRect > bounds
Definition: SkRecords.h:189
SK_SPI int CountUTF8(const char *utf8, size_t byteLength)
Definition: SkUTF.cpp:47
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
font
Font Metadata and Metrics.
dst
Definition: cp.py:12
constexpr bool contains(std::string_view str, std::string_view needle)
Definition: SkStringView.h:41
SkScalar w
#define T
Definition: precompiler.cc:65
Definition: SkMD5.cpp:120
constexpr int32_t y() const
Definition: SkPoint_impl.h:52
constexpr int32_t x() const
Definition: SkPoint_impl.h:46
Definition: SkRect.h:32
void join(const SkIRect &r)
Definition: SkRect.cpp:31
void offset(int32_t dx, int32_t dy)
Definition: SkRect.h:367
bool contains(int32_t x, int32_t y) const
Definition: SkRect.h:463
constexpr float y() const
Definition: SkPoint_impl.h:187
constexpr float x() const
Definition: SkPoint_impl.h:181
constexpr SkRect makeOffset(float dx, float dy) const
Definition: SkRect.h:965
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63