Re: Word Underlining (mistakenly sent to gtk-devel first)



OK, I heard back from no one developers on this list but, I did hear
back from Damon Chaplin in regards to a similar email.  He sent me an
older version of his patch ( to gtk-i18n Subject: Patch to add word
underlining on 21 Oct 2002 19:42:00 +0100).  His patch had some
problems.  It seems to me where so much is alike between
PANGO_ATTR_UNDERLINE_WORD and PANG_ATTR_UNDERLINE that it should be done
this way.  I have reworked the Pango part of his patch (my original
work, nearly complete, is not available as I blew it away when I
realized Pango already had functionality used in this patch and didn't
need my silly hacks to handle parts of lines).  I have included his
original GTK patch for someone else to look at.  Basically, unless my
below query is answered by SIMPLIFY, any occurrence of checking for
_ATTR_UNDERLINE needs to also check for _ATTR_UNDERLINE_WORD

The only change I see as maybe necessary to my patch would be to set
PANGO_ATTR_UNDERLINE instead of _ATTR_UNDERLINE_WORD internally (much
how the _UNDERLINE_NONE is done) to allow simpler code paths elsewhere. 
Is this desired?

Thank you for your consideration of my rework of Damon Chaplin's patch. 
His understanding of how the various parts of Pango exceeded that of my
20 minutes of reading the code.

Other things I plan on doing (off a list he and I have):

 o Displaying invisible chars, like spaces, tabs, paragraph terminators.
 o Small caps for first n lines of paragraph.
 o Kerning - customizable kerning for particular character pairs.
 o Tracking - customizable for particular paragraphs.
 o Runarounds & shaped text boxes - would need to cooperate with
   higher-level code to determine where text can be placed on each line.
 o Leading - locking to a baseline grid.

Small caps for first n lines might be something to work in the app and
not the library.  The rest indeed seem to belong in the library.  Any
complaints or objections?  My next project will likely be the invisible
characters. After that, kerning.  I see this as a program asking for an
override in specific cases, not telling the library to always do xyz
when seeing abc.  After all, that is for the program to know.

Again, please carbon copy me as I can't handle much list volume at this
time.

Trever

P.S. I have since been thinking maybe Damon had the right idea.  I am
thinking about removing _ATTR_UNDERLINE_WORD and make underline styles
have WORD_SINGLE or SINGLE_WORD and DOUBLE_WORD.  This would make the
changes to other programs and libraries and even to the internals of
Pango simpler.

S.P.S.  I am also thinking it would indeed be better to have the
function that does all the work for this WORD UNDERLINING silently
rewrite it to use the older types for the same reason.

On Wed, 2003-10-22 at 01:06, Trever L. Adams wrote:
> Currently, I see Pango has the ability to do underlines, but it doesn't
> break for white-spaces (namely spaces, though tabs seem to be in there
> as well).  I am wanting to work on this to get this fixed.  I see adding
> the following enums:
> 
>   PANGO_ATTR_UNDERLINE_WORD,	/* PangoAttrInt - This doesn't underline
> whitespace */ to PangoAttrType;
> 
>   PANGO_UNDERLINE_SPECIAL       /* This should underline with a squigly
> bit for spell checking, etc. */ to PangoUnderline;
> 
> I am thinking of doing something like this: 
> 
> I plan on creating a structure similar to ink_rect that looks a bit like
> this:
> 
> struct _PangoRectangleList
> {
>   int x;
>   int y;
>   int width;
>   int height;
>   _PangoRectangleList *next
> };
> 
> Or, it could just be a wrapper struct, whichever is preffered (i.e.
> struct PRList { _PangoRectangle PangoRectangle; _PangoRectangle *next};
> 
*SNIP*
> 
> Please, carbon copy me as I am not on the list and I really desire to
> know these answers.
> 
> Also, is it too late to get these into 2.4 or whatever the next
> pango/gtk release will be?
> 
> Thank you,
> Trever Adams
> --
> "One Woman can make you fly like an eagle Another can give you the
> strength of a lion But only One in the cycle of life can fill your heart
> with wonder And the wisdom that you have known a singular joy." --
> Unknown
--
"...the measure of a man is what he will do for another man, knowing he
will get nothing in return." -- Unknown
--- gtktextdisplay.c.orig	Mon Oct 21 18:48:59 2002
+++ gtktextdisplay.c	Mon Oct 21 18:48:09 2002
@@ -258,6 +258,7 @@
       gint risen_y;
       gint shaped_width_pixels = 0;
       gboolean need_ink = FALSE;
+      PangoUnderline underline;
       
       tmp_list = tmp_list->next;
 
@@ -281,8 +282,21 @@
           fg_gc = render_state->fg_gc;
         }
       
