📄 pango-layout.c
字号:
/* Pango * pango-layout.c: High-level layout driver * * Copyright (C) 2000, 2001, 2006 Red Hat Software * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */#include <config.h>#include "pango-glyph.h" /* For pango_shape() */#include "pango-break.h"#include "pango-item.h"#include "pango-engine.h"#include "pango-impl-utils.h"#include "pango-glyph-item-private.h"#include <string.h>#include "pango-layout-private.h"typedef struct _Extents Extents;typedef struct _ItemProperties ItemProperties;typedef struct _ParaBreakState ParaBreakState;struct _Extents{ /* Vertical position of the line's baseline in layout coords */ int baseline; /* Line extents in layout coords */ PangoRectangle ink_rect; PangoRectangle logical_rect;};struct _ItemProperties{ PangoUnderline uline; gboolean strikethrough; gint rise; gint letter_spacing; gboolean shape_set; PangoRectangle *shape_ink_rect; PangoRectangle *shape_logical_rect;};struct _PangoLayoutIter{ PangoLayout *layout; GSList *line_list_link; PangoLayoutLine *line; /* If run is NULL, it means we're on a "virtual run" * at the end of the line with 0 width */ GSList *run_list_link; PangoLayoutRun *run; /* FIXME nuke this, just keep the link */ int index; /* list of Extents for each line in layout coordinates */ GSList *line_extents; GSList *line_extents_link; /* X position of the current run */ int run_x; /* Width of the current run */ int run_width; /* this run is left-to-right */ gboolean ltr; /* X position of the left side of the current cluster */ int cluster_x; /* The width of the current cluster */ int cluster_width; /* glyph offset to the current cluster start */ int cluster_start; /* first glyph in the next cluster */ int next_cluster_glyph; /* number of Unicode chars in current cluster */ int cluster_num_chars; /* visual position of current character within the cluster */ int character_position; /* the real width of layout */ int layout_width;};typedef struct _PangoLayoutLinePrivate PangoLayoutLinePrivate;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{ GObjectClass parent_class;};#define LINE_IS_VALID(line) ((line)->layout != NULL)#ifdef G_DISABLE_CHECKS#define ITER_IS_INVALID(iter) FALSE#else#define ITER_IS_INVALID(iter) G_UNLIKELY (check_invalid ((iter), G_STRLOC))static gbooleancheck_invalid (PangoLayoutIter *iter, const char *loc){ if (iter->line->layout == NULL) { g_warning ("%s: PangoLayout changed since PangoLayoutIter was created, iterator invalid", loc); return TRUE; } else { return FALSE; }}#endifstatic void pango_layout_clear_lines (PangoLayout *layout);static void pango_layout_check_lines (PangoLayout *layout);static PangoAttrList *pango_layout_get_effective_attributes (PangoLayout *layout);static PangoLayoutLine * pango_layout_line_new (PangoLayout *layout);static void pango_layout_line_postprocess (PangoLayoutLine *line, ParaBreakState *state, gboolean wrapped);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);static void pango_layout_get_empty_extents_at_index (PangoLayout *layout, int index, PangoRectangle *logical_rect);static void pango_layout_finalize (GObject *object);G_DEFINE_TYPE (PangoLayout, pango_layout, G_TYPE_OBJECT)static voidpango_layout_init (PangoLayout *layout){ layout->attrs = NULL; layout->font_desc = NULL; layout->text = NULL; layout->length = 0; layout->width = -1; layout->height = -1; layout->indent = 0; layout->alignment = PANGO_ALIGN_LEFT; layout->justify = FALSE; layout->auto_dir = TRUE; layout->log_attrs = NULL; layout->lines = NULL; layout->tab_width = -1; layout->unknown_glyphs_count = -1; layout->wrap = PANGO_WRAP_WORD; layout->is_wrapped = FALSE; layout->ellipsize = PANGO_ELLIPSIZE_NONE; layout->is_ellipsized = FALSE;}static voidpango_layout_class_init (PangoLayoutClass *klass){ GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = pango_layout_finalize;}static voidpango_layout_finalize (GObject *object){ PangoLayout *layout; layout = PANGO_LAYOUT (object); pango_layout_clear_lines (layout); if (layout->context) g_object_unref (layout->context); if (layout->attrs) pango_attr_list_unref (layout->attrs); g_free (layout->text); if (layout->font_desc) pango_font_description_free (layout->font_desc); if (layout->tabs) pango_tab_array_free (layout->tabs); G_OBJECT_CLASS (pango_layout_parent_class)->finalize (object);}/** * pango_layout_new: * @context: a #PangoContext * * Create a new #PangoLayout object with attributes initialized to * default values for a particular #PangoContext. * * Return value: the newly allocated #PangoLayout, with a reference * count of one, which should be freed with * g_object_unref(). **/PangoLayout *pango_layout_new (PangoContext *context){ PangoLayout *layout; g_return_val_if_fail (context != NULL, NULL); layout = g_object_new (PANGO_TYPE_LAYOUT, NULL); layout->context = context; g_object_ref (context); return layout;}/** * pango_layout_copy: * @src: a #PangoLayout * * Does a deep copy-by-value of the @src layout. The attribute list, * tab array, and text from the original layout are all copied by * value. * * Return value: the newly allocated #PangoLayout, with a reference * count of one, which should be freed with * g_object_unref(). **/PangoLayout*pango_layout_copy (PangoLayout *src){ PangoLayout *layout; g_return_val_if_fail (PANGO_IS_LAYOUT (src), NULL); layout = pango_layout_new (src->context); if (src->attrs) layout->attrs = pango_attr_list_copy (src->attrs); if (src->font_desc) layout->font_desc = pango_font_description_copy (src->font_desc); 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; layout->auto_dir = src->auto_dir; layout->alignment = src->alignment; layout->n_chars = src->n_chars; layout->tab_width = src->tab_width; if (src->tabs) layout->tabs = pango_tab_array_copy (src->tabs); layout->wrap = src->wrap; layout->ellipsize = src->ellipsize; layout->unknown_glyphs_count = -1; /* unknown_glyphs_count, is_wrapped, is_ellipsized, log_attrs, lines * fields are updated by check_lines */ return layout;}/** * pango_layout_get_context: * @layout: a #PangoLayout * * Retrieves the #PangoContext used for this layout. * * Return value: the #PangoContext for the layout. This does not * have an additional refcount added, so if you want to keep * a copy of this around, you must reference it yourself. **/PangoContext *pango_layout_get_context (PangoLayout *layout){ g_return_val_if_fail (layout != NULL, NULL); return layout->context;}/** * pango_layout_set_width: * @layout: a #PangoLayout. * @width: the desired width in Pango units, or -1 to indicate that no * wrapping or ellipsization should be performed. * * Sets the width to which the lines of the #PangoLayout should wrap or * ellipsized. The default value is -1: no width set. **/voidpango_layout_set_width (PangoLayout *layout, int width){ g_return_if_fail (layout != NULL); if (width != layout->width) { layout->width = width; pango_layout_clear_lines (layout); }}/** * pango_layout_get_width: * @layout: a #PangoLayout * * Gets the width to which the lines of the #PangoLayout should wrap. * * Return value: the width in Pango units, or -1 if no width set. **/intpango_layout_get_width (PangoLayout *layout){ g_return_val_if_fail (layout != NULL, 0); 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 omitted, * 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 is negative, it will be the (negative of) 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. * This behvaior may be changed in the future to act per layout instead of per * paragraph. File a bug against pango at <ulink * url="http://bugzilla.gnome.org/">http://bugzilla.gnome.org/</ulink> if your * code relies on this behavior. * * Height setting only has effect if a positive width is set on * @layout and ellipsization mode of @layout is not %PANGO_ELLIPSIZE_NONE. * The behavior is undefined if a height other than -1 is set and * ellipsization mode is set to %PANGO_ELLIPSIZE_NONE, and may change in the * future. * * Since: 1.20 **/voidpango_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 **/intpango_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 * * Sets the wrap mode; the wrap mode only has effect if a width * is set on the layout with pango_layout_set_width(). * To turn off wrapping, set the width to -1. **/voidpango_layout_set_wrap (PangoLayout *layout, PangoWrapMode wrap){ g_return_if_fail (PANGO_IS_LAYOUT (layout)); if (layout->wrap != wrap) { layout->wrap = wrap; if (layout->is_wrapped) pango_layout_clear_lines (layout); }}/** * pango_layout_get_wrap: * @layout: a #PangoLayout * * Gets the wrap mode for the layout. * * Use pango_layout_is_wrapped() to query whether any paragraphs * were actually wrapped. * * Return value: active wrap mode. **/PangoWrapModepango_layout_get_wrap (PangoLayout *layout){ g_return_val_if_fail (PANGO_IS_LAYOUT (layout), 0); return layout->wrap;}/**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -