summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2021-10-20 10:52:36 +0000
committerMatthias Clasen <mclasen@redhat.com>2021-10-20 10:52:36 +0000
commita0d7555fc00f04d1283acd5cac36feab77433e53 (patch)
treec7b5831dbf287db07cbae4192e7ccf9d5c98e2ed
parent5820cc12cb9f05b90149c7236166e588b5bda2bc (diff)
parent1a3c69d37200f42a5a744ab7775ab1ac30b7a1a2 (diff)
downloadpango-a0d7555fc00f04d1283acd5cac36feab77433e53.tar.gz
Merge branch 'empty-line-height-attr-fix' into 'main'
Fix empty line heights Closes #421 See merge request GNOME/pango!481
-rw-r--r--pango/pango-layout.c68
-rw-r--r--pango/pangocairo-fcfont.c14
-rw-r--r--pango/pangocairo-font.c43
-rw-r--r--tests/testmisc.c174
4 files changed, 260 insertions, 39 deletions
diff --git a/pango/pango-layout.c b/pango/pango-layout.c
index 74799ddc..6e761f2c 100644
--- a/pango/pango-layout.c
+++ b/pango/pango-layout.c
@@ -193,6 +193,7 @@ static void pango_layout_get_item_properties (PangoItem *item,
static void pango_layout_get_empty_extents_and_height_at_index (PangoLayout *layout,
int index,
PangoRectangle *logical_rect,
+ gboolean apply_line_height,
int *height);
static void pango_layout_finalize (GObject *object);
@@ -1908,17 +1909,15 @@ pango_layout_index_to_line_and_extents (PangoLayout *layout,
{
if (run_rect)
{
- *run_rect = *line_rect;
-
while (TRUE)
{
PangoLayoutRun *run = _pango_layout_iter_get_run (&iter);
- if (!run)
- break;
-
pango_layout_iter_get_run_extents (&iter, NULL, run_rect);
+ if (!run)
+ break;
+
if (run->item->offset <= index && index < run->item->offset + run->item->length)
break;
@@ -4482,7 +4481,7 @@ pango_layout_check_lines (PangoLayout *layout)
{
PangoRectangle logical = { 0, };
int height = 0;
- pango_layout_get_empty_extents_and_height_at_index (layout, 0, &logical, &height);
+ pango_layout_get_empty_extents_and_height_at_index (layout, 0, &logical, TRUE, &height);
state.line_height = layout->line_spacing == 0.0 ? logical.height : layout->line_spacing * height;
}
@@ -5115,6 +5114,7 @@ static void
pango_layout_get_empty_extents_and_height_at_index (PangoLayout *layout,
int index,
PangoRectangle *logical_rect,
+ gboolean apply_line_height,
int *height)
{
if (logical_rect)
@@ -5122,6 +5122,8 @@ pango_layout_get_empty_extents_and_height_at_index (PangoLayout *layout,
PangoFont *font;
PangoFontDescription *font_desc = NULL;
gboolean free_font_desc = FALSE;
+ double line_height_factor = 0.0;
+ int absolute_line_height = 0;
font_desc = pango_context_get_font_description (layout->context);
@@ -5147,6 +5149,8 @@ pango_layout_get_empty_extents_and_height_at_index (PangoLayout *layout,
if (start <= index && index < end)
{
+ PangoAttribute *attr;
+
if (!free_font_desc)
{
font_desc = pango_font_description_copy_static (font_desc);
@@ -5158,6 +5162,14 @@ pango_layout_get_empty_extents_and_height_at_index (PangoLayout *layout,
NULL,
NULL);
+ attr = pango_attr_iterator_get (&iter, PANGO_ATTR_LINE_HEIGHT);
+ if (attr)
+ line_height_factor = ((PangoAttrFloat *)attr)->value;
+
+ attr = pango_attr_iterator_get (&iter, PANGO_ATTR_ABSOLUTE_LINE_HEIGHT);
+ if (attr)
+ absolute_line_height = ((PangoAttrInt *)attr)->value;
+
break;
}
@@ -5183,6 +5195,18 @@ pango_layout_get_empty_extents_and_height_at_index (PangoLayout *layout,
*height = pango_font_metrics_get_height (metrics);
pango_font_metrics_unref (metrics);
+
+ if (apply_line_height &&
+ (absolute_line_height != 0 || line_height_factor != 0.0))
+ {
+ int line_height, leading;
+
+ line_height = MAX (absolute_line_height, ceilf (line_height_factor * logical_rect->height));
+
+ leading = line_height - logical_rect->height;
+ logical_rect->y -= leading / 2;
+ logical_rect->height += leading;
+ }
}
else
{
@@ -5206,14 +5230,6 @@ pango_layout_get_empty_extents_and_height_at_index (PangoLayout *layout,
}
static void
-pango_layout_line_get_empty_extents_and_height (PangoLayoutLine *line,
- PangoRectangle *logical_rect,
- int *height)
-{
- pango_layout_get_empty_extents_and_height_at_index (line->layout, line->start_index, logical_rect, height);
-}
-
-static void
pango_layout_run_get_extents_and_height (PangoLayoutRun *run,
PangoRectangle *run_ink,
PangoRectangle *run_logical,
@@ -5347,6 +5363,7 @@ pango_layout_run_get_extents_and_height (PangoLayoutRun *run,
int line_height, leading;
line_height = MAX (properties.absolute_line_height, ceilf (properties.line_height * line_logical->height));
+
leading = line_height - line_logical->height;
line_logical->y -= leading / 2;
line_logical->height += leading;
@@ -5479,7 +5496,7 @@ pango_layout_line_get_extents_and_height (PangoLayoutLine *line,
PangoRectangle r, *rect;
rect = logical_rect ? logical_rect : &r;
- pango_layout_line_get_empty_extents_and_height (line, rect, height);
+ pango_layout_get_empty_extents_and_height_at_index (line->layout, line->start_index, rect, TRUE, height);
}
if (caching)
@@ -7341,18 +7358,35 @@ pango_layout_iter_get_run_extents (PangoLayoutIter *iter,
}
else
{
- /* The empty run at the end of a line */
+ if (iter->line->runs)
+ {
+ /* The empty run at the end of a non-empty line */
+ PangoLayoutRun *run = g_slist_last (iter->line->runs)->data;
+ pango_layout_run_get_extents_and_height (run, ink_rect, logical_rect, NULL, NULL);
+ }
+ else
+ {
+ PangoRectangle r;
- pango_layout_iter_get_line_extents (iter, ink_rect, logical_rect);
+ pango_layout_get_empty_extents_and_height_at_index (iter->layout, 0, &r, FALSE, NULL);
+
+ if (ink_rect)
+ *ink_rect = r;
+
+ if (logical_rect)
+ *logical_rect = r;
+ }
if (ink_rect)
{
+ offset_y (iter, &ink_rect->y);
ink_rect->x = iter->run_x;
ink_rect->width = 0;
}
if (logical_rect)
{
+ offset_y (iter, &logical_rect->y);
logical_rect->x = iter->run_x;
logical_rect->width = 0;
}
diff --git a/pango/pangocairo-fcfont.c b/pango/pangocairo-fcfont.c
index 0019f83a..85cc45c8 100644
--- a/pango/pangocairo-fcfont.c
+++ b/pango/pangocairo-fcfont.c
@@ -76,8 +76,20 @@ pango_cairo_fc_font_create_base_metrics_for_context (PangoCairoFont *cfont,
PangoContext *context)
{
PangoFcFont *fcfont = (PangoFcFont *) (cfont);
+ PangoFontMetrics *metrics;
+ const cairo_font_options_t *options;
- return pango_fc_font_create_base_metrics_for_context (fcfont, context);
+ metrics = pango_fc_font_create_base_metrics_for_context (fcfont, context);
+
+ options = pango_cairo_context_get_font_options (context);
+ if (cairo_font_options_get_hint_metrics (options) == CAIRO_HINT_METRICS_ON)
+ {
+ metrics->ascent = PANGO_PIXELS_CEIL (metrics->ascent) * PANGO_SCALE;
+ metrics->descent = PANGO_PIXELS_CEIL (metrics->descent) * PANGO_SCALE;
+ metrics->height = PANGO_PIXELS_CEIL (metrics->height) * PANGO_SCALE;
+ }
+
+ return metrics;
}
static void
diff --git a/pango/pangocairo-font.c b/pango/pangocairo-font.c
index 69c375c3..15c5be4a 100644
--- a/pango/pangocairo-font.c
+++ b/pango/pangocairo-font.c
@@ -784,40 +784,41 @@ struct _PangoCairoFontGlyphExtentsCacheEntry
static gboolean
_pango_cairo_font_private_glyph_extents_cache_init (PangoCairoFontPrivate *cf_priv)
{
- cairo_scaled_font_t *scaled_font = _pango_cairo_font_private_get_scaled_font (cf_priv);
- cairo_font_extents_t font_extents;
-
- if (G_UNLIKELY (scaled_font == NULL || cairo_scaled_font_status (scaled_font) != CAIRO_STATUS_SUCCESS))
- return FALSE;
-
- cairo_scaled_font_extents (scaled_font, &font_extents);
+ PangoCairoFont *cfont = cf_priv->cfont;
+ PangoFontMetrics *metrics = _pango_cairo_font_get_metrics (PANGO_FONT (cfont), NULL);
cf_priv->font_extents.x = 0;
cf_priv->font_extents.width = 0;
- cf_priv->font_extents.height = pango_units_from_double (font_extents.ascent + font_extents.descent);
+ cf_priv->font_extents.height = metrics->ascent + metrics->descent;
+
switch (cf_priv->gravity)
{
default:
case PANGO_GRAVITY_AUTO:
case PANGO_GRAVITY_SOUTH:
- cf_priv->font_extents.y = - pango_units_from_double (font_extents.ascent);
- break;
+ cf_priv->font_extents.y = - metrics->ascent;
+ break;
case PANGO_GRAVITY_NORTH:
- cf_priv->font_extents.y = - pango_units_from_double (font_extents.descent);
- break;
+ cf_priv->font_extents.y = - metrics->descent;
+ break;
case PANGO_GRAVITY_EAST:
case PANGO_GRAVITY_WEST:
- {
- int ascent = pango_units_from_double (font_extents.ascent + font_extents.descent) / 2;
- if (cf_priv->is_hinted)
- ascent = PANGO_UNITS_ROUND (ascent);
- cf_priv->font_extents.y = - ascent;
- }
+ {
+ int ascent = (metrics->ascent + metrics->descent) / 2;
+ if (cf_priv->is_hinted)
+ ascent = PANGO_UNITS_ROUND (ascent);
+ cf_priv->font_extents.y = - ascent;
+ }
}
- cf_priv->glyph_extents_cache = g_new0 (PangoCairoFontGlyphExtentsCacheEntry, GLYPH_CACHE_NUM_ENTRIES);
- /* Make sure all cache entries are invalid initially */
- cf_priv->glyph_extents_cache[0].glyph = 1; /* glyph 1 cannot happen in bucket 0 */
+ pango_font_metrics_unref (metrics);
+
+ if (!cf_priv->glyph_extents_cache)
+ {
+ cf_priv->glyph_extents_cache = g_new0 (PangoCairoFontGlyphExtentsCacheEntry, GLYPH_CACHE_NUM_ENTRIES);
+ /* Make sure all cache entries are invalid initially */
+ cf_priv->glyph_extents_cache[0].glyph = 1; /* glyph 1 cannot happen in bucket 0 */
+ }
return TRUE;
}
diff --git a/tests/testmisc.c b/tests/testmisc.c
index 60694134..b9ec81ea 100644
--- a/tests/testmisc.c
+++ b/tests/testmisc.c
@@ -126,6 +126,134 @@ test_line_height (void)
}
static void
+test_line_height2 (void)
+{
+ PangoContext *context;
+ PangoLayout *layout;
+ PangoLayoutLine *line;
+ int height1 = 0;
+ int height2 = 0;
+
+ context = pango_font_map_create_context (pango_cairo_font_map_get_default ());
+ layout = pango_layout_new (context);
+ pango_layout_set_text (layout, "one", -1);
+
+ line = pango_layout_get_line_readonly (layout, 0);
+ pango_layout_line_get_height (line, &height1);
+
+ pango_layout_set_text (layout, "", -1);
+
+ line = pango_layout_get_line_readonly (layout, 0);
+ pango_layout_line_get_height (line, &height2);
+
+ g_assert_cmpint (height1, ==, height2);
+
+ g_object_unref (layout);
+ g_object_unref (context);
+}
+
+static void
+test_line_height3 (void)
+{
+ PangoContext *context;
+ PangoLayout *layout;
+ PangoLayoutLine *line;
+ PangoAttrList *attrs;
+ int height1 = 0;
+ int height2 = 0;
+
+ context = pango_font_map_create_context (pango_cairo_font_map_get_default ());
+ layout = pango_layout_new (context);
+ pango_layout_set_text (layout, "one", -1);
+ attrs = pango_attr_list_new ();
+ pango_attr_list_insert (attrs, pango_attr_line_height_new (2.0));
+ pango_layout_set_attributes (layout, attrs);
+ pango_attr_list_unref (attrs);
+
+ line = pango_layout_get_line_readonly (layout, 0);
+ pango_layout_line_get_height (line, &height1);
+
+ pango_layout_set_text (layout, "", -1);
+
+ line = pango_layout_get_line_readonly (layout, 0);
+ pango_layout_line_get_height (line, &height2);
+
+ g_assert_cmpint (height1, ==, height2);
+
+ g_object_unref (layout);
+ g_object_unref (context);
+}
+
+static void
+test_run_height (void)
+{
+ PangoContext *context;
+ PangoLayout *layout;
+ PangoLayoutIter *iter;
+ PangoRectangle logical1, logical2;
+
+ context = pango_font_map_create_context (pango_cairo_font_map_get_default ());
+ layout = pango_layout_new (context);
+ pango_layout_set_text (layout, "one", -1);
+
+ iter = pango_layout_get_iter (layout);
+ pango_layout_iter_get_run_extents (iter, NULL, &logical1);
+ pango_layout_iter_free (iter);
+
+ pango_layout_set_text (layout, "", -1);
+
+ iter = pango_layout_get_iter (layout);
+ pango_layout_iter_get_run_extents (iter, NULL, &logical2);
+ pango_layout_iter_free (iter);
+
+ g_assert_cmpint (logical1.height, ==, logical2.height);
+
+ g_object_unref (layout);
+ g_object_unref (context);
+}
+
+static void
+test_cursor_height (void)
+{
+ PangoContext *context;
+ PangoLayout *layout;
+ PangoRectangle strong;
+
+ context = pango_font_map_create_context (pango_cairo_font_map_get_default ());
+ layout = pango_layout_new (context);
+ pango_layout_set_text (layout, "one\ttwo", -1);
+ pango_layout_get_cursor_pos (layout, 0, &strong, NULL);
+
+ g_assert_cmpint (strong.height, >, 0);
+
+ g_object_unref (layout);
+ g_object_unref (context);
+}
+
+static void
+test_cursor_height2 (void)
+{
+ PangoContext *context;
+ PangoLayout *layout;
+ PangoRectangle strong1, strong2;
+
+ context = pango_font_map_create_context (pango_cairo_font_map_get_default ());
+ layout = pango_layout_new (context);
+ pango_layout_set_text (layout, "one", -1);
+
+ pango_layout_get_cursor_pos (layout, 0, &strong1, NULL);
+
+ pango_layout_set_text (layout, "", -1);
+
+ pango_layout_get_cursor_pos (layout, 0, &strong2, NULL);
+
+ g_assert_cmpint (strong1.height, ==, strong2.height);
+
+ g_object_unref (layout);
+ g_object_unref (context);
+}
+
+static void
test_attr_list_update (void)
{
PangoAttribute *weight_attr;
@@ -489,6 +617,46 @@ test_extents (void)
g_object_unref (context);
}
+static void
+test_empty_line_height (void)
+{
+ PangoContext *context;
+ PangoLayout *layout;
+ PangoRectangle ext1, ext2, ext3;
+ cairo_font_options_t *options;
+ int hint;
+
+ context = pango_font_map_create_context (pango_cairo_font_map_get_default ());
+
+ for (hint = CAIRO_HINT_METRICS_OFF; hint <= CAIRO_HINT_METRICS_ON; hint++)
+ {
+ options = cairo_font_options_create ();
+ cairo_font_options_set_hint_metrics (options, hint);
+ pango_cairo_context_set_font_options (context, options);
+ cairo_font_options_destroy (options);
+
+ layout = pango_layout_new (context);
+
+ pango_layout_get_extents (layout, NULL, &ext1);
+
+ pango_layout_set_text (layout, "a", 1);
+
+ pango_layout_get_extents (layout, NULL, &ext2);
+
+ g_assert_cmpint (ext1.height, ==, ext2.height);
+
+ pango_layout_set_text (layout, "Pg", 1);
+
+ pango_layout_get_extents (layout, NULL, &ext3);
+
+ g_assert_cmpint (ext2.height, ==, ext3.height);
+
+ g_object_unref (layout);
+ }
+
+ g_object_unref (context);
+}
+
int
main (int argc, char *argv[])
{
@@ -500,6 +668,11 @@ main (int argc, char *argv[])
g_test_add_func ("/layout/short-string-crash", test_short_string_crash);
g_test_add_func ("/language/emoji-crash", test_language_emoji_crash);
g_test_add_func ("/layout/line-height", test_line_height);
+ g_test_add_func ("/layout/line-height2", test_line_height2);
+ g_test_add_func ("/layout/line-height3", test_line_height3);
+ g_test_add_func ("/layout/run-height", test_run_height);
+ g_test_add_func ("/layout/cursor-height", test_cursor_height);
+ g_test_add_func ("/layout/cursor-height2", test_cursor_height2);
g_test_add_func ("/attr-list/update", test_attr_list_update);
g_test_add_func ("/misc/version-info", test_version_info);
g_test_add_func ("/misc/is-zerowidth", test_is_zero_width);
@@ -514,6 +687,7 @@ main (int argc, char *argv[])
g_test_add_func ("/bidi/get-cursor", test_get_cursor);
g_test_add_func ("/layout/index-to-x", test_index_to_x);
g_test_add_func ("/layout/extents", test_extents);
+ g_test_add_func ("/layout/empty-line-height", test_empty_line_height);
return g_test_run ();
}