[gnome-characters/wip/dueno/font-features: 2/2] Respect OpenType font features



commit 5bde7a3bbcd2a564a03e07c7efe54f3a7efdfbec
Author: Daiki Ueno <dueno src gnome org>
Date:   Mon Aug 17 18:23:59 2015 +0900

    Respect OpenType font features

 configure.ac         |    3 +-
 data/application.css |    2 +-
 data/character.ui    |    6 ++--
 lib/gc.c             |   56 ++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/gc.h             |    5 ++++
 src/character.js     |   40 ++++++++++++++++++++++++++++++++---
 src/characterList.js |   17 ++++++++++----
 src/window.js        |    3 +-
 8 files changed, 117 insertions(+), 15 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 72e30a6..c3be601 100644
--- a/configure.ac
+++ b/configure.ac
@@ -40,7 +40,8 @@ PKG_CHECK_MODULES([DEPS], [gdk-3.0
                            glib-2.0
                            gobject-2.0
                            gtk+-3.0
-                           gjs-1.0 >= $GJS_MIN_VERSION])
+                           gjs-1.0 >= $GJS_MIN_VERSION
+                           harfbuzz >= 1.0.0])
 
 AC_PATH_PROG([GJS],[gjs])
 
diff --git a/data/application.css b/data/application.css
index 8047ea3..cde8c87 100644
--- a/data/application.css
+++ b/data/application.css
@@ -28,7 +28,7 @@ Gjs_MenuPopover .list-row {
     background-color: rgb(255, 255, 255);
 }
 
