# -*- coding: utf-8 -*-
# vim:et sts=4 sw=4
#
# ibus-typing-booster - A completion input method for IBus
#
# Copyright (c) 2015-2016 Mike FABIAN <mfabian@redhat.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>
'''A module to find out which fonts are used by pango to render a string
'''
import sys
import ctypes
class glib__GSList(ctypes.Structure):
pass
glib__GSList._fields_ = [
('data', ctypes.c_void_p),
('next', ctypes.POINTER(glib__GSList)),
]
class libgtk3__GtkWidget(ctypes.Structure):
pass
class libpango__PangoAttribute(ctypes.Structure):
pass
class libpango__PangoAttrList(ctypes.Structure):
pass
class libpango__PangoContext(ctypes.Structure):
pass
class libpango__PangoLayout(ctypes.Structure):
pass
class libpango__PangoFontDescription(ctypes.Structure):
pass
class libpango__PangoLayoutLine(ctypes.Structure):
pass
libpango__PangoLayoutLine._fields_ = [
('layout', ctypes.POINTER(libpango__PangoLayout)),
('start_index', ctypes.c_int), # start of line as byte index into layout->text
('length', ctypes.c_int), # length of line in bytes
('runs', ctypes.POINTER(glib__GSList)),
('is_paragraph_start', ctypes.c_uint), # TRUE if this is the first line of the paragraph
('resolved_dir', ctypes.c_uint), # Resolved PangoDirection of line
]
class libpango__PangoGlyphString(ctypes.Structure):
pass
class libpango__PangoEngineShape(ctypes.Structure):
pass
class libpango__PangoEngineLang(ctypes.Structure):
pass
class libpango__PangoFont(ctypes.Structure):
pass
class libpango__PangoLanguage(ctypes.Structure):
pass
class libpango__PangoAnalysis(ctypes.Structure):
_fields_ = [
('shape_engine', ctypes.POINTER(libpango__PangoEngineShape)),
('lang_engine', ctypes.POINTER(libpango__PangoEngineLang)),
('font', ctypes.POINTER(libpango__PangoFont)),
('level', ctypes.c_uint8),
('gravity', ctypes.c_uint8),
('flags', ctypes.c_uint8),
('script', ctypes.c_uint8),
('language', ctypes.POINTER(libpango__PangoLanguage)),
('extra_attrs', ctypes.POINTER(glib__GSList)),
]
class libpango__PangoItem(ctypes.Structure):
pass
libpango__PangoItem._fields_ = [
('offset', ctypes.c_int),
('length', ctypes.c_int),
('num_chars', ctypes.c_int),
('analysis', libpango__PangoAnalysis),
]
class libpango__PangoGlyphItem(ctypes.Structure):
pass
libpango__PangoGlyphItem._fields_ = [
('item', ctypes.POINTER(libpango__PangoItem)),
('glyphs', ctypes.POINTER(libpango__PangoGlyphString)),
]
libglib__lib = None
libgtk3__lib = None
libpango__lib = None
libglib__g_slist_length = None
libglib__g_slist_nth_data = None
libgtk3__gtk_init = None
libgtk3__gtk_label_new = None
libgtk3__gtk_widget_get_pango_context = None
libpango__pango_layout_new = None
libpango__pango_font_description_from_string = None
libpango__pango_layout_set_font_description = None
libpango__pango_layout_set_text = None
libpango__pango_attr_list_new = None
libpango__pango_attr_list_unref = None
libpango__pango_attr_fallback_new = None
libpango__pango_attribute_destroy = None
libpango__pango_attr_list_insert = None
libpango__pango_layout_set_attributes = None
libpango__pango_layout_get_line_readonly = None
libpango__pango_font_describe = None
libpango__pango_font_description_get_family = None
def get_fonts_used_for_text(font, text, fallback=True):
'''Return a list of fonts which were really used to render a text
:param font: The font requested to render the text in
:type font: String
:param text: The text to render
:type text: String
:param fallback: Whether to enable font fallback. If disabled, then
glyphs will only be used from the closest matching
font on the system. No fallback will be done to other
fonts on the system that might contain the glyphs needed
for the text.
:type fallback: Boolean
:rtype: List of strings
Examples:
>>> get_fonts_used_for_text('DejaVu Sans Mono', '😀 ')
[('😀', 'Noto Color Emoji'), (' ', 'DejaVu Sans Mono')]
>>> get_fonts_used_for_text('DejaVu Sans', '日本語 नमस्ते')
[('日本語', 'IPAPGothic'), (' ', 'DejaVu Sans'), ('नमस्ते', 'Lohit Hindi')]
>>> get_fonts_used_for_text('DejaVu Sans', '日本語 🕉️')
[('日本語', 'IPAPGothic'), (' ', 'DejaVu Sans'), ('🕉️', 'Noto Color Emoji')]
'''
fonts_used = []
label = libgtk3__gtk_label_new(ctypes.c_char_p(b''))
pango_context_p = libgtk3__gtk_widget_get_pango_context(label)
pango_layout_p = libpango__pango_layout_new(pango_context_p)
pango_font_description_p = libpango__pango_font_description_from_string(
ctypes.c_char_p(font.encode('UTF-8', errors='replace')))
libpango__pango_layout_set_font_description(
pango_layout_p, pango_font_description_p)
pango_attr_list_p = libpango__pango_attr_list_new()
pango_attr_p = libpango__pango_attr_fallback_new(
ctypes.c_bool(fallback))
libpango__pango_attr_list_insert(
pango_attr_list_p, pango_attr_p)
libpango__pango_layout_set_attributes(
pango_layout_p, pango_attr_list_p)
text_utf8 = text.encode('UTF-8', errors='replace')
libpango__pango_layout_set_text(
pango_layout_p,
ctypes.c_char_p(text_utf8),
ctypes.c_int(-1))
pango_layout_line_p = libpango__pango_layout_get_line_readonly(
pango_layout_p, ctypes.c_int(0))
gs_list = pango_layout_line_p.contents.runs.contents
number_of_runs = libglib__g_slist_length(gs_list)
for index in range(0, number_of_runs):
gpointer = libglib__g_slist_nth_data(gs_list, ctypes.c_uint(index))
pango_glyph_item = ctypes.cast(
gpointer,
ctypes.POINTER(libpango__PangoGlyphItem)).contents
pango_item_p = pango_glyph_item.item
offset = pango_item_p.contents.offset
length = pango_item_p.contents.length
num_chars = pango_item_p.contents.num_chars
pango_analysis = pango_item_p.contents.analysis
pango_font_p = pango_analysis.font
font_description_used = libpango__pango_font_describe(pango_font_p)
run_text = text_utf8[offset:offset + length].decode('UTF-8', errors='replace')
run_family = libpango__pango_font_description_get_family(
font_description_used).decode('UTF-8', errors='replace')
fonts_used.append((run_text, run_family))
libpango__pango_attr_list_unref(pango_attr_list_p)
libpango__pango_attribute_destroy(pango_attr_p)
return fonts_used
def _init():
global libglib__lib
libglib__lib = ctypes.CDLL('libglib-2.0.so.0', mode=ctypes.RTLD_GLOBAL)
global libgtk3__lib
libgtk3__lib = ctypes.CDLL('libgtk-3.so.0', mode=ctypes.RTLD_GLOBAL)
global libpango__lib
libpango__lib = ctypes.CDLL('libpango-1.0.so.0', mode=ctypes.RTLD_GLOBAL)
global libglib__g_slist_length
libglib__g_slist_length = libglib__lib.g_slist_length
libglib__g_slist_length.argtypes = [
ctypes.POINTER(glib__GSList)]
libglib__g_slist_length.restype = ctypes.c_uint
global libglib__g_slist_nth_data
libglib__g_slist_nth_data = libglib__lib.g_slist_nth_data
libglib__g_slist_nth_data.argtypes = [
ctypes.POINTER(glib__GSList), ctypes.c_uint]
libglib__g_slist_nth_data.restype = ctypes.c_void_p
global libgtk3__gtk_init
libgtk3__gtk_init = libgtk3__lib.gtk_init
libgtk3__gtk_init.argtypes = [
ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.POINTER(ctypes.c_char_p))]
global libgtk3__gtk_label_new
libgtk3__gtk_label_new = libgtk3__lib.gtk_label_new
libgtk3__gtk_label_new.argtypes = [ctypes.c_char_p]
libgtk3__gtk_label_new.restype = ctypes.POINTER(
libgtk3__GtkWidget)
global libgtk3__gtk_widget_get_pango_context
libgtk3__gtk_widget_get_pango_context = libgtk3__lib.gtk_widget_get_pango_context
libgtk3__gtk_widget_get_pango_context.argtypes = [ctypes.POINTER(libgtk3__GtkWidget)]
libgtk3__gtk_widget_get_pango_context.restype = ctypes.POINTER(
libpango__PangoContext)
global libpango__pango_layout_new
libpango__pango_layout_new = libpango__lib.pango_layout_new
libpango__pango_layout_new.argtypes = [ctypes.POINTER(libpango__PangoContext)]
libpango__pango_layout_new.restype = ctypes.POINTER(
libpango__PangoLayout)
global libpango__pango_font_description_from_string
libpango__pango_font_description_from_string = libpango__lib.pango_font_description_from_string
libpango__pango_font_description_from_string.argtypes = [ctypes.c_char_p]
libpango__pango_font_description_from_string.restype = ctypes.POINTER(
libpango__PangoFontDescription)
global libpango__pango_layout_set_font_description
libpango__pango_layout_set_font_description = libpango__lib.pango_layout_set_font_description
libpango__pango_layout_set_font_description.argtypes = [
ctypes.POINTER(libpango__PangoLayout),
ctypes.POINTER(libpango__PangoFontDescription)]
global libpango__pango_layout_set_text
libpango__pango_layout_set_text = libpango__lib.pango_layout_set_text
libpango__pango_layout_set_text.argtypes = [
ctypes.POINTER(libpango__PangoLayout), ctypes.c_char_p, ctypes.c_int]
global libpango__pango_attr_list_new
libpango__pango_attr_list_new = libpango__lib.pango_attr_list_new
libpango__pango_attr_list_new.argtypes = []
libpango__pango_attr_list_new.restype = ctypes.POINTER(
libpango__PangoAttrList)
global libpango__pango_attr_list_unref
libpango__pango_attr_list_unref = libpango__lib.pango_attr_list_unref
libpango__pango_attr_list_unref.argtypes = [
ctypes.POINTER(libpango__PangoAttrList)]
global libpango__pango_attr_fallback_new
libpango__pango_attr_fallback_new = libpango__lib.pango_attr_fallback_new
libpango__pango_attr_fallback_new.argtypes = [
ctypes.c_bool]
libpango__pango_attr_fallback_new.restype = ctypes.POINTER(
libpango__PangoAttribute)
global libpango__pango_attribute_destroy
libpango__pango_attribute_destroy = libpango__lib.pango_attribute_destroy
libpango__pango_attribute_destroy.argtypes = [
ctypes.POINTER(libpango__PangoAttribute)]
global libpango__pango_attr_list_insert
libpango__pango_attr_list_insert = libpango__lib.pango_attr_list_insert
libpango__pango_attr_list_insert.argtypes = [
ctypes.POINTER(libpango__PangoAttrList),
ctypes.POINTER(libpango__PangoAttribute)]
global libpango__pango_layout_set_attributes
libpango__pango_layout_set_attributes = libpango__lib.pango_layout_set_attributes
libpango__pango_layout_set_attributes.argtypes = [
ctypes.POINTER(libpango__PangoLayout),
ctypes.POINTER(libpango__PangoAttrList)]
global libpango__pango_layout_get_line_readonly
libpango__pango_layout_get_line_readonly = libpango__lib.pango_layout_get_line_readonly
libpango__pango_layout_get_line_readonly.argtypes = [
ctypes.POINTER(libpango__PangoLayout), ctypes.c_int]
libpango__pango_layout_get_line_readonly.restype = ctypes.POINTER(
libpango__PangoLayoutLine)
global libpango__pango_font_describe
libpango__pango_font_describe = libpango__lib.pango_font_describe
libpango__pango_font_describe.argtypes = [
ctypes.POINTER(libpango__PangoFont)]
libpango__pango_font_describe.restype = ctypes.POINTER(
libpango__PangoFontDescription)
global libpango__pango_font_description_get_family
libpango__pango_font_description_get_family = libpango__lib.pango_font_description_get_family
libpango__pango_font_description_get_family.argtypes = [
ctypes.POINTER(libpango__PangoFontDescription)]
libpango__pango_font_description_get_family.restype = ctypes.c_char_p
libgtk3__gtk_init(
ctypes.byref(ctypes.c_int(0)),
ctypes.byref(ctypes.pointer(ctypes.c_char_p(b''))))
def _del():
'''Cleanup'''
pass
class __ModuleInitializer:
def __init__(self):
_init()
return
def __del__(self):
return
__module_init = __ModuleInitializer()
if __name__ == "__main__":
import doctest
(failed, attempted) = doctest.testmod()
if failed:
sys.exit(1)
else:
sys.exit(0)