1746 lines
60 KiB
Diff
1746 lines
60 KiB
Diff
From 1e358f28a2b36743847584671ef533769036b40d Mon Sep 17 00:00:00 2001
|
|
From: fujiwarat <takao.fujiwara1@gmail.com>
|
|
Date: Sun, 22 Oct 2017 10:45:33 +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
|
|
---
|
|
bindings/vala/IBusFontSet-1.0.metadata | 1 +
|
|
bindings/vala/Makefile.am | 83 +++
|
|
bindings/vala/ibus-fontset-1.0.deps | 1 +
|
|
configure.ac | 29 +
|
|
ui/gtk3/Makefile.am | 32 +
|
|
ui/gtk3/emojier.vala | 100 +++-
|
|
ui/gtk3/ibusfontset.c | 1030 ++++++++++++++++++++++++++++++++
|
|
ui/gtk3/ibusfontset.h | 302 ++++++++++
|
|
8 files changed, 1576 insertions(+), 2 deletions(-)
|
|
create mode 100644 bindings/vala/IBusFontSet-1.0.metadata
|
|
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/bindings/vala/IBusFontSet-1.0.metadata b/bindings/vala/IBusFontSet-1.0.metadata
|
|
new file mode 100644
|
|
index 00000000..73037d7f
|
|
--- /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 fc8e2f01..f7b9e97a 100644
|
|
--- a/bindings/vala/Makefile.am
|
|
+++ b/bindings/vala/Makefile.am
|
|
@@ -83,8 +83,10 @@ EXTRA_DIST = \
|
|
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)
|
|
@@ -131,6 +133,15 @@ libibus_emoji_dialog_1_0_la_LDFLAGS = \
|
|
if test ! -f $@ ; then \
|
|
$(LN_S) $(top_srcdir)/ui/gtk3/$@ .; \
|
|
fi;
|
|
+ibusfontset.c: $(ibus_vapi) ibusfontset.h
|
|
+ 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)
|
|
@@ -184,6 +195,78 @@ 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
|
|
|
|
diff --git a/bindings/vala/ibus-fontset-1.0.deps b/bindings/vala/ibus-fontset-1.0.deps
|
|
new file mode 100644
|
|
index 00000000..129fe166
|
|
--- /dev/null
|
|
+++ b/bindings/vala/ibus-fontset-1.0.deps
|
|
@@ -0,0 +1 @@
|
|
+cairo
|
|
diff --git a/configure.ac b/configure.ac
|
|
index 14556a3a..6ff8f4a9 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
|
|
@@ -743,6 +771,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/ui/gtk3/Makefile.am b/ui/gtk3/Makefile.am
|
|
index 786b80e6..cd1e9c2c 100644
|
|
--- a/ui/gtk3/Makefile.am
|
|
+++ b/ui/gtk3/Makefile.am
|
|
@@ -156,6 +156,8 @@ EXTRA_DIST = \
|
|
$(man_seven_in_files) \
|
|
emojierapp.vala \
|
|
gtkpanel.xml.in \
|
|
+ ibusfontset.c \
|
|
+ ibusfontset.h \
|
|
notification-item.xml \
|
|
notification-watcher.xml \
|
|
$(NULL)
|
|
@@ -198,6 +200,36 @@ emojierapp.o: $(srcdir)/emojierapp.c
|
|
$(AM_V_CC_no)$(COMPILE) -c -o $@ $<
|
|
$(NULL)
|
|
|
|
+if ENABLE_HARFBUZZ_FOR_EMOJI
|
|
+ibus_ui_gtk3_SOURCES += \
|
|
+ ibusfontset.c \
|
|
+ $(NULL)
|
|
+
|
|
+ibus_ui_emojier_SOURCES += \
|
|
+ ibusfontset.c \
|
|
+ $(NULL)
|
|
+
|
|
+AM_CFLAGS += \
|
|
+ @CAIRO_CFLAGS@ \
|
|
+ @FONTCONFIG_CFLAGS@ \
|
|
+ @HARFBUZZ_CFLAGS@ \
|
|
+ $(NULL)
|
|
+
|
|
+AM_LDADD += \
|
|
+ @CAIRO_LIBS@ \
|
|
+ @FONTCONFIG_LIBS@ \
|
|
+ @HARFBUZZ_LIBS@ \
|
|
+ $(NULL)
|
|
+
|
|
+AM_VALAFLAGS += \
|
|
+ -D ENABLE_HARFBUZZ_FOR_EMOJI \
|
|
+ --pkg=cairo \
|
|
+ --pkg=ibus-fontset-1.0 \
|
|
+ $(NULL)
|
|
+
|
|
+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)
|
|
man_sevendir = $(mandir)/man7
|
|
diff --git a/ui/gtk3/emojier.vala b/ui/gtk3/emojier.vala
|
|
index f3e9f15c..58a26dd6 100644
|
|
--- a/ui/gtk3/emojier.vala
|
|
+++ b/ui/gtk3/emojier.vala
|
|
@@ -99,6 +99,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"
|
|
@@ -106,8 +109,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"
|
|
@@ -116,7 +189,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"
|
|
@@ -231,6 +304,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;
|
|
@@ -1666,6 +1742,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;
|
|
@@ -1696,6 +1788,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/ibusfontset.c b/ui/gtk3/ibusfontset.c
|
|
new file mode 100644
|
|
index 00000000..16ceef05
|
|
--- /dev/null
|
|
+++ b/ui/gtk3/ibusfontset.c
|
|
@@ -0,0 +1,1030 @@
|
|
+/* -*- 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))
|
|
+#define MONOSPACE "monospace"
|
|
+#define SERIF "serif"
|
|
+#define SANS "sans"
|
|
+
|
|
+typedef struct _FcFontSetEx {
|
|
+ int nfont;
|
|
+ int sfont;
|
|
+ FcPattern **fonts;
|
|
+ FT_Face *ft_faces;
|
|
+} FcFontSetEx;
|
|
+
|
|
+static gboolean m_color_supported;
|
|
+static FT_Library m_ftlibrary;
|
|
+static FcFontSetEx *m_fcfontset;
|
|
+static gchar *m_family;
|
|
+static guint m_size;
|
|
+static gchar *m_language;
|
|
+static GHashTable *m_font_index_per_char_table;
|
|
+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,
|
|
+ gboolean has_color);
|
|
+
|
|
+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;
|
|
+
|
|
+ m_color_supported = (FcGetVersion () >= 21205);
|
|
+ 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,
|
|
+ TRUE);
|
|
+ }
|
|
+ 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,
|
|
+ gboolean has_color)
|
|
+{
|
|
+ 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);
|
|
+
|
|
+ if (m_color_supported) {
|
|
+ font_name = g_strdup_printf ("%s %u:color=%s",
|
|
+ family, size,
|
|
+ has_color ? "TRUE" : "FALSE");
|
|
+ } else {
|
|
+ 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);
|
|
+/* FC_VERSION is for the build check of FC_COLOR and m_color_supported is
|
|
+ * for the runtime check.
|
|
+ */
|
|
+#if FC_VERSION >= 21205
|
|
+ if (m_color_supported)
|
|
+ FcPatternAddBool (pattern, FC_COLOR, has_color);
|
|
+#endif
|
|
+ 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,
|
|
+ FALSE);
|
|
+ (*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;
|
|
+ gboolean has_color = TRUE;
|
|
+ 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);
|
|
+#if FC_VERSION >= 21205
|
|
+ if (m_color_supported)
|
|
+ FcPatternGetBool (buff->fcfont, FC_COLOR, 0, &has_color);
|
|
+#endif
|
|
+ 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,
|
|
+ has_color);
|
|
+ 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;
|
|
+}
|
|
+
|
|
+static 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);
|
|
+}
|
|
+
|
|
+static void
|
|
+ibus_fcfontset_destroy_ex (FcFontSetEx *fcfontset_ex)
|
|
+{
|
|
+ FcFontSet *fcfontset = NULL;
|
|
+ int i;
|
|
+
|
|
+ g_return_if_fail (fcfontset_ex != NULL);
|
|
+
|
|
+ for (i = 0; i < fcfontset_ex->nfont; i++)
|
|
+ FT_Done_Face (fcfontset_ex->ft_faces[i]);
|
|
+ fcfontset = FcFontSetCreate ();
|
|
+ fcfontset->nfont = fcfontset_ex->nfont;
|
|
+ fcfontset->sfont = fcfontset_ex->sfont;
|
|
+ fcfontset->fonts = fcfontset_ex->fonts;
|
|
+ FcFontSetDestroy (fcfontset);
|
|
+ g_free (fcfontset_ex->ft_faces);
|
|
+ g_free (fcfontset_ex);
|
|
+}
|
|
+
|
|
+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;
|
|
+ FcFontSet *fcfontset = NULL;
|
|
+ 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_font_index_per_char_table)
|
|
+ g_hash_table_destroy (m_font_index_per_char_table);
|
|
+ if (m_fcfontset)
|
|
+ g_clear_pointer (&m_fcfontset, ibus_fcfontset_destroy_ex);
|
|
+
|
|
+ m_font_index_per_char_table = g_hash_table_new (g_direct_hash,
|
|
+ g_direct_equal);
|
|
+ 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);
|
|
+#if FC_VERSION >= 21205
|
|
+ if (m_color_supported &&
|
|
+ (!g_ascii_strncasecmp (family, MONOSPACE, strlen (MONOSPACE)) ||
|
|
+ !g_ascii_strncasecmp (family, SERIF, strlen (SERIF)) ||
|
|
+ !g_ascii_strncasecmp (family, SANS, strlen (SANS)))) {
|
|
+ FcPatternAddBool (pattern, FC_COLOR, TRUE);
|
|
+ }
|
|
+#endif
|
|
+ FcConfigSubstitute (NULL, pattern, FcMatchPattern);
|
|
+ FcConfigSubstitute (NULL, pattern, FcMatchFont);
|
|
+ FcDefaultSubstitute (pattern);
|
|
+ fcfontset = FcFontSort (NULL, pattern, FcTrue, NULL, &result);
|
|
+ FcPatternDestroy (pattern);
|
|
+ if (result == FcResultNoMatch || fcfontset->nfont == 0) {
|
|
+ g_warning ("No FcFontSet for %s", family ? family : "(null)");
|
|
+ return FALSE;
|
|
+ }
|
|
+ m_fcfontset = g_new0 (FcFontSetEx, 1);
|
|
+ m_fcfontset->nfont = fcfontset->nfont;
|
|
+ m_fcfontset->sfont = fcfontset->sfont;
|
|
+ m_fcfontset->fonts = fcfontset->fonts;
|
|
+ m_fcfontset->ft_faces = g_new0 (FT_Face, fcfontset->nfont);
|
|
+ fcfontset->nfont = 0;
|
|
+ fcfontset->sfont = 0;
|
|
+ fcfontset->fonts = NULL;
|
|
+ FcFontSetDestroy (fcfontset);
|
|
+ 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;
|
|
+ }
|
|
+ i = GPOINTER_TO_INT (g_hash_table_lookup (m_font_index_per_char_table,
|
|
+ GINT_TO_POINTER (c)));
|
|
+ if (i > 0) {
|
|
+ i--;
|
|
+ if (i >= m_fcfontset->nfont) {
|
|
+ g_warning ("i:%d >= m_fcfontset->nfont:%d",
|
|
+ i, m_fcfontset->nfont);
|
|
+ } else {
|
|
+ buff[n].fcfont = m_fcfontset->fonts[i];
|
|
+ has_glyphs = TRUE;
|
|
+ }
|
|
+ }
|
|
+ for (; i < m_fcfontset->nfont; i++) {
|
|
+ if (!has_glyphs && g_unichar_iscntrl (c) && !g_unichar_isspace (c))
|
|
+ break;
|
|
+ FT_Face ft_face = m_fcfontset->ft_faces[i];
|
|
+ if (!has_glyphs && ft_face == 0) {
|
|
+ ft_face = ibus_fontset_get_ftface_from_fcfont (
|
|
+ fontset,
|
|
+ m_fcfontset->fonts[i]);
|
|
+ m_fcfontset->ft_faces[i] = ft_face;
|
|
+ }
|
|
+ if (has_glyphs || FT_Get_Char_Index (ft_face, c) != 0) {
|
|
+ FcChar8 *font_file = NULL;
|
|
+ FcPatternGetString (m_fcfontset->fonts[i], FC_FILE, 0, &font_file);
|
|
+ buff[n].fcfont = m_fcfontset->fonts[i];
|
|
+ if (!has_glyphs) {
|
|
+ g_hash_table_insert (m_font_index_per_char_table,
|
|
+ GINT_TO_POINTER (c),
|
|
+ GINT_TO_POINTER (i + 1));
|
|
+ }
|
|
+ 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;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ 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 = m_fcfontset->ft_faces[i];
|
|
+ if (ft_face == 0) {
|
|
+ ft_face = ibus_fontset_get_ftface_from_fcfont (
|
|
+ fontset,
|
|
+ m_fcfontset->fonts[i]);
|
|
+ m_fcfontset->ft_faces[i] = ft_face;
|
|
+ }
|
|
+ /* 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) {
|
|
+ FcChar8 *font_file = NULL;
|
|
+ FcPatternGetString (m_fcfontset->fonts[i], FC_FILE, 0, &font_file);
|
|
+ buff[n].fcfont = m_fcfontset->fonts[i];
|
|
+ g_hash_table_insert (m_font_index_per_char_table,
|
|
+ GINT_TO_POINTER (c),
|
|
+ GINT_TO_POINTER (i + 1));
|
|
+ has_glyphs = TRUE;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ if (!has_glyphs) {
|
|
+ buff[n].fcfont = m_fcfontset->fonts[0];
|
|
+ g_hash_table_insert (m_font_index_per_char_table,
|
|
+ GINT_TO_POINTER (c),
|
|
+ GINT_TO_POINTER (1));
|
|
+ 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 00000000..efcaa286
|
|
--- /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.13.4
|
|
|