-      if (appearance->underline != PANGO_UNDERLINE_NONE ||
-          appearance->strikethrough)
+      /* If word-underlining is used, check if this is a non-word run, in
+       * which case we don't display the underline. (Pango will already have
+       * made sure the text is split into word and non-word runs.)
+       */
+      underline = appearance->underline;
+      if (underline == PANGO_UNDERLINE_WORD && run->item->num_chars)
+	{
+	  const char *text = pango_layout_get_text (line->layout);
+	  gunichar ch= g_utf8_get_char (text + run->item->offset);
+
+	  if (!g_unichar_isgraph (ch))
+	    underline = PANGO_UNDERLINE_NONE;
+	}
+
+      if (underline != PANGO_UNDERLINE_NONE || appearance->strikethrough)
         need_ink = TRUE;
       
       if (appearance->is_text)
@@ -434,7 +448,7 @@
             g_assert_not_reached (); /* not a pixbuf or widget */
         }
 
-      switch (appearance->underline)
+      switch (underline)
         {
         case PANGO_UNDERLINE_NONE:
           break;
@@ -447,6 +461,7 @@
                          risen_y + 3);
           /* Fall through */
         case PANGO_UNDERLINE_SINGLE:
+        case PANGO_UNDERLINE_WORD:
           g_assert (need_ink);
           gdk_draw_line (drawable, fg_gc,
                          x + (x_off + ink_rect.x) / PANGO_SCALE - 1,
diff -ur pango-1.2.5.orig/pango/pango-attributes.c pango-1.2.5/pango/pango-attributes.c
--- pango-1.2.5.orig/pango/pango-attributes.c	2003-06-25 15:13:23.000000000 -0400
+++ pango-1.2.5/pango/pango-attributes.c	2003-10-23 04:23:10.885468774 -0400
@@ -555,7 +555,6 @@
   return (PangoAttribute *)result;
 }
 
-
 /**
  * pango_attr_underline_new:
  * @underline: the underline style.
@@ -578,6 +577,27 @@
 }
 
 /**
+ * pango_attr_underline_word_new:
+ * @underline-word: the underline-word style.
+ * 
+ * Create a new underline-word-style object.
+ * 
+ * Return value: the new #PangoAttribute.
+ **/
+PangoAttribute *
+pango_attr_underline_word_new (PangoUnderline underline)
+{
+  static const PangoAttrClass klass = {
+    PANGO_ATTR_UNDERLINE_WORD,
+    pango_attr_int_copy,
+    pango_attr_int_destroy,
+    pango_attr_int_equal
+  };
+
+  return pango_attr_int_new (&klass, (int)underline);
+}
+
+/**
  * pango_attr_strikethrough_new:
  * @strikethrough: %TRUE if the text should be struck-through.
  * 
diff -ur pango-1.2.5.orig/pango/pango-attributes.h pango-1.2.5/pango/pango-attributes.h
--- pango-1.2.5.orig/pango/pango-attributes.h	2002-12-10 18:45:26.000000000 -0500
+++ pango-1.2.5/pango/pango-attributes.h	2003-10-23 04:47:36.642539940 -0400
@@ -80,7 +80,8 @@
   PANGO_ATTR_STRIKETHROUGH,	/* PangoAttrInt */
   PANGO_ATTR_RISE,		/* PangoAttrInt */
   PANGO_ATTR_SHAPE,		/* PangoAttrShape */
