2711 lines
94 KiB
Diff
2711 lines
94 KiB
Diff
From e6bab7ab78c69d238a70a64e60963dd5a6711ffe Mon Sep 17 00:00:00 2001
|
|
From: Felix Yan <felixonmars@archlinux.org>
|
|
Date: Fri, 19 May 2017 12:13:04 +0900
|
|
Subject: [PATCH] Fix a typo in configure.ac
|
|
|
|
BUG=https://github.com/ibus/ibus/pull/1927
|
|
R=Shawn.P.Huang@gmail.com
|
|
|
|
Review URL: https://codereview.appspot.com/317640043
|
|
|
|
Patch from Felix Yan <felixonmars@archlinux.org>.
|
|
---
|
|
configure.ac | 2 +-
|
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
|
diff --git a/configure.ac b/configure.ac
|
|
index 219b89d..2cc96d1 100644
|
|
--- a/configure.ac
|
|
+++ b/configure.ac
|
|
@@ -727,7 +727,7 @@ Build options:
|
|
Enable surrounding-text $enable_surrounding_text
|
|
Enable libnotify $enable_libnotify
|
|
Enable Emoji dict $enable_emoji_dict
|
|
- Uicode Emoji directory $UNICODE_EMOJI_DIR
|
|
+ Unicode Emoji directory $UNICODE_EMOJI_DIR
|
|
CLDR annotation directory $EMOJI_ANNOTATION_DIR
|
|
Run test cases $enable_tests
|
|
])
|
|
--
|
|
2.9.3
|
|
|
|
From 4fe3050efa7335f82870fb1d5a1d170d20afc160 Mon Sep 17 00:00:00 2001
|
|
From: fujiwarat <takao.fujiwara1@gmail.com>
|
|
Date: Mon, 22 May 2017 12:04:28 +0900
|
|
Subject: [PATCH] configure: Change relative paths to absolute ones
|
|
|
|
BUG=https://github.com/ibus/ibus/issues/1926
|
|
R=Shawn.P.Huang@gmail.com
|
|
|
|
Review URL: https://codereview.appspot.com/322990043
|
|
---
|
|
configure.ac | 11 +++++++++++
|
|
1 file changed, 11 insertions(+)
|
|
|
|
diff --git a/configure.ac b/configure.ac
|
|
index 2cc96d1..cb48ad4 100644
|
|
--- a/configure.ac
|
|
+++ b/configure.ac
|
|
@@ -634,10 +634,21 @@ if test x"$enable_emoji_dict" = x"yes"; then
|
|
if test ! -f $UNICODE_EMOJI_DIR/emoji-test.txt ; then
|
|
AC_MSG_ERROR(Not found $UNICODE_EMOJI_DIR/emoji-test.txt. You can get \
|
|
the emoji files from http://www.unicode.org/Public/emoji/4.0/)
|
|
+ else
|
|
+ # POSIX SHELL has no ${FOO:0:1}
|
|
+ head=`echo "$UNICODE_EMOJI_DIR" | cut -c1`;
|
|
+ if test $head != "/" ; then
|
|
+ UNICODE_EMOJI_DIR=`realpath "$UNICODE_EMOJI_DIR"`
|
|
+ fi
|
|
fi
|
|
if test ! -f $EMOJI_ANNOTATION_DIR/en.xml ; then
|
|
AC_MSG_ERROR(Not found $EMOJI_ANNOTATION_DIR/en.xml. You can get \
|
|
https://github.com/fujiwarat/cldr-emoji-annotation)
|
|
+ else
|
|
+ head=`echo "$EMOJI_ANNOTATION_DIR" | cut -c1`;
|
|
+ if test $head != "/" ; then
|
|
+ EMOJI_ANNOTATION_DIR=`realpath "$EMOJI_ANNOTATION_DIR"`
|
|
+ fi
|
|
fi
|
|
enable_emoji_dict="yes (enabled, use --disable-emoji-dict to disable)"
|
|
fi
|
|
--
|
|
2.9.3
|
|
|
|
From 44d053577a6ac115f3fd3b7beb7bdd65da81aa64 Mon Sep 17 00:00:00 2001
|
|
From: fujiwarat <takao.fujiwara1@gmail.com>
|
|
Date: Wed, 24 May 2017 11:52:19 +0900
|
|
Subject: [PATCH] engine: Add Malay and Mongolian keymaps
|
|
|
|
R=Shawn.P.Huang@gmail.com
|
|
|
|
Review URL: https://codereview.appspot.com/325790043
|
|
---
|
|
engine/simple.xml.in | 22 ++++++++++++++++++++++
|
|
1 file changed, 22 insertions(+)
|
|
|
|
diff --git a/engine/simple.xml.in b/engine/simple.xml.in
|
|
index c08000f..f35d7a5 100644
|
|
--- a/engine/simple.xml.in
|
|
+++ b/engine/simple.xml.in
|
|
@@ -706,5 +706,27 @@
|
|
<icon>ibus-keyboard</icon>
|
|
<rank>1</rank>
|
|
</engine>
|
|
+ <engine>
|
|
+ <name>xkb:my::msa</name>
|
|
+ <language>ms</language>
|
|
+ <license>GPL</license>
|
|
+ <author>Peng Huang <shawn.p.huang@gmail.com></author>
|
|
+ <layout>my</layout>
|
|
+ <longname>Malay (Jawi)</longname>
|
|
+ <description>Malay (Jawi)</description>
|
|
+ <icon>ibus-keyboard</icon>
|
|
+ <rank>1</rank>
|
|
+ </engine>
|
|
+ <engine>
|
|
+ <name>xkb:mn::mon</name>
|
|
+ <language>mn</language>
|
|
+ <license>GPL</license>
|
|
+ <author>Peng Huang <shawn.p.huang@gmail.com></author>
|
|
+ <layout>mn</layout>
|
|
+ <longname>Mongolian</longname>
|
|
+ <description>Mongolian</description>
|
|
+ <icon>ibus-keyboard</icon>
|
|
+ <rank>1</rank>
|
|
+ </engine>
|
|
</engines>
|
|
</component>
|
|
--
|
|
2.9.3
|
|
|
|
From 081d09f1a927f459dacda3bcc59a1678ca2f9a95 Mon Sep 17 00:00:00 2001
|
|
From: fujiwarat <takao.fujiwara1@gmail.com>
|
|
Date: Mon, 29 May 2017 11:54:31 +0900
|
|
Subject: [PATCH] ui/gtk3: Emojier supports Ctrl-c,v,x and Ctrl-Shift-c
|
|
|
|
Ctrl-[c|v|x] copy, paste, or cut the emoji annotatons.
|
|
Ctrl-Shift-c copies the selected emoji.
|
|
Also Ctrl-Backspace is implemented to delete an annotation word.
|
|
Also updated ibus-emoji.7.in man page.
|
|
|
|
R=penghuang@google.com
|
|
|
|
Review URL: https://codereview.appspot.com/316650043
|
|
---
|
|
ui/gtk3/emojier.vala | 58 +++++++++++++++++++++++++++++++++++++++++++++++--
|
|
ui/gtk3/ibus-emoji.7.in | 11 ++++++++++
|
|
2 files changed, 67 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/ui/gtk3/emojier.vala b/ui/gtk3/emojier.vala
|
|
index d0d69ed..1d105fd 100644
|
|
--- a/ui/gtk3/emojier.vala
|
|
+++ b/ui/gtk3/emojier.vala
|
|
@@ -1392,7 +1392,26 @@ class IBusEmojier : Gtk.ApplicationWindow {
|
|
return true;
|
|
case Gdk.Key.BackSpace:
|
|
if (m_entry.get_text().len() > 0) {
|
|
- GLib.Signal.emit_by_name(m_entry, "backspace");
|
|
+ if ((modifiers & Gdk.ModifierType.CONTROL_MASK) != 0) {
|
|
+ GLib.Signal.emit_by_name(m_entry, "delete-from-cursor",
|
|
+ Gtk.DeleteType.WORD_ENDS, -1);
|
|
+ } else {
|
|
+ GLib.Signal.emit_by_name(m_entry, "backspace");
|
|
+ }
|
|
+ return true;
|
|
+ }
|
|
+ break;
|
|
+ case Gdk.Key.Delete:
|
|
+ case Gdk.Key.KP_Delete:
|
|
+ if (m_entry.get_text().len() > 0) {
|
|
+ if ((modifiers & Gdk.ModifierType.CONTROL_MASK) != 0) {
|
|
+ GLib.Signal.emit_by_name(m_entry, "delete-from-cursor",
|
|
+ Gtk.DeleteType.WORD_ENDS, 1);
|
|
+ } else {
|
|
+ GLib.Signal.emit_by_name(m_entry, "delete-from-cursor",
|
|
+ Gtk.DeleteType.CHARS, 1);
|
|
+ }
|
|
+ return true;
|
|
}
|
|
break;
|
|
case Gdk.Key.space:
|
|
@@ -1445,6 +1464,10 @@ class IBusEmojier : Gtk.ApplicationWindow {
|
|
if (key_press_cursor_home_end(keyval, modifiers))
|
|
return true;
|
|
break;
|
|
+ case Gdk.Key.Insert:
|
|
+ case Gdk.Key.KP_Insert:
|
|
+ GLib.Signal.emit_by_name(m_entry, "toggle-overwrite");
|
|
+ return true;
|
|
}
|
|
|
|
if ((modifiers & Gdk.ModifierType.CONTROL_MASK) != 0) {
|
|
@@ -1470,8 +1493,13 @@ class IBusEmojier : Gtk.ApplicationWindow {
|
|
return true;
|
|
break;
|
|
case Gdk.Key.u:
|
|
- if (key_press_escape())
|
|
+ if (m_entry.get_text().len() > 0) {
|
|
+ GLib.Signal.emit_by_name(m_entry,
|
|
+ "delete-from-cursor",
|
|
+ Gtk.DeleteType.PARAGRAPH_ENDS,
|
|
+ -1);
|
|
return true;
|
|
+ }
|
|
break;
|
|
case Gdk.Key.a:
|
|
if (m_entry.get_text().len() > 0) {
|
|
@@ -1479,6 +1507,32 @@ class IBusEmojier : Gtk.ApplicationWindow {
|
|
return true;
|
|
}
|
|
break;
|
|
+ case Gdk.Key.x:
|
|
+ if (m_entry.get_text().len() > 0) {
|
|
+ GLib.Signal.emit_by_name(m_entry, "cut-clipboard");
|
|
+ return true;
|
|
+ }
|
|
+ break;
|
|
+ case Gdk.Key.C:
|
|
+ case Gdk.Key.c:
|
|
+ if ((modifiers & Gdk.ModifierType.SHIFT_MASK) != 0) {
|
|
+ if (m_candidate_panel_is_visible) {
|
|
+ uint index = m_lookup_table.get_cursor_pos();
|
|
+ var text = m_lookup_table.get_candidate(index).text;
|
|
+ Gtk.Clipboard clipboard =
|
|
+ Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD);
|
|
+ clipboard.set_text(text, -1);
|
|
+ clipboard.store();
|
|
+ return true;
|
|
+ }
|
|
+ } else if (m_entry.get_text().len() > 0) {
|
|
+ GLib.Signal.emit_by_name(m_entry, "copy-clipboard");
|
|
+ return true;
|
|
+ }
|
|
+ break;
|
|
+ case Gdk.Key.v:
|
|
+ GLib.Signal.emit_by_name(m_entry, "paste-clipboard");
|
|
+ return true;
|
|
}
|
|
return false;
|
|
}
|
|
diff --git a/ui/gtk3/ibus-emoji.7.in b/ui/gtk3/ibus-emoji.7.in
|
|
index a5045f6..4ee8636 100644
|
|
--- a/ui/gtk3/ibus-emoji.7.in
|
|
+++ b/ui/gtk3/ibus-emoji.7.in
|
|
@@ -83,6 +83,17 @@ Move to the next or previous page in the emoji list.
|
|
\fBHead, End, Control-h or Control-e\fR
|
|
Select the first or last emoji on the list if an annotation is not typed.
|
|
Otherwise move the cursor to the head or end in the typed annotation.
|
|
+.TP
|
|
+\fBControl-u\fR
|
|
+Erase the typed annotation.
|
|
+.TP
|
|
+\fBControl-x or Control-v or Control-c\fR
|
|
+Cut the selected annotation to the clipboard with Control-x. Paste
|
|
+the contents of the clipboard into the annotation entry with Control-v.
|
|
+Copy the selected annotation to the clipboard with Control-c.
|
|
+.TP
|
|
+\fBControl-Shift-c\fR
|
|
+Copy the selected emoji to the clipboard.
|
|
|
|
.SH BUGS
|
|
If you find a bug, please report it at https://github.com/ibus/ibus/issues
|
|
--
|
|
2.9.3
|
|
|
|
From ad80999f5a10faee1a665a2232e1cf60be901cc8 Mon Sep 17 00:00:00 2001
|
|
From: fujiwarat <takao.fujiwara1@gmail.com>
|
|
Date: Mon, 29 May 2017 12:03:41 +0900
|
|
Subject: [PATCH] Make all emoji dicts for fully qualified
|
|
|
|
Currently only emoji-en.dict enables fully qualified since it imports
|
|
emoji-test.txt and it causes to hardly compare emojis between
|
|
emoji-en.dict and emoji-$lang.dict when m_show_emoji_variant
|
|
is enabled. E.g. U+1F3CC-FE0F-200D-2642-FE0F
|
|
Now emoji-$lang.dict also import emoji-test.txt and enables
|
|
fully qualified.
|
|
|
|
R=penghuang@google.com
|
|
|
|
Review URL: https://codereview.appspot.com/323860043
|
|
---
|
|
src/Makefile.am | 1 +
|
|
src/emoji-parser.c | 167 +++++++++++++++++++++++++++++++++++++++++++++------
|
|
src/ibusemoji.c | 2 +-
|
|
ui/gtk3/emojier.vala | 34 +++++------
|
|
4 files changed, 169 insertions(+), 35 deletions(-)
|
|
|
|
diff --git a/src/Makefile.am b/src/Makefile.am
|
|
index 27cd168..e7bc8be 100644
|
|
--- a/src/Makefile.am
|
|
+++ b/src/Makefile.am
|
|
@@ -263,6 +263,7 @@ dicts/emoji-en.dict: emoji-parser
|
|
--out $@; \
|
|
else \
|
|
$(builddir)/emoji-parser \
|
|
+ --unicode-emoji-dir $(UNICODE_EMOJI_DIR) \
|
|
--xml $(EMOJI_ANNOTATION_DIR)/$$f.xml \
|
|
$$xml_derived_option \
|
|
--out dicts/emoji-$$f.dict; \
|
|
diff --git a/src/emoji-parser.c b/src/emoji-parser.c
|
|
index 5e6155b..fe3e4ef 100644
|
|
--- a/src/emoji-parser.c
|
|
+++ b/src/emoji-parser.c
|
|
@@ -31,12 +31,20 @@
|
|
* ASCII emoji annotations are saved in ../data/annotations/en_ascii.xml
|
|
*/
|
|
|
|
+#ifdef HAVE_CONFIG_H
|
|
+#include <config.h>
|
|
+#endif
|
|
+
|
|
#include <glib.h>
|
|
|
|
#ifdef HAVE_JSON_GLIB1
|
|
#include <json-glib/json-glib.h>
|
|
#endif
|
|
|
|
+#ifdef HAVE_LOCALE_H
|
|
+#include <locale.h>
|
|
+#endif
|
|
+
|
|
#include <string.h>
|
|
|
|
#include "ibusemoji.h"
|
|
@@ -65,8 +73,73 @@ struct _EmojiData {
|
|
EmojiDataSearchType search_type;
|
|
};
|
|
|
|
+typedef struct _NoTransData NoTransData;
|
|
+struct _NoTransData {
|
|
+ const gchar *xml_file;
|
|
+ const gchar *xml_derived_file;
|
|
+ GSList *emoji_list;
|
|
+};
|
|
+
|
|
static gchar *unicode_emoji_version;
|
|
|
|
+
|
|
+static void
|
|
+init_annotations (IBusEmojiData *emoji,
|
|
+ gpointer user_data)
|
|
+{
|
|
+ g_return_if_fail (IBUS_IS_EMOJI_DATA (emoji));
|
|
+ ibus_emoji_data_set_annotations (emoji, NULL);
|
|
+ ibus_emoji_data_set_description (emoji, "");
|
|
+}
|
|
+
|
|
+static void
|
|
+check_no_trans (IBusEmojiData *emoji,
|
|
+ NoTransData *no_trans_data)
|
|
+{
|
|
+ const gchar *str = NULL;
|
|
+ g_return_if_fail (IBUS_IS_EMOJI_DATA (emoji));
|
|
+ if (ibus_emoji_data_get_annotations (emoji) != NULL)
|
|
+ return;
|
|
+ str = ibus_emoji_data_get_emoji (emoji);
|
|
+ if (g_getenv ("IBUS_EMOJI_PARSER_DEBUG") != NULL) {
|
|
+ gchar *basename = NULL;
|
|
+ if (no_trans_data->xml_file)
|
|
+ basename = g_path_get_basename (no_trans_data->xml_file);
|
|
+ else if (no_trans_data->xml_derived_file)
|
|
+ basename = g_path_get_basename (no_trans_data->xml_derived_file);
|
|
+ else
|
|
+ basename = g_strdup ("WRONG FILE");
|
|
+ g_warning ("Not found emoji %s in the file %s", str, basename);
|
|
+ g_free (basename);
|
|
+ }
|
|
+ no_trans_data->emoji_list =
|
|
+ g_slist_append (no_trans_data->emoji_list, g_strdup (str));
|
|
+}
|
|
+
|
|
+int
|
|
+strcmp_ibus_emoji_data_str (IBusEmojiData *emoji,
|
|
+ const gchar *str)
|
|
+{
|
|
+ g_return_val_if_fail (IBUS_IS_EMOJI_DATA (emoji), -1);
|
|
+ return g_strcmp0 (ibus_emoji_data_get_emoji (emoji), str);
|
|
+}
|
|
+
|
|
+static void
|
|
+delete_emoji_from_list (const gchar *str,
|
|
+ GSList **list)
|
|
+{
|
|
+ IBusEmojiData *emoji;
|
|
+
|
|
+ g_return_if_fail (list != NULL);
|
|
+ GSList *p = g_slist_find_custom (*list,
|
|
+ str,
|
|
+ (GCompareFunc)strcmp_ibus_emoji_data_str);
|
|
+ g_return_if_fail (p != NULL);
|
|
+ emoji = p->data;
|
|
+ *list = g_slist_remove (*list, emoji);
|
|
+ g_object_unref (emoji);
|
|
+}
|
|
+
|
|
static void
|
|
reset_emoji_element (EmojiData *data)
|
|
{
|
|
@@ -79,6 +152,13 @@ reset_emoji_element (EmojiData *data)
|
|
g_clear_pointer (&data->description, g_free);
|
|
}
|
|
|
|
+/**
|
|
+ * strcmp_novariant:
|
|
+ *
|
|
+ * Return 0 between non-fully-qualified and fully-qualified emojis.
|
|
+ * E.g. U+1F3CC-200D-2642 and U+1F3CC-FE0F-200D-2642-FE0F
|
|
+ * in case @a_variant or @b_variant == U+FE0F
|
|
+ */
|
|
gint
|
|
strcmp_novariant (const gchar *a,
|
|
const gchar *b,
|
|
@@ -86,40 +166,54 @@ strcmp_novariant (const gchar *a,
|
|
gunichar b_variant)
|
|
{
|
|
gint retval;
|
|
- gchar *p = NULL;
|
|
GString *buff = NULL;;
|
|
+ gchar *head = NULL;
|
|
+ gchar *p;
|
|
+ gchar *variant = NULL;
|
|
gchar *substr = NULL;
|
|
|
|
if (a_variant > 0) {
|
|
- if ((p = g_utf8_strchr (a, -1, a_variant)) != NULL) {
|
|
+ if (g_utf8_strchr (a, -1, a_variant) != NULL) {
|
|
buff = g_string_new (NULL);
|
|
- if (a != p) {
|
|
- substr = g_strndup (a, p - a);
|
|
- g_string_append (buff, substr);
|
|
- g_free (substr);
|
|
+ p = head = g_strdup (a);
|
|
+ while (*p != '\0') {
|
|
+ if ((variant = g_utf8_strchr (p, -1, a_variant)) == NULL) {
|
|
+ g_string_append (buff, p);
|
|
+ break;
|
|
+ }
|
|
+ if (p != variant) {
|
|
+ substr = g_strndup (p, variant - p);
|
|
+ g_string_append (buff, substr);
|
|
+ g_free (substr);
|
|
+ }
|
|
+ p = g_utf8_next_char (variant);
|
|
}
|
|
- p = g_utf8_next_char (p);
|
|
- if (*p != '\0')
|
|
- g_string_append (buff, p);
|
|
retval = g_strcmp0 (buff->str, b);
|
|
g_string_free (buff, TRUE);
|
|
+ g_free (head);
|
|
return retval;
|
|
} else {
|
|
return -1;
|
|
}
|
|
} else if (b_variant > 0) {
|
|
- if ((p = g_utf8_strchr (b, -1, b_variant)) != NULL) {
|
|
+ if (g_utf8_strchr (b, -1, b_variant) != NULL) {
|
|
buff = g_string_new (NULL);
|
|
- if (b != p) {
|
|
- substr = g_strndup (b, p - b);
|
|
- g_string_append (buff, substr);
|
|
- g_free (substr);
|
|
+ p = head = g_strdup (b);
|
|
+ while (*p != '\0') {
|
|
+ if ((variant = g_utf8_strchr (p, -1, b_variant)) == NULL) {
|
|
+ g_string_append (buff, p);
|
|
+ break;
|
|
+ }
|
|
+ if (p != variant) {
|
|
+ substr = g_strndup (p, variant - p);
|
|
+ g_string_append (buff, substr);
|
|
+ g_free (substr);
|
|
+ }
|
|
+ p = g_utf8_next_char (variant);
|
|
}
|
|
- p = g_utf8_next_char (p);
|
|
- if (*p != '\0')
|
|
- g_string_append (buff, p);
|
|
retval = g_strcmp0 (a, buff->str);
|
|
g_string_free (buff, TRUE);
|
|
+ g_free (head);
|
|
return retval;
|
|
} else {
|
|
return -1;
|
|
@@ -1117,6 +1211,12 @@ main (int argc, char *argv[])
|
|
GOptionContext *context;
|
|
GError *error = NULL;
|
|
GSList *list = NULL;
|
|
+ gboolean is_en = TRUE;
|
|
+
|
|
+#ifdef HAVE_LOCALE_H
|
|
+ /* To output emoji warnings. */
|
|
+ setlocale (LC_ALL, "");
|
|
+#endif
|
|
|
|
prgname = g_path_get_basename (argv[0]);
|
|
g_set_prgname (prgname);
|
|
@@ -1144,12 +1244,45 @@ main (int argc, char *argv[])
|
|
#endif
|
|
if (emoji_dir)
|
|
unicode_emoji_parse_dir (emoji_dir, &list);
|
|
+ if (list) {
|
|
+#define CHECK_IS_EN(file) if ((file)) { \
|
|
+ gchar *basename = g_path_get_basename ((file)); \
|
|
+ is_en = (g_ascii_strncasecmp (basename, "en.", 3) == 0) ? \
|
|
+ TRUE : FALSE; \
|
|
+ g_free (basename); \
|
|
+}
|
|
+
|
|
+ CHECK_IS_EN(xml_derived_file);
|
|
+ CHECK_IS_EN(xml_file);
|
|
+#undef CHECK_IS_EN
|
|
+
|
|
+ /* Use English emoji-test.txt to get fully-qualified. */
|
|
+ if (!is_en)
|
|
+ g_slist_foreach (list, (GFunc)init_annotations, NULL);
|
|
+ }
|
|
if (xml_file)
|
|
unicode_annotations_parse_xml_file (xml_file, &list, FALSE);
|
|
if (xml_derived_file)
|
|
unicode_annotations_parse_xml_file (xml_derived_file, &list, TRUE);
|
|
if (xml_ascii_file)
|
|
unicode_annotations_parse_xml_file (xml_ascii_file, &list, FALSE);
|
|
+ if (list != NULL && !is_en) {
|
|
+ /* If emoji-test.txt has an emoji but $lang.xml does not, clear it
|
|
+ * since the language dicts do not want English annotations.
|
|
+ */
|
|
+ NoTransData no_trans_data = {
|
|
+ xml_file,
|
|
+ xml_derived_file,
|
|
+ NULL
|
|
+ };
|
|
+ g_slist_foreach (list, (GFunc)check_no_trans, &no_trans_data);
|
|
+ if (no_trans_data.emoji_list) {
|
|
+ g_slist_foreach (no_trans_data.emoji_list,
|
|
+ (GFunc)delete_emoji_from_list,
|
|
+ &list);
|
|
+ g_slist_free_full (no_trans_data.emoji_list, g_free);
|
|
+ }
|
|
+ }
|
|
if (list != NULL && output)
|
|
ibus_emoji_data_save (output, list);
|
|
if (list != NULL && output_category)
|
|
diff --git a/src/ibusemoji.c b/src/ibusemoji.c
|
|
index d2e16c5..3d38c2a 100644
|
|
--- a/src/ibusemoji.c
|
|
+++ b/src/ibusemoji.c
|
|
@@ -29,7 +29,7 @@
|
|
#include "ibusinternal.h"
|
|
|
|
#define IBUS_EMOJI_DATA_MAGIC "IBusEmojiData"
|
|
-#define IBUS_EMOJI_DATA_VERSION (4)
|
|
+#define IBUS_EMOJI_DATA_VERSION (5)
|
|
|
|
enum {
|
|
PROP_0 = 0,
|
|
diff --git a/ui/gtk3/emojier.vala b/ui/gtk3/emojier.vala
|
|
index 1d105fd..95912bf 100644
|
|
--- a/ui/gtk3/emojier.vala
|
|
+++ b/ui/gtk3/emojier.vala
|
|
@@ -190,9 +190,6 @@ class IBusEmojier : Gtk.ApplicationWindow {
|
|
private const string EMOJI_CATEGORY_OTHERS = N_("Others");
|
|
private const unichar[] EMOJI_VARIANT_LIST = {
|
|
0x1f3fb, 0x1f3fc, 0x1f3fd, 0x1f3fe, 0x1f3ff, 0x200d };
|
|
- private const GLib.ActionEntry[] m_action_entries = {
|
|
- { "variant", check_action_variant_cb, null, "false", null }
|
|
- };
|
|
|
|
// Set the actual default values in the constructor
|
|
// because these fields are used for class_init() and static functions,
|
|
@@ -253,7 +250,13 @@ class IBusEmojier : Gtk.ApplicationWindow {
|
|
focus_visible : true
|
|
);
|
|
|
|
- add_action_entries(m_action_entries, this);
|
|
+ // GLib.ActionEntry accepts const variables only.
|
|
+ var action = new GLib.SimpleAction.stateful(
|
|
+ "variant",
|
|
+ null,
|
|
+ new GLib.Variant.boolean(m_show_emoji_variant));
|
|
+ action.activate.connect(check_action_variant_cb);
|
|
+ add_action(action);
|
|
if (m_current_lang_id == null)
|
|
m_current_lang_id = "en";
|
|
if (m_emoji_font_family == null)
|
|
@@ -521,18 +524,7 @@ class IBusEmojier : Gtk.ApplicationWindow {
|
|
m_emoji_to_data_dict.replace(emoji, data);
|
|
} else {
|
|
unowned IBus.EmojiData? en_data = null;
|
|
- // If emoji presentation (+= 0xfe0f) is already saved in dict,
|
|
- // update it instead of no presentation.
|
|
- // emoji-test.txt has all emoji presentations but $lang.xml has
|
|
- // some no emoji presentations.
|
|
- if (emoji.chr(-1, 0xfe0f) == null) {
|
|
- var buff = new GLib.StringBuilder();
|
|
- buff.append(emoji);
|
|
- buff.append_unichar(0xfe0f);
|
|
- en_data = m_emoji_to_data_dict.lookup(buff.str);
|
|
- }
|
|
- if (en_data == null)
|
|
- en_data = m_emoji_to_data_dict.lookup(emoji);
|
|
+ en_data = m_emoji_to_data_dict.lookup(emoji);
|
|
if (en_data == null) {
|
|
m_emoji_to_data_dict.insert(emoji, data);
|
|
return;
|
|
@@ -923,7 +915,12 @@ class IBusEmojier : Gtk.ApplicationWindow {
|
|
m_vbox.add(button);
|
|
button.show_all();
|
|
button.button_press_event.connect((w, e) => {
|
|
- hide_candidate_panel();
|
|
+ // Bring back to emoji candidate panel in case
|
|
+ // m_show_emoji_variant is enabled and shows variants.
|
|
+ if (m_backward_index >= 0 && m_backward != null)
|
|
+ show_emoji_for_category(m_backward);
|
|
+ else
|
|
+ hide_candidate_panel();
|
|
return true;
|
|
});
|
|
}
|
|
@@ -1269,6 +1266,9 @@ class IBusEmojier : Gtk.ApplicationWindow {
|
|
GLib.Variant? parameter) {
|
|
m_show_emoji_variant = !action.get_state().get_boolean();
|
|
action.set_state(new GLib.Variant.boolean(m_show_emoji_variant));
|
|
+ // Redraw emoji candidate panel for m_show_emoji_variant
|
|
+ if (m_candidate_panel_is_visible)
|
|
+ show_candidate_panel();
|
|
}
|
|
|
|
|
|
--
|
|
2.9.3
|
|
|
|
From e10a2e344a947c3125190bdd55bbb7d0f6bc188e Mon Sep 17 00:00:00 2001
|
|
From: fujiwarat <takao.fujiwara1@gmail.com>
|
|
Date: Thu, 13 Jul 2017 18:46:26 +0900
|
|
Subject: [PATCH] Integrate custom rendering to use HarfBuzz glyph info
|
|
|
|
IBusFontSet offers FcFontSet, glyph info with HarfBuzz and rendering
|
|
on Cairo context.
|
|
Current Pango changes fonts by emoji variants and draws the separated
|
|
glyphs [1] but actually the emoji characters with variants can be drawn
|
|
as one glyph so this class manages Fontconfig fontsets to select a font,
|
|
HarfBuzz to get glyphs for emoji variants, Cairo to draw glyphs.
|
|
Need configure --enable-harfbuzz-for-emoji option to enable this feature.
|
|
|
|
[1]: https://bugzilla.gnome.org/show_bug.cgi?id=780669
|
|
https://bugzilla.gnome.org/show_bug.cgi?id=781123
|
|
---
|
|
.../vala}/IBusEmojiDialog-1.0.metadata | 0
|
|
bindings/vala/IBusFontSet-1.0.metadata | 1 +
|
|
bindings/vala/Makefile.am | 244 +++++-
|
|
.../vala}/ibus-emoji-dialog-1.0.deps | 0
|
|
bindings/vala/ibus-fontset-1.0.deps | 1 +
|
|
configure.ac | 29 +
|
|
po/POTFILES.skip | 5 +
|
|
ui/gtk3/Makefile.am | 131 ++-
|
|
ui/gtk3/emojier.vala | 119 ++-
|
|
ui/gtk3/ibusemojidialog.h | 26 +
|
|
ui/gtk3/ibusfontset.c | 922 +++++++++++++++++++++
|
|
ui/gtk3/ibusfontset.h | 302 +++++++
|
|
12 files changed, 1674 insertions(+), 106 deletions(-)
|
|
rename {ui/gtk3 => bindings/vala}/IBusEmojiDialog-1.0.metadata (100%)
|
|
create mode 100644 bindings/vala/IBusFontSet-1.0.metadata
|
|
rename {ui/gtk3 => bindings/vala}/ibus-emoji-dialog-1.0.deps (100%)
|
|
create mode 100644 bindings/vala/ibus-fontset-1.0.deps
|
|
create mode 100644 ui/gtk3/ibusfontset.c
|
|
create mode 100644 ui/gtk3/ibusfontset.h
|
|
|
|
diff --git a/ui/gtk3/IBusEmojiDialog-1.0.metadata b/bindings/vala/IBusEmojiDialog-1.0.metadata
|
|
similarity index 100%
|
|
rename from ui/gtk3/IBusEmojiDialog-1.0.metadata
|
|
rename to bindings/vala/IBusEmojiDialog-1.0.metadata
|
|
diff --git a/bindings/vala/IBusFontSet-1.0.metadata b/bindings/vala/IBusFontSet-1.0.metadata
|
|
new file mode 100644
|
|
index 0000000..73037d7
|
|
--- /dev/null
|
|
+++ b/bindings/vala/IBusFontSet-1.0.metadata
|
|
@@ -0,0 +1 @@
|
|
+IBusFontSet cheader_filename="ibusfontset.h"
|
|
diff --git a/bindings/vala/Makefile.am b/bindings/vala/Makefile.am
|
|
index 4e34afc..261e1f3 100644
|
|
--- a/bindings/vala/Makefile.am
|
|
+++ b/bindings/vala/Makefile.am
|
|
@@ -3,7 +3,8 @@
|
|
# ibus - The Input Bus
|
|
#
|
|
# Copyright (c) 2007-2016 Peng Huang <shawn.p.huang@gmail.com>
|
|
-# Copyright (c) 2007-2016 Red Hat, Inc.
|
|
+# Copyright (c) 2017 Takao Fujiwara <takao.fujiwara1@gmail.com>
|
|
+# Copyright (c) 2007-2017 Red Hat, Inc.
|
|
#
|
|
# This library is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU Lesser General Public
|
|
@@ -22,15 +23,47 @@
|
|
|
|
-include $(VAPIGEN_MAKEFILE)
|
|
|
|
+libibus = $(top_builddir)/src/libibus-@IBUS_API_VERSION@.la
|
|
+
|
|
+noinst_LTLIBRARIES =
|
|
+noinst_DATA =
|
|
+INTROSPECTION_GIRS =
|
|
+girdir = $(datadir)/gir-1.0
|
|
+
|
|
+AM_CPPFLAGS = \
|
|
+ -I$(top_srcdir)/src \
|
|
+ -I$(top_builddir)/src \
|
|
+ -include $(CONFIG_HEADER) \
|
|
+ $(NULL)
|
|
+AM_CFLAGS = \
|
|
+ -DG_LOG_DOMAIN=\"IBUS\" \
|
|
+ -DPKGDATADIR=\"$(pkgdatadir)\" \
|
|
+ -DIBUS_DISABLE_DEPRECATED \
|
|
+ -Wno-unused-variable \
|
|
+ -Wno-unused-but-set-variable \
|
|
+ -Wno-unused-function \
|
|
+ $(NULL)
|
|
+AM_VALAFLAGS = \
|
|
+ --vapidir=$(builddir) \
|
|
+ --vapidir=$(srcdir) \
|
|
+ --pkg=posix \
|
|
+ --pkg=gtk+-3.0 \
|
|
+ --pkg=gdk-x11-3.0 \
|
|
+ --pkg=ibus-1.0 \
|
|
+ --pkg=config \
|
|
+ --pkg=xi \
|
|
+ --target-glib="$(VALA_TARGET_GLIB_VERSION)" \
|
|
+ $(NULL)
|
|
+
|
|
vapi_deps = \
|
|
IBus-1.0.metadata \
|
|
- IBus-1.0-custom.vala \
|
|
$(top_builddir)/src/IBus-1.0.gir \
|
|
$(NULL)
|
|
|
|
ibus-1.0.vapi: $(vapi_deps)
|
|
|
|
-VAPIGEN_VAPIS = ibus-1.0.vapi
|
|
+ibus_vapi = ibus-1.0.vapi
|
|
+VAPIGEN_VAPIS = $(ibus_vapi)
|
|
|
|
ibus_1_0_vapi_DEPS = gio-2.0
|
|
ibus_1_0_vapi_METADATADIRS = $(srcdir)
|
|
@@ -40,18 +73,201 @@ ibus_1_0_vapi_FILES = \
|
|
$(NULL)
|
|
|
|
vapidir = $(datadir)/vala/vapi
|
|
-vapi_DATA = $(VAPIGEN_VAPIS) $(VAPIGEN_VAPIS:.vapi=.deps)
|
|
+vapi_DATA = $(ibus_vapi) $(ibus_vapi:.vapi=.deps)
|
|
|
|
-MAINTAINERCLEANFILES = $(VAPIGEN_VAPIS)
|
|
-DISTCLEANFILES = $(VAPIGEN_VAPIS)
|
|
+MAINTAINERCLEANFILES = $(ibus_vapi)
|
|
+DISTCLEANFILES = $(ibus_vapi)
|
|
|
|
-EXTRA_DIST = \
|
|
- $(VAPIGEN_VAPIS) \
|
|
- IBus-1.0.metadata \
|
|
- IBus-1.0-custom.vala \
|
|
- ibus-1.0.deps \
|
|
- config.vapi \
|
|
- xi.vapi \
|
|
- $(NULL)
|
|
+EXTRA_DIST = \
|
|
+ $(ibus_vapi) \
|
|
+ IBus-1.0.metadata \
|
|
+ IBus-1.0-custom.vala \
|
|
+ IBusEmojiDialog-1.0.metadata \
|
|
+ IBusFontSet-1.0.metadata \
|
|
+ ibus-1.0.deps \
|
|
+ ibus-emoji-dialog-1.0.deps \
|
|
+ ibus-fontset-1.0.deps \
|
|
+ config.vapi \
|
|
+ xi.vapi \
|
|
+ $(NULL)
|
|
+
|
|
+if ENABLE_EMOJI_DICT
|
|
+AM_VALAFLAGS += --define=EMOJI_DICT
|
|
+
|
|
+libibus_emoji_dialog = libibus-emoji-dialog-1.0.la
|
|
+noinst_LTLIBRARIES += $(libibus_emoji_dialog)
|
|
+
|
|
+libibus_emoji_dialog_1_0_la_SOURCES = \
|
|
+ candidatearea.vala \
|
|
+ emojier.vala \
|
|
+ iconwidget.vala \
|
|
+ pango.vala \
|
|
+ separator.vala \
|
|
+ $(NULL)
|
|
+libibus_emoji_dialog_1_0_la_CFLAGS = \
|
|
+ $(AM_CFLAGS) \
|
|
+ @GLIB2_CFLAGS@ \
|
|
+ @GIO2_CFLAGS@ \
|
|
+ @GTHREAD2_CFLAGS@ \
|
|
+ @GTK3_CFLAGS@ \
|
|
+ @X11_CFLAGS@ \
|
|
+ -DBINDIR=\"$(bindir)\" \
|
|
+ $(NULL)
|
|
+libibus_emoji_dialog_1_0_la_LIBADD = \
|
|
+ @GLIB2_LIBS@ \
|
|
+ @GIO2_LIBS@ \
|
|
+ @GTHREAD2_LIBS@ \
|
|
+ @GTK3_LIBS@ \
|
|
+ @X11_LIBS@ \
|
|
+ -lXi \
|
|
+ $(libibus) \
|
|
+ $(NULL)
|
|
+libibus_emoji_dialog_1_0_la_LDFLAGS = \
|
|
+ -no-undefined \
|
|
+ -export-symbols-regex "ibus_.*" \
|
|
+ $(NULL)
|
|
+
|
|
+# per file setting is needed to avoid conflicting LN_S by calling
|
|
+# duplicated times in parallel make
|
|
+%.vala: $(ibus_vapi)
|
|
+ if test ! -f $@ ; then \
|
|
+ $(LN_S) $(top_srcdir)/ui/gtk3/$@ .; \
|
|
+ fi;
|
|
+ibusfontset.c: $(ibus_vapi)
|
|
+ if test ! -f $@ ; then \
|
|
+ $(LN_S) $(top_srcdir)/ui/gtk3/$@ .; \
|
|
+ fi;
|
|
+ibusfontset.h: $(ibus_vapi)
|
|
+ if test ! -f $@ ; then \
|
|
+ $(LN_S) $(top_srcdir)/ui/gtk3/$@ .; \
|
|
+ fi;
|
|
+
|
|
+
|
|
+MAINTAINERCLEANFILES += $(libibus_emoji_dialog_1_0_la_SOURCES)
|
|
+DISTCLEANFILES += $(libibus_emoji_dialog_1_0_la_SOURCES)
|
|
+
|
|
+if HAVE_INTROSPECTION
|
|
+-include $(INTROSPECTION_MAKEFILE)
|
|
+INTROSPECTION_SCANNER_ARGS =
|
|
+INTROSPECTION_COMPILER_ARGS = \
|
|
+ --includedir=$(srcdir) \
|
|
+ --includedir=. \
|
|
+ --includedir=$(top_srcdir)/src \
|
|
+ $(NULL)
|
|
+
|
|
+
|
|
+emoji_headers = \
|
|
+ $(top_srcdir)/ui/gtk3/ibusemojidialog.h \
|
|
+ $(NULL)
|
|
+
|
|
+IBusEmojiDialog-1.0.gir: $(libibus_emoji_dialog) Makefile
|
|
+IBusEmojiDialog_1_0_gir_SCANNERFLAGS = \
|
|
+ --pkg-export=ibus-1.0 \
|
|
+ --pkg=gtk+-3.0 \
|
|
+ $(IBUS_GIR_SCANNERFLAGS) \
|
|
+ $(NULL)
|
|
+IBusEmojiDialog_1_0_gir_INCLUDES = Gtk-3.0 GLib-2.0 GObject-2.0 Gio-2.0
|
|
+IBusEmojiDialog_1_0_gir_LIBS = $(libibus_emoji_dialog) $(libibus)
|
|
+IBusEmojiDialog_1_0_gir_FILES = $(emoji_headers)
|
|
+IBusEmojiDialog_1_0_gir_CFLAGS = \
|
|
+ -I$(srcdir) \
|
|
+ -I$(builddir) \
|
|
+ -I$(top_srcdir)/src \
|
|
+ $(NULL)
|
|
+
|
|
+ibus_emoji_dialog_gir = IBusEmojiDialog-1.0.gir
|
|
+INTROSPECTION_GIRS += $(ibus_emoji_dialog_gir)
|
|
+noinst_DATA += $(ibus_emoji_dialog_gir)
|
|
+EXTRA_DIST += $(ibus_emoji_dialog_gir)
|
|
+MAINTAINERCLEANFILES += $(ibus_emoji_dialog_gir)
|
|
+DISTCLEANFILES += $(ibus_emoji_dialog_gir)
|
|
+
|
|
+ibus-emoji-dialog-1.0.vapi: $(ibus_emoji_dialog_gir) IBusEmojiDialog-1.0.metadata
|
|
+ibus_emoji_dialog_vapi = ibus-emoji-dialog-1.0.vapi
|
|
+ibus_emoji_dialog_1_0_vapi_DEPS = gtk+-3.0 gio-2.0
|
|
+ibus_emoji_dialog_1_0_vapi_METADATADIRS = $(srcdir)
|
|
+ibus_emoji_dialog_1_0_vapi_FILES = IBusEmojiDialog-1.0.gir
|
|
+VAPIGEN_VAPIS += $(ibus_emoji_dialog_vapi)
|
|
+noinst_DATA += $(ibus_emoji_dialog_vapi)
|
|
+EXTRA_DIST += $(ibus_emoji_dialog_vapi)
|
|
+MAINTAINERCLEANFILES += $(ibus_emoji_dialog_vapi)
|
|
+DISTCLEANFILES += $(ibus_emoji_dialog_vapi)
|
|
+
|
|
+endif
|
|
+#end of HAVE_INTROSPECTION
|
|
+
|
|
+
|
|
+if ENABLE_HARFBUZZ_FOR_EMOJI
|
|
+libibus_fontset = libibus-fontset-1.0.la
|
|
+noinst_LTLIBRARIES += $(libibus_fontset)
|
|
+
|
|
+libibus_fontset_1_0_la_SOURCES = \
|
|
+ ibusfontset.c \
|
|
+ $(NULL)
|
|
+libibus_fontset_1_0_la_CFLAGS = \
|
|
+ $(AM_CFLAGS) \
|
|
+ @CAIRO_CFLAGS@ \
|
|
+ @FONTCONFIG_CFLAGS@ \
|
|
+ @GLIB2_CFLAGS@ \
|
|
+ @HARFBUZZ_CFLAGS@ \
|
|
+ @PANGO_CFLAGS@ \
|
|
+ $(NULL)
|
|
+libibus_fontset_1_0_la_LIBADD = \
|
|
+ @CAIRO_LIBS@ \
|
|
+ @FONTCONFIG_LIBS@ \
|
|
+ @GLIB2_LIBS@ \
|
|
+ @HARFBUZZ_LIBS@ \
|
|
+ @PANGO_LIBS@ \
|
|
+ $(NULL)
|
|
+libibus_fontset_1_0_la_LDFLAGS = \
|
|
+ -no-undefined \
|
|
+ -export-symbols-regex "ibus_.*" \
|
|
+ $(NULL)
|
|
+
|
|
+MAINTAINERCLEANFILES += ibusfontset.c ibusfontset.h
|
|
+DISTCLEANFILES += ibusfontset.c ibusfontset.h
|
|
+
|
|
+if HAVE_INTROSPECTION
|
|
+IBusFontSet-1.0.gir: $(libibus_fontset) Makefile
|
|
+IBusFontSet_1_0_gir_SCANNERFLAGS = \
|
|
+ --pkg-export=ibus-1.0 \
|
|
+ --pkg=cairo \
|
|
+ --pkg=fontconfig \
|
|
+ --pkg=harfbuzz \
|
|
+ $(IBUS_GIR_SCANNERFLAGS) \
|
|
+ $(NULL)
|
|
+IBusFontSet_1_0_gir_LIBS = $(libibus_fontset) $(libibus)
|
|
+IBusFontSet_1_0_gir_INCLUDES = cairo-1.0 GLib-2.0 GObject-2.0
|
|
+IBusFontSet_1_0_gir_FILES = \
|
|
+ ibusfontset.h \
|
|
+ $(NULL)
|
|
+IBusFontSet_1_0_gir_CFLAGS = \
|
|
+ -I$(srcdir) \
|
|
+ -I$(builddir) \
|
|
+ -I$(top_srcdir)/src \
|
|
+ $(NULL)
|
|
+ibus_fontset_gir = IBusFontSet-1.0.gir
|
|
+INTROSPECTION_GIRS += $(ibus_fontset_gir)
|
|
+noinst_DATA += $(ibus_fontset_gir)
|
|
+EXTRA_DIST += $(ibus_fontset_gir)
|
|
+MAINTAINERCLEANFILES += $(ibus_fontset_gir)
|
|
+DISTCLEANFILES += $(ibus_fontset_gir)
|
|
+
|
|
+ibus-fontset-1.0.vapi: $(ibus_fontset_gir) IBusFontSet-1.0.metadata
|
|
+ibus_fontset_vapi = ibus-fontset-1.0.vapi
|
|
+ibus_fontset_1_0_vapi_METADATADIRS = $(srcdir)
|
|
+ibus_fontset_1_0_vapi_FILES = IBusFontSet-1.0.gir
|
|
+VAPIGEN_VAPIS += $(ibus_fontset_vapi)
|
|
+noinst_DATA += $(ibus_fontset_vapi)
|
|
+EXTRA_DIST += $(ibus_fontset_vapi)
|
|
+MAINTAINERCLEANFILES += $(ibus_fontset_vapi)
|
|
+DISTCLEANFILES += $(ibus_fontset_vapi)
|
|
+
|
|
+endif
|
|
+# end of HAVE_INTROSPECTION
|
|
+endif
|
|
+# end of ENABLE_HARFBUZZ_FOR_EMOJI
|
|
+endif
|
|
+# end of ENABLE_EMOJI_DICT
|
|
|
|
-include $(top_srcdir)/git.mk
|
|
diff --git a/ui/gtk3/ibus-emoji-dialog-1.0.deps b/bindings/vala/ibus-emoji-dialog-1.0.deps
|
|
similarity index 100%
|
|
rename from ui/gtk3/ibus-emoji-dialog-1.0.deps
|
|
rename to bindings/vala/ibus-emoji-dialog-1.0.deps
|
|
diff --git a/bindings/vala/ibus-fontset-1.0.deps b/bindings/vala/ibus-fontset-1.0.deps
|
|
new file mode 100644
|
|
index 0000000..129fe16
|
|
--- /dev/null
|
|
+++ b/bindings/vala/ibus-fontset-1.0.deps
|
|
@@ -0,0 +1 @@
|
|
+cairo
|
|
diff --git a/configure.ac b/configure.ac
|
|
index cb48ad4..d2aa222 100644
|
|
--- a/configure.ac
|
|
+++ b/configure.ac
|
|
@@ -653,6 +653,34 @@ https://github.com/fujiwarat/cldr-emoji-annotation)
|
|
enable_emoji_dict="yes (enabled, use --disable-emoji-dict to disable)"
|
|
fi
|
|
|
|
+AC_ARG_ENABLE(harfbuzz-for-emoji,
|
|
+ AS_HELP_STRING([--enable-harfbuzz-for-emoji],
|
|
+ [Enable HarBuzz to draw emoji characters.
|
|
+ Current Pango has a problem to draw emoji variants and
|
|
+ this way enables to use HarfBuzz directly in GtkLabel.]),
|
|
+ [enable_harfbuzz_for_emoji=$enableval],
|
|
+ [enable_harfbuzz_for_emoji=no]
|
|
+)
|
|
+AM_CONDITIONAL([ENABLE_HARFBUZZ_FOR_EMOJI],
|
|
+ [test x"$enable_harfbuzz_for_emoji" = x"yes"])
|
|
+
|
|
+if test x"$enable_harfbuzz_for_emoji" = x"yes"; then
|
|
+ PKG_CHECK_MODULES(CAIRO, [
|
|
+ cairo
|
|
+ ])
|
|
+ PKG_CHECK_MODULES(FONTCONFIG, [
|
|
+ fontconfig
|
|
+ ])
|
|
+ PKG_CHECK_MODULES(HARFBUZZ, [
|
|
+ harfbuzz
|
|
+ ])
|
|
+ PKG_CHECK_MODULES(PANGO, [
|
|
+ pango
|
|
+ ])
|
|
+else
|
|
+ enable_harfbuzz_for_emoji="no (disabled, use --enable-harfbuzz-for-emoji to enable)"
|
|
+fi
|
|
+
|
|
# Check iso-codes.
|
|
PKG_CHECK_MODULES(ISOCODES, [
|
|
iso-codes
|
|
@@ -740,6 +768,7 @@ Build options:
|
|
Enable Emoji dict $enable_emoji_dict
|
|
Unicode Emoji directory $UNICODE_EMOJI_DIR
|
|
CLDR annotation directory $EMOJI_ANNOTATION_DIR
|
|
+ Enable HarfBuzz for Emoji $enable_harfbuzz_for_emoji
|
|
Run test cases $enable_tests
|
|
])
|
|
|
|
diff --git a/po/POTFILES.skip b/po/POTFILES.skip
|
|
index 7190221..10b8829 100644
|
|
--- a/po/POTFILES.skip
|
|
+++ b/po/POTFILES.skip
|
|
@@ -2,6 +2,11 @@
|
|
# Please keep this file in alphabetical order.
|
|
# Files under ui/gtk2/ are not shipped in the distribution, but kept
|
|
# in the git repository for reference.
|
|
+bindings/vala/candidatearea.c
|
|
+bindings/vala/emojier.c
|
|
+bindings/vala/iconwidget.c
|
|
+bindings/vala/pango.c
|
|
+bindings/vala/separator.c
|
|
ibus/_config.py
|
|
tools/main.c
|
|
ui/gtk2/candidatepanel.py
|
|
diff --git a/ui/gtk3/Makefile.am b/ui/gtk3/Makefile.am
|
|
index c79641a..cd1e9c2 100644
|
|
--- a/ui/gtk3/Makefile.am
|
|
+++ b/ui/gtk3/Makefile.am
|
|
@@ -81,10 +81,6 @@ AM_VALAFLAGS = \
|
|
--target-glib="$(VALA_TARGET_GLIB_VERSION)" \
|
|
$(NULL)
|
|
|
|
-MAINTAINERCLEANFILES =
|
|
-DISTCLEANFILES =
|
|
-noinst_DATA =
|
|
-
|
|
if ENABLE_LIBNOTIFY
|
|
AM_CFLAGS += \
|
|
@LIBNOTIFY_CFLAGS@ \
|
|
@@ -158,9 +154,10 @@ man_seven_in_files = ibus-emoji.7.in
|
|
EXTRA_DIST = \
|
|
$(emoji_headers) \
|
|
$(man_seven_in_files) \
|
|
- IBusEmojiDialog-1.0.metadata \
|
|
+ emojierapp.vala \
|
|
gtkpanel.xml.in \
|
|
- ibus-emoji-dialog-1.0.deps \
|
|
+ ibusfontset.c \
|
|
+ ibusfontset.h \
|
|
notification-item.xml \
|
|
notification-watcher.xml \
|
|
$(NULL)
|
|
@@ -168,98 +165,70 @@ EXTRA_DIST = \
|
|
if ENABLE_EMOJI_DICT
|
|
AM_VALAFLAGS += --define=EMOJI_DICT
|
|
|
|
-libibus_emoji_dialog = libibus-emoji-dialog-1.0.la
|
|
-
|
|
-noinst_LTLIBRARIES = $(libibus_emoji_dialog)
|
|
-
|
|
-libibus_emoji_dialog_1_0_la_CFLAGS = $(AM_CFLAGS)
|
|
-libibus_emoji_dialog_1_0_la_LDFLAGS = \
|
|
- -no-undefined \
|
|
- -export-symbols-regex "ibus_.*" \
|
|
- -version-info @LT_VERSION_INFO@ \
|
|
- $(NULL)
|
|
-libibus_emoji_dialog_1_0_la_SOURCES = \
|
|
- candidatearea.vala \
|
|
- emojier.vala \
|
|
- iconwidget.vala \
|
|
- pango.vala \
|
|
- separator.vala \
|
|
- $(NULL)
|
|
-
|
|
libexec_PROGRAMS += ibus-ui-emojier
|
|
|
|
-ibus_ui_emojier_SOURCES = \
|
|
- $(libibus_emoji_dialog_1_0_la_SOURCES) \
|
|
+ibus_ui_emojier_VALASOURCES = \
|
|
emojierapp.vala \
|
|
+ candidatearea.vala \
|
|
+ emojier.vala \
|
|
+ iconwidget.vala \
|
|
+ pango.vala \
|
|
+ separator.vala \
|
|
+ $(NULL)
|
|
+ibus_ui_emojier_SOURCES = \
|
|
+ $(ibus_ui_emojier_VALASOURCES:.vala=.c) \
|
|
$(NULL)
|
|
|
|
ibus_ui_emojier_LDADD = \
|
|
$(AM_LDADD) \
|
|
$(NULL)
|
|
|
|
--include $(INTROSPECTION_MAKEFILE)
|
|
-INTROSPECTION_SCANNER_ARGS =
|
|
-INTROSPECTION_COMPILER_ARGS = \
|
|
- --includedir=$(srcdir) \
|
|
- --includedir=. \
|
|
- --includedir=$(top_srcdir)/src \
|
|
- $(NULL)
|
|
-
|
|
-if HAVE_INTROSPECTION
|
|
-introspection_sources = \
|
|
- $(emoji_headers) \
|
|
- $(NULL)
|
|
-IBusEmojiDialog-1.0.gir: $(libibus_emoji_dialog) Makefile
|
|
-IBusEmojiDialog_1_0_gir_SCANNERFLAGS = \
|
|
- --pkg-export=ibus-1.0 \
|
|
- --pkg=gtk+-3.0 \
|
|
- $(IBUS_GIR_SCANNERFLAGS) \
|
|
+ibus_ui_emojier_VALAFLAGS = \
|
|
+ $(AM_VALAFLAGS) \
|
|
$(NULL)
|
|
-IBusEmojiDialog-1.0.gir: $(libibus_emoji_dialog) Makefile
|
|
-IBusEmojiDialog_1_0_gir_INCLUDES = Gtk-3.0 GLib-2.0 GObject-2.0 Gio-2.0
|
|
-IBusEmojiDialog_1_0_gir_LIBS = $(libibus_emoji_dialog) $(libibus)
|
|
-IBusEmojiDialog_1_0_gir_FILES = \
|
|
- $(addprefix $(srcdir)/,$(introspection_sources)) \
|
|
- $(NULL)
|
|
-IBusEmojiDialog_1_0_gir_CFLAGS = \
|
|
- -DIBUS_COMPILATION \
|
|
- -I$(srcdir) \
|
|
- -I$(builddir) \
|
|
- -I$(top_srcdir)/src \
|
|
- $(NULL)
|
|
-INTROSPECTION_GIRS = IBusEmojiDialog-1.0.gir
|
|
-
|
|
-girdir = $(datadir)/gir-1.0
|
|
-noinst_DATA += $(INTROSPECTION_GIRS)
|
|
-CLEANFILES += $(INTROSPECTION_GIRS)
|
|
|
|
-typelibsdir = $(libdir)/girepository-1.0
|
|
-noinst_DATA += $(INTROSPECTION_GIRS:.gir=.typelib)
|
|
-CLEANFILES += $(INTROSPECTION_GIRS:.gir=.typelib)
|
|
-
|
|
-
|
|
-if ENABLE_VAPIGEN
|
|
--include $(VAPIGEN_MAKEFILE)
|
|
+# This line and foo_VALASOURCES line can delete the duplicated entries
|
|
+# of emojier.c: emojier.vala
|
|
+emojierapp.c: $(ibus_ui_emojier_VALASOURCES)
|
|
+ $(AM_V_VALAC)$(am__cd) $(srcdir) && $(VALAC) $(AM_VALAFLAGS) \
|
|
+$(VALAFLAGS) -C $(ibus_ui_emojier_VALASOURCES)
|
|
+ $(NULL)
|
|
+# make dist creates .c files in a different srcdir
|
|
+emojierapp.o: $(srcdir)/emojierapp.c
|
|
+ $(AM_V_CC)source='$<' object='$@' libtool=no \
|
|
+ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \
|
|
+ $(AM_V_CC_no)$(COMPILE) -c -o $@ $<
|
|
+ $(NULL)
|
|
|
|
-ibus-emoji-dialog-1.0.vapi: $(INTROSPECTION_GIRS) IBusEmojiDialog-1.0.metadata
|
|
+if ENABLE_HARFBUZZ_FOR_EMOJI
|
|
+ibus_ui_gtk3_SOURCES += \
|
|
+ ibusfontset.c \
|
|
+ $(NULL)
|
|
|
|
-VAPIGEN_VAPIS = ibus-emoji-dialog-1.0.vapi
|
|
+ibus_ui_emojier_SOURCES += \
|
|
+ ibusfontset.c \
|
|
+ $(NULL)
|
|
|
|
-ibus_emoji_dialog_1_0_vapi_DEPS = gtk+-3.0 gio-2.0
|
|
-ibus_emoji_dialog_1_0_vapi_METADATADIRS = $(srcdir)
|
|
-ibus_emoji_dialog_1_0_vapi_FILES = $(INTROSPECTION_GIRS)
|
|
+AM_CFLAGS += \
|
|
+ @CAIRO_CFLAGS@ \
|
|
+ @FONTCONFIG_CFLAGS@ \
|
|
+ @HARFBUZZ_CFLAGS@ \
|
|
+ $(NULL)
|
|
|
|
-vapidir = $(datadir)/vala/vapi
|
|
-noinst_DATA += $(VAPIGEN_VAPIS) $(VAPIGEN_VAPIS:.vapi=.deps)
|
|
+AM_LDADD += \
|
|
+ @CAIRO_LIBS@ \
|
|
+ @FONTCONFIG_LIBS@ \
|
|
+ @HARFBUZZ_LIBS@ \
|
|
+ $(NULL)
|
|
|
|
-MAINTAINERCLEANFILES += $(VAPIGEN_VAPIS)
|
|
-DISTCLEANFILES += $(VAPIGEN_VAPIS)
|
|
-EXTRA_DIST += $(VAPIGEN_VAPIS)
|
|
+AM_VALAFLAGS += \
|
|
+ -D ENABLE_HARFBUZZ_FOR_EMOJI \
|
|
+ --pkg=cairo \
|
|
+ --pkg=ibus-fontset-1.0 \
|
|
+ $(NULL)
|
|
|
|
-# end of ENABLE_VAPIGEN
|
|
-endif
|
|
-# end of HAVE_INTROSPECTION
|
|
endif
|
|
+# end of ENABLE_HARFBUZZ_FOR_EMOJI
|
|
|
|
man_seven_files = $(man_seven_in_files:.7.in=.7)
|
|
man_seven_DATA =$(man_seven_files:.7=.7.gz)
|
|
@@ -276,7 +245,7 @@ CLEANFILES += \
|
|
$(man_seven_files) \
|
|
$(NULL)
|
|
|
|
-# end of ENABLE_EMOJI_DICT
|
|
endif
|
|
+# end of ENABLE_EMOJI_DICT
|
|
|
|
-include $(top_srcdir)/git.mk
|
|
diff --git a/ui/gtk3/emojier.vala b/ui/gtk3/emojier.vala
|
|
index 95912bf..72e0093 100644
|
|
--- a/ui/gtk3/emojier.vala
|
|
+++ b/ui/gtk3/emojier.vala
|
|
@@ -80,6 +80,9 @@ class IBusEmojier : Gtk.ApplicationWindow {
|
|
}
|
|
}
|
|
private class EWhiteLabel : Gtk.Label {
|
|
+#if ENABLE_HARFBUZZ_FOR_EMOJI
|
|
+ IBus.RequisitionEx m_requisition;
|
|
+#endif
|
|
public EWhiteLabel(string text) {
|
|
GLib.Object(
|
|
name : "IBusEmojierWhiteLabel"
|
|
@@ -87,8 +90,78 @@ class IBusEmojier : Gtk.ApplicationWindow {
|
|
if (text != "")
|
|
set_label(text);
|
|
}
|
|
+#if ENABLE_HARFBUZZ_FOR_EMOJI
|
|
+ private void get_preferred_size_with_hb(out int minimum_width,
|
|
+ out int natural_width,
|
|
+ out int minimum_height,
|
|
+ out int natural_height) {
|
|
+ minimum_width = 0;
|
|
+ natural_width = 0;
|
|
+ minimum_height = 0;
|
|
+ natural_height = 0;
|
|
+ var text = this.get_text();
|
|
+ if (text == null || text == "")
|
|
+ return;
|
|
+ var context = this.get_pango_context();
|
|
+ var language = context.get_language();
|
|
+ update_fontset(language);
|
|
+ Cairo.RectangleInt widest = Cairo.RectangleInt();
|
|
+ m_requisition = m_fontset.get_preferred_size_hb(text, out widest);
|
|
+ minimum_width = widest.width;
|
|
+ natural_width = widest.width;
|
|
+ minimum_height = widest.height;
|
|
+ natural_height = widest.height;
|
|
+ }
|
|
+ public override void get_preferred_width(out int minimum_width,
|
|
+ out int natural_width) {
|
|
+ get_preferred_size_with_hb(out minimum_width,
|
|
+ out natural_width,
|
|
+ null, null);
|
|
+ }
|
|
+ public override void get_preferred_height(out int minimum_height,
|
|
+ out int natural_height) {
|
|
+ get_preferred_size_with_hb(null, null,
|
|
+ out minimum_height,
|
|
+ out natural_height);
|
|
+ }
|
|
+ public override bool draw(Cairo.Context cr) {
|
|
+ if (m_fontset == null)
|
|
+ return true;
|
|
+ if (m_requisition == null)
|
|
+ return true;
|
|
+ if (m_requisition.cairo_lines == null)
|
|
+ return true;
|
|
+ var style_context = get_style_context();
|
|
+ Gtk.Allocation allocation;
|
|
+ get_allocation(out allocation);
|
|
+ style_context.render_background(cr,
|
|
+ 0, 0,
|
|
+ allocation.width,
|
|
+ allocation.height);
|
|
+ Gdk.RGBA *normal_fg = null;
|
|
+ style_context.get(Gtk.StateFlags.NORMAL,
|
|
+ "color",
|
|
+ out normal_fg);
|
|
+ cr.set_operator(Cairo.Operator.OVER);
|
|
+ cr.set_source_rgba(normal_fg.red, normal_fg.green, normal_fg.blue,
|
|
+ normal_fg.alpha);
|
|
+ cr.save();
|
|
+ double x = 0.0;
|
|
+ double y = 0.0;
|
|
+ if (allocation.width > m_requisition.width)
|
|
+ x = (allocation.width - m_requisition.width) / 2.0;
|
|
+ if (allocation.height > m_requisition.height)
|
|
+ y = (allocation.height - m_requisition.height) / 2.0;
|
|
+ cr.translate(x, y);
|
|
+ m_fontset.draw_cairo_with_requisition_ex(cr, m_requisition);
|
|
+ cr.restore();
|
|
+ normal_fg.free();
|
|
+ normal_fg = null;
|
|
+ return true;
|
|
+ }
|
|
+#endif
|
|
}
|
|
- private class ESelectedLabel : Gtk.Label {
|
|
+ private class ESelectedLabel : EWhiteLabel {
|
|
public ESelectedLabel(string text) {
|
|
GLib.Object(
|
|
name : "IBusEmojierSelectedLabel"
|
|
@@ -97,7 +170,7 @@ class IBusEmojier : Gtk.ApplicationWindow {
|
|
set_label(text);
|
|
}
|
|
}
|
|
- private class EGoldLabel : Gtk.Label {
|
|
+ private class EGoldLabel : EWhiteLabel {
|
|
public EGoldLabel(string text) {
|
|
GLib.Object(
|
|
name : "IBusEmojierGoldLabel"
|
|
@@ -212,6 +285,9 @@ class IBusEmojier : Gtk.ApplicationWindow {
|
|
m_category_to_emojis_dict;
|
|
private static GLib.HashTable<string, GLib.SList<string>>?
|
|
m_emoji_to_emoji_variants_dict;
|
|
+#if ENABLE_HARFBUZZ_FOR_EMOJI
|
|
+ private static IBus.FontSet m_fontset;
|
|
+#endif
|
|
|
|
private ThemedRGBA m_rgba;
|
|
private Gtk.Box m_vbox;
|
|
@@ -1120,6 +1196,7 @@ class IBusEmojier : Gtk.ApplicationWindow {
|
|
m_category_active_index = (int)list.length();
|
|
}
|
|
Gtk.Adjustment adjustment = m_list_box.get_adjustment();
|
|
+ m_scrolled_window.set_hadjustment(new Gtk.Adjustment(0, 0, 0, 0, 0, 0));
|
|
m_scrolled_window.set_vadjustment(adjustment);
|
|
show_category_list();
|
|
}
|
|
@@ -1137,7 +1214,7 @@ class IBusEmojier : Gtk.ApplicationWindow {
|
|
else if (keyval == Gdk.Key.Right)
|
|
m_lookup_table.cursor_down();
|
|
show_candidate_panel();
|
|
- } else if (m_entry.get_text().len() > 0) {
|
|
+ } else if (m_entry.get_text().length > 0) {
|
|
int step = 0;
|
|
if (keyval == Gdk.Key.Left)
|
|
step = -1;
|
|
@@ -1192,7 +1269,7 @@ class IBusEmojier : Gtk.ApplicationWindow {
|
|
show_candidate_panel();
|
|
return true;
|
|
}
|
|
- if (m_entry.get_text().len() > 0) {
|
|
+ if (m_entry.get_text().length > 0) {
|
|
int step = 0;
|
|
if (keyval == Gdk.Key.Home)
|
|
step = -1;
|
|
@@ -1391,7 +1468,7 @@ class IBusEmojier : Gtk.ApplicationWindow {
|
|
key_press_enter();
|
|
return true;
|
|
case Gdk.Key.BackSpace:
|
|
- if (m_entry.get_text().len() > 0) {
|
|
+ if (m_entry.get_text().length > 0) {
|
|
if ((modifiers & Gdk.ModifierType.CONTROL_MASK) != 0) {
|
|
GLib.Signal.emit_by_name(m_entry, "delete-from-cursor",
|
|
Gtk.DeleteType.WORD_ENDS, -1);
|
|
@@ -1403,7 +1480,7 @@ class IBusEmojier : Gtk.ApplicationWindow {
|
|
break;
|
|
case Gdk.Key.Delete:
|
|
case Gdk.Key.KP_Delete:
|
|
- if (m_entry.get_text().len() > 0) {
|
|
+ if (m_entry.get_text().length > 0) {
|
|
if ((modifiers & Gdk.ModifierType.CONTROL_MASK) != 0) {
|
|
GLib.Signal.emit_by_name(m_entry, "delete-from-cursor",
|
|
Gtk.DeleteType.WORD_ENDS, 1);
|
|
@@ -1417,7 +1494,7 @@ class IBusEmojier : Gtk.ApplicationWindow {
|
|
case Gdk.Key.space:
|
|
case Gdk.Key.KP_Space:
|
|
if ((modifiers & Gdk.ModifierType.SHIFT_MASK) != 0) {
|
|
- if (m_entry.get_text().len() > 0)
|
|
+ if (m_entry.get_text().length > 0)
|
|
entry_enter_keyval(keyval);
|
|
} else if (m_candidate_panel_is_visible) {
|
|
enter_notify_disable_with_timer();
|
|
@@ -1493,7 +1570,7 @@ class IBusEmojier : Gtk.ApplicationWindow {
|
|
return true;
|
|
break;
|
|
case Gdk.Key.u:
|
|
- if (m_entry.get_text().len() > 0) {
|
|
+ if (m_entry.get_text().length > 0) {
|
|
GLib.Signal.emit_by_name(m_entry,
|
|
"delete-from-cursor",
|
|
Gtk.DeleteType.PARAGRAPH_ENDS,
|
|
@@ -1502,13 +1579,13 @@ class IBusEmojier : Gtk.ApplicationWindow {
|
|
}
|
|
break;
|
|
case Gdk.Key.a:
|
|
- if (m_entry.get_text().len() > 0) {
|
|
+ if (m_entry.get_text().length > 0) {
|
|
m_entry.select_region(0, -1);
|
|
return true;
|
|
}
|
|
break;
|
|
case Gdk.Key.x:
|
|
- if (m_entry.get_text().len() > 0) {
|
|
+ if (m_entry.get_text().length > 0) {
|
|
GLib.Signal.emit_by_name(m_entry, "cut-clipboard");
|
|
return true;
|
|
}
|
|
@@ -1525,7 +1602,7 @@ class IBusEmojier : Gtk.ApplicationWindow {
|
|
clipboard.store();
|
|
return true;
|
|
}
|
|
- } else if (m_entry.get_text().len() > 0) {
|
|
+ } else if (m_entry.get_text().length > 0) {
|
|
GLib.Signal.emit_by_name(m_entry, "copy-clipboard");
|
|
return true;
|
|
}
|
|
@@ -1581,6 +1658,22 @@ class IBusEmojier : Gtk.ApplicationWindow {
|
|
}
|
|
|
|
|
|
+#if ENABLE_HARFBUZZ_FOR_EMOJI
|
|
+ private static void update_fontset(Pango.Language language) {
|
|
+ if (m_fontset != null) {
|
|
+ m_fontset.set_family(m_emoji_font_family);
|
|
+ m_fontset.set_size(m_emoji_font_size);
|
|
+ m_fontset.set_language(language.to_string());
|
|
+ m_fontset.update_fcfontset();
|
|
+ } else {
|
|
+ m_fontset = new IBus.FontSet.with_font(
|
|
+ m_emoji_font_family,
|
|
+ m_emoji_font_size,
|
|
+ language.to_string());
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+
|
|
public static bool has_loaded_emoji_dict() {
|
|
if (m_emoji_to_data_dict == null)
|
|
return false;
|
|
@@ -1611,6 +1704,10 @@ class IBusEmojier : Gtk.ApplicationWindow {
|
|
int font_size = font_desc.get_size() / Pango.SCALE;
|
|
if (font_size != 0)
|
|
m_emoji_font_size = font_size;
|
|
+#if ENABLE_HARFBUZZ_FOR_EMOJI
|
|
+ var widget = new Gtk.Label("");
|
|
+ update_fontset(widget.get_pango_context().get_language());
|
|
+#endif
|
|
}
|
|
|
|
|
|
diff --git a/ui/gtk3/ibusemojidialog.h b/ui/gtk3/ibusemojidialog.h
|
|
index 24d195c..ed8886a 100644
|
|
--- a/ui/gtk3/ibusemojidialog.h
|
|
+++ b/ui/gtk3/ibusemojidialog.h
|
|
@@ -170,5 +170,31 @@ void ibus_emojier_set_favorites (gchar** favorites,
|
|
favorite_annotations,
|
|
int
|
|
favorite_annotations_length);
|
|
+
|
|
+/**
|
|
+ * ibus_emojier_set_partial_match:
|
|
+ * @has_partial_match: Enable the partial match if %TRUE. Otherwise if %FALSE.
|
|
+ *
|
|
+ * Set partial match for emoji annotations.
|
|
+ */
|
|
+void ibus_emojier_set_partial_match (gboolean has_partial_match);
|
|
+
|
|
+/**
|
|
+ * ibus_emojier_set_partial_match_length:
|
|
+ * @length: minimum lenght to match partially.
|
|
+ *
|
|
+ * Set the minimum lenght to match partially.
|
|
+ */
|
|
+void ibus_emojier_set_partial_match_length
|
|
+ (gint length);
|
|
+
|
|
+/**
|
|
+ * ibus_emojier_set_partial_match_condition:
|
|
+ * @condition: condition id between 0 and 2.
|
|
+ *
|
|
+ * Set the partial match condition with the integer.
|
|
+ */
|
|
+void ibus_emojier_set_partial_match_condition
|
|
+ (gint condition);
|
|
G_END_DECLS
|
|
#endif
|
|
diff --git a/ui/gtk3/ibusfontset.c b/ui/gtk3/ibusfontset.c
|
|
new file mode 100644
|
|
index 0000000..72dfa28
|
|
--- /dev/null
|
|
+++ b/ui/gtk3/ibusfontset.c
|
|
@@ -0,0 +1,922 @@
|
|
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
|
|
+/* vim:set et sts=4: */
|
|
+/* ibus - The Input Bus
|
|
+ * Copyright (C) 2017 Takao Fujiwara <takao.fujiwara1@gmail.com>
|
|
+ * Copyright (C) 2017 Red Hat, Inc.
|
|
+ *
|
|
+ * This library is free software; you can redistribute it and/or
|
|
+ * modify it under the terms of the GNU Lesser General Public
|
|
+ * License as published by the Free Software Foundation; either
|
|
+ * version 2.1 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
|
|
+ * Lesser General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU Lesser General Public
|
|
+ * License along with this library; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
|
+ * USA
|
|
+ */
|
|
+
|
|
+#include <cairo-ft.h>
|
|
+#include <fontconfig/fontconfig.h>
|
|
+#include <ft2build.h>
|
|
+#include FT_FREETYPE_H
|
|
+#include <glib.h>
|
|
+#include <hb-ot.h>
|
|
+#include <pango/pango.h>
|
|
+
|
|
+#include "ibusfontset.h"
|
|
+
|
|
+#define XPAD 2
|
|
+#define YPAD 2
|
|
+#define UNKNOWN_FONT_SIZE 7
|
|
+#define IBUS_FONTSET_GET_PRIVATE(o) \
|
|
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_FONTSET, IBusFontSetPrivate))
|
|
+
|
|
+
|
|
+static FT_Library m_ftlibrary;
|
|
+static FcFontSet *m_fcfontset;
|
|
+static gchar *m_family;
|
|
+static guint m_size;
|
|
+static gchar *m_language;
|
|
+static GHashTable *m_scaled_font_table;
|
|
+static GHashTable *m_hb_font_table;
|
|
+
|
|
+enum {
|
|
+ PROP_0,
|
|
+ PROP_FAMILY,
|
|
+ PROP_SIZE,
|
|
+ PROP_LANGUAGE
|
|
+};
|
|
+
|
|
+typedef struct {
|
|
+ gunichar ch;
|
|
+ FcPattern *fcfont;
|
|
+} FontPerChar;
|
|
+
|
|
+struct _IBusFontSetPrivate {
|
|
+ gchar *family;
|
|
+ guint size;
|
|
+ gchar *language;
|
|
+};
|
|
+
|
|
+static GObject * ibus_fontset_constructor (GType type,
|
|
+ guint n,
|
|
+ GObjectConstructParam *args);
|
|
+static void ibus_fontset_destroy (IBusFontSet *fontset);
|
|
+static void ibus_fontset_set_property (IBusFontSet *fontset,
|
|
+ guint prop_id,
|
|
+ const GValue *value,
|
|
+ GParamSpec *pspec);
|
|
+static void ibus_fontset_get_property (IBusFontSet *fontset,
|
|
+ guint prop_id,
|
|
+ GValue *value,
|
|
+ GParamSpec *pspec);
|
|
+static cairo_scaled_font_t *
|
|
+ ibus_fontset_cairo_scaled_font_new_with_font
|
|
+ (const gchar *family,
|
|
+ guint size);
|
|
+
|
|
+G_DEFINE_BOXED_TYPE (IBusCairoLine,
|
|
+ ibus_cairo_line,
|
|
+ ibus_cairo_line_copy,
|
|
+ ibus_cairo_line_free);
|
|
+G_DEFINE_BOXED_TYPE (IBusRequisitionEx,
|
|
+ ibus_requisition_ex,
|
|
+ ibus_requisition_ex_copy,
|
|
+ ibus_requisition_ex_free);
|
|
+G_DEFINE_TYPE (IBusFontSet, ibus_fontset, IBUS_TYPE_OBJECT)
|
|
+
|
|
+static void
|
|
+ibus_fontset_class_init (IBusFontSetClass *class)
|
|
+{
|
|
+ GObjectClass *gobject_class = G_OBJECT_CLASS (class);
|
|
+ IBusObjectClass *object_class = IBUS_OBJECT_CLASS (class);
|
|
+ cairo_glyph_t dummy;
|
|
+ IBusGlyph dummy2;
|
|
+
|
|
+ gobject_class->constructor = ibus_fontset_constructor;
|
|
+ gobject_class->get_property =
|
|
+ (GObjectGetPropertyFunc) ibus_fontset_get_property;
|
|
+ gobject_class->set_property =
|
|
+ (GObjectSetPropertyFunc) ibus_fontset_set_property;
|
|
+ object_class->destroy = (IBusObjectDestroyFunc) ibus_fontset_destroy;
|
|
+
|
|
+ /* install properties */
|
|
+ /**
|
|
+ * IBusFontSet:family:
|
|
+ *
|
|
+ * Font family of this IBusFontSet.
|
|
+ */
|
|
+ g_object_class_install_property (gobject_class,
|
|
+ PROP_FAMILY,
|
|
+ g_param_spec_string ("family",
|
|
+ "family",
|
|
+ "family",
|
|
+ "",
|
|
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
|
+
|
|
+ /**
|
|
+ * IBusFontSet:size:
|
|
+ *
|
|
+ * Font size of this IBusFontSet.
|
|
+ */
|
|
+ g_object_class_install_property (gobject_class,
|
|
+ PROP_SIZE,
|
|
+ g_param_spec_uint ("size",
|
|
+ "size",
|
|
+ "size",
|
|
+ 0, G_MAXUINT16, 0,
|
|
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
|
+
|
|
+ /**
|
|
+ * IBusFontSet:language:
|
|
+ *
|
|
+ * Font language of this IBusFontSet.
|
|
+ */
|
|
+ g_object_class_install_property (gobject_class,
|
|
+ PROP_LANGUAGE,
|
|
+ g_param_spec_string ("language",
|
|
+ "language",
|
|
+ "language",
|
|
+ "",
|
|
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
|
+
|
|
+ g_type_class_add_private (class, sizeof (IBusFontSetPrivate));
|
|
+ FT_Init_FreeType (&m_ftlibrary);
|
|
+ m_scaled_font_table = g_hash_table_new_full (
|
|
+ g_str_hash, g_str_equal,
|
|
+ g_free,
|
|
+ (GDestroyNotify) cairo_scaled_font_destroy);
|
|
+ m_hb_font_table = g_hash_table_new_full (
|
|
+ g_str_hash, g_str_equal,
|
|
+ g_free,
|
|
+ (GDestroyNotify) hb_font_destroy);
|
|
+
|
|
+ /* hb_glyph_t is not available in Vala so override it with IBusGlyph. */
|
|
+ g_assert (sizeof (dummy) == sizeof (dummy2));
|
|
+ g_assert (sizeof (dummy.index) == sizeof (dummy2.index));
|
|
+ g_assert (sizeof (dummy.x) == sizeof (dummy2.x));
|
|
+ g_assert (sizeof (dummy.y) == sizeof (dummy2.y));
|
|
+}
|
|
+
|
|
+static void
|
|
+ibus_fontset_init (IBusFontSet *fontset)
|
|
+{
|
|
+ fontset->priv = IBUS_FONTSET_GET_PRIVATE (fontset);
|
|
+}
|
|
+
|
|
+
|
|
+static GObject *
|
|
+ibus_fontset_constructor (GType type,
|
|
+ guint n,
|
|
+ GObjectConstructParam *args)
|
|
+{
|
|
+ GObject *object;
|
|
+ IBusFontSet *fontset;
|
|
+ const gchar *family;
|
|
+ guint size;
|
|
+
|
|
+ object = G_OBJECT_CLASS (ibus_fontset_parent_class)->constructor (
|
|
+ type, n ,args);
|
|
+ fontset = IBUS_FONTSET (object);
|
|
+ family = ibus_fontset_get_family (fontset);
|
|
+ size = ibus_fontset_get_size (fontset);
|
|
+ ibus_fontset_update_fcfontset (fontset);
|
|
+ if (family != NULL && size > 0) {
|
|
+ /* cache the font */
|
|
+ ibus_fontset_cairo_scaled_font_new_with_font (family,
|
|
+ size);
|
|
+ }
|
|
+ return object;
|
|
+}
|
|
+
|
|
+static void
|
|
+ibus_fontset_destroy (IBusFontSet *fontset)
|
|
+{
|
|
+ g_clear_pointer (&fontset->priv->family, g_free);
|
|
+ g_clear_pointer (&fontset->priv->language, g_free);
|
|
+}
|
|
+
|
|
+static void
|
|
+ibus_fontset_set_property (IBusFontSet *fontset,
|
|
+ guint prop_id,
|
|
+ const GValue *value,
|
|
+ GParamSpec *pspec)
|
|
+{
|
|
+ switch (prop_id) {
|
|
+ case PROP_FAMILY:
|
|
+ ibus_fontset_set_family (fontset, g_value_get_string (value));
|
|
+ break;
|
|
+ case PROP_SIZE:
|
|
+ ibus_fontset_set_size (fontset, g_value_get_uint (value));
|
|
+ break;
|
|
+ case PROP_LANGUAGE:
|
|
+ ibus_fontset_set_language (fontset, g_value_get_string (value));
|
|
+ break;
|
|
+ default:
|
|
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (fontset, prop_id, pspec);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+ibus_fontset_get_property (IBusFontSet *fontset,
|
|
+ guint prop_id,
|
|
+ GValue *value,
|
|
+ GParamSpec *pspec)
|
|
+{
|
|
+ switch (prop_id) {
|
|
+ case PROP_FAMILY:
|
|
+ g_value_set_string (value, ibus_fontset_get_family (fontset));
|
|
+ break;
|
|
+ case PROP_SIZE:
|
|
+ g_value_set_uint (value, ibus_fontset_get_size (fontset));
|
|
+ break;
|
|
+ case PROP_LANGUAGE:
|
|
+ g_value_set_string (value, ibus_fontset_get_language (fontset));
|
|
+ break;
|
|
+ default:
|
|
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (fontset, prop_id, pspec);
|
|
+ }
|
|
+}
|
|
+
|
|
+static cairo_scaled_font_t *
|
|
+ibus_fontset_cairo_scaled_font_new_with_font (const gchar *family,
|
|
+ guint size)
|
|
+{
|
|
+ gchar *font_name;
|
|
+ cairo_scaled_font_t *scaled_font = NULL;
|
|
+ FcPattern *pattern, *resolved;
|
|
+ FcResult result;
|
|
+ cairo_font_options_t *font_options;
|
|
+ double pixel_size = 0.;
|
|
+ FcMatrix fc_matrix, *fc_matrix_val;
|
|
+ cairo_font_face_t *cairo_face = NULL;
|
|
+ cairo_matrix_t font_matrix;
|
|
+ cairo_matrix_t ctm;
|
|
+ int i;
|
|
+
|
|
+ g_return_val_if_fail (family != NULL, NULL);
|
|
+ g_return_val_if_fail (m_scaled_font_table != NULL, NULL);
|
|
+
|
|
+ font_name = g_strdup_printf ("%s %u", family, size);
|
|
+ scaled_font = g_hash_table_lookup (m_scaled_font_table, font_name);
|
|
+ if (scaled_font != NULL) {
|
|
+ g_free (font_name);
|
|
+ return scaled_font;
|
|
+ }
|
|
+ pattern = FcPatternCreate ();
|
|
+ FcPatternAddString (pattern, FC_FAMILY, (FcChar8*) family);
|
|
+ FcPatternAddDouble (pattern, FC_SIZE, (double) size);
|
|
+ FcPatternAddDouble (pattern, FC_DPI, 96);
|
|
+ FcConfigSubstitute(NULL, pattern, FcMatchPattern);
|
|
+ font_options = cairo_font_options_create ();
|
|
+ cairo_ft_font_options_substitute (font_options, pattern);
|
|
+ FcDefaultSubstitute (pattern);
|
|
+ resolved = FcFontMatch (NULL, pattern, &result);
|
|
+ FcPatternDestroy (pattern);
|
|
+ FcPatternGetDouble (resolved, FC_PIXEL_SIZE, 0, &pixel_size);
|
|
+ if (pixel_size == 0.)
|
|
+ g_warning ("Failed to scaled the font: %s %u", family, size);
|
|
+ cairo_face = cairo_ft_font_face_create_for_pattern (resolved);
|
|
+ FcMatrixInit (&fc_matrix);
|
|
+ for (i = 0;
|
|
+ FcPatternGetMatrix (resolved, FC_MATRIX, i, &fc_matrix_val)
|
|
+ == FcResultMatch;
|
|
+ i++) {
|
|
+ FcMatrixMultiply (&fc_matrix, &fc_matrix, fc_matrix_val);
|
|
+ }
|
|
+ FcPatternDestroy (resolved);
|
|
+ cairo_matrix_init (&font_matrix,
|
|
+ fc_matrix.xx, -fc_matrix.yx,
|
|
+ -fc_matrix.xy, fc_matrix.yy,
|
|
+ 0., 0.);
|
|
+ if (pixel_size != 0.)
|
|
+ cairo_matrix_scale (&font_matrix, pixel_size, pixel_size);
|
|
+ cairo_matrix_init_identity (&ctm);
|
|
+ scaled_font = cairo_scaled_font_create (cairo_face,
|
|
+ &font_matrix, &ctm,
|
|
+ font_options);
|
|
+ cairo_font_face_destroy (cairo_face);
|
|
+ if (font_name)
|
|
+ g_hash_table_insert(m_scaled_font_table, font_name, scaled_font);
|
|
+
|
|
+ return scaled_font;
|
|
+}
|
|
+
|
|
+static hb_font_t *
|
|
+ibus_fontset_hb_font_new_with_font_path (const gchar *font_path)
|
|
+{
|
|
+ hb_font_t *hb_font;
|
|
+ GError *error = NULL;
|
|
+ GMappedFile *mf;
|
|
+ char *font_data = NULL;
|
|
+ gsize len;
|
|
+ hb_blob_t *hb_blob;
|
|
+ hb_face_t *hb_face;
|
|
+
|
|
+ g_return_val_if_fail (font_path != NULL, NULL);
|
|
+ g_return_val_if_fail (m_hb_font_table != NULL, NULL);
|
|
+
|
|
+ hb_font = g_hash_table_lookup (m_hb_font_table, font_path);
|
|
+ if (hb_font != NULL)
|
|
+ return hb_font;
|
|
+
|
|
+ mf = g_mapped_file_new (font_path, FALSE, &error);
|
|
+ if (mf == NULL) {
|
|
+ g_warning ("Not found font %s", font_path);
|
|
+ return NULL;
|
|
+ }
|
|
+ font_data = g_mapped_file_get_contents (mf);
|
|
+ len = g_mapped_file_get_length (mf);
|
|
+ if (len == 0) {
|
|
+ g_warning ("zero size font %s", font_path);
|
|
+ g_mapped_file_unref (mf);
|
|
+ return NULL;
|
|
+ }
|
|
+ hb_blob = hb_blob_create (font_data, len,
|
|
+ HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE,
|
|
+ mf, (hb_destroy_func_t)g_mapped_file_unref);
|
|
+ hb_face = hb_face_create (hb_blob, 0);
|
|
+ hb_blob_destroy (hb_blob);
|
|
+ hb_font = hb_font_create (hb_face);
|
|
+ unsigned int upem = hb_face_get_upem (hb_face);
|
|
+ hb_font_set_scale (hb_font, upem, upem);
|
|
+ hb_face_destroy (hb_face);
|
|
+ hb_ot_font_set_funcs (hb_font);
|
|
+ g_hash_table_insert (m_hb_font_table, g_strdup (font_path), hb_font);
|
|
+
|
|
+ return hb_font;
|
|
+}
|
|
+
|
|
+static void
|
|
+get_font_extents_with_scaled_font (cairo_scaled_font_t *scaled_font,
|
|
+ PangoRectangle *font_rect)
|
|
+{
|
|
+ cairo_font_extents_t font_extents;
|
|
+
|
|
+ g_assert (scaled_font != NULL && font_rect != NULL);
|
|
+
|
|
+ cairo_scaled_font_extents (scaled_font, &font_extents);
|
|
+ font_rect->x = 0;
|
|
+ font_rect->y = - pango_units_from_double (font_extents.ascent);
|
|
+ font_rect->width = 0;
|
|
+ font_rect->height = pango_units_from_double (
|
|
+ font_extents.ascent + font_extents.descent);
|
|
+}
|
|
+
|
|
+static void
|
|
+get_glyph_extents_with_scaled_hb_font (const gchar *str,
|
|
+ cairo_scaled_font_t *scaled_font,
|
|
+ hb_font_t *hb_font,
|
|
+ PangoRectangle *font_rect,
|
|
+ IBusCairoLine **cairo_lines,
|
|
+ FcChar8 *fallback_family)
|
|
+{
|
|
+ gboolean has_unknown_glyph = FALSE;
|
|
+ hb_buffer_t *hb_buffer;
|
|
+ unsigned int len, n, i;
|
|
+ hb_glyph_info_t *info;
|
|
+ hb_glyph_position_t *pos;
|
|
+ double x;
|
|
+ cairo_glyph_t *glyph;
|
|
+ cairo_text_extents_t text_extents = { 0, };
|
|
+
|
|
+ g_return_if_fail (str != NULL);
|
|
+
|
|
+ hb_buffer = hb_buffer_create ();
|
|
+ hb_buffer_add_utf8 (hb_buffer, str, -1, 0, -1);
|
|
+ hb_buffer_guess_segment_properties (hb_buffer);
|
|
+ for (n = 0; *cairo_lines && (*cairo_lines)[n].scaled_font; n++);
|
|
+ if (n == 0)
|
|
+ *cairo_lines = g_new0 (IBusCairoLine, 2);
|
|
+ else
|
|
+ *cairo_lines = g_renew (IBusCairoLine, *cairo_lines, n + 2);
|
|
+ (*cairo_lines)[n + 1].scaled_font = NULL;
|
|
+ (*cairo_lines)[n + 1].num_glyphs = 0;
|
|
+ (*cairo_lines)[n + 1].glyphs = NULL;
|
|
+ hb_shape (hb_font, hb_buffer, NULL, 0);
|
|
+ len = hb_buffer_get_length (hb_buffer);
|
|
+ info = hb_buffer_get_glyph_infos (hb_buffer, NULL);
|
|
+ pos = hb_buffer_get_glyph_positions (hb_buffer, NULL);
|
|
+ (*cairo_lines)[n].scaled_font = scaled_font;
|
|
+ (*cairo_lines)[n].num_glyphs = len;
|
|
+ (*cairo_lines)[n].glyphs = (IBusGlyph*) cairo_glyph_allocate (len + 1);
|
|
+ x = 0.;
|
|
+ for (i = 0; i < len; i++) {
|
|
+ hb_codepoint_t c = info[i].codepoint;
|
|
+ if (c) {
|
|
+ (*cairo_lines)[n].glyphs[i].index = info[i].codepoint;
|
|
+ (*cairo_lines)[n].glyphs[i].x = x;
|
|
+ (*cairo_lines)[n].glyphs[i].y = -font_rect->y / PANGO_SCALE;
|
|
+ glyph = (cairo_glyph_t *) &((*cairo_lines)[n].glyphs[i]);
|
|
+ cairo_scaled_font_glyph_extents (scaled_font, glyph,
|
|
+ 1, &text_extents);
|
|
+ x += text_extents.width;
|
|
+ } else {
|
|
+ has_unknown_glyph = TRUE;
|
|
+ c = g_utf8_get_char (str);
|
|
+ (*cairo_lines)[n].glyphs[i].index = PANGO_GET_UNKNOWN_GLYPH (c);
|
|
+ (*cairo_lines)[n].glyphs[i].x = x;
|
|
+ (*cairo_lines)[n].glyphs[i].y = -font_rect->y / PANGO_SCALE;
|
|
+ glyph = (cairo_glyph_t *) &((*cairo_lines)[n].glyphs[i]);
|
|
+ cairo_scaled_font_glyph_extents (scaled_font, glyph,
|
|
+ 1, &text_extents);
|
|
+ x += 10;
|
|
+ }
|
|
+ }
|
|
+ (*cairo_lines)[n].glyphs[i].index = -1;
|
|
+ (*cairo_lines)[n].glyphs[i].x = 0;
|
|
+ (*cairo_lines)[n].glyphs[i].y = 0;
|
|
+ glyph = (cairo_glyph_t *) (*cairo_lines)[n].glyphs;
|
|
+ cairo_scaled_font_glyph_extents (scaled_font, glyph,
|
|
+ len, &text_extents);
|
|
+ if (text_extents.width) {
|
|
+ font_rect->width = pango_units_from_double (text_extents.width);
|
|
+ } else {
|
|
+ font_rect->width = font_rect->height;
|
|
+ }
|
|
+ if (has_unknown_glyph && fallback_family != NULL) {
|
|
+ cairo_scaled_font_t *unknown_font;
|
|
+ unknown_font = ibus_fontset_cairo_scaled_font_new_with_font (
|
|
+ (const gchar *) fallback_family,
|
|
+ UNKNOWN_FONT_SIZE);
|
|
+ (*cairo_lines)[n].scaled_font = unknown_font;
|
|
+ }
|
|
+ hb_buffer_destroy (hb_buffer);
|
|
+}
|
|
+
|
|
+static void
|
|
+get_string_extents_with_font (const gchar *str,
|
|
+ FontPerChar *buff,
|
|
+ cairo_rectangle_int_t *rect,
|
|
+ IBusCairoLine **cairo_lines)
|
|
+{
|
|
+ FcChar8 *family = NULL;
|
|
+ FcChar8 *font_path = NULL;
|
|
+ guint size = 0;
|
|
+ cairo_scaled_font_t *scaled_font = NULL;
|
|
+ PangoRectangle font_rect = { 0, };
|
|
+ hb_font_t *hb_font;
|
|
+
|
|
+ g_return_if_fail (str != NULL);
|
|
+ g_return_if_fail (buff != NULL && buff->fcfont != NULL);
|
|
+
|
|
+ FcPatternGetString (buff->fcfont, FC_FAMILY, 0, &family);
|
|
+ g_return_if_fail (family != NULL);
|
|
+ size = m_size;
|
|
+ if (size == 0) {
|
|
+ g_warning ("Font size is not right for font %s.", family);
|
|
+ size = 14;
|
|
+ }
|
|
+ scaled_font = ibus_fontset_cairo_scaled_font_new_with_font (
|
|
+ (const gchar *) family,
|
|
+ size);
|
|
+ g_return_if_fail (scaled_font != NULL);
|
|
+ get_font_extents_with_scaled_font (scaled_font, &font_rect);
|
|
+
|
|
+ FcPatternGetString (buff->fcfont, FC_FILE, 0, &font_path);
|
|
+ g_return_if_fail (font_path != NULL);
|
|
+ hb_font = ibus_fontset_hb_font_new_with_font_path (
|
|
+ (const gchar *) font_path);
|
|
+ if (hb_font == NULL)
|
|
+ return;
|
|
+ get_glyph_extents_with_scaled_hb_font (str,
|
|
+ scaled_font,
|
|
+ hb_font,
|
|
+ &font_rect,
|
|
+ cairo_lines,
|
|
+ family);
|
|
+ rect->width += font_rect.width / PANGO_SCALE;
|
|
+ rect->height += font_rect.height / PANGO_SCALE;
|
|
+}
|
|
+
|
|
+static FT_Face
|
|
+ibus_fontset_get_ftface_from_fcfont (IBusFontSet *fontset,
|
|
+ FcPattern *fcfont)
|
|
+{
|
|
+ FcChar8 *font_file = NULL;
|
|
+ FT_Face ft_face;
|
|
+ guint size = ibus_fontset_get_size (fontset);
|
|
+
|
|
+ g_return_val_if_fail (IBUS_IS_FONTSET (fontset), NULL);
|
|
+ g_return_val_if_fail (fcfont != NULL, NULL);
|
|
+
|
|
+ size = ibus_fontset_get_size (fontset);
|
|
+ FcPatternGetString (fcfont, FC_FILE, 0, &font_file);
|
|
+ FT_New_Face (m_ftlibrary, (const gchar *) font_file, 0, &ft_face);
|
|
+ FT_Set_Pixel_Sizes (ft_face, size, size);
|
|
+ return ft_face;
|
|
+}
|
|
+
|
|
+void
|
|
+_cairo_show_unknown_glyphs (cairo_t *cr,
|
|
+ const cairo_glyph_t *glyphs,
|
|
+ guint num_glyphs,
|
|
+ guint width,
|
|
+ guint height)
|
|
+{
|
|
+ gunichar ch;
|
|
+ gboolean invalid_input;
|
|
+ int rows = 2;
|
|
+ int cols;
|
|
+ int row, col;
|
|
+ char buf[7];
|
|
+ double cx = 0.;
|
|
+ double cy;
|
|
+ const double box_descent = 3.;
|
|
+ double x0;
|
|
+ double y0;
|
|
+ const double digit_width = 5.;
|
|
+ const double digit_height= 6.;
|
|
+ char hexbox_string[2] = {0, 0};
|
|
+
|
|
+ g_assert (glyphs != NULL);
|
|
+ g_assert (num_glyphs > 0);
|
|
+
|
|
+ ch = glyphs[0].index & ~PANGO_GLYPH_UNKNOWN_FLAG;
|
|
+ invalid_input = G_UNLIKELY (glyphs[0].index == PANGO_GLYPH_INVALID_INPUT ||
|
|
+ ch > 0x10FFFF);
|
|
+ if (G_UNLIKELY (invalid_input)) {
|
|
+ g_warning ("Unsupported U+%06X", ch);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ cairo_save (cr);
|
|
+
|
|
+ cols = (ch > 0xffff ? 6 : 4) / rows;
|
|
+ g_snprintf (buf, sizeof(buf), (ch > 0xffff) ? "%06X" : "%04X", ch);
|
|
+ cy = (double) height;
|
|
+ x0 = cx + box_descent + XPAD / 2;
|
|
+ y0 = cy - box_descent - YPAD / 2;
|
|
+
|
|
+ for (row = 0; row < rows; row++) {
|
|
+ double y = y0 - (rows - 1 - row) * (digit_height + YPAD);
|
|
+ for (col = 0; col < cols; col++) {
|
|
+ double x = x0 + col * (digit_width + XPAD);
|
|
+ cairo_move_to (cr, x, y);
|
|
+ hexbox_string[0] = buf[row * cols + col];
|
|
+ cairo_show_text (cr, hexbox_string);
|
|
+ }
|
|
+ }
|
|
+ cairo_move_to (cr, XPAD, YPAD);
|
|
+ cairo_line_to (cr, width - XPAD, YPAD);
|
|
+ cairo_line_to (cr, width - XPAD,
|
|
+ height - YPAD);
|
|
+ cairo_line_to (cr, XPAD, height - YPAD);
|
|
+ cairo_line_to (cr, XPAD, YPAD);
|
|
+ cairo_set_line_width (cr, 1.);
|
|
+ cairo_stroke (cr);
|
|
+
|
|
+ cairo_restore (cr);
|
|
+}
|
|
+
|
|
+IBusCairoLine *
|
|
+ibus_cairo_line_copy (IBusCairoLine *cairo_lines)
|
|
+{
|
|
+ IBusCairoLine *ret;
|
|
+ guint n, i, j, num_glyphs;
|
|
+ if (!cairo_lines)
|
|
+ return NULL;
|
|
+
|
|
+ for (n = 0; cairo_lines[n].scaled_font; n++);
|
|
+ ret = g_new0 (IBusCairoLine, n + 1);
|
|
+ for (i = 0; i < n; i++) {
|
|
+ ret[i].scaled_font = cairo_lines[i].scaled_font;
|
|
+ num_glyphs = cairo_lines[i].num_glyphs;
|
|
+ ret[i].num_glyphs = num_glyphs;
|
|
+ ret[i].glyphs = (IBusGlyph *) cairo_glyph_allocate (num_glyphs + 1);
|
|
+ for (j = 0; j < num_glyphs; j++) {
|
|
+ ret[i].glyphs[j] = cairo_lines[i].glyphs[j];
|
|
+ }
|
|
+ ret[i].glyphs[j].index = -1;
|
|
+ ret[i].glyphs[j].x = 0;
|
|
+ ret[i].glyphs[j].y = 0;
|
|
+ }
|
|
+ ret[i].scaled_font = NULL;
|
|
+ ret[i].num_glyphs = 0;
|
|
+ ret[i].glyphs = NULL;
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+void
|
|
+ibus_cairo_line_free (IBusCairoLine *cairo_lines)
|
|
+{
|
|
+ guint i;
|
|
+ if (!cairo_lines)
|
|
+ return;
|
|
+ for (i = 0; cairo_lines[i].scaled_font; i++) {
|
|
+ g_free (cairo_lines[i].glyphs);
|
|
+ }
|
|
+ g_free (cairo_lines);
|
|
+}
|
|
+
|
|
+IBusRequisitionEx *
|
|
+ibus_requisition_ex_copy (IBusRequisitionEx *req)
|
|
+{
|
|
+ IBusRequisitionEx *ret;
|
|
+ if (!req)
|
|
+ return NULL;
|
|
+ ret = g_new0 (IBusRequisitionEx, 1);
|
|
+ ret->width = req->width;
|
|
+ ret->height = req->height;
|
|
+ ret->cairo_lines = ibus_cairo_line_copy (req->cairo_lines);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+void
|
|
+ibus_requisition_ex_free (IBusRequisitionEx *req)
|
|
+{
|
|
+ if (!req)
|
|
+ return;
|
|
+ g_clear_pointer (&req->cairo_lines, ibus_cairo_line_free);
|
|
+ g_free (req);
|
|
+}
|
|
+
|
|
+IBusFontSet *
|
|
+ibus_fontset_new (const gchar *first_property_name, ...)
|
|
+{
|
|
+ va_list var_args;
|
|
+ IBusFontSet *fontset;
|
|
+
|
|
+ g_assert (first_property_name);
|
|
+
|
|
+ va_start (var_args, first_property_name);
|
|
+ fontset = (IBusFontSet *)g_object_new_valist (IBUS_TYPE_FONTSET,
|
|
+ first_property_name,
|
|
+ var_args);
|
|
+ va_end (var_args);
|
|
+ g_assert (fontset->priv->family);
|
|
+ g_assert (fontset->priv->language);
|
|
+ return fontset;
|
|
+}
|
|
+
|
|
+IBusFontSet *
|
|
+ibus_fontset_new_with_font (const gchar *family,
|
|
+ guint size,
|
|
+ const gchar *language)
|
|
+{
|
|
+ return ibus_fontset_new ("family", family,
|
|
+ "size", size,
|
|
+ "language", language,
|
|
+ NULL);
|
|
+}
|
|
+
|
|
+void
|
|
+ibus_fontset_exit ()
|
|
+{
|
|
+ g_clear_pointer (&m_ftlibrary, FT_Done_FreeType);
|
|
+}
|
|
+
|
|
+const gchar *
|
|
+ibus_fontset_get_family (IBusFontSet *fontset)
|
|
+{
|
|
+ g_return_val_if_fail (IBUS_IS_FONTSET (fontset), NULL);
|
|
+ return fontset->priv->family;
|
|
+}
|
|
+
|
|
+void
|
|
+ibus_fontset_set_family (IBusFontSet *fontset,
|
|
+ const gchar *family)
|
|
+{
|
|
+ g_return_if_fail (IBUS_IS_FONTSET (fontset));
|
|
+ g_free (fontset->priv->family);
|
|
+ fontset->priv->family = g_strdup (family);
|
|
+}
|
|
+
|
|
+guint
|
|
+ibus_fontset_get_size (IBusFontSet *fontset)
|
|
+{
|
|
+ g_return_val_if_fail (IBUS_IS_FONTSET (fontset), 0);
|
|
+ return fontset->priv->size;
|
|
+}
|
|
+
|
|
+void
|
|
+ibus_fontset_set_size (IBusFontSet *fontset,
|
|
+ guint size)
|
|
+{
|
|
+ g_return_if_fail (IBUS_IS_FONTSET (fontset));
|
|
+ fontset->priv->size = size;
|
|
+}
|
|
+
|
|
+const gchar *
|
|
+ibus_fontset_get_language (IBusFontSet *fontset)
|
|
+{
|
|
+ g_return_val_if_fail (IBUS_IS_FONTSET (fontset), NULL);
|
|
+ return fontset->priv->language;
|
|
+}
|
|
+
|
|
+void
|
|
+ibus_fontset_set_language (IBusFontSet *fontset,
|
|
+ const gchar *language)
|
|
+{
|
|
+ g_return_if_fail (IBUS_IS_FONTSET (fontset));
|
|
+ g_free (fontset->priv->language);
|
|
+ fontset->priv->language = g_strdup (language);
|
|
+}
|
|
+
|
|
+gboolean
|
|
+ibus_fontset_update_fcfontset (IBusFontSet *fontset)
|
|
+{
|
|
+ FcPattern *pattern;
|
|
+ const gchar *family;
|
|
+ guint size;
|
|
+ const gchar *language;
|
|
+ gboolean update_fontset = FALSE;
|
|
+ FcResult result;
|
|
+
|
|
+ g_return_val_if_fail (IBUS_IS_FONTSET (fontset), FALSE);
|
|
+
|
|
+ pattern = FcPatternCreate ();
|
|
+ family = fontset->priv->family;
|
|
+ size = fontset->priv->size;
|
|
+ language = fontset->priv->language;
|
|
+
|
|
+ if (g_strcmp0 (m_family, family)) {
|
|
+ g_free (m_family);
|
|
+ m_family = g_strdup (family);
|
|
+ update_fontset = TRUE;
|
|
+ }
|
|
+ if (m_size != size) {
|
|
+ m_size = size;
|
|
+ update_fontset = TRUE;
|
|
+ }
|
|
+ if (g_strcmp0 (m_language, language)) {
|
|
+ g_free (m_language);
|
|
+ m_language = g_strdup (language);
|
|
+ update_fontset = TRUE;
|
|
+ }
|
|
+ if (!update_fontset && m_fcfontset != NULL)
|
|
+ return FALSE;
|
|
+
|
|
+ if (m_fcfontset)
|
|
+ g_clear_pointer (&m_fcfontset, FcFontSetDestroy);
|
|
+
|
|
+ if (g_strcmp0 (family, ""))
|
|
+ FcPatternAddString (pattern, FC_FAMILY, (const FcChar8*) family);
|
|
+ if (size > 0)
|
|
+ FcPatternAddDouble (pattern, FC_SIZE, (double) size);
|
|
+ if (g_strcmp0 (language, ""))
|
|
+ FcPatternAddString (pattern, FC_LANG, (const FcChar8*) language);
|
|
+ FcPatternAddInteger (pattern, FC_WEIGHT, FC_WEIGHT_NORMAL);
|
|
+ FcPatternAddInteger (pattern, FC_WIDTH, FC_WIDTH_NORMAL);
|
|
+ FcPatternAddInteger (pattern, FC_DPI, 96);
|
|
+ FcConfigSubstitute (NULL, pattern, FcMatchPattern);
|
|
+ FcConfigSubstitute (NULL, pattern, FcMatchFont);
|
|
+ FcDefaultSubstitute (pattern);
|
|
+ m_fcfontset = FcFontSort (NULL, pattern, FcTrue, NULL, &result);
|
|
+ if (result == FcResultNoMatch || m_fcfontset->nfont == 0) {
|
|
+ g_warning ("No FcFontSet for %s", family ? family : "(null)");
|
|
+ return FALSE;
|
|
+ }
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+void
|
|
+ibus_fontset_unref (IBusFontSet *fontset)
|
|
+{
|
|
+ g_object_unref (fontset);
|
|
+}
|
|
+
|
|
+IBusRequisitionEx *
|
|
+ibus_fontset_get_preferred_size_hb (IBusFontSet *fontset,
|
|
+ const gchar *text,
|
|
+ cairo_rectangle_int_t *widest)
|
|
+{
|
|
+ gchar *copied_text;
|
|
+ gchar *p;
|
|
+ FontPerChar *buff;
|
|
+ IBusCairoLine *cairo_lines = NULL;
|
|
+ IBusRequisitionEx *req = NULL;
|
|
+ GString *str = NULL;
|
|
+ int text_length;
|
|
+ int i, n = 0;
|
|
+
|
|
+ g_return_val_if_fail (IBUS_IS_FONTSET (fontset), NULL);
|
|
+ g_return_val_if_fail (m_fcfontset != NULL, NULL);
|
|
+
|
|
+ copied_text = g_strdup (text);
|
|
+ text_length = g_utf8_strlen (text, -1);
|
|
+ buff = g_slice_alloc0 (sizeof (FontPerChar) * text_length);
|
|
+ str = g_string_new (NULL);
|
|
+
|
|
+ for (p = copied_text; *p != '\0'; p = g_utf8_next_char (p)) {
|
|
+ gunichar c = g_utf8_get_char (p);
|
|
+ gboolean has_glyphs = FALSE;
|
|
+ buff[n].ch = c;
|
|
+ if ((c == 0xfe0eu || c == 0xfe0fu) && n > 0) {
|
|
+ buff[n].fcfont = buff[n-1].fcfont;
|
|
+ ++n;
|
|
+ continue;
|
|
+ }
|
|
+ for (i = 0; i < m_fcfontset->nfont; i++) {
|
|
+ if (g_unichar_iscntrl (c) && !g_unichar_isspace (c))
|
|
+ break;
|
|
+ FT_Face ft_face = ibus_fontset_get_ftface_from_fcfont (
|
|
+ fontset,
|
|
+ m_fcfontset->fonts[i]);
|
|
+ if (FT_Get_Char_Index (ft_face, c) != 0) {
|
|
+ buff[n].fcfont = m_fcfontset->fonts[i];
|
|
+ if (n > 0 && buff[n - 1].fcfont != buff[n].fcfont) {
|
|
+ get_string_extents_with_font (str->str,
|
|
+ &buff[n - 1],
|
|
+ widest,
|
|
+ &cairo_lines);
|
|
+ g_string_free (str, TRUE);
|
|
+ str = g_string_new (NULL);
|
|
+ g_string_append_unichar (str, c);
|
|
+ } else {
|
|
+ g_string_append_unichar (str, c);
|
|
+ }
|
|
+ ++n;
|
|
+ has_glyphs = TRUE;
|
|
+ FT_Done_Face (ft_face);
|
|
+ break;
|
|
+ }
|
|
+ FT_Done_Face (ft_face);
|
|
+ }
|
|
+ if (!has_glyphs) {
|
|
+ if (n > 0) {
|
|
+ buff[n].fcfont = buff[n - 1].fcfont;
|
|
+ } else {
|
|
+ /* Search a font for non-glyph char to draw the code points
|
|
+ * likes Pango.
|
|
+ */
|
|
+ for (i = 0; i < m_fcfontset->nfont; i++) {
|
|
+ FT_Face ft_face = ibus_fontset_get_ftface_from_fcfont (
|
|
+ fontset,
|
|
+ m_fcfontset->fonts[i]);
|
|
+ /* Check alphabets instead of space or digits
|
|
+ * because 'Noto Emoji Color' font's digits are
|
|
+ * white color and cannot change the font color.
|
|
+ * the font does not have alphabets.
|
|
+ */
|
|
+ if (FT_Get_Char_Index (ft_face, 'A') != 0) {
|
|
+ buff[n].fcfont = m_fcfontset->fonts[i];
|
|
+ FT_Done_Face (ft_face);
|
|
+ has_glyphs = TRUE;
|
|
+ break;
|
|
+ }
|
|
+ FT_Done_Face (ft_face);
|
|
+ }
|
|
+ if (!has_glyphs) {
|
|
+ buff[n].fcfont = m_fcfontset->fonts[0];
|
|
+ g_warning ("Not found fonts for unicode %04X at %d in %s",
|
|
+ c, n, text);
|
|
+ }
|
|
+ }
|
|
+ n++;
|
|
+ g_string_append_unichar (str, c);
|
|
+ }
|
|
+ }
|
|
+ if (str->str) {
|
|
+ get_string_extents_with_font (str->str,
|
|
+ &buff[n - 1],
|
|
+ widest,
|
|
+ &cairo_lines);
|
|
+ g_string_free (str, TRUE);
|
|
+ }
|
|
+ g_slice_free1 (sizeof (FontPerChar) * text_length, buff);
|
|
+ g_free (copied_text);
|
|
+ widest->width += XPAD * 2;
|
|
+ widest->height += YPAD * 2;
|
|
+ req = g_new0 (IBusRequisitionEx, 1);
|
|
+ req->width = widest->width;
|
|
+ req->height = widest->height;
|
|
+ req->cairo_lines = cairo_lines;
|
|
+ return req;
|
|
+}
|
|
+
|
|
+void
|
|
+ibus_fontset_draw_cairo_with_requisition_ex (IBusFontSet *fontset,
|
|
+ cairo_t *cr,
|
|
+ IBusRequisitionEx *ex)
|
|
+{
|
|
+ IBusCairoLine *cairo_lines;
|
|
+ int i;
|
|
+
|
|
+ g_return_if_fail (IBUS_IS_FONTSET (fontset));
|
|
+ g_return_if_fail (cr != NULL);
|
|
+ g_return_if_fail (ex != NULL);
|
|
+
|
|
+ cairo_lines = ex->cairo_lines;
|
|
+ g_return_if_fail (cairo_lines != NULL);
|
|
+
|
|
+ for (i = 0; cairo_lines[i].scaled_font; i++) {
|
|
+ const cairo_glyph_t *glyphs = (cairo_glyph_t *) cairo_lines[i].glyphs;
|
|
+ guint num_glyphs = cairo_lines[i].num_glyphs;
|
|
+
|
|
+ cairo_ft_scaled_font_lock_face (cairo_lines[i].scaled_font);
|
|
+ cairo_set_scaled_font (cr, cairo_lines[i].scaled_font);
|
|
+ if (num_glyphs > 0 && glyphs[0].index & PANGO_GLYPH_UNKNOWN_FLAG) {
|
|
+ _cairo_show_unknown_glyphs (cr, glyphs, num_glyphs,
|
|
+ ex->width, ex->height);
|
|
+ } else {
|
|
+ cairo_show_glyphs (cr, glyphs, num_glyphs);
|
|
+ }
|
|
+ cairo_ft_scaled_font_unlock_face (cairo_lines[i].scaled_font);
|
|
+ }
|
|
+}
|
|
diff --git a/ui/gtk3/ibusfontset.h b/ui/gtk3/ibusfontset.h
|
|
new file mode 100644
|
|
index 0000000..efcaa28
|
|
--- /dev/null
|
|
+++ b/ui/gtk3/ibusfontset.h
|
|
@@ -0,0 +1,302 @@
|
|
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
|
|
+/* vim:set et sts=4: */
|
|
+/* ibus - The Input Bus
|
|
+ * Copyright (C) 2017 Takao Fujiwara <takao.fujiwara1@gmail.com>
|
|
+ * Copyright (C) 2017 Red Hat, Inc.
|
|
+ *
|
|
+ * This library is free software; you can redistribute it and/or
|
|
+ * modify it under the terms of the GNU Lesser General Public
|
|
+ * License as published by the Free Software Foundation; either
|
|
+ * version 2.1 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
|
|
+ * Lesser General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU Lesser General Public
|
|
+ * License along with this library; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
|
+ * USA
|
|
+ */
|
|
+
|
|
+#ifndef __IBUS_HARFBUZZ_H_
|
|
+#define __IBUS_HARFBUZZ_H_
|
|
+
|
|
+/**
|
|
+ * SECTION: ibusfontset
|
|
+ * @short_description: Object for HarfBuzz and Fontconfig.
|
|
+ * @title: IBusFontSet
|
|
+ * @stability: Unstable
|
|
+ *
|
|
+ * IBusFontSet offers FcFontSet, glyph info with HarfBuzz and rendering
|
|
+ * on Cairo context.
|
|
+ * Current Pango changes fonts by emoji variants and draws the separated
|
|
+ * glyphs [1] but actually the emoji characters with variants can be drawn
|
|
+ * as one glyph so this class manages Fontconfig fontsets to select a font,
|
|
+ * HarfBuzz to get glyphs for emoji variants, Cairo to draw glyphs.
|
|
+ *
|
|
+ * [1]: https://bugzilla.gnome.org/show_bug.cgi?id=780669
|
|
+ * https://bugzilla.gnome.org/show_bug.cgi?id=781123
|
|
+ */
|
|
+
|
|
+#include <ibus.h>
|
|
+#include <cairo.h>
|
|
+
|
|
+#define IBUS_TYPE_CAIRO_LINE (ibus_cairo_line_get_type ())
|
|
+#define IBUS_TYPE_REQUISITION_EX (ibus_requisition_ex_get_type ())
|
|
+#define IBUS_TYPE_FONTSET (ibus_fontset_get_type ())
|
|
+#define IBUS_FONTSET(obj) (G_TYPE_CHECK_INSTANCE_CAST (\
|
|
+ (obj), \
|
|
+ IBUS_TYPE_FONTSET, \
|
|
+ IBusFontSet))
|
|
+#define IBUS_FONTSET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST (\
|
|
+ (klass), \
|
|
+ IBUS_TYPE_FONTSET, \
|
|
+ IBusFontSetClass))
|
|
+#define IBUS_IS_FONTSET(obj) (G_TYPE_CHECK_INSTANCE_TYPE (\
|
|
+ (obj), \
|
|
+ IBUS_TYPE_FONTSET))
|
|
+#define IBUS_IS_FONTSET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE (\
|
|
+ (klass), \
|
|
+ IBUS_TYPE_FONTSET))
|
|
+#define IBUS_FONTSET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS (\
|
|
+ (obj), \
|
|
+ IBUS_TYPE_FONTSET, \
|
|
+ IBusFontSetClass))
|
|
+
|
|
+G_BEGIN_DECLS
|
|
+
|
|
+typedef struct _IBusGlyph IBusGlyph;
|
|
+typedef struct _IBusCairoLine IBusCairoLine;
|
|
+typedef struct _IBusRequisitionEx IBusRequisitionEx;
|
|
+typedef struct _IBusFontSet IBusFontSet;
|
|
+typedef struct _IBusFontSetPrivate IBusFontSetPrivate;
|
|
+typedef struct _IBusFontSetClass IBusFontSetClass;
|
|
+
|
|
+struct _IBusGlyph {
|
|
+ unsigned long index;
|
|
+ double x;
|
|
+ double y;
|
|
+};
|
|
+
|
|
+struct _IBusCairoLine {
|
|
+ IBusGlyph *glyphs;
|
|
+ guint num_glyphs;
|
|
+ cairo_scaled_font_t *scaled_font;
|
|
+ gpointer pdummy[5];
|
|
+};
|
|
+
|
|
+struct _IBusRequisitionEx {
|
|
+ guint width;
|
|
+ guint height;
|
|
+ IBusCairoLine *cairo_lines;
|
|
+ gpointer pdummy[5];
|
|
+};
|
|
+
|
|
+struct _IBusFontSet {
|
|
+ IBusObject parent_instance;
|
|
+ IBusFontSetPrivate *priv;
|
|
+};
|
|
+
|
|
+struct _IBusFontSetClass {
|
|
+ IBusObjectClass parent_class;
|
|
+ /* signals */
|
|
+ /*< private >*/
|
|
+ /* padding */
|
|
+ gpointer pdummy[10];
|
|
+};
|
|
+
|
|
+GType ibus_cairo_line_get_type (void) G_GNUC_CONST;
|
|
+
|
|
+/**
|
|
+ * ibus_cairo_line_copy:
|
|
+ * @cairo_lines: #IBusCairoLine
|
|
+ *
|
|
+ * Creates a copy of @cairo_liens, which should be freed with
|
|
+ * ibus_cairo_line_free(). Primarily used by language bindings,
|
|
+ * not that useful otherwise (since @req can just be copied
|
|
+ * by assignment in C).
|
|
+ *
|
|
+ * Returns: the newly allocated #IBusCairoLine, which should
|
|
+ * be freed with ibus_cairo_line_free(), or %NULL
|
|
+ * if @cairo_lines was %NULL.
|
|
+ **/
|
|
+IBusCairoLine * ibus_cairo_line_copy (IBusCairoLine *cairo_lines);
|
|
+
|
|
+/**
|
|
+ * ibus_cairo_line_free:
|
|
+ * @cairo_lines: #IBusCairoLine
|
|
+ *
|
|
+ * Free an #IBusCairoLine.
|
|
+ */
|
|
+void ibus_cairo_line_free (IBusCairoLine *cairo_lines);
|
|
+
|
|
+
|
|
+GType ibus_requisition_ex_get_type (void) G_GNUC_CONST;
|
|
+
|
|
+/**
|
|
+ * ibus_requisition_ex_copy:
|
|
+ * @req: #IBusRequisitionEx
|
|
+ *
|
|
+ * Creates a copy of @req, which should be freed with
|
|
+ * ibus_requisition_ex_free(). Primarily used by language bindings,
|
|
+ * not that useful otherwise (since @req can just be copied
|
|
+ * by assignment in C).
|
|
+ *
|
|
+ * Returns: the newly allocated #IBusRequisitionEx, which should
|
|
+ * be freed with ibus_requisition_ex_free(), or %NULL
|
|
+ * if @req was %NULL.
|
|
+ **/
|
|
+IBusRequisitionEx *
|
|
+ ibus_requisition_ex_copy (IBusRequisitionEx *req);
|
|
+
|
|
+/**
|
|
+ * ibus_requisition_ex_free:
|
|
+ * @req: #IBusRequisitionEx
|
|
+ *
|
|
+ * Free an #IBusRequisitionEx.
|
|
+ */
|
|
+void ibus_requisition_ex_free (IBusRequisitionEx *req);
|
|
+
|
|
+
|
|
+GType ibus_fontset_get_type (void);
|
|
+
|
|
+/**
|
|
+ * ibus_fontset_new:
|
|
+ * @first_property_name:
|
|
+ *
|
|
+ * Creates a new #IBusFcFontSet.
|
|
+ *
|
|
+ * Returns: (transfer full): A newly allocated #IBusFontSet and includes
|
|
+ * #FcFontSet internally. E.g. ibus_fontset_new ("family",
|
|
+ * "Noto Emoji Color", "size", 16, "language", "ja-jp");
|
|
+ */
|
|
+IBusFontSet * ibus_fontset_new (const gchar
|
|
+ *first_property_name,
|
|
+ ...);
|
|
+
|
|
+/**
|
|
+ * ibus_fontset_new_with_font:
|
|
+ * @family: font family
|
|
+ * @size: font size
|
|
+ * @language: font language
|
|
+ *
|
|
+ * Creates a new #IBusFcFontSet.
|
|
+ *
|
|
+ * Returns: (transfer full): A newly allocated #IBusFcFontSet and includes
|
|
+ * #FcFontSet internally.
|
|
+ */
|
|
+IBusFontSet * ibus_fontset_new_with_font (const gchar *family,
|
|
+ guint size,
|
|
+ const gchar *language);
|
|
+/**
|
|
+ * ibus_fontset_get_family:
|
|
+ * @fontset: #IBusFcFontSet
|
|
+ *
|
|
+ * Return the base font family of #FcFontSet
|
|
+ *
|
|
+ * Returns: Base font family of #FcFontSet
|
|
+ */
|
|
+const gchar * ibus_fontset_get_family (IBusFontSet *fontset);
|
|
+
|
|
+/**
|
|
+ * ibus_fontset_set_family:
|
|
+ * @fontset: #IBusFcFontSet
|
|
+ * @family: base font family for #FcFontSet
|
|
+ *
|
|
+ * Set the base font family for #FcFontSet
|
|
+ */
|
|
+void ibus_fontset_set_family (IBusFontSet *fontset,
|
|
+ const gchar *family);
|
|
+/**
|
|
+ * ibus_fontset_get_size:
|
|
+ * @fontset: #IBusFcFontSet
|
|
+ *
|
|
+ * Return the font size of #FcFontSet
|
|
+ *
|
|
+ * Returns: Font size of #FcFontSet
|
|
+ */
|
|
+guint ibus_fontset_get_size (IBusFontSet *fontset);
|
|
+
|
|
+/**
|
|
+ * ibus_fontset_set_size:
|
|
+ * @fontset: #IBusFcFontSet
|
|
+ * @size: font size for #FcFontSet
|
|
+ *
|
|
+ * Set the font size for #FcFontSet
|
|
+ */
|
|
+void ibus_fontset_set_size (IBusFontSet *fontset,
|
|
+ guint size);
|
|
+/**
|
|
+ * ibus_fontset_get_language:
|
|
+ * @fontset: #IBusFcFontSet
|
|
+ *
|
|
+ * Return the font language of #FcFontSet
|
|
+ *
|
|
+ * Returns: Font language of #FcFontSet
|
|
+ */
|
|
+const gchar * ibus_fontset_get_language (IBusFontSet *fontset);
|
|
+
|
|
+/**
|
|
+ * ibus_fontset_set_language:
|
|
+ * @fontset: #IBusFcFontSet
|
|
+ * @language: font langauge for #FcFontSet
|
|
+ *
|
|
+ * Set the font language for #FcFontSet
|
|
+ */
|
|
+void ibus_fontset_set_language (IBusFontSet *fontset,
|
|
+ const gchar *language);
|
|
+
|
|
+/**
|
|
+ * ibus_fontset_update_fcfontset:
|
|
+ * @fontset: #IBusFcFontSet
|
|
+ *
|
|
+ * Update #FcFontSet from font family, size and langauge of @fontset.
|
|
+ * Returns: %TRUE if #FcFontSet is updated. %FALSE otherwise.
|
|
+ */
|
|
+gboolean ibus_fontset_update_fcfontset (IBusFontSet *fontset);
|
|
+
|
|
+/**
|
|
+ * ibus_fontset_get_preferred_size_hb:
|
|
+ * @fontset: #IBusFcFontSet
|
|
+ * @text: a string to be calculate the preferred rectangle size.
|
|
+ * @widest: (out): #cairo_rectangle_int_t is updated.
|
|
+ *
|
|
+ * Calculate @widest for @text.
|
|
+ *
|
|
+ * Returns: #IBusRequisitionEx which includes the glyphs and coordinates.
|
|
+ */
|
|
+IBusRequisitionEx *
|
|
+ ibus_fontset_get_preferred_size_hb
|
|
+ (IBusFontSet *fontset,
|
|
+ const gchar *text,
|
|
+ cairo_rectangle_int_t
|
|
+ *widest);
|
|
+
|
|
+/**
|
|
+ * ibus_fontset_draw_cairo_lines:
|
|
+ * @fontset: #IBusFcFontSet
|
|
+ * @cr: #cairo_t in #GtkWidget.draw().
|
|
+ * @ex: #IBusRequisitionEx which includes glyph, x, y values, char width
|
|
+ * and height.
|
|
+ *
|
|
+ * Draw glyphs in @ex using cairo @cr.
|
|
+ */
|
|
+void ibus_fontset_draw_cairo_with_requisition_ex
|
|
+ (IBusFontSet *fontset,
|
|
+ cairo_t *cr,
|
|
+ IBusRequisitionEx
|
|
+ *ex);
|
|
+
|
|
+/**
|
|
+ * ibus_fontset_unref:
|
|
+ * @fontset: #IBusFcFontSet
|
|
+ *
|
|
+ * Call g_object_unref().
|
|
+ * FIXME: Seems Vala needs this API.
|
|
+ */
|
|
+void ibus_fontset_unref (IBusFontSet *fontset);
|
|
+
|
|
+G_END_DECLS
|
|
+#endif
|
|
--
|
|
2.9.3
|
|
|