mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Start a python interface to FreeType
This commit is contained in:
parent
ade7c9280a
commit
42f2f945e7
@ -8,6 +8,7 @@ let g:syntastic_cpp_include_dirs = [
|
|||||||
\'/usr/include/qt4/QtCore',
|
\'/usr/include/qt4/QtCore',
|
||||||
\'/usr/include/qt4/QtGui',
|
\'/usr/include/qt4/QtGui',
|
||||||
\'/usr/include/qt4',
|
\'/usr/include/qt4',
|
||||||
|
\'/usr/include/freetype2',
|
||||||
\'src/qtcurve/common', 'src/qtcurve',
|
\'src/qtcurve/common', 'src/qtcurve',
|
||||||
\'/usr/include/ImageMagick',
|
\'/usr/include/ImageMagick',
|
||||||
\]
|
\]
|
||||||
|
@ -84,6 +84,7 @@ qt_inc = pyqt.qt_inc_dir
|
|||||||
qt_lib = pyqt.qt_lib_dir
|
qt_lib = pyqt.qt_lib_dir
|
||||||
ft_lib_dirs = []
|
ft_lib_dirs = []
|
||||||
ft_libs = []
|
ft_libs = []
|
||||||
|
ft_inc_dirs = []
|
||||||
jpg_libs = []
|
jpg_libs = []
|
||||||
jpg_lib_dirs = []
|
jpg_lib_dirs = []
|
||||||
fc_inc = '/usr/include/fontconfig'
|
fc_inc = '/usr/include/fontconfig'
|
||||||
@ -116,6 +117,7 @@ if iswindows:
|
|||||||
jpg_libs = ['jpeg']
|
jpg_libs = ['jpeg']
|
||||||
ft_lib_dirs = [sw_lib_dir]
|
ft_lib_dirs = [sw_lib_dir]
|
||||||
ft_libs = ['freetype']
|
ft_libs = ['freetype']
|
||||||
|
ft_inc_dirs = [sw_inc_dir]
|
||||||
|
|
||||||
magick_inc_dirs = [os.path.join(prefix, 'build', 'ImageMagick-6.7.6')]
|
magick_inc_dirs = [os.path.join(prefix, 'build', 'ImageMagick-6.7.6')]
|
||||||
magick_lib_dirs = [os.path.join(magick_inc_dirs[0], 'VisualMagick', 'lib')]
|
magick_lib_dirs = [os.path.join(magick_inc_dirs[0], 'VisualMagick', 'lib')]
|
||||||
@ -135,6 +137,8 @@ elif isosx:
|
|||||||
png_inc_dirs = consolidate('PNG_INC_DIR', '/sw/include')
|
png_inc_dirs = consolidate('PNG_INC_DIR', '/sw/include')
|
||||||
png_lib_dirs = consolidate('PNG_LIB_DIR', '/sw/lib')
|
png_lib_dirs = consolidate('PNG_LIB_DIR', '/sw/lib')
|
||||||
png_libs = ['png12']
|
png_libs = ['png12']
|
||||||
|
ft_libs = ['freetype']
|
||||||
|
ft_inc_dirs = ['/sw/include/freetype2']
|
||||||
else:
|
else:
|
||||||
# Include directories
|
# Include directories
|
||||||
png_inc_dirs = pkgconfig_include_dirs('libpng', 'PNG_INC_DIR',
|
png_inc_dirs = pkgconfig_include_dirs('libpng', 'PNG_INC_DIR',
|
||||||
@ -150,6 +154,10 @@ else:
|
|||||||
if not magick_libs:
|
if not magick_libs:
|
||||||
magick_libs = ['MagickWand', 'MagickCore']
|
magick_libs = ['MagickWand', 'MagickCore']
|
||||||
png_libs = ['png']
|
png_libs = ['png']
|
||||||
|
ft_inc_dirs = pkgconfig_include_dirs('freetype2', 'FT_INC_DIR',
|
||||||
|
'/usr/include/freetype2')
|
||||||
|
ft_lib_dirs = pkgconfig_lib_dirs('freetype2', 'FT_LIB_DIR', '/usr/lib')
|
||||||
|
ft_libs = pkgconfig_libs('freetype2', '', '')
|
||||||
|
|
||||||
|
|
||||||
fc_inc = os.environ.get('FC_INC_DIR', fc_inc)
|
fc_inc = os.environ.get('FC_INC_DIR', fc_inc)
|
||||||
|
@ -17,7 +17,7 @@ from setup.build_environment import (fc_inc, fc_lib, chmlib_inc_dirs, fc_error,
|
|||||||
podofo_inc, podofo_lib, podofo_error, pyqt, OSX_SDK, NMAKE, QMAKE,
|
podofo_inc, podofo_lib, podofo_error, pyqt, OSX_SDK, NMAKE, QMAKE,
|
||||||
msvc, MT, win_inc, win_lib, win_ddk, magick_inc_dirs, magick_lib_dirs,
|
msvc, MT, win_inc, win_lib, win_ddk, magick_inc_dirs, magick_lib_dirs,
|
||||||
magick_libs, chmlib_lib_dirs, sqlite_inc_dirs, icu_inc_dirs,
|
magick_libs, chmlib_lib_dirs, sqlite_inc_dirs, icu_inc_dirs,
|
||||||
icu_lib_dirs, win_ddk_lib_dirs)
|
icu_lib_dirs, win_ddk_lib_dirs, ft_libs, ft_lib_dirs, ft_inc_dirs)
|
||||||
MT
|
MT
|
||||||
isunix = islinux or isosx or isbsd
|
isunix = islinux or isosx or isbsd
|
||||||
|
|
||||||
@ -119,6 +119,12 @@ extensions = [
|
|||||||
'calibre/utils/lzx/mspack.h'],
|
'calibre/utils/lzx/mspack.h'],
|
||||||
inc_dirs=['calibre/utils/lzx']),
|
inc_dirs=['calibre/utils/lzx']),
|
||||||
|
|
||||||
|
Extension('freetype',
|
||||||
|
['calibre/utils/fonts/freetype.cpp'],
|
||||||
|
inc_dirs = ft_inc_dirs,
|
||||||
|
libraries=ft_libs,
|
||||||
|
lib_dirs=ft_lib_dirs),
|
||||||
|
|
||||||
Extension('fontconfig',
|
Extension('fontconfig',
|
||||||
['calibre/utils/fonts/fontconfig.c'],
|
['calibre/utils/fonts/fontconfig.c'],
|
||||||
inc_dirs = [fc_inc],
|
inc_dirs = [fc_inc],
|
||||||
|
@ -89,6 +89,7 @@ class Plugins(collections.Mapping):
|
|||||||
'chm_extra',
|
'chm_extra',
|
||||||
'icu',
|
'icu',
|
||||||
'speedup',
|
'speedup',
|
||||||
|
'freetype',
|
||||||
]
|
]
|
||||||
if iswindows:
|
if iswindows:
|
||||||
plugins.extend(['winutil', 'wpd', 'winfonts'])
|
plugins.extend(['winutil', 'wpd', 'winfonts'])
|
||||||
|
@ -32,6 +32,11 @@ def test_lxml():
|
|||||||
else:
|
else:
|
||||||
raise RuntimeError('lxml failed')
|
raise RuntimeError('lxml failed')
|
||||||
|
|
||||||
|
def test_freetype():
|
||||||
|
from calibre.utils.fonts.freetype import test
|
||||||
|
test()
|
||||||
|
print ('FreeType OK!')
|
||||||
|
|
||||||
def test_fontconfig():
|
def test_fontconfig():
|
||||||
from calibre.utils.fonts import fontconfig
|
from calibre.utils.fonts import fontconfig
|
||||||
families = fontconfig.find_font_families()
|
families = fontconfig.find_font_families()
|
||||||
@ -103,7 +108,7 @@ def test_icu():
|
|||||||
def test_wpd():
|
def test_wpd():
|
||||||
wpd = plugins['wpd'][0]
|
wpd = plugins['wpd'][0]
|
||||||
try:
|
try:
|
||||||
wpd.init()
|
wpd.init('calibre', 1, 1, 1)
|
||||||
except wpd.NoWPD:
|
except wpd.NoWPD:
|
||||||
print ('This computer does not have WPD')
|
print ('This computer does not have WPD')
|
||||||
else:
|
else:
|
||||||
@ -112,6 +117,7 @@ def test_wpd():
|
|||||||
def test():
|
def test():
|
||||||
test_plugins()
|
test_plugins()
|
||||||
test_lxml()
|
test_lxml()
|
||||||
|
test_freetype()
|
||||||
test_fontconfig()
|
test_fontconfig()
|
||||||
test_sqlite()
|
test_sqlite()
|
||||||
test_qt()
|
test_qt()
|
||||||
|
@ -55,7 +55,7 @@ class Fonts(object):
|
|||||||
files = self.backend.files_for_family(family, normalize=normalize)
|
files = self.backend.files_for_family(family, normalize=normalize)
|
||||||
ans = {}
|
ans = {}
|
||||||
for ft, val in files.iteritems():
|
for ft, val in files.iteritems():
|
||||||
name, f = val
|
f, name = val
|
||||||
ext = f.rpartition('.')[-1].lower()
|
ext = f.rpartition('.')[-1].lower()
|
||||||
ans[ft] = (ext, name, open(f, 'rb').read())
|
ans[ft] = (ext, name, open(f, 'rb').read())
|
||||||
return ans
|
return ans
|
||||||
|
289
src/calibre/utils/fonts/freetype.cpp
Normal file
289
src/calibre/utils/fonts/freetype.cpp
Normal file
@ -0,0 +1,289 @@
|
|||||||
|
/*
|
||||||
|
* freetype.cpp
|
||||||
|
* Copyright (C) 2012 Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
*
|
||||||
|
* Distributed under terms of the GPL3 license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _UNICODE
|
||||||
|
#define UNICODE
|
||||||
|
#define PY_SSIZE_T_CLEAN
|
||||||
|
#include <Python.h>
|
||||||
|
|
||||||
|
#include <ft2build.h>
|
||||||
|
#include FT_FREETYPE_H
|
||||||
|
|
||||||
|
static PyObject *FreeTypeError = NULL;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
PyObject_HEAD
|
||||||
|
FT_Face *face;
|
||||||
|
// Every face must keep a reference to the FreeType library object to
|
||||||
|
// ensure it is garbage collected before the library object, to prevent
|
||||||
|
// segfaults.
|
||||||
|
PyObject *library;
|
||||||
|
} Face;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
PyObject_HEAD
|
||||||
|
FT_Library *library;
|
||||||
|
} FreeType;
|
||||||
|
|
||||||
|
// Face.__init__() {{{
|
||||||
|
static void
|
||||||
|
Face_dealloc(Face* self)
|
||||||
|
{
|
||||||
|
if (self->face != NULL) {
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
FT_Done_Face(*(self->face));
|
||||||
|
free(self->face);
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
}
|
||||||
|
self->face = NULL;
|
||||||
|
|
||||||
|
Py_DECREF(self->library);
|
||||||
|
self->library = NULL;
|
||||||
|
|
||||||
|
self->ob_type->tp_free((PyObject*)self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
Face_init(Face *self, PyObject *args, PyObject *kwds)
|
||||||
|
{
|
||||||
|
FT_Error error = 0;
|
||||||
|
char *data;
|
||||||
|
Py_ssize_t sz;
|
||||||
|
PyObject *ft;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "Os#", &ft, &data, &sz)) return -1;
|
||||||
|
self->face = (FT_Face*)calloc(1, sizeof(FT_Face));
|
||||||
|
if (self->face == NULL) { PyErr_NoMemory(); return -1; }
|
||||||
|
self->library = ft;
|
||||||
|
Py_XINCREF(ft);
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
error = FT_New_Memory_Face( *(( (FreeType*)ft )->library),
|
||||||
|
(const FT_Byte*)data, (FT_Long)sz, 0, self->face);
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
if (error) {
|
||||||
|
free(self->face); self->face = NULL;
|
||||||
|
if ( error == FT_Err_Unknown_File_Format || error == FT_Err_Invalid_Stream_Operation)
|
||||||
|
PyErr_SetString(FreeTypeError, "Not a supported font format");
|
||||||
|
else
|
||||||
|
PyErr_Format(FreeTypeError, "Failed to initialize the Font with error: 0x%x", error);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
supports_text(Face *self, PyObject *args) {
|
||||||
|
PyObject *chars, *fast, *ret = Py_True;
|
||||||
|
Py_ssize_t sz, i;
|
||||||
|
FT_ULong code;
|
||||||
|
FT_Face face;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "O", &chars)) return NULL;
|
||||||
|
fast = PySequence_Fast(chars, "List of chars is not a sequence");
|
||||||
|
if (fast == NULL) return NULL;
|
||||||
|
sz = PySequence_Fast_GET_SIZE(fast);
|
||||||
|
face = *(self->face);
|
||||||
|
|
||||||
|
for (i = 0; i < sz; i++) {
|
||||||
|
code = (FT_ULong)PyNumber_AsSsize_t(PySequence_Fast_GET_ITEM(fast, i), NULL);
|
||||||
|
if (FT_Get_Char_Index(face, code) == 0) {
|
||||||
|
ret = Py_False;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Py_DECREF(fast);
|
||||||
|
Py_XINCREF(ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyMethodDef Face_methods[] = {
|
||||||
|
{"supports_text", (PyCFunction)supports_text, METH_VARARGS,
|
||||||
|
"supports_text(sequence of unicode character codes) -> Return True iff this font has glyphs for all the specified characters."
|
||||||
|
},
|
||||||
|
|
||||||
|
{NULL} /* Sentinel */
|
||||||
|
};
|
||||||
|
|
||||||
|
// FreeType.__init__() {{{
|
||||||
|
static void
|
||||||
|
dealloc(FreeType* self)
|
||||||
|
{
|
||||||
|
if (self->library != NULL) {
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
FT_Done_FreeType(*(self->library));
|
||||||
|
free(self->library);
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
}
|
||||||
|
self->library = NULL;
|
||||||
|
|
||||||
|
self->ob_type->tp_free((PyObject*)self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
init(FreeType *self, PyObject *args, PyObject *kwds)
|
||||||
|
{
|
||||||
|
FT_Error error = 0;
|
||||||
|
self->library = (FT_Library*)calloc(1, sizeof(FT_Library));
|
||||||
|
if (self->library == NULL) { PyErr_NoMemory(); return -1; }
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
error = FT_Init_FreeType(self->library);
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
if (error) {
|
||||||
|
free(self->library);
|
||||||
|
self->library = NULL;
|
||||||
|
PyErr_Format(FreeTypeError, "Failed to initialize the FreeType library with error: %d", error);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
static PyTypeObject FaceType = { // {{{
|
||||||
|
PyObject_HEAD_INIT(NULL)
|
||||||
|
0, /*ob_size*/
|
||||||
|
"freetype.Face", /*tp_name*/
|
||||||
|
sizeof(Face), /*tp_basicsize*/
|
||||||
|
0, /*tp_itemsize*/
|
||||||
|
(destructor)Face_dealloc, /*tp_dealloc*/
|
||||||
|
0, /*tp_print*/
|
||||||
|
0, /*tp_getattr*/
|
||||||
|
0, /*tp_setattr*/
|
||||||
|
0, /*tp_compare*/
|
||||||
|
0, /*tp_repr*/
|
||||||
|
0, /*tp_as_number*/
|
||||||
|
0, /*tp_as_sequence*/
|
||||||
|
0, /*tp_as_mapping*/
|
||||||
|
0, /*tp_hash */
|
||||||
|
0, /*tp_call*/
|
||||||
|
0, /*tp_str*/
|
||||||
|
0, /*tp_getattro*/
|
||||||
|
0, /*tp_setattro*/
|
||||||
|
0, /*tp_as_buffer*/
|
||||||
|
Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
|
||||||
|
"Face", /* tp_doc */
|
||||||
|
0, /* tp_traverse */
|
||||||
|
0, /* tp_clear */
|
||||||
|
0, /* tp_richcompare */
|
||||||
|
0, /* tp_weaklistoffset */
|
||||||
|
0, /* tp_iter */
|
||||||
|
0, /* tp_iternext */
|
||||||
|
Face_methods, /* tp_methods */
|
||||||
|
0, /* tp_members */
|
||||||
|
0, /* tp_getset */
|
||||||
|
0, /* tp_base */
|
||||||
|
0, /* tp_dict */
|
||||||
|
0, /* tp_descr_get */
|
||||||
|
0, /* tp_descr_set */
|
||||||
|
0, /* tp_dictoffset */
|
||||||
|
(initproc)Face_init, /* tp_init */
|
||||||
|
0, /* tp_alloc */
|
||||||
|
0, /* tp_new */
|
||||||
|
}; // }}}
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
load_font(FreeType *self, PyObject *args) {
|
||||||
|
PyObject *ret, *arg_list, *bytes;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "O", &bytes)) return NULL;
|
||||||
|
|
||||||
|
arg_list = Py_BuildValue("OO", self, bytes);
|
||||||
|
if (arg_list == NULL) return NULL;
|
||||||
|
|
||||||
|
ret = PyObject_CallObject((PyObject *) &FaceType, arg_list);
|
||||||
|
Py_DECREF(arg_list);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyMethodDef FreeType_methods[] = {
|
||||||
|
{"load_font", (PyCFunction)load_font, METH_VARARGS,
|
||||||
|
"load_font(bytestring) -> Load a font from font data."
|
||||||
|
},
|
||||||
|
|
||||||
|
{NULL} /* Sentinel */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static PyTypeObject FreeTypeType = { // {{{
|
||||||
|
PyObject_HEAD_INIT(NULL)
|
||||||
|
0, /*ob_size*/
|
||||||
|
"freetype.FreeType", /*tp_name*/
|
||||||
|
sizeof(FreeType), /*tp_basicsize*/
|
||||||
|
0, /*tp_itemsize*/
|
||||||
|
(destructor)dealloc, /*tp_dealloc*/
|
||||||
|
0, /*tp_print*/
|
||||||
|
0, /*tp_getattr*/
|
||||||
|
0, /*tp_setattr*/
|
||||||
|
0, /*tp_compare*/
|
||||||
|
0, /*tp_repr*/
|
||||||
|
0, /*tp_as_number*/
|
||||||
|
0, /*tp_as_sequence*/
|
||||||
|
0, /*tp_as_mapping*/
|
||||||
|
0, /*tp_hash */
|
||||||
|
0, /*tp_call*/
|
||||||
|
0, /*tp_str*/
|
||||||
|
0, /*tp_getattro*/
|
||||||
|
0, /*tp_setattro*/
|
||||||
|
0, /*tp_as_buffer*/
|
||||||
|
Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
|
||||||
|
"FreeType", /* tp_doc */
|
||||||
|
0, /* tp_traverse */
|
||||||
|
0, /* tp_clear */
|
||||||
|
0, /* tp_richcompare */
|
||||||
|
0, /* tp_weaklistoffset */
|
||||||
|
0, /* tp_iter */
|
||||||
|
0, /* tp_iternext */
|
||||||
|
FreeType_methods, /* tp_methods */
|
||||||
|
0, /* tp_members */
|
||||||
|
0, /* tp_getset */
|
||||||
|
0, /* tp_base */
|
||||||
|
0, /* tp_dict */
|
||||||
|
0, /* tp_descr_get */
|
||||||
|
0, /* tp_descr_set */
|
||||||
|
0, /* tp_dictoffset */
|
||||||
|
(initproc)init, /* tp_init */
|
||||||
|
0, /* tp_alloc */
|
||||||
|
0, /* tp_new */
|
||||||
|
}; // }}}
|
||||||
|
|
||||||
|
static
|
||||||
|
PyMethodDef methods[] = {
|
||||||
|
{NULL, NULL, 0, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
PyMODINIT_FUNC
|
||||||
|
initfreetype(void) {
|
||||||
|
PyObject *m;
|
||||||
|
|
||||||
|
FreeTypeType.tp_new = PyType_GenericNew;
|
||||||
|
if (PyType_Ready(&FreeTypeType) < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
FaceType.tp_new = PyType_GenericNew;
|
||||||
|
if (PyType_Ready(&FaceType) < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m = Py_InitModule3(
|
||||||
|
"freetype", methods,
|
||||||
|
"FreeType API"
|
||||||
|
);
|
||||||
|
if (m == NULL) return;
|
||||||
|
|
||||||
|
FreeTypeError = PyErr_NewException((char*)"freetype.FreeTypeError", NULL, NULL);
|
||||||
|
if (FreeTypeError == NULL) return;
|
||||||
|
PyModule_AddObject(m, "FreeTypeError", FreeTypeError);
|
||||||
|
|
||||||
|
Py_INCREF(&FreeTypeType);
|
||||||
|
PyModule_AddObject(m, "FreeType", (PyObject *)&FreeTypeType);
|
||||||
|
PyModule_AddObject(m, "Face", (PyObject *)&FaceType);
|
||||||
|
}
|
||||||
|
|
69
src/calibre/utils/fonts/freetype.py
Normal file
69
src/calibre/utils/fonts/freetype.py
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai
|
||||||
|
from __future__ import (unicode_literals, division, absolute_import,
|
||||||
|
print_function)
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
import threading
|
||||||
|
from functools import wraps
|
||||||
|
from future_builtins import map
|
||||||
|
|
||||||
|
from calibre.constants import plugins
|
||||||
|
|
||||||
|
class ThreadingViolation(Exception):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
Exception.__init__(self,
|
||||||
|
'You cannot use the MTP driver from a thread other than the '
|
||||||
|
' thread in which startup() was called')
|
||||||
|
|
||||||
|
def same_thread(func):
|
||||||
|
@wraps(func)
|
||||||
|
def check_thread(self, *args, **kwargs):
|
||||||
|
if self.start_thread is not threading.current_thread():
|
||||||
|
raise ThreadingViolation()
|
||||||
|
return func(self, *args, **kwargs)
|
||||||
|
return check_thread
|
||||||
|
|
||||||
|
class Face(object):
|
||||||
|
|
||||||
|
def __init__(self, face):
|
||||||
|
self.start_thread = threading.current_thread()
|
||||||
|
self.face = face
|
||||||
|
|
||||||
|
@same_thread
|
||||||
|
def supports_text(self, text):
|
||||||
|
if not isinstance(text, unicode):
|
||||||
|
raise TypeError('%r is not a unicode object'%text)
|
||||||
|
chars = tuple(frozenset(map(ord, text)))
|
||||||
|
return self.face.supports_text(chars)
|
||||||
|
|
||||||
|
class FreeType(object):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.start_thread = threading.current_thread()
|
||||||
|
ft, ft_err = plugins['freetype']
|
||||||
|
if ft_err:
|
||||||
|
raise RuntimeError('Failed to load FreeType module with error: %s'
|
||||||
|
% ft_err)
|
||||||
|
self.ft = ft.FreeType()
|
||||||
|
|
||||||
|
@same_thread
|
||||||
|
def load_font(self, data):
|
||||||
|
return Face(self.ft.load_font(data))
|
||||||
|
|
||||||
|
def test():
|
||||||
|
data = P('fonts/calibreSymbols.otf', data=True)
|
||||||
|
ft = FreeType()
|
||||||
|
font = ft.load_font(data)
|
||||||
|
if not font.supports_text('.\u2605★'):
|
||||||
|
raise RuntimeError('Incorrectly returning that text is not supported')
|
||||||
|
if font.supports_text('abc'):
|
||||||
|
raise RuntimeError('Incorrectly claiming that text is supported')
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
test()
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user