diff options
-rw-r--r-- | ChangeLog | 36 | ||||
-rw-r--r-- | docs/pango-sections.txt | 2 | ||||
-rw-r--r-- | docs/tmpl/layout.sgml | 18 | ||||
-rw-r--r-- | pango-view/viewer-render.c | 33 | ||||
-rw-r--r-- | pango/ellipsize.c | 14 | ||||
-rw-r--r-- | pango/glyphstring.c | 2 | ||||
-rw-r--r-- | pango/pango-layout-private.h | 6 | ||||
-rw-r--r-- | pango/pango-layout.c | 170 | ||||
-rw-r--r-- | pango/pango-layout.h | 3 | ||||
-rw-r--r-- | pango/pango.def | 2 | ||||
-rw-r--r-- | pango/pangowin32.c | 4 |
11 files changed, 218 insertions, 72 deletions
@@ -1,5 +1,41 @@ +2008-01-14 Behdad Esfahbod <behdad@gnome.org> + + Bug 469313 – Add pango_layout_set_height() + Bug 508179 – PangoGlyphUnit confusion + + * pango/pango-layout.h: + * pango/pango-layout-private.h: + * pango/pango-layout.c: + * pango/ellipsize.c (_pango_layout_line_ellipsize): + New public API: + + pango_layout_set_height() + + See docs for semantics. Currently only negative height values (number + of lines) is implemented. + + * pango-view/viewer-render.c (make_layout), (output_body), + (parse_options): + Implement --height. + + * pango/pango.def: + * docs/pango-sections.txt: + * docs/tmpl/layout.sgml: + Update. + +2008-01-14 Behdad Esfahbod <behdad@gnome.org> + + Bug 508179 – PangoGlyphUnit confusion + + * pango/pangowin32.c: + * pango/glyphstring.c: + * pango/pango-layout.c (process_item): Remove all traces of + #PangoGlyphUnit + 2008-01-08 Behdad Esfahbod <behdad@gnome.org> + Bug 508381 – indent and center alignment don't mix + * pango/pango-layout.c: Ignore indent if aligned center, and document so. This assumption was present in some places and not the others. Fixed now. diff --git a/docs/pango-sections.txt b/docs/pango-sections.txt index 71e0bfd7..ab799b6d 100644 --- a/docs/pango-sections.txt +++ b/docs/pango-sections.txt @@ -448,6 +448,8 @@ pango_layout_set_font_description pango_layout_get_font_description pango_layout_set_width pango_layout_get_width +pango_layout_set_height +pango_layout_get_height pango_layout_set_wrap pango_layout_get_wrap pango_layout_is_wrapped diff --git a/docs/tmpl/layout.sgml b/docs/tmpl/layout.sgml index 8f599ae5..afcc6499 100644 --- a/docs/tmpl/layout.sgml +++ b/docs/tmpl/layout.sgml @@ -192,6 +192,24 @@ has no user-visible fields. @Returns: +<!-- ##### FUNCTION pango_layout_set_height ##### --> +<para> + +</para> + +@layout: +@height: + + +<!-- ##### FUNCTION pango_layout_get_height ##### --> +<para> + +</para> + +@layout: +@Returns: + + <!-- ##### FUNCTION pango_layout_set_wrap ##### --> <para> diff --git a/pango-view/viewer-render.c b/pango-view/viewer-render.c index bc98da85..c0ecf054 100644 --- a/pango-view/viewer-render.c +++ b/pango-view/viewer-render.c @@ -53,6 +53,7 @@ gboolean opt_auto_dir = TRUE; const char *opt_text = NULL; gboolean opt_waterfall = FALSE; int opt_width = -1; +int opt_height = -1; int opt_indent = 0; gboolean opt_justify = 0; int opt_runs = 1; @@ -117,16 +118,19 @@ make_layout(PangoContext *context, pango_layout_set_ellipsize (layout, opt_ellipsize); pango_layout_set_justify (layout, opt_justify); pango_layout_set_single_paragraph_mode (layout, opt_single_par); + pango_layout_set_wrap (layout, opt_wrap); font_description = get_font_description (); if (size > 0) pango_font_description_set_size (font_description, size * PANGO_SCALE); if (opt_width > 0) - { - pango_layout_set_wrap (layout, opt_wrap); - pango_layout_set_width (layout, (opt_width * opt_dpi * PANGO_SCALE + 36) / 72); - } + pango_layout_set_width (layout, (opt_width * opt_dpi * PANGO_SCALE + 36) / 72); + + if (opt_height > 0) + pango_layout_set_height (layout, (opt_height * opt_dpi * PANGO_SCALE + 36) / 72); + else + pango_layout_set_height (layout, opt_height); if (opt_indent != 0) pango_layout_set_indent (layout, (opt_indent * opt_dpi * PANGO_SCALE + 36) / 72); @@ -220,14 +224,16 @@ output_body (PangoLayout *layout, pango_font_description_free (desc); } - pango_layout_get_extents (layout, NULL, &logical_rect); + pango_layout_get_pixel_extents (layout, NULL, &logical_rect); if (render_cb) (*render_cb) (layout, x, y+*height, cb_context, cb_data); - *width = MAX (*width, PANGO_PIXELS (logical_rect.x + logical_rect.width)); - *width = MAX (*width, PANGO_PIXELS (pango_layout_get_width (layout))); - *height += PANGO_PIXELS (logical_rect.height); + *width = MAX (*width, + MAX (logical_rect.x + logical_rect.width, + PANGO_PIXELS (pango_layout_get_width (layout)))); + *height += MAX (logical_rect.y + logical_rect.height, + PANGO_PIXELS (pango_layout_get_height (layout))); } } @@ -516,7 +522,6 @@ backend_description (void) } - static gboolean parse_backend (const char *name, const char *arg, @@ -592,6 +597,8 @@ parse_options (int argc, char *argv[]) "Gravity hint", "natural/strong/line"}, {"header", 0, 0, G_OPTION_ARG_NONE, &opt_header, "Display the options in the output", NULL}, + {"height", 0, 0, G_OPTION_ARG_INT, &opt_height, + "Height in points (positive) or number of lines (negative) for ellipsizing", "+points/-numlines"}, {"hinting", 0, 0, G_OPTION_ARG_CALLBACK, &parse_hinting, "Hinting style", "none/auto/full"}, {"indent", 0, 0, G_OPTION_ARG_INT, &opt_indent, @@ -623,7 +630,7 @@ parse_options (int argc, char *argv[]) {"waterfall", 0, 0, G_OPTION_ARG_NONE, &opt_waterfall, "Create a waterfall display", NULL}, {"width", 'w', 0, G_OPTION_ARG_INT, &opt_width, - "Width in points to which to wrap output", "points"}, + "Width in points to which to wrap lines or ellipsize", "points"}, {"wrap", 0, 0, G_OPTION_ARG_CALLBACK, &parse_wrap, "Text wrapping mode (needs a width to be set)", "word/char/word-char"}, {NULL} @@ -665,12 +672,6 @@ parse_options (int argc, char *argv[]) fail ("No viewer backend found"); } - /* if wrap mode is set then width must be set */ - if (opt_width < 0 && opt_wrap_set) - { - g_printerr ("The wrap mode only has effect if a width is set\n"); - } - /* Get the text */ if (opt_text) diff --git a/pango/ellipsize.c b/pango/ellipsize.c index aa49720d..71e291a0 100644 --- a/pango/ellipsize.c +++ b/pango/ellipsize.c @@ -723,22 +723,16 @@ current_width (EllipsizeState *state) **/ gboolean _pango_layout_line_ellipsize (PangoLayoutLine *line, - PangoAttrList *attrs) + PangoAttrList *attrs, + int goal_width) { EllipsizeState state; - int goal_width; gboolean is_ellipsized = FALSE; - if (line->layout->ellipsize == PANGO_ELLIPSIZE_NONE || - line->layout->width < 0) - goto ret; + g_return_val_if_fail (line->layout->ellipsize != PANGO_ELLIPSIZE_NONE && goal_width >= 0, is_ellipsized); init_state (&state, line, attrs); - goal_width = state.layout->width; - if (state.layout->indent > 0 && state.layout->alignment != PANGO_ALIGN_CENTER) - goal_width -= state.layout->indent; - if (state.total_width <= goal_width) goto out; @@ -758,6 +752,6 @@ _pango_layout_line_ellipsize (PangoLayoutLine *line, out: free_state (&state); - ret: + return is_ellipsized; } diff --git a/pango/glyphstring.c b/pango/glyphstring.c index 307c9faf..5d6fb378 100644 --- a/pango/glyphstring.c +++ b/pango/glyphstring.c @@ -504,7 +504,7 @@ pango_glyph_string_index_to_x (PangoGlyphString *glyphs, * @text: the text for the run * @length: the number of bytes (not characters) in text. * @analysis: the analysis information return from pango_itemize() - * @x_pos: the x offset (in #PangoGlyphUnit) + * @x_pos: the x offset (in Pango units) * @index_: location to store calculated byte index within @text * @trailing: location to store a boolean indicating * whether the user clicked on the leading or trailing diff --git a/pango/pango-layout-private.h b/pango/pango-layout-private.h index a71865fc..f82c589c 100644 --- a/pango/pango-layout-private.h +++ b/pango/pango-layout-private.h @@ -40,7 +40,8 @@ struct _PangoLayout gchar *text; int length; /* length of text in bytes */ - int width; /* wrap width, in device units */ + int width; /* wrap/ellipsize width, in device units, or -1 if not set */ + int height; /* ellipsize width, in device units if positive, number of lines if negative */ int indent; /* amount by which first line should be shorter */ int spacing; /* spacing between lines */ @@ -75,7 +76,8 @@ struct _PangoLayout }; gboolean _pango_layout_line_ellipsize (PangoLayoutLine *line, - PangoAttrList *attrs); + PangoAttrList *attrs, + int goal_width); G_END_DECLS diff --git a/pango/pango-layout.c b/pango/pango-layout.c index df4772af..3198c78a 100644 --- a/pango/pango-layout.c +++ b/pango/pango-layout.c @@ -189,6 +189,7 @@ pango_layout_init (PangoLayout *layout) layout->text = NULL; layout->length = 0; layout->width = -1; + layout->height = -1; layout->indent = 0; layout->alignment = PANGO_ALIGN_LEFT; @@ -298,6 +299,7 @@ pango_layout_copy (PangoLayout *src) layout->text = g_strdup (src->text); layout->length = src->length; layout->width = src->width; + layout->height = src->height; layout->indent = src->indent; layout->spacing = src->spacing; layout->justify = src->justify; @@ -341,9 +343,10 @@ pango_layout_get_context (PangoLayout *layout) * pango_layout_set_width: * @layout: a #PangoLayout. * @width: the desired width in Pango units, or -1 to indicate that no - * wrapping should be performed. + * wrapping or ellipsization should be performed. * - * Sets the width to which the lines of the #PangoLayout should wrap. + * Sets the width to which the lines of the #PangoLayout should wrap or + * ellipsized. The default value is -1: no width set. **/ void pango_layout_set_width (PangoLayout *layout, @@ -364,7 +367,7 @@ pango_layout_set_width (PangoLayout *layout, * * Gets the width to which the lines of the #PangoLayout should wrap. * - * Return value: the width, or -1 if no width set. + * Return value: the width in Pango units, or -1 if no width set. **/ int pango_layout_get_width (PangoLayout *layout) @@ -374,6 +377,66 @@ pango_layout_get_width (PangoLayout *layout) } /** + * pango_layout_set_height: + * @layout: a #PangoLayout. + * @height: the desired height of the layout in Pango units if positive, + * or desired number of lines if negative. + * + * Sets the height to which the #PangoLayout should be ellipsized at. There + * are two different behaviors, based on whether @height is positive or + * negative. + * + * If @height is positive, it will be the maximum height of the layout. Only + * lines would be shown that would fit, and if there is any text ommitted, + * an ellipsis added. At least one line is included in each paragraph regardless + * of how small the height value is. A value of zero will render exactly one + * line for the entire layout. + * + * If @height if it is negative, it will be the maximum number of lines per + * paragraph. That is, the total number of lines shown may well be more than + * this value if the layout contains multiple paragraphs of text. + * The default value of -1 means that first line of each paragraph is ellipsized. + * + * The height setting only has effect if a positive width is set on @layout + * and ellipsization mode of @layout is not %PANGO_ELLIPSIZE_NONE, + * + * Since: 1.20 + **/ +void +pango_layout_set_height (PangoLayout *layout, + int height) +{ + g_return_if_fail (layout != NULL); + + if (height != layout->height) + { + layout->height = height; + + if (layout->ellipsize != PANGO_ELLIPSIZE_NONE) + pango_layout_clear_lines (layout); + } +} + +/** + * pango_layout_get_height: + * @layout: a #PangoLayout + * + * Gets the height of layout used for ellipsization. See + * pango_layout_set_height() for details. + * + * Return value: the height, in Pango units if positive, or + * number of lines if negative. + * + * Since: 1.20 + **/ +int +pango_layout_get_height (PangoLayout *layout) +{ + g_return_val_if_fail (layout != NULL, 0); + return layout->height; +} + +/** * pango_layout_set_wrap: * @layout: a #PangoLayout * @wrap: the wrap mode @@ -475,7 +538,7 @@ pango_layout_set_indent (PangoLayout *layout, * Gets the paragraph indent width in Pango units. A negative value * indicates a hanging indentation. * - * Return value: the indent. + * Return value: the indent in Pango units. **/ int pango_layout_get_indent (PangoLayout *layout) @@ -489,9 +552,8 @@ pango_layout_get_indent (PangoLayout *layout) * @layout: a #PangoLayout. * @spacing: the amount of spacing * - * Sets the amount of spacing in #PangoGlyphUnit between the lines of the + * Sets the amount of spacing in Pango unit between the lines of the * layout. - * **/ void pango_layout_set_spacing (PangoLayout *layout, @@ -510,10 +572,9 @@ pango_layout_set_spacing (PangoLayout *layout, * pango_layout_get_spacing: * @layout: a #PangoLayout * - * Gets the amount of spacing in #PangoGlyphUnit between the lines of the - * layout. + * Gets the amount of spacing between the lines of the layout. * - * Return value: the spacing. + * Return value: the spacing in Pango units. **/ int pango_layout_get_spacing (PangoLayout *layout) @@ -804,7 +865,6 @@ pango_layout_get_tabs (PangoLayout *layout) * as paragraph separators; instead, keep all text in a single paragraph, * and display a glyph for paragraph separator characters. Used when * you want to allow editing of newlines on a single text line. - * **/ void pango_layout_set_single_paragraph_mode (PangoLayout *layout, @@ -846,12 +906,15 @@ pango_layout_get_single_paragraph_mode (PangoLayout *layout) * * Sets the type of ellipsization being performed for @layout. * Depending on the ellipsization mode @ellipsize text is - * removed from the start, middle, or end of lines so they - * fit within the width of layout set with pango_layout_set_width (). + * removed from the start, middle, or end of text so they + * fit within the width and height of layout set with + * pango_layout_set_width() and pango_layout_set_height(). * * If the layout contains characters such as newlines that - * force it to be layed out in multiple lines, then each line - * is ellipsized separately. + * force it to be layed out in multiple paragraphs, then whether + * each paragraph is ellipsized separately or the entire layout + * is ellipsized as a whole depends on the set height of the layout. + * See pango_layout_set_height() for details. * * Since: 1.6 **/ @@ -1348,7 +1411,7 @@ pango_layout_get_line_readonly (PangoLayout *layout, * @trailing: an integer indicating the edge of the grapheme to retrieve * the position of. If > 0, the trailing edge of the grapheme, * if 0, the leading of the grapheme. - * @x_pos: location to store the x_offset (in #PangoGlyphUnit) + * @x_pos: location to store the x_offset (in Pango unit) * * Converts an index within a line to a X position. * @@ -1735,9 +1798,9 @@ pango_layout_move_cursor_visually (PangoLayout *layout, /** * pango_layout_xy_to_index: * @layout: a #PangoLayout - * @x: the X offset (in #PangoGlyphUnit) + * @x: the X offset (in Pango units) * from the left edge of the layout. - * @y: the Y offset (in #PangoGlyphUnit) + * @y: the Y offset (in Pango units) * from the top edge of the layout * @index_: location to store calculated byte index * @trailing: location to store a integer indicating where @@ -2940,16 +3003,17 @@ struct _ParaBreakState PangoAttrList *attrs; /* Attributes being used for itemization */ GList *items; /* This paragraph turned into items */ PangoDirection base_dir; /* Current resolved base direction */ - gboolean first_line; /* TRUE if this is the first line of the paragraph */ + gboolean line_of_par; /* Line of the paragraph, starting at 1 for first line */ int line_start_index; /* Start index (byte offset) of line in layout->text */ int line_start_offset; /* Character offset of line in layout->text */ + int line_width; /* Goal width of line currently processing; < 0 is infinite */ int remaining_width; /* Amount of space remaining on line; < 0 is infinite */ int start_offset; /* Character offset of first item in state->items in layout->text */ PangoGlyphString *glyphs; /* Glyphs for the first item in state->items */ ItemProperties properties; /* Properties for the first item in state->items */ - PangoGlyphUnit *log_widths; /* Logical widths for first item in state->items.. */ + int *log_widths; /* Logical widths for first item in state->items.. */ int log_widths_offset; /* Offset into log_widths to the point corresponding * to the remaining portion of the first item */ }; @@ -3146,7 +3210,7 @@ process_item (PangoLayout *layout, if (processing_new_item) { - state->log_widths = g_new (PangoGlyphUnit, item->num_chars); + state->log_widths = g_new (int, item->num_chars); pango_glyph_string_get_logical_widths (state->glyphs, layout->text + item->offset, item->length, item->analysis.level, state->log_widths); @@ -3298,6 +3362,15 @@ line_set_resolved_dir (PangoLayoutLine *line, } } +static gboolean +should_ellipsize_current_line (PangoLayout *layout, + ParaBreakState *state) +{ + return G_UNLIKELY (layout->ellipsize != PANGO_ELLIPSIZE_NONE && + layout->width >= 0 && + state->line_of_par == - layout->height); +} + static void process_line (PangoLayout *layout, ParaBreakState *state) @@ -3312,23 +3385,25 @@ process_line (PangoLayout *layout, line = pango_layout_line_new (layout); line->start_index = state->line_start_index; - line->is_paragraph_start = state->first_line; + line->is_paragraph_start = state->line_of_par == 1; line_set_resolved_dir (line, state->base_dir); - if (layout->ellipsize != PANGO_ELLIPSIZE_NONE) - state->remaining_width = -1; - else + state->line_width = layout->width; + if (state->line_width >= 0 && layout->alignment != PANGO_ALIGN_CENTER) { - state->remaining_width = layout->width; - - if (layout->alignment != PANGO_ALIGN_CENTER) - { - if (state->first_line && layout->indent >= 0) - state->remaining_width -= layout->indent; - else if (!state->first_line && layout->indent < 0) - state->remaining_width += layout->indent; - } + if (line->is_paragraph_start && layout->indent >= 0) + state->line_width -= layout->indent; + else if (!line->is_paragraph_start && layout->indent < 0) + state->line_width += layout->indent; + + if (state->line_width < 0) + state->line_width = 0; } + + if (G_UNLIKELY (should_ellipsize_current_line (layout, state))) + state->remaining_width = -1; + else + state->remaining_width = state->line_width; DEBUG ("starting to fill line", line, state); while (state->items) @@ -3398,10 +3473,10 @@ process_line (PangoLayout *layout, } done: - layout->is_wrapped = layout->is_wrapped || wrapped; + layout->is_wrapped |= wrapped; pango_layout_line_postprocess (line, state, wrapped); layout->lines = g_slist_prepend (layout->lines, line); - state->first_line = FALSE; + state->line_of_par++; state->line_start_index += line->length; state->line_start_offset = state->start_offset; } @@ -3637,8 +3712,8 @@ pango_layout_check_lines (PangoLayout *layout) if (state.items) { - state.first_line = TRUE; state.base_dir = base_dir; + state.line_of_par = 1; state.start_offset = start_offset; state.line_start_offset = start_offset; state.line_start_index = start - layout->text; @@ -3646,6 +3721,11 @@ pango_layout_check_lines (PangoLayout *layout) state.glyphs = NULL; state.log_widths = NULL; + /* for deterministic bug haunting's sake set everything! */ + state.line_width = -1; + state.remaining_width = -1; + state.log_widths_offset = 0; + while (state.items) process_line (layout, &state); } @@ -3746,7 +3826,7 @@ pango_layout_line_get_type (void) /** * pango_layout_line_x_to_index: * @line: a #PangoLayoutLine - * @x_pos: the X offset (in #PangoGlyphUnit) + * @x_pos: the X offset (in Pango units) * from the left edge of the line. * @index_: location to store calculated byte index for * the grapheme in which the user clicked. @@ -3970,7 +4050,7 @@ pango_layout_line_x_to_index (PangoLayoutLine *line, * with each range starting at <literal>(*ranges)[2*n]</literal> * and of width <literal>(*ranges)[2*n + 1] - (*ranges)[2*n]</literal>. * This array must be freed with g_free(). The coordinates are relative - * to the layout and are in #PangoGlyphUnit. + * to the layout and are in Pango units. * @n_ranges: The number of ranges stored in @ranges. * * Gets a list of visual ranges corresponding to a given logical range. @@ -4846,6 +4926,9 @@ justify_words (PangoLayoutLine *line, ADJUST } mode; + /* FIXME + * if ellipsized the current line, remaining_width is -1 so we + * end up not justifying the ellipsized line. */ total_remaining_width = state->remaining_width; if (total_remaining_width <= 0) return; @@ -4924,6 +5007,7 @@ pango_layout_line_postprocess (PangoLayoutLine *line, gboolean wrapped) { PangoLayoutRun *last_run = line->runs->data; + gboolean ellipsized = FALSE; /* NB: the runs are in reverse order at this point, since we prepended them to the list */ @@ -4936,8 +5020,12 @@ pango_layout_line_postprocess (PangoLayoutLine *line, /* Ellipsize the line if necessary */ - if (_pango_layout_line_ellipsize (line, state->attrs)) - line->layout->is_ellipsized = TRUE; + if (G_UNLIKELY (state->line_width >= 0 && + should_ellipsize_current_line (line->layout, state))) + { + ellipsized = _pango_layout_line_ellipsize (line, state->attrs, state->line_width); + line->layout->is_ellipsized |= ellipsized; + } /* Truncate the logical-final whitespace in the line if we broke the line at it */ @@ -4960,7 +5048,7 @@ pango_layout_line_postprocess (PangoLayoutLine *line, /* Distribute extra space between words if justifying and line was wrapped */ - if (wrapped && line->layout->justify) + if (line->layout->justify && (wrapped || ellipsized)) justify_words (line, state); DEBUG ("after justification", line, state); diff --git a/pango/pango-layout.h b/pango/pango-layout.h index 2deeedcf..108ce872 100644 --- a/pango/pango-layout.h +++ b/pango/pango-layout.h @@ -121,6 +121,9 @@ G_CONST_RETURN PangoFontDescription *pango_layout_get_font_description (PangoLay void pango_layout_set_width (PangoLayout *layout, int width); int pango_layout_get_width (PangoLayout *layout); +void pango_layout_set_height (PangoLayout *layout, + int height); +int pango_layout_get_height (PangoLayout *layout); void pango_layout_set_wrap (PangoLayout *layout, PangoWrapMode wrap); PangoWrapMode pango_layout_get_wrap (PangoLayout *layout); diff --git a/pango/pango.def b/pango/pango.def index 985c03aa..69fe4651 100644 --- a/pango/pango.def +++ b/pango/pango.def @@ -221,6 +221,7 @@ EXPORTS pango_layout_get_ellipsize pango_layout_get_extents pango_layout_get_font_description + pango_layout_get_height pango_layout_get_indent pango_layout_get_iter pango_layout_get_justify @@ -281,6 +282,7 @@ EXPORTS pango_layout_set_auto_dir pango_layout_set_ellipsize pango_layout_set_font_description + pango_layout_set_height pango_layout_set_indent pango_layout_set_justify pango_layout_set_markup diff --git a/pango/pangowin32.c b/pango/pangowin32.c index 10809c7b..c7c27503 100644 --- a/pango/pangowin32.c +++ b/pango/pangowin32.c @@ -240,7 +240,7 @@ pango_win32_render (HDC hdc, guint16 *glyph_indexes; gint *dX; gint this_x; - PangoGlyphUnit start_x_offset, x_offset, next_x_offset, cur_y_offset; + gint start_x_offset, x_offset, next_x_offset, cur_y_offset; /* in Pango units */ g_return_if_fail (glyphs != NULL); @@ -278,7 +278,7 @@ pango_win32_render (HDC hdc, * rendered by one call to ExtTextOutW(). * * In order to minimize buildup of rounding errors, we keep track of - * where the glyphs should be rendered in PangoGlyphUnits, and round + * where the glyphs should be rendered in Pango units, and round * to pixels separately for each glyph, */ |