-.character-label {
+.character-button {
     font-size: 7em;
     font-weight: bold;
 }
diff --git a/data/character.ui b/data/character.ui
index b123d76..861ef37 100644
--- a/data/character.ui
+++ b/data/character.ui
@@ -17,14 +17,14 @@
                <property name="orientation">vertical</property>
                <property name="row_spacing">50</property>
                <child>
-                 <object class="GtkLabel" id="character-label">
+                 <object class="GtkButton" id="character-button">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
-                   <property name="ellipsize">end</property>
                    <property name="halign">center</property>
                    <property name="valign">center</property>
+                   <property name="relief">none</property>
                    <style>
-                     <class name="character-label"/>
+                     <class name="character-button"/>
                    </style>
                  </object>
                  <packing>
diff --git a/lib/gc.c b/lib/gc.c
index 9f4e3be..d14b293 100644
--- a/lib/gc.c
+++ b/lib/gc.c
@@ -17,6 +17,8 @@
 
 #define PANGO_ENABLE_ENGINE 1
 #include <pango/pangofc-font.h>
+#include <harfbuzz/hb-ft.h>
+#include <harfbuzz/hb-ot.h>
 
 static const uc_block_t *all_blocks;
 static size_t all_block_count;
@@ -926,6 +928,60 @@ gc_pango_context_font_has_glyph (PangoContext *context,
   return retval == 0;
 }
 
+void
+gc_pango_layout_set_font_features (PangoLayout *layout, gchar *features)
+{
+  PangoAttrList *attr_list;
+
+  attr_list = pango_layout_get_attributes (layout);
+  if (!attr_list)
+    {
+      attr_list = pango_attr_list_new ();
+      pango_layout_set_attributes (layout, attr_list);
+    }
+  pango_attr_list_insert (attr_list, pango_attr_font_features_new (features));
+}
+
+/**
+ * gc_pango_list_font_features:
+ * @font: a #PangoFont
+ *
+ * Returns: (transfer full) (nullable) (array zero-terminated=1): A
+ *   list of OpenType feature tags.
+ */
+gchar **
+gc_pango_list_font_features (PangoFont *font)
+{
+#ifdef HAVE_PANGOFT2
+  if (PANGO_IS_FC_FONT (font))
+    {
+      FT_Face ftface = pango_fc_font_lock_face (PANGO_FC_FONT (font));
+      hb_face_t *hbface = hb_ft_face_create_cached (ftface);
+      unsigned int count, i;
+      hb_tag_t *features;
+      gchar buf[5];
+      gchar **result;
+
+      count = hb_ot_layout_table_get_feature_tags (hbface, HB_OT_TAG_GSUB, 0,
+                                                  NULL, NULL);
+      features = g_new (hb_tag_t, count + 1);
+      hb_ot_layout_table_get_feature_tags (hbface, HB_OT_TAG_GSUB, 0,
+                                          &count, features);
+      result = g_new0 (gchar *, count + 1);
+      for (i = 0; i < count; i++)
+       {
+         buf[4] = '\0';
+         hb_tag_to_string (features[i], buf);
+         result[i] = g_strdup (buf);
+       }
+      g_free (features);
+      pango_fc_font_unlock_face (PANGO_FC_FONT (font));
+      return result;
+    }
+#endif
+  return NULL;
+}
+
 /**
  * gc_get_current_language:
  *
diff --git a/lib/gc.h b/lib/gc.h
index 688c3a3..8e1806f 100644
--- a/lib/gc.h
+++ b/lib/gc.h
@@ -72,6 +72,11 @@ GtkClipboard   *gc_gtk_clipboard_get      (void);
 /* Pango support.  PangoAttrFallback is not accessible from GI.  */
 void            gc_pango_layout_disable_fallback
                                           (PangoLayout          *layout);
+void            gc_pango_layout_set_font_features
+                                          (PangoLayout          *layout,
+                                          gchar                *features);
+gchar         **gc_pango_list_font_features
+                                          (PangoFont            *font);
 
 gboolean        gc_pango_context_font_has_glyph
                                           (PangoContext         *context,
diff --git a/src/character.js b/src/character.js
index d39e663..54e1716 100644
--- a/src/character.js
+++ b/src/character.js
@@ -21,6 +21,7 @@ const Params = imports.params;
 const Gio = imports.gi.Gio;
 const GLib = imports.gi.GLib;
 const GObject = imports.gi.GObject;
+const Gdk = imports.gi.Gdk;
 const Gtk = imports.gi.Gtk;
 const Pango = imports.gi.Pango;
 const Gc = imports.gi.Gc;
@@ -31,12 +32,13 @@ const CharacterDialog = new Lang.Class({
     Name: 'CharacterDialog',
     Extends: Gtk.Dialog,
     Template: 'resource:///org/gnome/Characters/character.ui',
-    InternalChildren: ['main-stack', 'character-label', 'detail-label',
+    InternalChildren: ['main-stack', 'character-button', 'detail-label',
                        'copy-button', 'related-listbox'],
 
     _init: function(params) {
         let filtered = Params.filter(params, { character: null,
-                                               fontDescription: null });
+                                               fontDescription: null,
+                                               fontFeatures: null });
         params = Params.fill(params, { use_header_bar: true,
                                        width_request: 400,
                                        height_request: 400 });
@@ -62,8 +64,38 @@ const CharacterDialog = new Lang.Class({
                     this._main_stack.visible_child_name = 'character';
             }));
 
-        this._character_label.override_font(filtered.fontDescription);
+        this._character_button.override_font(filtered.fontDescription);
         this._setCharacter(filtered.character);
+
+        this._fontFeatures = [];
+        let lastFeature = null;
+        let start = 0;
+        for (let index in filtered.fontFeatures) {
+            let feature = filtered.fontFeatures[index];
+            if (lastFeature == feature)
+                start++;
+            else {
+                start = 0;
+                lastFeature = feature;
+            }
+            this._fontFeatures.push('%s %d'.format(feature, start));
+        }
+        this._fontFeaturesIndex = 0;
+
+        this._character_button.connect('clicked', Lang.bind(this, this._characterLabelClicked));
+    },
+
+    _characterLabelClicked: function(event) {
+        if (this._fontFeatures.length == 0)
+            return;
+
+        this._fontFeaturesIndex =
+            (this._fontFeaturesIndex + 1) % this._fontFeatures.length;
+        let label = this._character_button.get_child();
+        label.set_attributes(null);
+        let layout = label.get_layout();
+        Gc.pango_layout_set_font_features(layout, this._fontFeatures[this._fontFeaturesIndex]);
+        print(this._fontFeatures[this._fontFeaturesIndex]);
     },
 
     _finishSearch: function(result) {
@@ -107,7 +139,7 @@ const CharacterDialog = new Lang.Class({
         this._character = uc;
 
         this._character = this._character;
-        this._character_label.label = this._character;
+        this._character_button.label = this._character;
 
         let codePoint = Util.toCodePoint(this._character);
         let codePointHex = codePoint.toString(16).toUpperCase();
diff --git a/src/characterList.js b/src/characterList.js
index 2f79f43..ba1a5af 100644
--- a/src/characterList.js
+++ b/src/characterList.js
@@ -317,20 +317,27 @@ const CharacterListView = new Lang.Class({
         return this._fontDescription;
     },
 
+    getFontFeatures: function() {
+        return this._fontFeatures;
+    },
+
     updateCharacterList: function() {
         let characters = this._characters;
-        let fontDescription = this._fontDescription;
+        let fontDescription = this._filterFontDescription ?
+            this._filterFontDescription : this._fontDescription;
+
+        let context = this.get_pango_context();
+        let font = context.load_font(fontDescription);
+        this._fontFeatures = Gc.pango_list_font_features(font);
+
         if (this._filterFontDescription) {
-            let context = this.get_pango_context();
-            let filterFont = context.load_font(this._filterFontDescription);
             let filteredCharacters = [];
             for (let index = 0; index < characters.length; index++) {
                 let uc = characters[index];
-                if (Gc.pango_context_font_has_glyph(context, filterFont, uc))
+                if (Gc.pango_context_font_has_glyph(context, font, uc))
                     filteredCharacters.push(uc);
             }
             characters = filteredCharacters;
-            fontDescription = this._filterFontDescription;
         }
 
         this._characterList.setFontDescription(fontDescription);
diff --git a/src/window.js b/src/window.js
index 4d4b8a9..b61fc23 100644
--- a/src/window.js
+++ b/src/window.js
@@ -349,7 +349,8 @@ const MainView = new Lang.Class({
             character: uc,
             modal: true,
             transient_for: this.get_toplevel(),
-            fontDescription: this.visible_child.getFontDescription()
+            fontDescription: this.visible_child.getFontDescription(),
+            fontFeatures: this.visible_child.getFontFeatures()
         });
 
         dialog.show();


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