From a587385de0b004399090480b852a907ced46f66f Mon Sep 17 00:00:00 2001 From: Colomban Wendling Date: Fri, 5 Apr 2019 14:06:48 +0200 Subject: [PATCH] scintilla: Accessible: use the built-in character position cache It's quite a lot faster even after trying and optimizing the custom version, and it makes the code simpler. Also improve ByteOffsetFromCharacterOffset() to make use of the cache, making it drastically faster. X-Scintilla-Bug-URL: https://sourceforge.net/p/scintilla/bugs/2094/ X-Scintilla-Commit-ID: 01aab5f24e50ed14551c8c9c8ecce7ece0594c09 X-Scintilla-Commit-ID: 2c8b52af4ae5de2abe7c00fd18e78be60340cbf9 Fixes #2092. --- scintilla/gtk/ScintillaGTK.cxx | 2 +- scintilla/gtk/ScintillaGTKAccessible.cxx | 16 +++++------- scintilla/gtk/ScintillaGTKAccessible.h | 32 +++++++++++++----------- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/scintilla/gtk/ScintillaGTK.cxx b/scintilla/gtk/ScintillaGTK.cxx index c7364fd162..2deac8c75c 100644 --- a/scintilla/gtk/ScintillaGTK.cxx +++ b/scintilla/gtk/ScintillaGTK.cxx @@ -859,7 +859,7 @@ sptr_t ScintillaGTK::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam if (accessible) { ScintillaGTKAccessible *sciAccessible = ScintillaGTKAccessible::FromAccessible(accessible); if (sciAccessible) { - sciAccessible->SetAccessibility(); + sciAccessible->SetAccessibility(accessibilityEnabled); } } break; diff --git a/scintilla/gtk/ScintillaGTKAccessible.cxx b/scintilla/gtk/ScintillaGTKAccessible.cxx index 84bf90c45f..a2eea39250 100644 --- a/scintilla/gtk/ScintillaGTKAccessible.cxx +++ b/scintilla/gtk/ScintillaGTKAccessible.cxx @@ -158,6 +158,7 @@ ScintillaGTKAccessible::ScintillaGTKAccessible(GtkAccessible *accessible_, GtkWi sci(ScintillaGTK::FromWidget(widget_)), deletionLengthChar(0), old_pos(-1) { + SetAccessibility(true); g_signal_connect(widget_, "sci-notify", G_CALLBACK(SciNotify), this); } @@ -861,10 +862,12 @@ void ScintillaGTKAccessible::NotifyReadOnly() { #endif } -void ScintillaGTKAccessible::SetAccessibility() { +void ScintillaGTKAccessible::SetAccessibility(bool enabled) { // Called by ScintillaGTK when application has enabled or disabled accessibility - character_offsets.resize(0); - character_offsets.push_back(0); + if (enabled) + sci->pdoc->AllocateLineCharacterIndex(SC_LINECHARACTERINDEX_UTF32); + else + sci->pdoc->ReleaseLineCharacterIndex(SC_LINECHARACTERINDEX_UTF32); } void ScintillaGTKAccessible::Notify(GtkWidget *, gint, SCNotification *nt) { @@ -872,13 +875,6 @@ void ScintillaGTKAccessible::Notify(GtkWidget *, gint, SCNotification *nt) { return; switch (nt->nmhdr.code) { case SCN_MODIFIED: { - if (nt->modificationType & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT)) { - // invalidate character offset cache if applicable - const Sci::Line line = sci->pdoc->LineFromPosition(nt->position); - if (character_offsets.size() > static_cast(line + 1)) { - character_offsets.resize(line + 1); - } - } if (nt->modificationType & SC_MOD_INSERTTEXT) { int startChar = CharacterOffsetFromByteOffset(nt->position); int lengthChar = sci->pdoc->CountCharacters(nt->position, nt->position + nt->length); diff --git a/scintilla/gtk/ScintillaGTKAccessible.h b/scintilla/gtk/ScintillaGTKAccessible.h index 2c39d52575..21517e5e7f 100644 --- a/scintilla/gtk/ScintillaGTKAccessible.h +++ b/scintilla/gtk/ScintillaGTKAccessible.h @@ -18,9 +18,6 @@ class ScintillaGTKAccessible { GtkAccessible *accessible; ScintillaGTK *sci; - // cache holding character offset for each line start, see CharacterOffsetFromByteOffset() - std::vector character_offsets; - // cached length of the deletion, in characters (see Notify()) int deletionLengthChar; // local state for comparing @@ -37,6 +34,19 @@ class ScintillaGTKAccessible { } Sci::Position ByteOffsetFromCharacterOffset(Sci::Position startByte, int characterOffset) { + if (!(sci->pdoc->LineCharacterIndex() & SC_LINECHARACTERINDEX_UTF32)) { + return startByte + characterOffset; + } + if (characterOffset > 0) { + // Try and reduce the range by reverse-looking into the character offset cache + Sci::Line lineStart = sci->pdoc->LineFromPosition(startByte); + Sci::Position posStart = sci->pdoc->IndexLineStart(lineStart, SC_LINECHARACTERINDEX_UTF32); + Sci::Line line = sci->pdoc->LineFromPositionIndex(posStart + characterOffset, SC_LINECHARACTERINDEX_UTF32); + if (line != lineStart) { + startByte += sci->pdoc->LineStart(line) - sci->pdoc->LineStart(lineStart); + characterOffset -= sci->pdoc->IndexLineStart(line, SC_LINECHARACTERINDEX_UTF32) - posStart; + } + } Sci::Position pos = sci->pdoc->GetRelativePosition(startByte, characterOffset); if (pos == INVALID_POSITION) { // clamp invalid positions inside the document @@ -54,18 +64,12 @@ class ScintillaGTKAccessible { } Sci::Position CharacterOffsetFromByteOffset(Sci::Position byteOffset) { - const Sci::Line line = sci->pdoc->LineFromPosition(byteOffset); - if (character_offsets.size() <= static_cast(line)) { - if (character_offsets.empty()) - character_offsets.push_back(0); - for (Sci::Position i = character_offsets.size(); i <= line; i++) { - const Sci::Position start = sci->pdoc->LineStart(i - 1); - const Sci::Position end = sci->pdoc->LineStart(i); - character_offsets.push_back(character_offsets[i - 1] + sci->pdoc->CountCharacters(start, end)); - } + if (!(sci->pdoc->LineCharacterIndex() & SC_LINECHARACTERINDEX_UTF32)) { + return byteOffset; } + const Sci::Line line = sci->pdoc->LineFromPosition(byteOffset); const Sci::Position lineStart = sci->pdoc->LineStart(line); - return character_offsets[line] + sci->pdoc->CountCharacters(lineStart, byteOffset); + return sci->pdoc->IndexLineStart(line, SC_LINECHARACTERINDEX_UTF32) + sci->pdoc->CountCharacters(lineStart, byteOffset); } void CharacterRangeFromByteRange(Sci::Position startByte, Sci::Position endByte, int *startChar, int *endChar) { @@ -135,7 +139,7 @@ class ScintillaGTKAccessible { // So ScintillaGTK can notify us void ChangeDocument(Document *oldDoc, Document *newDoc); void NotifyReadOnly(); - void SetAccessibility(); + void SetAccessibility(bool enabled); // Helper GtkWidget methods static AtkObject *WidgetGetAccessibleImpl(GtkWidget *widget, AtkObject **cache, gpointer widget_parent_class);