vte r2199 - in trunk: . src
- From: behdad svn gnome org
- To: svn-commits-list gnome org
- Subject: vte r2199 - in trunk: . src
- Date: Wed, 26 Nov 2008 19:12:30 +0000 (UTC)
Author: behdad
Date: Wed Nov 26 19:12:30 2008
New Revision: 2199
URL: http://svn.gnome.org/viewvc/vte?rev=2199&view=rev
Log:
2008-11-26 Behdad Esfahbod <behdad gnome org>
Bug 562332 â cleanup font infos on exit?
* src/vtepangocairo.c
(cleanup_delayed_font_info_destroys_predicate),
(cleanup_delayed_font_info_destroys), (ensure_quit_handler),
(font_info_register), (font_info_reference),
(font_info_destroy_delayed), (font_info_destroy):
Use gtk_quit_add() to complete delayed font_info destroys.
Modified:
trunk/ChangeLog
trunk/src/vtepangocairo.c
Modified: trunk/src/vtepangocairo.c
==============================================================================
--- trunk/src/vtepangocairo.c (original)
+++ trunk/src/vtepangocairo.c Wed Nov 26 19:12:30 2008
@@ -31,10 +31,99 @@
#include <pango/pangocairo.h>
-#define FONT_CACHE_TIMEOUT (30) /* seconds */
+
+/* Overview:
+ *
+ *
+ * This file implements vte rendering using pangocairo. Note that this does
+ * NOT implement any kind of complex text rendering. That's not currently a
+ * goal.
+ *
+ * The aim is to be super-fast and avoid unneeded work as much as possible.
+ * Here is an overview of how that is accomplished:
+ *
+ * - We attach a font_info to draw as our private data. A font_info has
+ * all the information to quickly draw text.
+ *
+ * - A font_info keeps uses unichar_font_info structs that represent all
+ * information needed to quickly draw a single gunichar. The font_info
+ * creates those unichar_font_info structs on demand and caches them
+ * indefinitely. It uses a direct array for the ASCII range and a hash
+ * table for the rest.
+ *
+ *
+ * Fast rendering of unichars:
+ *
+ * A unichar_font_info (uinfo) calls Pango to set text for the unichar upon
+ * initialization and then caches information needed to draw the results
+ * later. It uses three different internal representations and respectively
+ * three drawing paths:
+ *
+ * - COVERAGE_USE_CAIRO_GLYPH:
+ * Keeping a single glyph index and a cairo scaled-font. This is the
+ * fastest way to draw text as it bypasses Pango completely and allows
+ * for stuffing multiple glyphs into a single cairo_show_glyphs() request
+ * (if scaled-fonts match). This method is used if the glyphs used for
+ * the gunichar as determined by Pango consists of a single regular glyph
+ * positioned at 0,0 using a regular font. This method is used for more
+ * than 99% of the cases. Only exceptional cases fall through to the
+ * other two methods.
+ *
+ * - COVERAGE_USE_PANGO_GLYPH_STRING:
+ * Keeping a pango glyphstring and a pango font. This is slightly slower
+ * than the previous case as drawing each glyph goes through pango
+ * separately and causes a separate cairo_show_glyphs() call. This method
+ * is used when the previous method cannot be used by the glyphs for the
+ * character all use a single font. This is the method used for hexboxes
+ * and "empty" characters like U+200C ZERO WIDTH NON-JOINER for example.
+ *
+ * - COVERAGE_USE_PANGO_LAYOUT_LINE:
+ * Keeping a pango layout line. This method is used only in the very
+ * weird and exception case that a single gunichar uses more than one font
+ * to be drawn. This is not expected to happen, but exists for
+ * completeness, to make sure we can deal with any junk pango decides to
+ * throw at us.
+ *
+ *
+ * Caching of font infos:
+ *
+ * To avoid recreating font info structs for the same font again and again we
+ * do the following:
+ *
+ * - Use a global cache to share font info structs across different widgets.
+ * We use cairo font options, resolution, and font description as the key
+ * for our hash table.
+ *
+ * - When a font info struct is no longer used by any widget, we delay
+ * destroying it for a while (FONT_CACHE_TIMEOUT seconds). This is
+ * supposed to serve two purposes:
+ *
+ * * Destroying a terminal widget and creating it again right after will
+ * reuse the font info struct from the previous widget.
+ *
+ * * Zooming in and out a terminal reuses the font info structs.
+ *
+ * Since we use gdk timeout to schedule the delayed destruction, we also
+ * add a gtk quit handler which is run when the innermost main loop exits
+ * to cleanup any pending delayed destructions.
+ *
+ *
+ * Pre-caching ASCII letters:
+ *
+ * When initializing a font info struct we measure a string consisting of all
+ * ASCII letters and some other ASCII characters. Since we have a shaped pango
+ * layout at hand, we walk over it and cache unichar font info for the ASCII
+ * letters if we can do that easily using COVERAGE_USE_CAIRO_GLYPH. This
+ * means that we precache all ASCII letters without any extra pango shaping
+ * involved.
+ */
+
+
#undef VTEPANGOCAIRO_PROFILE
+#define FONT_CACHE_TIMEOUT (30) /* seconds */
+
/* All shared data structures are implicitly protected by GDK mutex, because
* that's how vte.c works and we only get called from there. */
@@ -365,11 +454,46 @@
static GHashTable *font_info_for_context;
+static guint quit_id;
+
+static gboolean
+cleanup_delayed_font_info_destroys_predicate (PangoContext *context,
+ struct font_info *info)
+{
+ if (info->destroy_timeout) {
+ g_source_remove (info->destroy_timeout);
+ info->destroy_timeout = 0;
+
+ font_info_free (info);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+cleanup_delayed_font_info_destroys (void)
+{
+ g_hash_table_foreach_remove (font_info_for_context,
+ (GHRFunc) cleanup_delayed_font_info_destroys_predicate,
+ NULL);
+
+ quit_id = 0;
+ return 0;
+}
+
+static void
+ensure_quit_handler (void)
+{
+ if (G_UNLIKELY (quit_id == 0))
+ quit_id = gtk_quit_add (1,
+ (GtkFunction) cleanup_delayed_font_info_destroys,
+ NULL);
+}
static struct font_info *
font_info_register (struct font_info *info)
{
- /* claims the context reference, but doesn't hold a ref to font_info */
g_hash_table_insert (font_info_for_context,
pango_layout_get_context (info->layout),
info);
@@ -393,8 +517,10 @@
g_return_val_if_fail (info->ref_count >= 0, info);
- if (info->ref_count == 0)
+ if (info->destroy_timeout) {
g_source_remove (info->destroy_timeout);
+ info->destroy_timeout = 0;
+ }
info->ref_count++;
@@ -404,6 +530,8 @@
static gboolean
font_info_destroy_delayed (struct font_info *info)
{
+ info->destroy_timeout = 0;
+
font_info_unregister (info);
font_info_free (info);
@@ -427,6 +555,7 @@
#endif
/* Delay destruction by a few seconds, in case we need it again */
+ ensure_quit_handler ();
info->destroy_timeout = gdk_threads_add_timeout_seconds (FONT_CACHE_TIMEOUT,
(GSourceFunc) font_info_destroy_delayed,
info);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]