[gedit/wip/spell-checking] auto-spell: check only visible region



commit fed02f5a80e4eebbb9dd70226fbc4cb828629c18
Author: Sébastien Wilmet <swilmet gnome org>
Date:   Tue Jul 21 12:25:16 2015 +0200

    auto-spell: check only visible region

 plugins/spell/gedit-automatic-spell-checker.c |  150 ++++++++++++++++++++++---
 1 files changed, 135 insertions(+), 15 deletions(-)
---
diff --git a/plugins/spell/gedit-automatic-spell-checker.c b/plugins/spell/gedit-automatic-spell-checker.c
index abdf688..3ef0a8c 100644
--- a/plugins/spell/gedit-automatic-spell-checker.c
+++ b/plugins/spell/gedit-automatic-spell-checker.c
@@ -177,38 +177,158 @@ check_subregion (GeditAutomaticSpellChecker *spell,
 }
 
 static void
-check_region (GeditAutomaticSpellChecker *spell)
+check_region (GeditAutomaticSpellChecker *spell,
+             GtkTextRegion              *region)
 {
        GtkTextRegionIterator region_iter;
-#if ENABLE_DEBUG
-       GTimer *timer;
-#endif
 
-       if (spell->scan_region == NULL)
+       if (region == NULL)
        {
                return;
        }
 
-#if ENABLE_DEBUG
-       timer = g_timer_new ();
-#endif
-
-       gtk_text_region_get_iterator (spell->scan_region, &region_iter, 0);
+       gtk_text_region_get_iterator (region, &region_iter, 0);
 
        while (!gtk_text_region_iterator_is_end (&region_iter))
        {
                GtkTextIter start;
                GtkTextIter end;
 
-               gtk_text_region_iterator_get_subregion (&region_iter, &start, &end);
+               if (!gtk_text_region_iterator_get_subregion (&region_iter, &start, &end))
+               {
+                       return;
+               }
 
                check_subregion (spell, &start, &end);
 
                gtk_text_region_iterator_next (&region_iter);
        }
+}
+
+static void
+get_visible_region (GtkTextView *view,
+                   GtkTextIter *start,
+                   GtkTextIter *end)
+{
+       GdkRectangle visible_rect;
+
+       gtk_text_view_get_visible_rect (view, &visible_rect);
+
+       gtk_text_view_get_line_at_y (view,
+                                    start,
+                                    visible_rect.y,
+                                    NULL);
+
+       gtk_text_view_get_line_at_y (view,
+                                    end,
+                                    visible_rect.y + visible_rect.height,
+                                    NULL);
+
+       gtk_text_iter_backward_line (start);
+       gtk_text_iter_forward_line (end);
+}
+
+/* A TextRegion can contain empty subregions. So checking the number of
+ * subregions is not sufficient.
+ * When calling gtk_text_region_add() with equal iters, the subregion is not
+ * added. But when a subregion becomes empty, due to text deletion, the
+ * subregion is not removed from the TextRegion.
+ */
+static gboolean
+is_text_region_empty (GtkTextRegion *region)
+{
+       GtkTextRegionIterator region_iter;
+
+       if (region == NULL)
+       {
+               return TRUE;
+       }
+
+       gtk_text_region_get_iterator (region, &region_iter, 0);
+
+       while (!gtk_text_region_iterator_is_end (&region_iter))
+       {
+               GtkTextIter region_start;
+               GtkTextIter region_end;
+
+               if (!gtk_text_region_iterator_get_subregion (&region_iter,
+                                                            &region_start,
+                                                            &region_end))
+               {
+                       return TRUE;
+               }
+
+               if (!gtk_text_iter_equal (&region_start, &region_end))
+               {
+                       return FALSE;
+               }
+
+               gtk_text_region_iterator_next (&region_iter);
+       }
+
+       return TRUE;
+}
+
+static void
+check_visible_region_in_view (GeditAutomaticSpellChecker *spell,
+                             GtkTextView                *view)
+{
+       GtkTextIter visible_start;
+       GtkTextIter visible_end;
+       GtkTextRegion *intersect;
+
+       if (spell->scan_region == NULL)
+       {
+               return;
+       }
+
+       get_visible_region (view, &visible_start, &visible_end);
 
-       gtk_text_region_destroy (spell->scan_region);
-       spell->scan_region = NULL;
+       intersect = gtk_text_region_intersect (spell->scan_region,
+                                              &visible_start,
+                                              &visible_end);
+
+       if (intersect == NULL)
+       {
+               return;
+       }
+
+       check_region (spell, intersect);
+       gtk_text_region_destroy (intersect);
+
+       gtk_text_region_subtract (spell->scan_region,
+                                 &visible_start,
+                                 &visible_end);
+
+       if (is_text_region_empty (spell->scan_region))
+       {
+               gtk_text_region_destroy (spell->scan_region);
+               spell->scan_region = NULL;
+       }
+}
+
+static void
+check_visible_region (GeditAutomaticSpellChecker *spell)
+{
+       GSList *l;
+#if ENABLE_DEBUG
+       GTimer *timer;
+#endif
+
+       if (spell->scan_region == NULL)
+       {
+               return;
+       }
+
+#if ENABLE_DEBUG
+       timer = g_timer_new ();
+#endif
+
+       for (l = spell->views; l != NULL; l = l->next)
+       {
+               GtkTextView *view = l->data;
+               check_visible_region_in_view (spell, view);
+       }
 
 #if ENABLE_DEBUG
        g_print ("%s() executed in %lf seconds\n",
@@ -222,7 +342,7 @@ check_region (GeditAutomaticSpellChecker *spell)
 static gboolean
 timeout_cb (GeditAutomaticSpellChecker *spell)
 {
-       check_region (spell);
+       check_visible_region (spell);
 
        spell->timeout_id = 0;
        return G_SOURCE_REMOVE;
@@ -998,7 +1118,7 @@ gedit_automatic_spell_checker_recheck_all (GeditAutomaticSpellChecker *spell)
        gtk_text_buffer_get_bounds (spell->buffer, &start, &end);
 
        add_subregion_to_scan (spell, &start, &end);
-       check_region (spell);
+       check_visible_region (spell);
 }
 
 /* ex:set ts=8 noet: */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]