diff options
author | Matthias Clasen <mclasen@redhat.com> | 2021-08-09 03:04:21 +0000 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2021-08-09 03:04:21 +0000 |
commit | c4d138179443b49d817830c78ddcd1459cf5505f (patch) | |
tree | 105703add2c026aeff6d297d244bc6d9e2c579d7 /pango | |
parent | f437641bcc412d7e7ac2f706487bbbdeaeddc87e (diff) | |
parent | 336dca6530d9dc41b101018d7f4af4a27e70445d (diff) | |
download | pango-c4d138179443b49d817830c78ddcd1459cf5505f.tar.gz |
Merge branch 'line-height-attribute' into 'main'
Implement css-like line-height
See merge request GNOME/pango!390
Diffstat (limited to 'pango')
-rw-r--r-- | pango/pango-attributes.c | 53 | ||||
-rw-r--r-- | pango/pango-attributes.h | 8 | ||||
-rw-r--r-- | pango/pango-layout.c | 114 | ||||
-rw-r--r-- | pango/pango-markup.c | 38 |
4 files changed, 198 insertions, 15 deletions
diff --git a/pango/pango-attributes.c b/pango/pango-attributes.c index 1a4a9443..fdb37f56 100644 --- a/pango/pango-attributes.c +++ b/pango/pango-attributes.c @@ -1341,6 +1341,58 @@ pango_attr_overline_color_new (guint16 red, return pango_attr_color_new (&klass, red, green, blue); } +/** + * pango_attr_line_height_new: + * @factor: the scaling factor to apply to the logical height + * + * Modify the height of logical line extents by a factor. + * + * This affects the values returned by + * [method@Pango.LayoutLine.get_extents], + * [method@Pango.LayoutLine.get_pixel_extents] and + * [method@Pango.LayoutIter.get_line_extents]. + * + * + * Since: 1.50 + */ +PangoAttribute * +pango_attr_line_height_new (double factor) +{ + static const PangoAttrClass klass = { + PANGO_ATTR_LINE_HEIGHT, + pango_attr_float_copy, + pango_attr_float_destroy, + pango_attr_float_equal + }; + + return pango_attr_float_new (&klass, factor); +} + +/** + * pango_attr_line_height_new_absolute: + * @height: the line height, in %PANGO_SCALE-ths of a point + * + * Override the height of logical line extents to be @height. + * + * This affects the values returned by + * [method@Pango.LayoutLine.get_extents], + * [method@Pango.LayoutLine.get_pixel_extents] and + * [method@Pango.LayoutIter.get_line_extents]. + * + * Since: 1.50 + */ +PangoAttribute * +pango_attr_line_height_new_absolute (int height) +{ + static const PangoAttrClass klass = { + PANGO_ATTR_ABSOLUTE_LINE_HEIGHT, + pango_attr_int_copy, + pango_attr_int_destroy, + pango_attr_int_equal + }; + + return pango_attr_int_new (&klass, height); +} /* * Attribute List */ @@ -2559,6 +2611,7 @@ pango_attribute_as_float (PangoAttribute *attr) switch (attr->klass->type) { case PANGO_ATTR_SCALE: + case PANGO_ATTR_LINE_HEIGHT: return (PangoAttrFloat *)attr; default: diff --git a/pango/pango-attributes.h b/pango/pango-attributes.h index 6f18718e..c28623fb 100644 --- a/pango/pango-attributes.h +++ b/pango/pango-attributes.h @@ -160,6 +160,7 @@ typedef struct _PangoAttrIterator PangoAttrIterator; * @PANGO_ATTR_INSERT_HYPHENS: whether to insert hyphens at intra-word line breaks ([struct@Pango.AttrInt]). Since 1.44 * @PANGO_ATTR_OVERLINE: whether the text has an overline ([struct@Pango.AttrInt]). Since 1.46 * @PANGO_ATTR_OVERLINE_COLOR: overline color ([struct@Pango.AttrColor]). Since 1.46 + * @PANGO_ATTR_LINE_HEIGHT: line height factor ([struct@Pango.AttrFloat]). Since: 1.50 * * The `PangoAttrType` distinguishes between different types of attributes. * @@ -201,6 +202,8 @@ typedef enum PANGO_ATTR_INSERT_HYPHENS, /* PangoAttrInt */ PANGO_ATTR_OVERLINE, /* PangoAttrInt */ PANGO_ATTR_OVERLINE_COLOR, /* PangoAttrColor */ + PANGO_ATTR_LINE_HEIGHT, /* PangoAttrFloat */ + PANGO_ATTR_ABSOLUTE_LINE_HEIGHT, /* PangoAttrInt */ } PangoAttrType; /** @@ -611,6 +614,11 @@ typedef enum { PANGO_AVAILABLE_IN_1_44 PangoAttribute *pango_attr_show_new (PangoShowFlags flags); +PANGO_AVAILABLE_IN_1_50 +PangoAttribute *pango_attr_line_height_new (double factor); +PANGO_AVAILABLE_IN_1_50 +PangoAttribute *pango_attr_line_height_new_absolute (int height); + PANGO_AVAILABLE_IN_ALL GType pango_attr_list_get_type (void) G_GNUC_CONST; PANGO_AVAILABLE_IN_ALL diff --git a/pango/pango-layout.c b/pango/pango-layout.c index e0475a5e..2a3cb5a2 100644 --- a/pango/pango-layout.c +++ b/pango/pango-layout.c @@ -78,6 +78,7 @@ #include "pango-impl-utils.h" #include "pango-glyph-item.h" #include <string.h> +#include <math.h> #include "pango-layout-private.h" #include "pango-attributes-private.h" @@ -107,6 +108,8 @@ struct _ItemProperties gboolean shape_set; PangoRectangle *shape_ink_rect; PangoRectangle *shape_logical_rect; + double line_height; + int absolute_line_height; }; typedef struct _PangoLayoutLinePrivate PangoLayoutLinePrivate; @@ -177,7 +180,8 @@ static void pango_layout_line_postprocess (PangoLayoutLine *line, static void pango_layout_line_leaked (PangoLayoutLine *line); /* doesn't leak line */ -static PangoLayoutLine* _pango_layout_iter_get_line (PangoLayoutIter *iter); +static PangoLayoutLine * _pango_layout_iter_get_line (PangoLayoutIter *iter); +static PangoLayoutRun * _pango_layout_iter_get_run (PangoLayoutIter *iter); static void pango_layout_get_item_properties (PangoItem *item, ItemProperties *properties); @@ -587,9 +591,12 @@ pango_layout_get_indent (PangoLayout *layout) * The default value is 0. * * Note: Since 1.44, Pango is using the line height (as determined - * by the font) for placing lines when the line height factor is set + * by the font) for placing lines when the line spacing factor is set * to a non-zero value with [method@Pango.Layout.set_line_spacing]. * In that case, the @spacing set with this function is ignored. + * + * Note: for semantics that are closer to the CSS line-height + * property, see [func@Pango.attr_line_height_new]. */ void pango_layout_set_spacing (PangoLayout *layout, @@ -638,6 +645,9 @@ pango_layout_get_spacing (PangoLayout *layout) * * If @factor is zero (the default), spacing is applied as before. * + * Note: for semantics that are closer to the CSS line-height + * property, see [func@Pango.attr_line_height_new]. + * * Since: 1.44 */ void @@ -1793,7 +1803,8 @@ pango_layout_index_to_line (PangoLayout *layout, static PangoLayoutLine * pango_layout_index_to_line_and_extents (PangoLayout *layout, int index, - PangoRectangle *line_rect) + PangoRectangle *line_rect, + PangoRectangle *run_rect) { PangoLayoutIter iter; PangoLayoutLine *line = NULL; @@ -1813,7 +1824,26 @@ pango_layout_index_to_line_and_extents (PangoLayout *layout, pango_layout_iter_get_line_extents (&iter, NULL, line_rect); if (line->start_index + line->length > index) - break; + { + if (run_rect) + { + while (TRUE) + { + PangoLayoutRun *run = _pango_layout_iter_get_run (&iter); + + if (run->item->offset <= index && index < run->item->offset + run->item->length) + { + pango_layout_iter_get_run_extents (&iter, NULL, run_rect); + break; + } + + if (!pango_layout_iter_next_run (&iter)) + break; + } + } + + break; + } if (!pango_layout_iter_next_line (&iter)) break; /* Use end of last line */ @@ -2291,10 +2321,24 @@ pango_layout_index_to_pos (PangoLayout *layout, layout_line = tmp_line; - pango_layout_iter_get_line_extents (&iter, NULL, &logical_rect); - if (layout_line->start_index + layout_line->length > index) - break; + { + while (TRUE) + { + PangoLayoutRun *run = _pango_layout_iter_get_run (&iter); + + if (run->item->offset <= index && index < run->item->offset + run->item->length) + { + pango_layout_iter_get_run_extents (&iter, NULL, &logical_rect); + break; + } + + if (!pango_layout_iter_next_run (&iter)) + break; + } + + break; + } if (!pango_layout_iter_next_line (&iter)) { @@ -2367,7 +2411,7 @@ pango_layout_get_direction (PangoLayout *layout, { PangoLayoutLine *line; - line = pango_layout_index_to_line_and_extents (layout, index, NULL); + line = pango_layout_index_to_line_and_extents (layout, index, NULL, NULL); if (line) return pango_layout_line_get_char_direction (line, index); @@ -2400,6 +2444,7 @@ pango_layout_get_cursor_pos (PangoLayout *layout, PangoDirection dir1, dir2; int level1, level2; PangoRectangle line_rect; + PangoRectangle run_rect; PangoLayoutLine *layout_line = NULL; /* Quiet GCC */ int x1_trailing; int x2; @@ -2408,7 +2453,7 @@ pango_layout_get_cursor_pos (PangoLayout *layout, g_return_if_fail (index >= 0 && index <= layout->length); layout_line = pango_layout_index_to_line_and_extents (layout, index, - &line_rect); + &line_rect, &run_rect); g_assert (index >= layout_line->start_index); @@ -2457,9 +2502,9 @@ pango_layout_get_cursor_pos (PangoLayout *layout, else strong_pos->x += x2; - strong_pos->y = line_rect.y; + strong_pos->y = run_rect.y; strong_pos->width = 0; - strong_pos->height = line_rect.height; + strong_pos->height = run_rect.height; } if (weak_pos) @@ -2472,9 +2517,9 @@ pango_layout_get_cursor_pos (PangoLayout *layout, else weak_pos->x += x1_trailing; - weak_pos->y = line_rect.y; + weak_pos->y = run_rect.y; weak_pos->width = 0; - weak_pos->height = line_rect.height; + weak_pos->height = run_rect.height; } } @@ -4149,6 +4194,8 @@ affects_itemization (PangoAttribute *attr, case PANGO_ATTR_LETTER_SPACING: case PANGO_ATTR_SHAPE: case PANGO_ATTR_RISE: + case PANGO_ATTR_LINE_HEIGHT: + case PANGO_ATTR_ABSOLUTE_LINE_HEIGHT: return TRUE; default: return FALSE; @@ -5011,6 +5058,7 @@ static void pango_layout_run_get_extents_and_height (PangoLayoutRun *run, PangoRectangle *run_ink, PangoRectangle *run_logical, + PangoRectangle *line_logical, int *height) { PangoRectangle logical; @@ -5019,7 +5067,7 @@ pango_layout_run_get_extents_and_height (PangoLayoutRun *run, gboolean has_underline; gboolean has_overline; - if (G_UNLIKELY (!run_ink && !run_logical && !height)) + if (G_UNLIKELY (!run_ink && !run_logical && !line_logical && !height)) return; pango_layout_get_item_properties (run->item, &properties); @@ -5034,6 +5082,9 @@ pango_layout_run_get_extents_and_height (PangoLayoutRun *run, if (!run_logical && (has_underline || has_overline || properties.strikethrough)) run_logical = &logical; + if (!run_logical && line_logical) + run_logical = &logical; + if (properties.shape_set) _pango_shape_get_extents (run->item->num_chars, properties.shape_ink_rect, @@ -5104,6 +5155,7 @@ pango_layout_run_get_extents_and_height (PangoLayoutRun *run, if (!metrics) metrics = pango_font_get_metrics (run->item->analysis.font, run->item->analysis.language); + *height = pango_font_metrics_get_height (metrics); } @@ -5127,6 +5179,21 @@ pango_layout_run_get_extents_and_height (PangoLayoutRun *run, run_logical->y -= properties.rise; } + if (line_logical) + { + *line_logical = *run_logical; + + if (properties.absolute_line_height != 0 || properties.line_height != 0.0) + { + 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; + } + } + if (metrics) pango_font_metrics_unref (metrics); } @@ -5206,6 +5273,7 @@ pango_layout_line_get_extents_and_height (PangoLayoutLine *line, pango_layout_run_get_extents_and_height (run, ink_rect ? &run_ink : NULL, + NULL, &run_logical, height ? &run_height : NULL); @@ -5985,6 +6053,8 @@ pango_layout_get_item_properties (PangoItem *item, properties->shape_set = FALSE; properties->shape_ink_rect = NULL; properties->shape_logical_rect = NULL; + properties->line_height = 0.0; + properties->absolute_line_height = 0; while (tmp_list) { @@ -6048,6 +6118,14 @@ pango_layout_get_item_properties (PangoItem *item, properties->shape_ink_rect = &((PangoAttrShape *)attr)->ink_rect; break; + case PANGO_ATTR_LINE_HEIGHT: + properties->line_height = ((PangoAttrFloat *)attr)->value; + break; + + case PANGO_ATTR_ABSOLUTE_LINE_HEIGHT: + properties->absolute_line_height = ((PangoAttrInt *)attr)->value; + break; + default: break; } @@ -6446,6 +6524,12 @@ _pango_layout_iter_get_line (PangoLayoutIter *iter) return iter->line; } +static PangoLayoutRun * +_pango_layout_iter_get_run (PangoLayoutIter *iter) +{ + return iter->run; +} + /** * pango_layout_iter_get_line: * @iter: a `PangoLayoutIter` @@ -6907,7 +6991,7 @@ pango_layout_iter_get_run_extents (PangoLayoutIter *iter, if (iter->run) { - pango_layout_run_get_extents_and_height (iter->run, ink_rect, logical_rect, NULL); + pango_layout_run_get_extents_and_height (iter->run, ink_rect, logical_rect, NULL, NULL); if (ink_rect) { diff --git a/pango/pango-markup.c b/pango/pango-markup.c index 5394c772..00b16943 100644 --- a/pango/pango-markup.c +++ b/pango/pango-markup.c @@ -977,6 +977,29 @@ span_parse_int (const char *attr_name, } static gboolean +span_parse_float (const char *attr_name, + const char *attr_val, + double *val, + int line_number, + GError **error) +{ + *val = g_ascii_strtod (attr_val, NULL); + if (errno != 0) + { + g_set_error (error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_INVALID_CONTENT, + _("Value of '%s' attribute on <span> tag " + "on line %d could not be parsed; " + "should be a number, not '%s'"), + attr_name, line_number, attr_val); + return FALSE; + } + + return TRUE; +} + +static gboolean span_parse_boolean (const char *attr_name, const char *attr_val, gboolean *val, @@ -1200,6 +1223,7 @@ span_parse_func (MarkupData *md G_GNUC_UNUSED, const char *allow_breaks = NULL; const char *insert_hyphens = NULL; const char *show = NULL; + const char *line_height = NULL; g_markup_parse_context_get_position (context, &line_number, &char_number); @@ -1278,6 +1302,7 @@ span_parse_func (MarkupData *md G_GNUC_UNUSED, case 'l': CHECK_ATTRIBUTE (lang); CHECK_ATTRIBUTE (letter_spacing); + CHECK_ATTRIBUTE (line_height); break; case 'o': CHECK_ATTRIBUTE (overline); @@ -1639,6 +1664,19 @@ span_parse_func (MarkupData *md G_GNUC_UNUSED, add_attribute (tag, pango_attr_letter_spacing_new (n)); } + if (G_UNLIKELY (line_height)) + { + double f = 0; + + if (!span_parse_float ("line_height", line_height, &f, line_number, error)) + goto error; + + if (f > 1024.0 && strchr (line_height, ".") == 0) + add_attribute (tag, pango_attr_line_height_new_absolute ((int)f)); + else + add_attribute (tag, pango_attr_line_height_new (f)); + } + if (G_UNLIKELY (lang)) { add_attribute (tag, |