textview: optimize linedisplay cache based on number of visible rows
authorChristian Hergert <chergert@redhat.com>
Thu, 5 Sep 2019 23:45:49 +0000 (16:45 -0700)
committerChristian Hergert <chergert@redhat.com>
Fri, 6 Sep 2019 02:06:35 +0000 (19:06 -0700)
This tries to estimate the number of visible rows in a textview based on
the default text size and then tunes the GtkTextLineDisplayCache to keep
3*n_rows entries in the cache.

This was found imperically to be near the right cache size. In most cases,
this is less than the number of items we cache now. However, in some cases,
such as the "overview map" from GtkSourceView, it allows us to reach a
higher value such as 1000+. This is needed to keep scrolling smooth on
the larger view sizes.

With this patch, a HiDPI system with a GtkSourceView and GtkSourceMap
from the GTK 4 port can perform smooth scrolling simultaneously.

gtk/gtktextlayout.c
gtk/gtktextlayoutprivate.h
gtk/gtktextlinedisplaycache.c
gtk/gtktextlinedisplaycacheprivate.h
gtk/gtktextview.c

index fee6d59a4ad910e5fcb126810cedd3116fdf1b14..f51dd42fcb1adac43f4e3ce2aed91c36cd17399e 100644 (file)
@@ -4210,3 +4210,12 @@ gtk_text_line_display_compare (const GtkTextLineDisplay *display1,
   else
     return 0;
 }
+
+void
+gtk_text_layout_set_mru_size (GtkTextLayout *layout,
+                              guint          mru_size)
+{
+  GtkTextLayoutPrivate *priv = GTK_TEXT_LAYOUT_GET_PRIVATE (layout);
+
+  gtk_text_line_display_cache_set_mru_size (priv->cache, mru_size);
+}
index 27da15d2bd35656ad9cc7bafa82d026bdf3462c9..99d4f812e85379bc15b7f11ae5446119fbb8503d 100644 (file)
@@ -414,6 +414,9 @@ void gtk_text_layout_snapshot (GtkTextLayout        *layout,
                                const GdkRectangle   *clip,
                                float                 cursor_alpha);
 
+void gtk_text_layout_set_mru_size (GtkTextLayout *layout,
+                                   guint          mru_size);
+
 G_END_DECLS
 
 #endif  /* __GTK_TEXT_LAYOUT_PRIVATE_H__ */
index 267d9f61823a0b0b7272cbc52ebd204e7abc5791..2fe174c0f6d43c7ea7434014272a797a1142f90a 100644 (file)
@@ -24,7 +24,7 @@
 #include "gtktextiterprivate.h"
 #include "gtktextlinedisplaycacheprivate.h"
 
-#define MRU_MAX_SIZE             250
+#define DEFAULT_MRU_SIZE         250
 #define BLOW_CACHE_TIMEOUT_SEC   20
 #define DEBUG_LINE_DISPLAY_CACHE 0
 
@@ -35,6 +35,7 @@ struct _GtkTextLineDisplayCache
   GtkTextLine *cursor_line;
   GQueue       mru;
   GSource     *evict_source;
+  guint        mru_size;
 
 #if DEBUG_LINE_DISPLAY_CACHE
   guint       log_source;
@@ -78,6 +79,7 @@ gtk_text_line_display_cache_new (void)
   ret = g_slice_new0 (GtkTextLineDisplayCache);
   ret->sorted_by_line = g_sequence_new ((GDestroyNotify)gtk_text_line_display_unref);
   ret->line_to_display = g_hash_table_new (NULL, NULL);
+  ret->mru_size = DEFAULT_MRU_SIZE;
 
 #if DEBUG_LINE_DISPLAY_CACHE
   ret->log_source = g_timeout_add_seconds (1, dump_stats, ret);
@@ -200,7 +202,7 @@ gtk_text_line_display_cache_take_display (GtkTextLineDisplayCache *cache,
   g_queue_push_head_link (&cache->mru, &display->mru_link);
 
   /* Cull the cache if we're at capacity */
-  while (cache->mru.length > MRU_MAX_SIZE)
+  while (cache->mru.length > cache->mru_size)
     {
       display = g_queue_peek_tail (&cache->mru);
 
@@ -716,3 +718,27 @@ gtk_text_line_display_cache_set_cursor_line (GtkTextLineDisplayCache *cache,
   if (display != NULL)
     gtk_text_line_display_cache_invalidate_display (cache, display, FALSE);
 }
+
+void
+gtk_text_line_display_cache_set_mru_size (GtkTextLineDisplayCache *cache,
+                                          guint                    mru_size)
+{
+  GtkTextLineDisplay *display;
+
+  g_assert (cache != NULL);
+
+  if (mru_size == 0)
+    mru_size = DEFAULT_MRU_SIZE;
+
+  if (mru_size != cache->mru_size)
+    {
+      cache->mru_size = mru_size;
+
+      while (cache->mru.length > cache->mru_size)
+        {
+          display = g_queue_peek_tail (&cache->mru);
+
+          gtk_text_line_display_cache_invalidate_display (cache, display, FALSE);
+        }
+    }
+}
index 5639ec2070602ea9245309f72310ca46ab13676e..89adbffc2ddb3834b4e82fd5d268f15622077f65 100644 (file)
@@ -53,6 +53,8 @@ void                     gtk_text_line_display_cache_invalidate_y_range (GtkText
                                                                          gint                     y,
                                                                          gint                     height,
                                                                          gboolean                 cursors_only);
+void                     gtk_text_line_display_cache_set_mru_size       (GtkTextLineDisplayCache *cache,
+                                                                         guint                    mru_size);
 
 G_END_DECLS
 
index 6d405df097965fa11994faf523e4094775c83d04..1d01f9c4542518740789f98e079987534f79f532 100644 (file)
@@ -4109,6 +4109,8 @@ gtk_text_view_size_allocate (GtkWidget *widget,
   GdkRectangle top_rect;
   GdkRectangle bottom_rect;
   GtkWidget *chooser;
+  PangoLayout *layout;
+  guint mru_size;
   
   text_view = GTK_TEXT_VIEW (widget);
   priv = text_view->priv;
@@ -4178,6 +4180,16 @@ gtk_text_view_size_allocate (GtkWidget *widget,
   if (!gtk_adjustment_is_animating (priv->vadjustment))
     gtk_text_view_set_vadjustment_values (text_view);
 
+  /* Optimize display cache size */
+  layout = gtk_widget_create_pango_layout (widget, "X");
+  pango_layout_get_pixel_size (layout, &width, &height);
+  if (height > 0)
+    {
+      mru_size = SCREEN_HEIGHT (widget) / height * 3;
+      gtk_text_layout_set_mru_size (priv->layout, mru_size);
+    }
+  g_object_unref (layout);
+
   /* The GTK resize loop processes all the pending exposes right
    * after doing the resize stuff, so the idle sizer won't have a
    * chance to run. So we do the work here.