summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBehdad Esfahbod <behdad@gnome.org>2006-12-04 23:47:27 +0000
committerBehdad Esfahbod <behdad@src.gnome.org>2006-12-04 23:47:27 +0000
commitaab9ad8715dbbf3a23d4fc869a6551af1f56df57 (patch)
tree6b19cc04fb3384de8afeda5a3e2ad11c7a8aed88
parentea0ec593e49735b1c7157c73d24ac58423adafc0 (diff)
downloadpango-aab9ad8715dbbf3a23d4fc869a6551af1f56df57.tar.gz
Bug 135683 – Cache glyphstring extents
2006-12-04 Behdad Esfahbod <behdad@gnome.org> Bug 135683 – Cache glyphstring extents * pango/pango-layout.c (pango_layout_get_lines), (pango_layout_get_line), (pango_layout_line_leaked), (pango_layout_line_get_extents), (pango_layout_line_new), (pango_layout_iter_get_run), (pango_layout_iter_get_line): Cache line extents. Line extents are cached only if the user doesn't have a pointer to the line or any of its runs. Functions that give away such pointers mark the line as "leak"ed. * pango/pango-layout.c (pango_layout_index_to_line_and_extents), (pango_layout_xy_to_index), (pango_layout_index_to_pos): Use _pango_layout_iter_get_line() which is like pango_layout_iter_get_line() but doesn't leak the line. * pango/pango-layout-private.h: Add pango_layout_iter_get_line() duplicate _pango_layout_iter_get_line_readonly() that doesn't leak the line. * pango/pango-renderer.c (pango_renderer_draw_layout): Use _pango_layout_iter_get_line_readonly().
-rw-r--r--ChangeLog24
-rw-r--r--pango/pango-layout-private.h1
-rw-r--r--pango/pango-layout.c115
-rw-r--r--pango/pango-renderer.c3
4 files changed, 136 insertions, 7 deletions
diff --git a/ChangeLog b/ChangeLog
index 3fe56aa8..06688e28 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,29 @@
2006-12-04 Behdad Esfahbod <behdad@gnome.org>
+ Bug 135683 – Cache glyphstring extents
+
+ * pango/pango-layout.c (pango_layout_get_lines),
+ (pango_layout_get_line), (pango_layout_line_leaked),
+ (pango_layout_line_get_extents), (pango_layout_line_new),
+ (pango_layout_iter_get_run), (pango_layout_iter_get_line):
+ Cache line extents. Line extents are cached only if the user doesn't
+ have a pointer to the line or any of its runs. Functions that give
+ away such pointers mark the line as "leak"ed.
+
+ * pango/pango-layout.c (pango_layout_index_to_line_and_extents),
+ (pango_layout_xy_to_index), (pango_layout_index_to_pos):
+ Use _pango_layout_iter_get_line() which is like
+ pango_layout_iter_get_line() but doesn't leak the line.
+
+ * pango/pango-layout-private.h: Add pango_layout_iter_get_line()
+ duplicate _pango_layout_iter_get_line_readonly() that doesn't leak
+ the line.
+
+ * pango/pango-renderer.c (pango_renderer_draw_layout): Use
+ _pango_layout_iter_get_line_readonly().
+
+2006-12-04 Behdad Esfahbod <behdad@gnome.org>
+
* pango/pangocairo-render.c (_pango_cairo_renderer_draw_frame):
Improve upon last change. Suggested by Carl Worth: use
cairo_rectangle(x + width, y, -width, height) to do a rectangle with
diff --git a/pango/pango-layout-private.h b/pango/pango-layout-private.h
index fa4f7b5d..bcb5d7c6 100644
--- a/pango/pango-layout-private.h
+++ b/pango/pango-layout-private.h
@@ -67,5 +67,6 @@ G_END_DECLS
void _pango_layout_line_ellipsize (PangoLayoutLine *line,
PangoAttrList *attrs);
+PangoLayoutLine* _pango_layout_iter_get_line_readonly (PangoLayoutIter *iter);
#endif /* __PANGO_LAYOUT_PRIVATE_H__ */
diff --git a/pango/pango-layout.c b/pango/pango-layout.c
index 7fa0f70a..9f465468 100644
--- a/pango/pango-layout.c
+++ b/pango/pango-layout.c
@@ -112,6 +112,21 @@ struct _PangoLayoutLinePrivate
{
PangoLayoutLine line;
guint ref_count;
+
+ /* Extents cache status:
+ *
+ * LEAKED means that the user has access to this line structure or a
+ * run included in this line, and so can change the glyphs/glyph-widths.
+ * If this is true, extents caching will be disabled.
+ */
+ enum {
+ NOT_CACHED,
+ CACHED,
+ LEAKED
+ } cache_status;
+
+ PangoRectangle ink_rect;
+ PangoRectangle logical_rect;
};
struct _PangoLayoutClass
@@ -156,6 +171,10 @@ static int *pango_layout_line_get_log2vis_map (PangoLayoutLine *line,
gboolean strong);
static int *pango_layout_line_get_vis2log_map (PangoLayoutLine *line,
gboolean strong);
+static void pango_layout_line_leaked (PangoLayoutLine *line);
+
+/* doesn't leak line */
+static PangoLayoutLine* _pango_layout_iter_get_line (PangoLayoutIter *iter);
static void pango_layout_get_item_properties (PangoItem *item,
ItemProperties *properties);
@@ -1064,6 +1083,19 @@ GSList *
pango_layout_get_lines (PangoLayout *layout)
{
pango_layout_check_lines (layout);
+
+ if (layout->lines)
+ {
+ GSList *tmp_list = layout->lines;
+ while (tmp_list)
+ {
+ PangoLayoutLine *line = tmp_list->data;
+ tmp_list = tmp_list->next;
+
+ pango_layout_line_leaked (line);
+ }
+ }
+
return layout->lines;
}
@@ -1092,9 +1124,17 @@ pango_layout_get_line (PangoLayout *layout,
return NULL;
pango_layout_check_lines (layout);
+
list_item = g_slist_nth (layout->lines, line);
+
if (list_item)
- return list_item->data;
+ {
+ PangoLayoutLine *line = list_item->data;
+
+ pango_layout_line_leaked (line);
+ return line;
+ }
+
return NULL;
}
@@ -1239,7 +1279,7 @@ pango_layout_index_to_line_and_extents (PangoLayout *layout,
if (!ITER_IS_INVALID (iter))
while (TRUE)
{
- PangoLayoutLine *tmp_line = pango_layout_iter_get_line (iter);
+ PangoLayoutLine *tmp_line = _pango_layout_iter_get_line (iter);
if (tmp_line->start_index > index)
break; /* index was in paragraph delimiters */
@@ -1564,18 +1604,18 @@ pango_layout_xy_to_index (PangoLayout *layout,
if (prev_line == NULL)
outside = TRUE; /* off the top */
- found = pango_layout_iter_get_line (iter);
+ found = _pango_layout_iter_get_line (iter);
found_line_x = x - line_logical.x;
}
}
else if (y >= first_y &&
y < last_y)
{
- found = pango_layout_iter_get_line (iter);
+ found = _pango_layout_iter_get_line (iter);
found_line_x = x - line_logical.x;
}
- prev_line = pango_layout_iter_get_line (iter);
+ prev_line = _pango_layout_iter_get_line (iter);
prev_last = last_y;
prev_line_x = x - line_logical.x;
@@ -1638,7 +1678,7 @@ pango_layout_index_to_pos (PangoLayout *layout,
{
while (TRUE)
{
- PangoLayoutLine *tmp_line = pango_layout_iter_get_line (iter);
+ PangoLayoutLine *tmp_line = _pango_layout_iter_get_line (iter);
if (tmp_line->start_index > index)
{
@@ -2381,6 +2421,14 @@ pango_layout_clear_lines (PangoLayout *layout)
}
}
+static void
+pango_layout_line_leaked (PangoLayoutLine *line)
+{
+ PangoLayoutLinePrivate *private = (PangoLayoutLinePrivate *)line;
+
+ private->cache_status = LEAKED;
+}
+
/************************************************
* Some functions for handling PANGO_ATTR_SHAPE *
@@ -4096,14 +4144,41 @@ pango_layout_line_get_extents (PangoLayoutLine *line,
PangoRectangle *ink_rect,
PangoRectangle *logical_rect)
{
+ PangoLayoutLinePrivate *private = (PangoLayoutLinePrivate *)line;
GSList *tmp_list;
int x_pos = 0;
+ gboolean caching = FALSE;
g_return_if_fail (LINE_IS_VALID (line));
if (!LINE_IS_VALID (line))
return;
+ switch (private->cache_status)
+ {
+ case CACHED:
+ {
+ if (ink_rect)
+ *ink_rect = private->ink_rect;
+ if (logical_rect)
+ *logical_rect = private->logical_rect;
+ return;
+ }
+ case NOT_CACHED:
+ {
+ caching = TRUE;
+ if (!ink_rect)
+ ink_rect = &private->ink_rect;
+ if (!logical_rect)
+ logical_rect = &private->logical_rect;
+ break;
+ }
+ case LEAKED:
+ {
+ break;
+ }
+ }
+
if (ink_rect)
{
ink_rect->x = 0;
@@ -4172,6 +4247,15 @@ pango_layout_line_get_extents (PangoLayoutLine *line,
if (logical_rect && !line->runs)
pango_layout_line_get_empty_extents (line, logical_rect);
+
+ if (caching)
+ {
+ if (&private->ink_rect != ink_rect)
+ private->ink_rect = *ink_rect;
+ if (&private->logical_rect != logical_rect)
+ private->logical_rect = *logical_rect;
+ private->cache_status = CACHED;
+ }
}
static PangoLayoutLine *
@@ -4183,6 +4267,7 @@ pango_layout_line_new (PangoLayout *layout)
private->line.layout = layout;
private->line.runs = NULL;
private->line.length = 0;
+ private->cache_status = NOT_CACHED;
/* Note that we leave start_index, resolved_dir, and is_paragraph_start
* uninitialized */
@@ -4813,9 +4898,25 @@ pango_layout_iter_get_run (PangoLayoutIter *iter)
if (ITER_IS_INVALID (iter))
return NULL;
+ pango_layout_line_leaked (iter->line);
+
return iter->run;
}
+/* an inline-able version for local use */
+static PangoLayoutLine*
+_pango_layout_iter_get_line (PangoLayoutIter *iter)
+{
+ return iter->line;
+}
+
+/* a private one for pango-renderer.c use */
+PangoLayoutLine*
+_pango_layout_iter_get_line_readonly (PangoLayoutIter *iter)
+{
+ return iter->line;
+}
+
/**
* pango_layout_iter_get_line:
* @iter: a #PangoLayoutIter
@@ -4830,6 +4931,8 @@ pango_layout_iter_get_line (PangoLayoutIter *iter)
if (ITER_IS_INVALID (iter))
return NULL;
+ pango_layout_line_leaked (iter->line);
+
return iter->line;
}
diff --git a/pango/pango-renderer.c b/pango/pango-renderer.c
index 9a37bed9..4169c3b5 100644
--- a/pango/pango-renderer.c
+++ b/pango/pango-renderer.c
@@ -23,6 +23,7 @@
#include <stdlib.h>
#include "pango-renderer.h"
+#include "pango-layout-private.h"
#define N_RENDER_PARTS 4
@@ -176,7 +177,7 @@ pango_renderer_draw_layout (PangoRenderer *renderer,
PangoLayoutLine *line;
int baseline;
- line = pango_layout_iter_get_line (iter);
+ line = _pango_layout_iter_get_line_readonly (iter);
pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
baseline = pango_layout_iter_get_baseline (iter);