19 return r.
makeOffset((
float)p.x(), (
float)p.y());
30static void readlines(
const void* data,
size_t size,
F f) {
31 const char*
start = (
const char*)data;
33 const char* ptr =
start;
35 while (*ptr++ !=
'\n' && ptr <
end) {}
36 size_t len = ptr -
start;
44 return SkASSERT((str !=
nullptr) || (len == 0)),
45 StringSlice(str, (len > 0 && str[len - 1] ==
'\n') ? len - 1 : len);
48void Editor::markDirty(TextLine* line) {
49 line->fBlob =
nullptr;
50 line->fShaped =
false;
51 line->fWordBoundaries = std::vector<bool>();
56 fFont = std::move(
font);
58 for (
auto& l : fLines) { this->markDirty(&l); }
65 for (
auto& l : fLines) { this->markDirty(&l); }
72 for (
auto& l : fLines) { this->markDirty(&l); }
80 for (
size_t j = 0; j < fLines.size(); ++j) {
81 const TextLine&
line = fLines[j];
85 j + 1 < fLines.size() ? fLines[j + 1].fOrigin.y() : INT_MAX};
95 const std::vector<SkRect>&
pos =
line.fCursorPos;
96 for (
size_t i = 0; i <
pos.size(); ++i) {
101 approximatePosition = {xy.
x() <=
line.fOrigin.x() ? 0 :
line.fText.
size(), j};
103 return approximatePosition;
107 return ((
unsigned char)v & 0b11000000) ==
134 if (fLines.size() > 0) {
140 pos.fRight =
pos.fLeft + 1;
144 return SkRect{0, 0, 0, 0};
149 for (
char c : string) {
if (c ==
value) { ++
count; } }
154 if (!
valid_utf8(utf8Text, byteLen) || 0 == byteLen) {
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]);
165 fLines.push_back(Editor::TextLine(
StringSlice(utf8Text, byteLen)));
168 size_t newlinecount =
count_char(fLines[
pos.fParagraphIndex].fText,
'\n');
169 if (newlinecount > 0) {
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);
187 if (
start ==
end ||
start.fParagraphIndex == fLines.size()) {
190 fNeedsReshape =
true;
191 if (
start.fParagraphIndex ==
end.fParagraphIndex) {
193 fLines[
start.fParagraphIndex].fText.remove(
194 start.fTextByteIndex,
end.fTextByteIndex -
start.fTextByteIndex);
195 this->markDirty(&fLines[
start.fParagraphIndex]);
198 auto&
line = fLines[
start.fParagraphIndex];
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);
211static void append(
char** dst,
size_t*
count,
const char* src,
size_t n) {
213 ::memcpy(*dst, src, n);
226 if (
start ==
end ||
start.fParagraphIndex == fLines.size()) {
229 if (
start.fParagraphIndex ==
end.fParagraphIndex) {
231 auto& str = fLines[
start.fParagraphIndex].fText;
232 append(&dst, &size, str.begin() +
start.fTextByteIndex,
233 end.fTextByteIndex -
start.fTextByteIndex);
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;
242 append(&dst, &size, first.begin() +
start.fTextByteIndex, first.size() -
start.fTextByteIndex);
244 append(&dst, &size,
"\n", 1);
247 append(&dst, &size,
"\n", 1);
248 append(&dst, &size, last.begin(),
end.fTextByteIndex);
257 if (p >= str.
size()) {
267 return (
size_t)(std::upper_bound(list.begin(), list.end(),
value) - list.begin());
270static size_t find_closest_x(
const std::vector<SkRect>& bounds,
float x,
size_t b,
size_t e) {
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);
288 if (fLines.empty()) {
292 if (
pos.fParagraphIndex >= fLines.size()) {
293 pos.fParagraphIndex = fLines.size() - 1;
294 pos.fTextByteIndex = fLines[
pos.fParagraphIndex].fText.size();
300 SkASSERT(
pos.fTextByteIndex <= fLines[
pos.fParagraphIndex].fText.size());
302 SkASSERT(
pos.fTextByteIndex == fLines[
pos.fParagraphIndex].fText.size() ||
309 if (0 ==
pos.fTextByteIndex) {
310 if (
pos.fParagraphIndex > 0) {
311 --
pos.fParagraphIndex;
312 pos.fTextByteIndex = fLines[
pos.fParagraphIndex].fText.size();
315 const auto& str = fLines[
pos.fParagraphIndex].fText;
321 if (fLines[
pos.fParagraphIndex].fText.size() ==
pos.fTextByteIndex) {
322 if (
pos.fParagraphIndex + 1 < fLines.size()) {
323 ++
pos.fParagraphIndex;
324 pos.fTextByteIndex = 0;
327 const auto& str = fLines[
pos.fParagraphIndex].fText;
334 const std::vector<size_t>& list = fLines[
pos.fParagraphIndex].fLineEndOffsets;
336 pos.fTextByteIndex = f > 0 ? list[f - 1] : 0;
341 const std::vector<size_t>& list = fLines[
pos.fParagraphIndex].fLineEndOffsets;
343 if (f < list.size()) {
344 pos.fTextByteIndex = list[f] > 0 ? list[f] - 1 : 0;
346 pos.fTextByteIndex = fLines[
pos.fParagraphIndex].fText.size();
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;
360 (f == 1) ? 0 : list[f - 2],
362 }
else if (
pos.fParagraphIndex > 0) {
363 --
pos.fParagraphIndex;
364 const auto& newLine = fLines[
pos.fParagraphIndex];
365 size_t r = newLine.fLineEndOffsets.size();
368 newLine.fLineEndOffsets[r - 1],
369 newLine.fCursorPos.size());
372 newLine.fCursorPos.size());
381 const std::vector<size_t>& list = fLines[
pos.fParagraphIndex].fLineEndOffsets;
382 float x = fLines[
pos.fParagraphIndex].fCursorPos[
pos.fTextByteIndex].left();
385 if (f < list.size()) {
386 const auto& bounds = fLines[
pos.fParagraphIndex].fCursorPos;
388 f + 1 < list.size() ? list[f + 1]
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;
395 l2.size() > 0 ? l2[0] : bounds.size());
397 pos.fTextByteIndex = fLines[
pos.fParagraphIndex].fText.size();
405 if (
pos.fTextByteIndex == 0) {
409 const std::vector<bool>& words = fLines[
pos.fParagraphIndex].fWordBoundaries;
410 SkASSERT(words.size() == fLines[
pos.fParagraphIndex].fText.size());
412 --
pos.fTextByteIndex;
413 }
while (
pos.fTextByteIndex > 0 && !words[
pos.fTextByteIndex]);
419 if (
pos.fTextByteIndex ==
text.size()) {
423 const std::vector<bool>& words = fLines[
pos.fParagraphIndex].fWordBoundaries;
426 ++
pos.fTextByteIndex;
427 }
while (
pos.fTextByteIndex <
text.size() && !words[
pos.fTextByteIndex]);
451 const TextLine& l = fLines[
pos.fParagraphIndex];
455 if (fLines.size() > 0) {
460 for (
const TextLine&
line : fLines) {
467void Editor::reshapeAll() {
469 if (fLines.empty()) {
470 fLines.push_back(TextLine());
472 float shape_width = (float)(fWidth);
473 #ifdef SK_EDITOR_GO_FAST
477 for (TextLine&
line : fLines) {
479 executor->add([&]() {
481 fFont, fLocale, shape_width);
483 line.fLineEndOffsets = std::move(
result.lineBreakOffsets);
484 line.fCursorPos = std::move(
result.glyphBounds);
485 line.fWordBoundaries = std::move(
result.wordBreaks);
493 while (jobCount-- > 0) { semaphore.
wait(); }
495 for (TextLine&
line : fLines) {
498 fFont, fFontMgr, fLocale, shape_width);
500 line.fLineEndOffsets = std::move(
result.lineBreakOffsets);
501 line.fCursorPos = std::move(
result.glyphBounds);
502 line.fWordBoundaries = std::move(
result.wordBreaks);
509 for (TextLine&
line : fLines) {
510 line.fOrigin = {0,
y};
514 fNeedsReshape =
false;
static float next(float f)
static bool contains(const SkRect &r, SkPoint p)
void drawRect(const SkRect &rect, const SkPaint &paint)
void drawPaint(const SkPaint &paint)
void drawTextBlob(const SkTextBlob *blob, SkScalar x, SkScalar y, const SkPaint &paint)
static std::unique_ptr< SkExecutor > MakeFIFOThreadPool(int threads=0, bool allowBorrowing=true)
void paint(SkCanvas *canvas, PaintOpts)
SkRect getLocation(TextPosition)
void setFont(SkFont font)
StringView line(size_t i) const
size_t copy(TextPosition pos1, TextPosition pos2, char *dst=nullptr) const
void setFontMgr(sk_sp< SkFontMgr > fontMgr)
TextPosition move(Editor::Movement move, Editor::TextPosition pos) const
TextPosition insert(TextPosition, const char *utf8Text, size_t byteLen)
TextPosition getPosition(SkIPoint)
TextPosition remove(TextPosition, TextPosition)
const SkFont & font() const
static const char * align_utf8(const char *p, const char *begin)
static size_t find_first_larger(const std::vector< T > &list, T value)
static const char * prev_utf8(const char *p, const char *begin)
static const char * begin(const StringSlice &s)
static SkPoint to_point(SkIPoint p)
static void readlines(const void *data, size_t size, F f)
static constexpr SkRect kUnsetRect
static size_t align_column(const StringSlice &str, size_t p)
static const char * next_utf8(const char *p, const char *end)
static bool valid_utf8(const char *ptr, size_t size)
static bool is_utf8_continuation(char v)
static void append(char **dst, size_t *count, const char *src, size_t n)
static size_t count_char(const StringSlice &string, char value)
static size_t find_closest_x(const std::vector< SkRect > &bounds, float x, size_t b, size_t e)
static StringSlice remove_newline(const char *str, size_t len)
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
sk_sp< SkFontMgr > fontMgr
SK_SPI int CountUTF8(const char *utf8, size_t byteLength)
constexpr int32_t y() const
constexpr int32_t x() const
void join(const SkIRect &r)
void offset(int32_t dx, int32_t dy)
bool contains(int32_t x, int32_t y) const
constexpr float y() const
constexpr float x() const
constexpr SkRect makeOffset(float dx, float dy) const