Commit 0946d48d authored by Behdad Esfahbod's avatar Behdad Esfahbod Committed by Behdad Esfahbod
Browse files

Bug 469313 – Add pango_layout_set_height() Bug 508179 – PangoGlyphUnit

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


svn path=/trunk/; revision=2542
parent 7f7dbc1e
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.
......
......@@ -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
......
......@@ -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>
......
......@@ -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)
......
......@@ -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;
}
......@@ -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
......
......@@ -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
......
......@@ -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)
......@@ -373,6 +376,66 @@ pango_layout_get_width (PangoLayout *layout)
return layout->width;
}
/**
* 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
......@@ -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);
......
......@@ -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);
......
......@@ -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
......
......@@ -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,
*/
......
Markdown is supported
0% or .