⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ellipsize.c

📁 GTK+-2.0源码之pango-1.15.6.tar.gz
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Pango * ellipsize.c: Routine to ellipsize layout lines * * Copyright (C) 2004 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 <string.h>#include "pango-glyph-item-private.h"#include "pango-layout-private.h"#include "pango-engine-private.h"typedef struct _EllipsizeState EllipsizeState;typedef struct _RunInfo        RunInfo;typedef struct _LineIter       LineIter;/* Overall, the way we ellipsize is we grow a "gap" out from an original * gap center position until: * *  line_width - gap_width + ellipsize_width <= goal_width * * Line:  [-------------------------------------------] * Runs:  [------)[---------------)[------------------] * Gap center:                 * * Gap:             [----------------------] * * The gap center may be at the start or end in which case the gap grows * in only one direction. * * Note the line and last run are logically closed at the end; this allows * us to use a gap position at x=line_width and still have it be part of * of a run. * * We grow the gap out one "span" at a time, where a span is simply a * consecutive run of clusters that we can't interrupt with an ellipsis. * * When choosing whether to grow the gap at the start or the end, we * calculate the next span to remove in both directions and see which * causes the smaller increase in: * *  MAX (gap_end - gap_center, gap_start - gap_center) * * All computations are done using logical order; the ellipsization * process occurs before the runs are ordered into visual order. *//* Keeps information about a single run */struct _RunInfo{  PangoGlyphItem *run;  int start_offset;		/* Character offset of run start */  int width;			/* Width of run in Pango units */};/* Iterator to a position within the ellipsized line */struct _LineIter{  PangoGlyphItemIter run_iter;  int run_index;};/* State of ellipsization process */struct _EllipsizeState{  PangoLayout *layout;		/* Layout being ellipsized */  PangoAttrList *attrs;		/* Attributes used for itemization/shaping */  RunInfo *run_info;		/* Array of information about each run */  int n_runs;  int total_width;		/* Original width of line in Pango units */  int gap_center;		/* Goal for center of gap */  PangoGlyphItem *ellipsis_run;	/* Run created to hold ellipsis */  int ellipsis_width;		/* Width of ellipsis, in Pango units */  int ellipsis_is_cjk;		/* Whether the first character in the ellipsized				 * is wide; this triggers us to try to use a				 * mid-line ellipsis instead of a baseline				 */  PangoAttrIterator *line_start_attr; /* Cached PangoAttrIterator for the start of the run */  LineIter gap_start_iter;	/* Iteratator pointig to the first cluster in gap */  int gap_start_x;		/* x position of start of gap, in Pango units */  PangoAttrIterator *gap_start_attr; /* Attribute iterator pointing to a range containing				      * the first character in gap */  LineIter gap_end_iter;	/* Iterator pointing to last cluster in gap */  int gap_end_x;		/* x position of end of gap, in Pango units */};/* Compute global information needed for the itemization process */static voidinit_state (EllipsizeState  *state,	    PangoLayoutLine *line,	    PangoAttrList   *attrs){  GSList *l;  int i, j;  int start_offset;  state->layout = line->layout;  state->attrs = attrs;  state->n_runs = g_slist_length (line->runs);  state->run_info = g_new (RunInfo, state->n_runs);  start_offset = g_utf8_strlen (line->layout->text,				line->start_index);  state->total_width = 0;  for (l = line->runs, i = 0; l; l = l->next, i++)    {      PangoGlyphItem *run = l->data;      int width = 0;      for (j = 0; j < run->glyphs->num_glyphs; j++)	width += run->glyphs->glyphs[j].geometry.width;      state->run_info[i].run = run;      state->run_info[i].width = width;      state->run_info[i].start_offset = start_offset;      state->total_width += width;      start_offset += run->item->num_chars;    }  state->ellipsis_run = NULL;  state->ellipsis_is_cjk = FALSE;  state->line_start_attr = NULL;  state->gap_start_attr = NULL;}/* Cleanup memory allocation */static voidfree_state (EllipsizeState *state){  if (state->line_start_attr)    pango_attr_iterator_destroy (state->line_start_attr);  if (state->gap_start_attr)    pango_attr_iterator_destroy (state->gap_start_attr);  g_free (state->run_info);}/* Computes the width of a single cluster */static intget_cluster_width (LineIter *iter){  PangoGlyphItemIter *run_iter = &iter->run_iter;  PangoGlyphString *glyphs = run_iter->glyph_item->glyphs;  int width = 0;  int i;  if (run_iter->start_glyph < run_iter->end_glyph) /* LTR */    {      for (i = run_iter->start_glyph; i < run_iter->end_glyph; i++)	width += glyphs->glyphs[i].geometry.width;    }  else			                 /* RTL */    {      for (i = run_iter->start_glyph; i > run_iter->end_glyph; i--)	width += glyphs->glyphs[i].geometry.width;    }  return width;}/* Move forward one cluster. Returns %FALSE if we were already at the end */static gbooleanline_iter_next_cluster (EllipsizeState *state,			LineIter       *iter){  if (!_pango_glyph_item_iter_next_cluster (&iter->run_iter))    {      if (iter->run_index == state->n_runs - 1)	return FALSE;      else	{	  iter->run_index++;	  _pango_glyph_item_iter_init_start (&iter->run_iter,					     state->run_info[iter->run_index].run,					     state->layout->text);	}    }  return TRUE;}/* Move backward one cluster. Returns %FALSE if we were already at the end */static gbooleanline_iter_prev_cluster (EllipsizeState *state,			LineIter       *iter){  if (!_pango_glyph_item_iter_prev_cluster (&iter->run_iter))    {      if (iter->run_index == 0)	return FALSE;      else	{	  iter->run_index--;	  _pango_glyph_item_iter_init_end (&iter->run_iter,					   state->run_info[iter->run_index].run,					   state->layout->text);	}    }  return TRUE;}/* * An ellipsization boundary is defined by two things * * - Starts a cluster - forced by structure of code * - Starts a grapheme - checked here * * In the future we'd also like to add a check for cursive connectivity here. * This should be an addition to #PangoGlyphVisAttr * *//* Checks if there is a ellipsization boundary before the cluster @iter points to */static gbooleanstarts_at_ellipsization_boundary (EllipsizeState *state,				  LineIter       *iter){  RunInfo *run_info = &state->run_info[iter->run_index];  if (iter->run_iter.start_char == 0 && iter->run_index == 0)    return TRUE;  return state->layout->log_attrs[run_info->start_offset + iter->run_iter.start_char].is_cursor_position;}/* Checks if there is a ellipsization boundary after the cluster @iter points to */static gbooleanends_at_ellipsization_boundary (EllipsizeState *state,				LineIter       *iter){  RunInfo *run_info = &state->run_info[iter->run_index];  if (iter->run_iter.end_char == run_info->run->item->num_chars && iter->run_index == state->n_runs - 1)    return TRUE;  return state->layout->log_attrs[run_info->start_offset + iter->run_iter.end_char + 1].is_cursor_position;}/* Helper function to re-itemize a string of text */static PangoItem *itemize_text (EllipsizeState *state,	      const char     *text,	      PangoAttrList  *attrs){  GList *items;  PangoItem *item;  items = pango_itemize (state->layout->context, text, 0, strlen (text), attrs, NULL);  g_assert (g_list_length (items) == 1);  item = items->data;  g_list_free (items);  return item;}/* Shapes the ellipsis using the font and is_cjk information computed by * update_ellipsis_shape() from the first character in the gap. */static voidshape_ellipsis (EllipsizeState *state){  PangoAttrList *attrs = pango_attr_list_new ();  GSList *run_attrs;  PangoItem *item;  PangoGlyphString *glyphs;  GSList *l;  PangoAttribute *fallback;  const char *ellipsis_text;  int i;  /* Create/reset state->ellipsis_run   */  if (!state->ellipsis_run)    {      state->ellipsis_run = g_slice_new (PangoGlyphItem);      state->ellipsis_run->glyphs = pango_glyph_string_new ();      state->ellipsis_run->item = NULL;    }  if (state->ellipsis_run->item)    {      pango_item_free (state->ellipsis_run->item);      state->ellipsis_run->item = NULL;    }  /* Create an attribute list   */  run_attrs = pango_attr_iterator_get_attrs (state->gap_start_attr);  for (l = run_attrs; l; l = l->next)    {      PangoAttribute *attr = l->data;      attr->start_index = 0;      attr->end_index = G_MAXINT;      pango_attr_list_insert (attrs, attr);    }  g_slist_free (run_attrs);  fallback = pango_attr_fallback_new (FALSE);  fallback->start_index = 0;  fallback->end_index = G_MAXINT;  pango_attr_list_insert (attrs, fallback);  /* First try using a specific ellipsis character in the best matching font   */  if (state->ellipsis_is_cjk)    ellipsis_text = "\342\213\257";	/* U+22EF: MIDLINE HORIZONTAL ELLIPSIS, used for CJK */  else    ellipsis_text = "\342\200\246";	/* U+2026: HORIZONTAL ELLIPSIS */  item = itemize_text (state, ellipsis_text, attrs);  /* If that fails we use "..." in the first matching font   */  if (!item->analysis.font ||      !_pango_engine_shape_covers (item->analysis.shape_engine, item->analysis.font,				   item->analysis.language, g_utf8_get_char (ellipsis_text)))    {      pango_item_free (item);      /* Modify the fallback iter while it is inside the PangoAttrList; Don't try this at home       */      ((PangoAttrInt *)fallback)->value = TRUE;      ellipsis_text = "...";      item = itemize_text (state, ellipsis_text, attrs);    }  pango_attr_list_unref (attrs);  state->ellipsis_run->item = item;  /* Now shape   */  glyphs = state->ellipsis_run->glyphs;  pango_shape (ellipsis_text, strlen (ellipsis_text),	       &item->analysis, glyphs);  state->ellipsis_width = 0;  for (i = 0; i < glyphs->num_glyphs; i++)    state->ellipsis_width += glyphs->glyphs[i].geometry.width;}/* Helper function to advance a PangoAttrIterator to a particular * byte index. */static voidadvance_iterator_to (PangoAttrIterator *iter,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -