After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 738505 - Add fontfeatures support in PangoAttributes and markup
Add fontfeatures support in PangoAttributes and markup
Status: RESOLVED FIXED
Product: pango
Classification: Platform
Component: general
unspecified
Other Linux
: Normal enhancement
: ---
Assigned To: pango-maint
pango-maint
: 460831 545510 (view as bug list)
Depends on:
Blocks:
 
 
Reported: 2014-10-14 06:57 UTC by Akira TAGOH
Modified: 2015-08-11 04:43 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Initial patch to check the behavior (10.62 KB, patch)
2015-03-10 10:52 UTC, Akira TAGOH
none Details | Review
Bug 738505 - Add fontfeatures support in PangoAttributes and markup (12.13 KB, patch)
2015-03-11 00:58 UTC, Matthias Clasen
none Details | Review
Add support for OpenType features in attributes and markup (9.08 KB, patch)
2015-03-11 20:19 UTC, Matthias Clasen
none Details | Review
Add support for OpenType features in attributes and markup (12.50 KB, patch)
2015-06-07 02:27 UTC, Matthias Clasen
none Details | Review

Description Akira TAGOH 2014-10-14 06:57:36 UTC
(I thought I filed an RFE for that but seems not)

Pango has supported fontfeatures with fontconfig though, no support in PangoAttributes. that is hard to accomplish addidng kinda font-features-setting with CSS in GTK+. also nice to see that on Pango markup as well.
Comment 1 Behdad Esfahbod 2014-10-14 22:33:31 UTC
There should be a bug for it already.  Anyway, yes, needs to be done.
Comment 2 Akira TAGOH 2015-03-10 10:52:36 UTC
Created attachment 298964 [details] [review]
Initial patch to check the behavior

That might needs to be polished but hope that would be a good start.
Comment 3 Matthias Clasen 2015-03-10 23:07:19 UTC
Review of attachment 298964 [details] [review]:

I think it would be nice to use the syntax from http://www.w3.org/TR/css3-fonts/#propdef-font-feature-setting

::: modules/basic/basic-fc.c
@@ +401,3 @@
+
+      for (tmp_attrs = analysis->extra_attrs; tmp_attrs; tmp_attrs = tmp_attrs->next)
+	{

features here is currently a fixed-size array of length 8, so you should probably terminate this loop if num_features gets too big, or arrange for features to grow.

::: pango/pango-attributes.h
@@ +422,3 @@
+  PangoAttribute attr;
+  gchar *tag;
+  gchar *value;

I think value could probably be an integer here.
Comment 4 Matthias Clasen 2015-03-11 00:58:00 UTC
Created attachment 299064 [details] [review]
Bug 738505 - Add fontfeatures support in PangoAttributes and markup
Comment 5 Matthias Clasen 2015-03-11 01:00:56 UTC
Here's a slight revision of your patch that has a few of the suggested changes:

- store feature attributes as tag+int value
- parse a syntax more like css: <span font_feature_settings="dlig on, vert off, c2sc, swsh 2">
- be careful about overrun of the features array
Comment 6 Matthias Clasen 2015-03-11 05:21:56 UTC
I've written a small demo app here:

https://git.gnome.org/browse/gtk+/log/?h=wip/matthiasc/font-features
Comment 7 Akira TAGOH 2015-03-11 07:46:14 UTC
Thanks. looks good to me. though I'm not sure how often "overrun" happens. think of complaint about dropping the feature tag without any warnings, maybe good to grow the array perhaps if tags was too many.
Comment 8 Behdad Esfahbod 2015-03-11 08:01:16 UTC
Let me review this quickly.
Comment 9 Matthias Clasen 2015-03-11 13:53:51 UTC
Akira, do you have any recommendations for free opentype fonts to test this with ?
Comment 10 Khaled Hosny 2015-03-11 18:37:28 UTC
Shouldn’t hb_feature_from_string() be used here as it already supports the CSS syntax?
Comment 11 Behdad Esfahbod 2015-03-11 18:44:02 UTC
(11:41:42 AM) Behdad Esfahbod: mclasen: 1. try to use hb api as khaled noted.  we'll make hb a hard requirement at some point.  in the mean time feel free to copy it.
(11:42:02 AM) Behdad Esfahbod: mclasen: 2. I was under the impression that every part of a layout can have only one attribute of each type
(11:42:11 AM) Behdad Esfahbod: that means you can't have multiple tag:value features.
(11:42:19 AM) mclasen: I just copied that tag function because I didn't want to fiddle with LDFLAGS
(11:42:23 AM) Behdad Esfahbod: my recommendation would be to make the PangoAttrFontFeatures take a string.
(11:42:34 AM) Behdad Esfahbod: and parse the string during shaping.
(11:42:39 AM) Behdad Esfahbod: we do that in android for example
(11:42:59 AM) Behdad Esfahbod: (and rename it to PangoAttrFontFeatureSettings or FontFeatures as opposed to just Features)
(11:43:11 AM) mclasen: hmm, then you get markup syntax issues bleed into the shaper
(11:43:23 AM) Behdad Esfahbod: no it's not a markup limitation
(11:43:31 AM) Behdad Esfahbod: it's a pango layout attributes afair
(11:43:34 AM) Behdad Esfahbod: maybe I'm wrong
(11:43:44 AM) Behdad Esfahbod: I'll check in a bit.  got to run right now.
Comment 12 Matthias Clasen 2015-03-11 19:41:32 UTC
(In reply to Khaled Hosny from comment #10)
> Shouldn’t hb_feature_from_string() be used here as it already supports the
> CSS syntax?

Sounds like a good idea. I wasn't aware of this API.
Comment 13 Matthias Clasen 2015-03-11 20:19:24 UTC
Created attachment 299130 [details] [review]
Add support for OpenType features in attributes and markup

This commit adds support for a font_features attribute in
Pango markup, and a new PangoAttributeFontFeatures attribute
to hold it. The syntax of the value is very similar to the
font-feature-settings CSS3 property: a comma-separated list
of font feature strings. The individual font features are
parsed with hb_feature_from_string().
Comment 14 Matthias Clasen 2015-03-11 20:20:26 UTC
Version 3, along the lines outlined in comment 11
Comment 15 Akira TAGOH 2015-03-12 06:39:06 UTC
(In reply to Matthias Clasen from comment #9)
> Akira, do you have any recommendations for free opentype fonts to test this
> with ?

I tested test-feature-tag.markup with IPAexGothic font which is included in ipa-ex-gothic-fonts package in Fedora.
Comment 16 Akira TAGOH 2015-03-12 06:43:25 UTC
Review of attachment 299130 [details] [review]:

::: pango/pango-attributes.c
@@ +1956,3 @@
 		  PangoAttribute *old_attr = tmp_list2->data;
+		  if (attr->klass->type == old_attr->klass->type &&
+		      attr->klass->type != PANGO_ATTR_FONT_FEATURES)

Given that we don't want to have multiple same attributes in the layout, we need to update here. particularly to append the feature tags if already there I think.
Comment 17 Matthias Clasen 2015-03-12 20:00:46 UTC
(In reply to Akira TAGOH from comment #16)
> Review of attachment 299130 [details] [review] [review]:
> 
> ::: pango/pango-attributes.c
> @@ +1956,3 @@
>  		  PangoAttribute *old_attr = tmp_list2->data;
> +		  if (attr->klass->type == old_attr->klass->type &&
> +		      attr->klass->type != PANGO_ATTR_FONT_FEATURES)
> 
> Given that we don't want to have multiple same attributes in the layout, we
> need to update here. particularly to append the feature tags if already
> there I think.

Looking at the way the other attributes are handled in that loop makes me believe that the intended semantics here is 'last one wins', while the current handling for font features is 'first on wins'. Not sure merging makes sense, given that we don't even parse the string here. Behdad ?

Clearly, this needs a) a comment explaining the expected semantics and b) tests.
Comment 18 Matthias Clasen 2015-03-12 20:31:23 UTC
never mind about 'last one wins' - I was wrong. But still, writing that merging code will not be trivial.
Comment 19 Akira TAGOH 2015-03-13 02:02:00 UTC
Sure. though there has never been attributes that have the same key and different values not conflicting each other. plus, we may need to take care of dropping duplicate tags perhaps so that there are limitations to the amount of features at this moment. repeating same tags becomes flowing the space with it.
Comment 20 Matthias Clasen 2015-03-13 12:39:24 UTC
I wrote some tests (testattributes.c) to understand how attribute lists actually work, wrt. to conflicts and priorities.

My takeaways:

- It would be somewhat silly to write 'merging' code for feature strings, when pango already handles all the merging and coalescing for attributes

- Currently, the resolution is entirely based on attribute type

I see a few options:

- Go back to parsing the feature string at markup parsing time, and teach pango
  that font feature attributes only conflict if their ot tag is different

- Register separate attributes per ot tag. This is hard because we need to
  allocate a separate class struct per type, and keep those somewhere

- Give up on proper merging of font features - they are most likely going to
  be used globally anyway
Comment 21 Matthias Clasen 2015-03-13 12:55:44 UTC
- Go back to parsing the feature string at markup parsing time, and teach pango
  that font feature attributes only conflict if their ot tag is different

Here I meant "is the same" of course
Comment 22 Behdad Esfahbod 2015-03-13 22:27:28 UTC
*** Bug 460831 has been marked as a duplicate of this bug. ***
Comment 23 Behdad Esfahbod 2015-03-13 22:38:56 UTC
So here is why I never added fontfeatures to pango, because, like you, I wanted to add it properly.  Note that CSS also has this deficiency, that is, you cannot add style attributes to a span to enable a font feature without clearing whatever features it was inheriting from its parent elements.

Note that pango-markup.c to some extent takes care of a similar problem, which happens with any markup that affects the PangoFontDescription.

One way to fix this is to add a new function to attribute types to "reduce" or "merge" two of them.  Then one would only need to join the two strings for font-feature-settings using ",".
Comment 24 Behdad Esfahbod 2015-03-13 22:44:17 UTC
This is relevant:

https://bugzilla.gnome.org/show_bug.cgi?id=446355

I see PangoAttrClass is public and has no room for a new merge() method.  One possibility is to add a new PangoAttrClassExtended version, and differentiate by using the high bit (or some other indicator) of the PangoAttrType.  Then add pango_attr_type_register_extended().

Then add pango_attribute_merge(a, b).  a and b should be of the same attr type.  If the attr type is extended and implements merge(), this would call merge on it, which should return a new attribute that has b merged on top of a.  If not, it returns a copy of b.  Not sure how to reduce the number of copies...

Then update pango_attr_list_change() to call merge() when an attribute exists already.
Comment 25 Matthias Clasen 2015-03-13 23:48:32 UTC
Looking at https://git.gnome.org/browse/pango/commit/?id=1eda6add15f4694372d0ebe1de7904045292c5ea, there is no splitting and merging of attribute ranges happening at all, so my v3 patch is probably the best we can do here. We'll have the same limitation as css: font-features are all-or-nothing, can't do partial inheritance. But it appears the change I cite above already made it so for all the font-related attributes anyway. Reverting that commit would be a prerequisite for doing any more intelligent merging and inheritance.
Comment 26 Akira TAGOH 2015-04-03 07:49:11 UTC
just for the reference, we have the fi ligature issue here:
  https://bugzilla.redhat.com/show_bug.cgi?id=1099829

Once this feature is merged, we should have "liga off" in the text entry by default.
Comment 27 Khaled Hosny 2015-04-03 11:20:06 UTC
(In reply to Akira TAGOH from comment #26)
> Once this feature is merged, we should have "liga off" in the text entry by
> default.

This will break fonts that rely on liga for proper shaping (many Arabic fonts do).
Comment 28 Behdad Esfahbod 2015-04-03 16:35:12 UTC
(In reply to Akira TAGOH from comment #26)
> just for the reference, we have the fi ligature issue here:
>   https://bugzilla.redhat.com/show_bug.cgi?id=1099829
> 
> Once this feature is merged, we should have "liga off" in the text entry by
> default.

That bug looks like a font or text rendering issue.  Even if it's not and ligatures are still not desirable in that particular case, they should be turned off there.  I don't see how that bug justifies disabling ligatures by default!  That would be unacceptable.
Comment 29 Matthias Clasen 2015-04-04 22:20:11 UTC
I don't see any reason to turn ligatures off, just because one user doesn't like them.
Comment 30 Behdad Esfahbod 2015-05-01 18:08:01 UTC
I might have a few hours to work on this today or tomorrow.  Matthias, do you have any more comments I should take into account while fixing this?  I don't have a full plan yet, but I guess I'll start by adding the merge thing and see how that would work.  Touching attr_list_change frightens me but it might not be as bad as I think...
Comment 31 Matthias Clasen 2015-05-01 20:17:28 UTC
no more comments from me
Comment 32 Behdad Esfahbod 2015-05-05 19:05:17 UTC
FWIW here's a pad from the OpenType features session at Libre Graphics Meeting 2015 in Toronto:

  http://piratepad.net/GprTYzpjgr
Comment 33 Behdad Esfahbod 2015-05-27 18:27:41 UTC
Comment on attachment 298964 [details] [review]
Initial patch to check the behavior

>From 281a0dec828220db19c02e73775bfbe0fcd0bbd6 Mon Sep 17 00:00:00 2001
>From: Akira TAGOH <akira@tagoh.org>
>Date: Tue, 10 Mar 2015 19:50:54 +0900
>Subject: [PATCH] Bug 738505 - Add fontfeatures support in PangoAttributes and
> markup
>
>https://bugzilla.gnome.org/show_bug.cgi?id=738505
>---
> modules/basic/basic-fc.c           | 22 +++++++++++++
> pango-view/test-feature-tag.markup | 65 +++++++++++++++++++++++++++++++++++++
> pango/pango-attributes.c           | 66 +++++++++++++++++++++++++++++++++++++-
> pango/pango-attributes.h           | 22 ++++++++++++-
> pango/pango-markup.c               | 22 +++++++++++++
> 5 files changed, 195 insertions(+), 2 deletions(-)
> create mode 100644 pango-view/test-feature-tag.markup
>
>diff --git a/modules/basic/basic-fc.c b/modules/basic/basic-fc.c
>index 93c4478..048939d 100644
>--- a/modules/basic/basic-fc.c
>+++ b/modules/basic/basic-fc.c
>@@ -28,6 +28,7 @@
> #define PANGO_ENABLE_BACKEND 1 /* XXX */
> 
> #include "pango-engine.h"
>+#include "pango-attributes.h"
> #include "pango-utils.h"
> #include "pangofc-fontmap.h"
> #include "pangofc-font.h"
>@@ -394,6 +395,27 @@ basic_engine_shape (PangoEngineShape    *engine G_GNUC_UNUSED,
> 	  num_features++;
> 	}
>     }
>+  if (analysis->extra_attrs)
>+    {
>+      GSList *tmp_attrs;
>+
>+      for (tmp_attrs = analysis->extra_attrs; tmp_attrs; tmp_attrs = tmp_attrs->next)
>+	{
>+	  if (((PangoAttribute *) tmp_attrs->data)->klass->type == PANGO_ATTR_FEATURE)
>+	    {
>+	      const PangoAttrFeature *fattr = (const PangoAttrFeature *) tmp_attrs->data;
>+	      gboolean f = g_ascii_strcasecmp (fattr->value, "1") == 0 ||
>+		g_ascii_strcasecmp (fattr->value, "true") == 0 ||
>+		g_ascii_strcasecmp (fattr->value, "yes") == 0 ? TRUE : FALSE;
>+
>+	      features[num_features].tag = hb_tag_from_string (fattr->tag, -1);
>+	      features[num_features].value =  f;
>+	      features[num_features].start = 0;
>+	      features[num_features].end = (unsigned int) -1;
>+	      num_features++;
>+	    }
>+	}
>+    }
> 
>   hb_shape (hb_font, hb_buffer, features, num_features);
> 
>diff --git a/pango-view/test-feature-tag.markup b/pango-view/test-feature-tag.markup
>new file mode 100644
>index 0000000..cc2ba1b
>--- /dev/null
>+++ b/pango-view/test-feature-tag.markup
>@@ -0,0 +1,65 @@
>+<span font_desc="IPAexGothic 8">
>+ASCII:
>+0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
>+Full Widths:
>+<span font_feature_settings="fwid=1">
>+0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
>+</span>
>+Half Widths:
>+ããããã«ã¬ã¼
>+<span font_feature_settings="hwid=1">ããããã«ã¬ã¼</span>
>+
>+Standard Ligatures:
>+<span font_desc="FreeSans 8">
>+<span font_feature_settings="liga=0">ffl fi</span>
>+ffl fi
>+</span>
>+
>+Discretionary Ligatures:
>+æ ªå¼ä¼ç¤¾
>+<span font_feature_settings="dlig=1">æ ªå¼ä¼ç¤¾</span>
>+
>+Discretionary Ligatures (+ Vertical Alternates)
>+æ ªå¼ä¼ç¤¾
>+<span font_feature_settings="vert=1,dlig=1">æ ªå¼ä¼ç¤¾</span>
>+
>+Vertical Alternates:
>+<span font_feature_settings="vert=1">ç§ã®ååã¯ä¸­éã§ãã</span>
>+
>+Fractions:
>+<span font_desc="Linux Libertine O 8">
>+1/1000
>+<span font_feature_settings="frac=1">1/1000</span>
>+</span>
>+
>+Traditional Forms:
>+äº
>+<span font_feature_settings="trad=1">äº</span>
>+
>+JIS X 0213:2000
>+<span font_feature_settings="jp90=1">
>+é¢è¦é£´æº¢è¨é°¯æ·«è¿å©åé¤è¥è¿¦çå»»æ¢æ¦è¹èééç¿°ç¿«å¾½
>+ç¥æ±²ç¸ç¬å¿é¥åå°æ«å±ç²ç¥éå¦æ²ç½éµè«ºå··æ¢èéµ çå
>+æ¦è©é¯é鮫é¤æç¼é楯è¯è·å¨éæèè¨éæºæ°çç½ç©¿ç®­
>+è©®åé¡æéè¿è¸è¾¿æ¨½æ­è¨»ç¦ææ§éè¾»æºé­æ¢æººå堵屠賭
>+çéè¬ç楢禰çé秤é§ç®¸åæ½èª¹æ¨ç¨é¼è¬¬è±¹å»çæ§è½ç¥
>+èç¯å¨©é­åºè¬é±è¿å²é¤ç±¾çºéæç·æ¼£çç°¾æ¦å±¢å¤åå¬å²
>+åå¾ææ£æ©ç¡çç¦ç¼ç¥ç«ç­µç¯è±èèèèè è¨éé±é¨é´
>+</span>
>+
>+JIS X 0213:2004
>+<span font_feature_settings="jp04=1">
>+é¢è¦é£´æº¢è¨é°¯æ·«è¿å©åé¤è¥è¿¦çå»»æ¢æ¦è¹èééç¿°ç¿«å¾½
>+ç¥æ±²ç¸ç¬å¿é¥åå°æ«å±ç²ç¥éå¦æ²ç½éµè«ºå··æ¢èéµ çå
>+æ¦è©é¯é鮫é¤æç¼é楯è¯è·å¨éæèè¨éæºæ°çç½ç©¿ç®­
>+è©®åé¡æéè¿è¸è¾¿æ¨½æ­è¨»ç¦ææ§éè¾»æºé­æ¢æººå堵屠賭
>+çéè¬ç楢禰çé秤é§ç®¸åæ½èª¹æ¨ç¨é¼è¬¬è±¹å»çæ§è½ç¥
>+èç¯å¨©é­åºè¬é±è¿å²é¤ç±¾çºéæç·æ¼£çç°¾æ¦å±¢å¤åå¬å²
>+åå¾ææ£æ©ç¡çç¦ç¼ç¥ç«ç­µç¯è±èèèèè è¨éé±é¨é´
>+</span>
>+
>+Alternate Annotation Forms:
>+CR+12345ä¸äºä¸æç«æ°´æ¨éåæ¥æ ªæ社å
>+<span font_feature_settings="nalt=1">CR+12345ä¸äºä¸æç«æ°´æ¨éåæ¥æ ªæ社å</span>
>+
>+</span>
>diff --git a/pango/pango-attributes.c b/pango/pango-attributes.c
>index 09dcbbd..4a69258 100644
>--- a/pango/pango-attributes.c
>+++ b/pango/pango-attributes.c
>@@ -1101,6 +1101,69 @@ pango_attr_gravity_hint_new (PangoGravityHint hint)
>   return pango_attr_int_new (&klass, (int)hint);
> }
> 
>+static PangoAttribute *
>+pango_attr_feature_copy (const PangoAttribute *attr)
>+{
>+  const PangoAttrFeature *fattr = (PangoAttrFeature *)attr;
>+
>+  return pango_attr_feature_new (fattr->tag,
>+				 fattr->value);
>+}
>+
>+static void
>+pango_attr_feature_destroy (PangoAttribute *attr)
>+{
>+  PangoAttrFeature *fattr = (PangoAttrFeature *)attr;
>+
>+  g_free (fattr->tag);
>+  g_free (fattr->value);
>+  g_slice_free (PangoAttrFeature, fattr);
>+}
>+
>+static gboolean
>+pango_attr_feature_equal (const PangoAttribute *attr1,
>+			  const PangoAttribute *attr2)
>+{
>+  const PangoAttrFeature *fattr1 = (const PangoAttrFeature *)attr1;
>+  const PangoAttrFeature *fattr2 = (const PangoAttrFeature *)attr2;
>+  gboolean f1 = g_ascii_strcasecmp (fattr1->value, "1") == 0 ||
>+		g_ascii_strcasecmp (fattr1->value, "true") == 0 ||
>+		g_ascii_strcasecmp (fattr1->value, "yes") == 0 ? TRUE : FALSE;
>+  gboolean f2 = g_ascii_strcasecmp (fattr2->value, "1") == 0 ||
>+		g_ascii_strcasecmp (fattr2->value, "true") == 0 ||
>+		g_ascii_strcasecmp (fattr2->value, "yes") == 0 ? TRUE : FALSE;
>+
>+  return g_ascii_strcasecmp (fattr1->tag, fattr2->tag) == 0 && f1 == f2;
>+}
>+
>+/**
>+ * pango_attr_feature_new:
>+ * @feature: a feature tag
>+ * @value: a value to set for a feature tag
>+ *
>+ * Create a new feature tag attribute.
>+ *
>+ * Return value: (transfer full): the newly allocated #PangoAttribute,
>+ *               which should be freed with pango_attribute_destroy().
>+ **/
>+PangoAttribute *
>+pango_attr_feature_new (const char *feature,
>+			const char *value)
>+{
>+  PangoAttrFeature *result = g_slice_new (PangoAttrFeature);
>+  static const PangoAttrClass klass = {
>+    PANGO_ATTR_FEATURE,
>+    pango_attr_feature_copy,
>+    pango_attr_feature_destroy,
>+    pango_attr_feature_equal
>+  };
>+
>+  pango_attribute_init (&result->attr, &klass);
>+  result->tag = g_strdup (feature);
>+  result->value = g_strdup (value);
>+
>+  return (PangoAttribute *)result;
>+}
> 
> /*
>  * Attribute List
>@@ -1931,7 +1994,8 @@ pango_attr_iterator_get_font (PangoAttrIterator     *iterator,
> 	      while (tmp_list2)
> 		{
> 		  PangoAttribute *old_attr = tmp_list2->data;
>-		  if (attr->klass->type == old_attr->klass->type)
>+		  if (attr->klass->type == old_attr->klass->type &&
>+		      attr->klass->type != PANGO_ATTR_FEATURE)
> 		    {
> 		      found = TRUE;
> 		      break;
>diff --git a/pango/pango-attributes.h b/pango/pango-attributes.h
>index 1e0feb7..d373419 100644
>--- a/pango/pango-attributes.h
>+++ b/pango/pango-attributes.h
>@@ -75,6 +75,7 @@ typedef struct _PangoAttrFloat    PangoAttrFloat;
> typedef struct _PangoAttrColor    PangoAttrColor;
> typedef struct _PangoAttrFontDesc PangoAttrFontDesc;
> typedef struct _PangoAttrShape    PangoAttrShape;
>+typedef struct _PangoAttrFeature  PangoAttrFeature;
> 
> /**
>  * PANGO_TYPE_ATTR_LIST:
>@@ -167,7 +168,8 @@ typedef enum
>   PANGO_ATTR_STRIKETHROUGH_COLOR,/* PangoAttrColor */
>   PANGO_ATTR_ABSOLUTE_SIZE,	/* PangoAttrSize */
>   PANGO_ATTR_GRAVITY,		/* PangoAttrInt */
>-  PANGO_ATTR_GRAVITY_HINT	/* PangoAttrInt */
>+  PANGO_ATTR_GRAVITY_HINT,	/* PangoAttrInt */
>+  PANGO_ATTR_FEATURE		/* PangoAttrFeature */
> } PangoAttrType;
> 
> /**
>@@ -406,6 +408,22 @@ struct _PangoAttrFontDesc
>   PangoFontDescription *desc;
> };
> 
>+/**
>+ * PangoAttrFeature:
>+ * @attr: the common portion of the attribute
>+ * @tag: the feature tag for OpenType
>+ * @value: the value to set for @tag
>+ *
>+ * The #PangoAttrFeature structure is used to represent attributes that
>+ * is the feature tag in OpenType.
>+ */
>+struct _PangoAttrFeature
>+{
>+  PangoAttribute attr;
>+  gchar *tag;
>+  gchar *value;
>+};
>+
> PangoAttrType         pango_attr_type_register (const gchar        *name);
> const char *          pango_attr_type_get_name (PangoAttrType       type) G_GNUC_CONST;
> 
>@@ -456,6 +474,8 @@ PangoAttribute *pango_attr_shape_new_with_data (const PangoRectangle       *ink_
> 
> PangoAttribute *pango_attr_gravity_new      (PangoGravity     gravity);
> PangoAttribute *pango_attr_gravity_hint_new (PangoGravityHint hint);
>+PangoAttribute *pango_attr_feature_new      (const char       *feature,
>+					     const char       *value);
> 
> GType              pango_attr_list_get_type      (void) G_GNUC_CONST;
> PangoAttrList *    pango_attr_list_new           (void);
>diff --git a/pango/pango-markup.c b/pango/pango-markup.c
>index c96c29e..acdee36 100644
>--- a/pango/pango-markup.c
>+++ b/pango/pango-markup.c
>@@ -1077,6 +1077,7 @@ span_parse_func     (MarkupData            *md G_GNUC_UNUSED,
>   const char *fallback = NULL;
>   const char *gravity = NULL;
>   const char *gravity_hint = NULL;
>+  char **features = NULL;
> 
>   g_markup_parse_context_get_position (context,
> 				       &line_number, &char_number);
>@@ -1090,6 +1091,13 @@ span_parse_func     (MarkupData            *md G_GNUC_UNUSED,
> 			 names[i], line_number, char_number);           \
> 	    return FALSE;                                               \
> 	  }}G_STMT_END
>+#define CHECK_ATTRIBUTE_ARRAY2(var, name)		\
>+	if (attr_strcmp (names[i], (name)) == 0) {	\
>+	  CHECK_DUPLICATE (var);			\
>+	  (var) = g_strsplit_set (values[i], " ,", -1);	\
>+	  found = TRUE;					\
>+	  break;					\
>+	}
> #define CHECK_ATTRIBUTE2(var, name) \
> 	if (attr_strcmp (names[i], (name)) == 0) { \
> 	  CHECK_DUPLICATE (var); \
>@@ -1120,6 +1128,7 @@ span_parse_func     (MarkupData            *md G_GNUC_UNUSED,
> 
> 	CHECK_ATTRIBUTE (foreground);
> 	CHECK_ATTRIBUTE2 (foreground, "fgcolor");
>+	CHECK_ATTRIBUTE_ARRAY2 (features, "font_feature_settings");
> 	break;
>       case 's':
> 	CHECK_ATTRIBUTE (size);
>@@ -1430,6 +1439,19 @@ span_parse_func     (MarkupData            *md G_GNUC_UNUSED,
>       add_attribute (tag,
> 		     pango_attr_language_new (pango_language_from_string (lang)));
>     }
>+  if (G_UNLIKELY (features))
>+    {
>+      gint i;
>+
>+      for (i = 0; features[i]; i++)
>+	{
>+	  gchar **v = g_strsplit (features[i], "=", 2);
>+	  if (v[0])
>+	    add_attribute (tag, pango_attr_feature_new (v[0], v[1]));
>+	  g_strfreev (v);
>+	}
>+      g_strfreev (features);
>+    }
> 
>   return TRUE;
> 
>-- 
>2.1.0
>
Comment 34 Matthias Clasen 2015-06-07 02:27:11 UTC
Created attachment 304721 [details] [review]
Add support for OpenType features in attributes and markup

This commit adds support for a font_features attribute in
Pango markup, and a new PangoAttributeFontFeatures attribute
to hold it. The syntax of the value is very similar to the
font-feature-settings CSS3 property: a comma-separated list
of font feature strings. The individual font features are
parsed with hb_feature_from_string().
Comment 35 Matthias Clasen 2015-06-07 02:27:52 UTC
Version 4, against git master.
Comment 36 Behdad Esfahbod 2015-06-12 23:19:24 UTC
*** Bug 545510 has been marked as a duplicate of this bug. ***
Comment 37 Behdad Esfahbod 2015-06-18 18:51:55 UTC
Committed!  Thanks everyone!

commit ba53f29f7c2c105becb898d6417a4c160b7fc1e5
Author: Behdad Esfahbod <behdad@behdad.org>
Date:   Thu Jun 18 11:49:40 2015 -0700

    Bug 738505 - Add fontfeatures support in PangoAttributes and markup
    
    https://bugzilla.gnome.org/show_bug.cgi?id=738505
    
    Patch from Matthias Clasen, based on early patch from Akira TAGOH.
    
    There's room for improvement in how this is done, but it works now
    for simple cases, which is what most people will be using it for.
    
    Finally!
Comment 38 Khaled Hosny 2015-06-20 14:35:52 UTC
The test-feature-tag.markup file is missing.
Comment 39 Behdad Esfahbod 2015-06-21 00:58:27 UTC
Pushed.  Thanks.
Comment 40 Krasnaya Ploshchad’ 2015-08-11 04:43:19 UTC
I think you should also create a page to illustrate the usage of OpenType feature in Pango, you can create this page through a grey link that can be found in this page:

http://www.pango.org/ScriptGallery