-  PANGO_ATTR_SCALE              /* PangoAttrFloat */
+  PANGO_ATTR_SCALE,             /* PangoAttrFloat */
+  PANGO_ATTR_UNDERLINE_WORD	/* PangoAttrInt */
 } PangoAttrType;
 
 typedef enum {
@@ -174,6 +175,7 @@
 PangoAttribute *pango_attr_stretch_new       (PangoStretch                stretch);
 PangoAttribute *pango_attr_font_desc_new     (const PangoFontDescription *desc);
 PangoAttribute *pango_attr_underline_new     (PangoUnderline              underline);
+PangoAttribute *pango_attr_underline_word_new (PangoUnderline underline);
 PangoAttribute *pango_attr_strikethrough_new (gboolean                    strikethrough);
 PangoAttribute *pango_attr_rise_new          (int                         rise);
 PangoAttribute *pango_attr_shape_new         (const PangoRectangle       *ink_rect,
diff -ur pango-1.2.5.orig/pango/pango-context.c pango-1.2.5/pango/pango-context.c
--- pango-1.2.5.orig/pango/pango-context.c	2003-05-27 12:35:40.000000000 -0400
+++ pango-1.2.5/pango/pango-context.c	2003-10-23 03:59:55.000000000 -0400
@@ -385,6 +385,7 @@
   const char *p;
   const char *next;
   GList *result = NULL;
+  gboolean word_underline_on = FALSE, last_was_word_char = FALSE;
 
   PangoAnalysis *analyses;
 
@@ -435,10 +436,29 @@
     {
       PangoAnalysis *analysis = &analyses[i];
       PangoAnalysis *last_analysis = i > 0 ? &analyses[i-1] : 0;
+      gboolean need_new_item = FALSE;
       
       next = g_utf8_next_char (p);
       
-      if (i == 0 ||
+      if (word_underline_on)
+        {
+	  gboolean is_word_char;
+
+	  /* Check if we've just switched from a word char to a non-word
+	   * char, in which case we want to start a new run.
+	   */
+	  if (g_unichar_isgraph (g_utf8_get_char (p)))
+	    is_word_char = TRUE;
+	  else
+	    is_word_char = FALSE;
+
+	  if (is_word_char != last_was_word_char)
+	    need_new_item = TRUE;
+
+	  last_was_word_char = is_word_char;
+	}
+
+      if (i == 0 || need_new_item ||
 	  text_ucs4[i] == '\t' || text_ucs4[i-1] == '\t' ||
 	  embedding_levels[i] != embedding_levels[i-1] ||
 	  analysis->shape_engine != last_analysis->shape_engine ||
@@ -447,6 +467,8 @@
 	  analysis->language != last_analysis->language ||
 	  analysis->extra_attrs != last_analysis->extra_attrs)
 	{
+          GSList *tmp_list;
+
           /* assert that previous item got at least one char */
           g_assert (item == NULL || item->length > 0);
           g_assert (item == NULL || item->num_chars > 0);
@@ -478,6 +500,31 @@
 	  else
 	    item->analysis.extra_attrs = analysis->extra_attrs;
 
+	  word_underline_on = FALSE;
+	  for (tmp_list = item->analysis.extra_attrs; tmp_list;
+	       tmp_list = tmp_list->next)
+	    {
+	      PangoAttribute *attr = tmp_list->data;
+
+	      if (attr->klass->type == PANGO_ATTR_UNDERLINE_WORD)
+		{
+		  /* Set the flag to indicate word underlining is on, so we
+		   * look for word/non-word boundaries.
+		   */
+		  word_underline_on = TRUE;
+
+		  if (g_unichar_isgraph (g_utf8_get_char (p)))
+		    {
+		      last_was_word_char = TRUE;
+		    }
+		  else
+		    {
+		      last_was_word_char = FALSE;
+		      ((PangoAttrInt *)attr)->value = PANGO_UNDERLINE_NONE;
+		    }
+		}
+	    }
+
 	  result = g_list_prepend (result, item);
 	}
       else
diff -ur pango-1.2.5.orig/pango/pango.def pango-1.2.5/pango/pango.def
--- pango-1.2.5.orig/pango/pango.def	2001-11-23 08:12:51.000000000 -0500
+++ pango-1.2.5/pango/pango.def	2003-10-23 04:48:09.455938138 -0400
@@ -31,6 +31,7 @@
 	pango_attr_type_get_type
 	pango_attr_type_register
 	pango_attr_underline_new
+	pango_attr_underline_word_new
 	pango_attr_variant_new
 	pango_attr_weight_new
 	pango_attribute_copy
diff -ur pango-1.2.5.orig/pango/pango-enum-types.c pango-1.2.5/pango/pango-enum-types.c
--- pango-1.2.5.orig/pango/pango-enum-types.c	2003-07-24 15:12:13.000000000 -0400
+++ pango-1.2.5/pango/pango-enum-types.c	2003-10-23 04:46:35.001065007 -0400
@@ -26,6 +26,7 @@
       { PANGO_ATTR_RISE, "PANGO_ATTR_RISE", "rise" },
       { PANGO_ATTR_SHAPE, "PANGO_ATTR_SHAPE", "shape" },
       { PANGO_ATTR_SCALE, "PANGO_ATTR_SCALE", "scale" },
+      { PANGO_ATTR_UNDERLINE_WORD, "PANGO_ATTR_UNDERLINE_WORD", "underline-word" }
       { 0, NULL, NULL }
     };
     etype = g_enum_register_static ("PangoAttrType", values);
diff -ur pango-1.2.5.orig/pango/pangoft2.c pango-1.2.5/pango/pangoft2.c
--- pango-1.2.5.orig/pango/pangoft2.c	2003-08-08 13:05:05.000000000 -0400
+++ pango-1.2.5/pango/pangoft2.c	2003-10-23 04:06:28.419740064 -0400
@@ -1009,6 +1009,7 @@
       switch (attr->klass->type)
 	{
 	case PANGO_ATTR_UNDERLINE:
+	case PANGO_ATTR_UNDERLINE_WORD:
 	  if (uline)
 	    *uline = ((PangoAttrInt *)attr)->value;
 	  break;
diff -ur pango-1.2.5.orig/pango/pango-layout.c pango-1.2.5/pango/pango-layout.c
--- pango-1.2.5.orig/pango/pango-layout.c	2003-06-25 15:13:23.000000000 -0400
+++ pango-1.2.5/pango/pango-layout.c	2003-10-23 04:07:20.269012873 -0400
@@ -2873,7 +2873,8 @@
     PANGO_ATTR_BACKGROUND,
     PANGO_ATTR_UNDERLINE,
     PANGO_ATTR_STRIKETHROUGH,
-    PANGO_ATTR_RISE
+    PANGO_ATTR_RISE,
+    PANGO_ATTR_UNDERLINE_WORD
   };
 
   int i;
@@ -3882,6 +3883,7 @@
       switch (attr->klass->type)
 	{
 	case PANGO_ATTR_UNDERLINE:
+	case PANGO_ATTR_UNDERLINE_WORD:
 	  if (uline)
 	    *uline = ((PangoAttrInt *)attr)->value;
 	  break;
diff -ur pango-1.2.5.orig/pango/pango-markup.c pango-1.2.5/pango/pango-markup.c
--- pango-1.2.5.orig/pango/pango-markup.c	2002-07-02 13:15:22.000000000 -0400
+++ pango-1.2.5/pango/pango-markup.c	2003-10-23 04:57:59.918245671 -0400
@@ -152,6 +152,12 @@
                                      const gchar         **values,
                                      GMarkupParseContext  *context,
                                      GError              **error);
+static gboolean uw_parse_func        (MarkupData           *md,
+                                     OpenTag              *tag,
+                                     const gchar         **names,
+                                     const gchar         **values,
+                                     GMarkupParseContext  *context,
+                                     GError              **error);
 
 static double
 scale_factor (int scale_level, double base)
@@ -369,6 +375,11 @@
       if (strcmp ("u", element_name) == 0)
         parse_func = u_parse_func;
       break;
+
+    case 'uw':
+      if (strcmp ("uw", element_name) == 0)
+        parse_func = uw_parse_func;
+      break;
     }
 
   if (parse_func == NULL)
@@ -851,6 +862,7 @@
   const char *foreground = NULL;
   const char *background = NULL;
   const char *underline = NULL;
+  const char *underline_word = NULL;
   const char *strikethrough = NULL;
   const char *rise = NULL;
   const char *lang = NULL;
@@ -913,6 +925,11 @@
           CHECK_DUPLICATE (underline);
           underline = values[i];
         }
+      else if (strcmp (names[i], "underline_word") == 0)
+        {
+          CHECK_DUPLICATE (underline_word);
+          underline = values[i];
+        }
       else if (strcmp (names[i], "strikethrough") == 0)
         {
           CHECK_DUPLICATE (strikethrough);
@@ -1151,6 +1168,34 @@
       add_attribute (tag, pango_attr_underline_new (ul));
     }
 
+  else if (underline_word)
+    {
+      PangoUnderline ul = PANGO_UNDERLINE_NONE;
+
+      if (strcmp (underline_word, "single") == 0)
+        ul = PANGO_UNDERLINE_SINGLE;
+      else if (strcmp (underline_word, "double") == 0)
+        ul = PANGO_UNDERLINE_DOUBLE;
+      else if (strcmp (underline_word, "low") == 0)
+        ul = PANGO_UNDERLINE_LOW;
+      else if (strcmp (underline_word, "none") == 0)
+        ul = PANGO_UNDERLINE_NONE;
+      else
+        {
+          g_set_error (error,
+                       G_MARKUP_ERROR,
+                       G_MARKUP_ERROR_INVALID_CONTENT,
+                       _("'%s' is not a valid value for the 'underline' "
+                         "attribute on <span> tag, line %d; valid "
+                         "values are for example 'single', "
+                         "'double', 'low', 'none'"),
+                       underline_word, line_number);
+          goto error;
+        }
+
+      add_attribute (tag, pango_attr_underline_word_new (ul));
+    }
+
   if (strikethrough)
     {
       if (strcmp (strikethrough, "true") == 0)
@@ -1331,3 +1376,17 @@
 
   return TRUE;
 }
+
+static gboolean
+uw_parse_func        (MarkupData            *md,
+                     OpenTag               *tag,
+                     const gchar          **names,
+                     const gchar          **values,
+                     GMarkupParseContext   *context,
+                     GError               **error)
+{
+  CHECK_NO_ATTRS("uw");
+  add_attribute (tag, pango_attr_underline_word_new (PANGO_UNDERLINE_SINGLE));
+
+  return TRUE;
+}
diff -ur pango-1.2.5.orig/pango/pangowin32.c pango-1.2.5/pango/pangowin32.c
--- pango-1.2.5.orig/pango/pangowin32.c	2003-08-08 13:05:05.000000000 -0400
+++ pango-1.2.5/pango/pangowin32.c	2003-10-23 04:07:51.814719433 -0400
@@ -909,6 +909,7 @@
       switch (attr->klass->type)
 	{
 	case PANGO_ATTR_UNDERLINE:
+	case PANGO_ATTR_UNDERLINE_WORD:
 	  if (uline)
 	    *uline = ((PangoAttrInt *)attr)->value;
 	  break;
diff -ur pango-1.2.5.orig/pango/pangox.c pango-1.2.5/pango/pangox.c
--- pango-1.2.5.orig/pango/pangox.c	2003-05-27 16:13:46.000000000 -0400
+++ pango-1.2.5/pango/pangox.c	2003-10-23 04:08:31.181113569 -0400
@@ -1732,6 +1732,7 @@
       switch (attr->klass->type)
 	{
 	case PANGO_ATTR_UNDERLINE:
+	case PANGO_ATTR_UNDERLINE_WORD:
 	  if (uline)
 	    *uline = ((PangoAttrInt *)attr)->value;
 	  break;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]