Merge pull request #5062 from nulano/fribidi-link

Dynamically link FriBiDi instead of Raqm
This commit is contained in:
wiredfool 2021-03-27 16:29:04 +00:00 committed by GitHub
commit 3addd7df4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 2821 additions and 262 deletions

View File

@ -137,14 +137,11 @@ jobs:
if: steps.build-cache.outputs.cache-hit != 'true'
run: "& winbuild\\build\\build_dep_harfbuzz.cmd"
# Raqm dependencies
- name: Build dependencies / FriBidi
if: steps.build-cache.outputs.cache-hit != 'true'
run: "& winbuild\\build\\build_dep_fribidi.cmd"
- name: Build dependencies / Raqm
if: steps.build-cache.outputs.cache-hit != 'true'
run: "& winbuild\\build\\build_dep_libraqm.cmd"
# trim ~150MB x 9
- name: Optimize build cache
if: steps.build-cache.outputs.cache-hit != 'true'

120
setup.py
View File

@ -29,6 +29,8 @@ def get_version():
NAME = "Pillow"
PILLOW_VERSION = get_version()
FREETYPE_ROOT = None
HARFBUZZ_ROOT = None
FRIBIDI_ROOT = None
IMAGEQUANT_ROOT = None
JPEG2K_ROOT = None
JPEG_ROOT = None
@ -228,6 +230,19 @@ def _find_library_file(self, library):
return ret
def _find_include_dir(self, dirname, include):
for directory in self.compiler.include_dirs:
_dbg("Checking for include file %s in %s", (include, directory))
if os.path.isfile(os.path.join(directory, include)):
_dbg("Found %s in %s", (include, directory))
return True
subdir = os.path.join(directory, dirname)
_dbg("Checking for include file %s in %s", (include, subdir))
if os.path.isfile(os.path.join(subdir, include)):
_dbg("Found %s in %s", (include, subdir))
return subdir
def _cmd_exists(cmd):
return any(
os.access(os.path.join(path, cmd), os.X_OK)
@ -267,6 +282,7 @@ class pil_build_ext(build_ext):
"jpeg",
"tiff",
"freetype",
"raqm",
"lcms",
"webp",
"webpmux",
@ -276,6 +292,7 @@ class pil_build_ext(build_ext):
]
required = {"jpeg", "zlib"}
vendor = set()
def __init__(self):
for f in self.features:
@ -287,6 +304,9 @@ class pil_build_ext(build_ext):
def want(self, feat):
return getattr(self, feat) is None
def want_vendor(self, feat):
return feat in self.vendor
def __iter__(self):
yield from self.features
@ -296,6 +316,10 @@ class pil_build_ext(build_ext):
build_ext.user_options
+ [(f"disable-{x}", None, f"Disable support for {x}") for x in feature]
+ [(f"enable-{x}", None, f"Enable support for {x}") for x in feature]
+ [
(f"vendor-{x}", None, f"Use vendored version of {x}")
for x in ("raqm", "fribidi")
]
+ [
("disable-platform-guessing", None, "Disable platform guessing on Linux"),
("debug", None, "Debug logging"),
@ -310,6 +334,8 @@ class pil_build_ext(build_ext):
for x in self.feature:
setattr(self, f"disable_{x}", None)
setattr(self, f"enable_{x}", None)
for x in ("raqm", "fribidi"):
setattr(self, f"vendor_{x}", None)
def finalize_options(self):
build_ext.finalize_options(self)
@ -334,18 +360,40 @@ class pil_build_ext(build_ext):
raise ValueError(
f"Conflicting options: --enable-{x} and --disable-{x}"
)
if x == "freetype":
_dbg("--disable-freetype implies --disable-raqm")
if getattr(self, "enable_raqm"):
raise ValueError(
"Conflicting options: --enable-raqm and --disable-freetype"
)
setattr(self, "disable_raqm", True)
if getattr(self, f"enable_{x}"):
_dbg("Requiring %s", x)
self.feature.required.add(x)
if x == "raqm":
_dbg("--enable-raqm implies --enable-freetype")
self.feature.required.add("freetype")
for x in ("raqm", "fribidi"):
if getattr(self, f"vendor_{x}"):
if getattr(self, "disable_raqm"):
raise ValueError(
f"Conflicting options: --vendor-{x} and --disable-raqm"
)
if x == "fribidi" and not getattr(self, "vendor_raqm"):
raise ValueError(
f"Conflicting options: --vendor-{x} and not --vendor-raqm"
)
_dbg("Using vendored version of %s", x)
self.feature.vendor.add(x)
def _update_extension(self, name, libraries, define_macros=None, include_dirs=None):
def _update_extension(self, name, libraries, define_macros=None, sources=None):
for extension in self.extensions:
if extension.name == name:
extension.libraries += libraries
if define_macros is not None:
extension.define_macros += define_macros
if include_dirs is not None:
extension.include_dirs += include_dirs
if sources is not None:
extension.sources += sources
if FUZZING_BUILD:
extension.language = "c++"
extension.extra_link_args = ["--stdlib=libc++"]
@ -374,6 +422,8 @@ class pil_build_ext(build_ext):
TIFF_ROOT=("libtiff-5", "libtiff-4"),
ZLIB_ROOT="zlib",
FREETYPE_ROOT="freetype2",
HARFBUZZ_ROOT="harfbuzz",
FRIBIDI_ROOT="fribidi",
LCMS_ROOT="lcms2",
IMAGEQUANT_ROOT="libimagequant",
).items():
@ -659,6 +709,39 @@ class pil_build_ext(build_ext):
if subdir:
_add_directory(self.compiler.include_dirs, subdir, 0)
if feature.freetype and feature.want("raqm"):
if not feature.want_vendor("raqm"): # want system Raqm
_dbg("Looking for Raqm")
if _find_include_file(self, "raqm.h"):
if _find_library_file(self, "raqm"):
feature.raqm = "raqm"
elif _find_library_file(self, "libraqm"):
feature.raqm = "libraqm"
else: # want to build Raqm from src/thirdparty
_dbg("Looking for HarfBuzz")
feature.harfbuzz = None
hb_dir = _find_include_dir(self, "harfbuzz", "hb.h")
if hb_dir:
if isinstance(hb_dir, str):
_add_directory(self.compiler.include_dirs, hb_dir, 0)
if _find_library_file(self, "harfbuzz"):
feature.harfbuzz = "harfbuzz"
if feature.harfbuzz:
if not feature.want_vendor("fribidi"): # want system FriBiDi
_dbg("Looking for FriBiDi")
feature.fribidi = None
fribidi_dir = _find_include_dir(self, "fribidi", "fribidi.h")
if fribidi_dir:
if isinstance(fribidi_dir, str):
_add_directory(
self.compiler.include_dirs, fribidi_dir, 0
)
if _find_library_file(self, "fribidi"):
feature.fribidi = "fribidi"
feature.raqm = True
else: # want to build FriBiDi shim from src/thirdparty
feature.raqm = True
if feature.want("lcms"):
_dbg("Looking for lcms")
if _find_include_file(self, "lcms2.h"):
@ -754,9 +837,25 @@ class pil_build_ext(build_ext):
# additional libraries
if feature.freetype:
srcs = []
libs = ["freetype"]
defs = []
self._update_extension("PIL._imagingft", libs, defs)
if feature.raqm:
if not feature.want_vendor("raqm"): # using system Raqm
defs.append(("HAVE_RAQM", None))
defs.append(("HAVE_RAQM_SYSTEM", None))
libs.append(feature.raqm)
else: # building Raqm from src/thirdparty
defs.append(("HAVE_RAQM", None))
srcs.append("src/thirdparty/raqm/raqm.c")
libs.append(feature.harfbuzz)
if not feature.want_vendor("fribidi"): # using system FriBiDi
defs.append(("HAVE_FRIBIDI_SYSTEM", None))
libs.append(feature.fribidi)
else: # building FriBiDi shim from src/thirdparty
srcs.append("src/thirdparty/fribidi-shim/fribidi.c")
self._update_extension("PIL._imagingft", libs, defs, srcs)
else:
self._remove_extension("PIL._imagingft")
@ -803,6 +902,12 @@ class pil_build_ext(build_ext):
print(f" [{v.strip()}")
print("-" * 68)
raqm_extra_info = ""
if feature.want_vendor("raqm"):
raqm_extra_info += "bundled"
if feature.want_vendor("fribidi"):
raqm_extra_info += ", FriBiDi shim"
options = [
(feature.jpeg, "JPEG"),
(feature.jpeg2000, "OPENJPEG (JPEG2000)", feature.openjpeg_version),
@ -810,6 +915,7 @@ class pil_build_ext(build_ext):
(feature.imagequant, "LIBIMAGEQUANT"),
(feature.tiff, "LIBTIFF"),
(feature.freetype, "FREETYPE2"),
(feature.raqm, "RAQM (Text shaping)", raqm_extra_info),
(feature.lcms, "LITTLECMS2"),
(feature.webp, "WEBP"),
(feature.webpmux, "WEBPMUX"),
@ -819,10 +925,10 @@ class pil_build_ext(build_ext):
all = 1
for option in options:
if option[0]:
version = ""
extra_info = ""
if len(option) >= 3 and option[2]:
version = f" ({option[2]})"
print(f"--- {option[1]} support available{version}")
extra_info = f" ({option[2]})"
print(f"--- {option[1]} support available{extra_info}")
else:
print(f"*** {option[1]} support not available")
all = 0

View File

@ -118,6 +118,8 @@ features = {
"webp_mux": ("PIL._webp", "HAVE_WEBPMUX", None),
"transp_webp": ("PIL._webp", "HAVE_TRANSPARENCY", None),
"raqm": ("PIL._imagingft", "HAVE_RAQM", "raqm_version"),
"fribidi": ("PIL._imagingft", "HAVE_FRIBIDI", "fribidi_version"),
"harfbuzz": ("PIL._imagingft", "HAVE_HARFBUZZ", "harfbuzz_version"),
"libjpeg_turbo": ("PIL._imaging", "HAVE_LIBJPEGTURBO", "libjpeg_turbo_version"),
"libimagequant": ("PIL._imaging", "HAVE_LIBIMAGEQUANT", "imagequant_version"),
"xcb": ("PIL._imaging", "HAVE_XCB", None),
@ -274,6 +276,11 @@ def pilinfo(out=None, supported_formats=True):
# this check is also in src/_imagingcms.c:setup_module()
version_static = tuple(int(x) for x in v.split(".")) < (2, 7)
t = "compiled for" if version_static else "loaded"
if name == "raqm":
for f in ("fribidi", "harfbuzz"):
v2 = version_feature(f)
if v2 is not None:
v += f", {f} {v2}"
print("---", feature, "support ok,", t, v, file=out)
else:
print("---", feature, "support ok", file=out)

View File

@ -35,10 +35,6 @@
#define KEEP_PY_UNICODE
#ifndef _WIN32
#include <dlfcn.h>
#endif
#if !defined(FT_LOAD_TARGET_MONO)
#define FT_LOAD_TARGET_MONO FT_LOAD_MONOCHROME
#endif
@ -56,7 +52,21 @@
} \
;
#include "libImaging/raqm.h"
#ifdef HAVE_RAQM
# ifdef HAVE_RAQM_SYSTEM
# include <raqm.h>
# else
# include "thirdparty/raqm/raqm.h"
# ifdef HAVE_FRIBIDI_SYSTEM
# include <fribidi.h>
# else
# include "thirdparty/fribidi-shim/fribidi.h"
# include <hb.h>
# endif
# endif
#endif
static int have_raqm = 0;
#define LAYOUT_FALLBACK 0
#define LAYOUT_RAQM 1
@ -86,42 +96,6 @@ typedef struct {
static PyTypeObject Font_Type;
typedef const char *(*t_raqm_version_string)(void);
typedef bool (*t_raqm_version_atleast)(
unsigned int major, unsigned int minor, unsigned int micro);
typedef raqm_t *(*t_raqm_create)(void);
typedef int (*t_raqm_set_text)(raqm_t *rq, const uint32_t *text, size_t len);
typedef bool (*t_raqm_set_text_utf8)(raqm_t *rq, const char *text, size_t len);
typedef bool (*t_raqm_set_par_direction)(raqm_t *rq, raqm_direction_t dir);
typedef bool (*t_raqm_set_language)(
raqm_t *rq, const char *lang, size_t start, size_t len);
typedef bool (*t_raqm_add_font_feature)(raqm_t *rq, const char *feature, int len);
typedef bool (*t_raqm_set_freetype_face)(raqm_t *rq, FT_Face face);
typedef bool (*t_raqm_layout)(raqm_t *rq);
typedef raqm_glyph_t *(*t_raqm_get_glyphs)(raqm_t *rq, size_t *length);
typedef raqm_glyph_t_01 *(*t_raqm_get_glyphs_01)(raqm_t *rq, size_t *length);
typedef void (*t_raqm_destroy)(raqm_t *rq);
typedef struct {
void *raqm;
int version;
t_raqm_version_string version_string;
t_raqm_version_atleast version_atleast;
t_raqm_create create;
t_raqm_set_text set_text;
t_raqm_set_text_utf8 set_text_utf8;
t_raqm_set_par_direction set_par_direction;
t_raqm_set_language set_language;
t_raqm_add_font_feature add_font_feature;
t_raqm_set_freetype_face set_freetype_face;
t_raqm_layout layout;
t_raqm_get_glyphs get_glyphs;
t_raqm_get_glyphs_01 get_glyphs_01;
t_raqm_destroy destroy;
} p_raqm_func;
static p_raqm_func p_raqm;
/* round a 26.6 pixel coordinate to the nearest integer */
#define PIXEL(x) ((((x) + 32) & -64) >> 6)
@ -140,105 +114,6 @@ geterror(int code) {
return NULL;
}
static int
setraqm(void) {
/* set the static function pointers for dynamic raqm linking */
p_raqm.raqm = NULL;
/* Microsoft needs a totally different system */
#ifndef _WIN32
p_raqm.raqm = dlopen("libraqm.so.0", RTLD_LAZY);
if (!p_raqm.raqm) {
p_raqm.raqm = dlopen("libraqm.dylib", RTLD_LAZY);
}
#else
p_raqm.raqm = LoadLibrary("libraqm");
/* MSYS */
if (!p_raqm.raqm) {
p_raqm.raqm = LoadLibrary("libraqm-0");
}
#endif
if (!p_raqm.raqm) {
return 1;
}
#ifndef _WIN32
p_raqm.version_string =
(t_raqm_version_string)dlsym(p_raqm.raqm, "raqm_version_string");
p_raqm.version_atleast =
(t_raqm_version_atleast)dlsym(p_raqm.raqm, "raqm_version_atleast");
p_raqm.create = (t_raqm_create)dlsym(p_raqm.raqm, "raqm_create");
p_raqm.set_text = (t_raqm_set_text)dlsym(p_raqm.raqm, "raqm_set_text");
p_raqm.set_text_utf8 =
(t_raqm_set_text_utf8)dlsym(p_raqm.raqm, "raqm_set_text_utf8");
p_raqm.set_par_direction =
(t_raqm_set_par_direction)dlsym(p_raqm.raqm, "raqm_set_par_direction");
p_raqm.set_language = (t_raqm_set_language)dlsym(p_raqm.raqm, "raqm_set_language");
p_raqm.add_font_feature =
(t_raqm_add_font_feature)dlsym(p_raqm.raqm, "raqm_add_font_feature");
p_raqm.set_freetype_face =
(t_raqm_set_freetype_face)dlsym(p_raqm.raqm, "raqm_set_freetype_face");
p_raqm.layout = (t_raqm_layout)dlsym(p_raqm.raqm, "raqm_layout");
p_raqm.destroy = (t_raqm_destroy)dlsym(p_raqm.raqm, "raqm_destroy");
if (dlsym(p_raqm.raqm, "raqm_index_to_position")) {
p_raqm.get_glyphs = (t_raqm_get_glyphs)dlsym(p_raqm.raqm, "raqm_get_glyphs");
p_raqm.version = 2;
} else {
p_raqm.version = 1;
p_raqm.get_glyphs_01 =
(t_raqm_get_glyphs_01)dlsym(p_raqm.raqm, "raqm_get_glyphs");
}
if (dlerror() ||
!(p_raqm.create && p_raqm.set_text && p_raqm.set_text_utf8 &&
p_raqm.set_par_direction && p_raqm.set_language && p_raqm.add_font_feature &&
p_raqm.set_freetype_face && p_raqm.layout &&
(p_raqm.get_glyphs || p_raqm.get_glyphs_01) && p_raqm.destroy)) {
dlclose(p_raqm.raqm);
p_raqm.raqm = NULL;
return 2;
}
#else
p_raqm.version_string =
(t_raqm_version_string)GetProcAddress(p_raqm.raqm, "raqm_version_string");
p_raqm.version_atleast =
(t_raqm_version_atleast)GetProcAddress(p_raqm.raqm, "raqm_version_atleast");
p_raqm.create = (t_raqm_create)GetProcAddress(p_raqm.raqm, "raqm_create");
p_raqm.set_text = (t_raqm_set_text)GetProcAddress(p_raqm.raqm, "raqm_set_text");
p_raqm.set_text_utf8 =
(t_raqm_set_text_utf8)GetProcAddress(p_raqm.raqm, "raqm_set_text_utf8");
p_raqm.set_par_direction =
(t_raqm_set_par_direction)GetProcAddress(p_raqm.raqm, "raqm_set_par_direction");
p_raqm.set_language =
(t_raqm_set_language)GetProcAddress(p_raqm.raqm, "raqm_set_language");
p_raqm.add_font_feature =
(t_raqm_add_font_feature)GetProcAddress(p_raqm.raqm, "raqm_add_font_feature");
p_raqm.set_freetype_face =
(t_raqm_set_freetype_face)GetProcAddress(p_raqm.raqm, "raqm_set_freetype_face");
p_raqm.layout = (t_raqm_layout)GetProcAddress(p_raqm.raqm, "raqm_layout");
p_raqm.destroy = (t_raqm_destroy)GetProcAddress(p_raqm.raqm, "raqm_destroy");
if (GetProcAddress(p_raqm.raqm, "raqm_index_to_position")) {
p_raqm.get_glyphs =
(t_raqm_get_glyphs)GetProcAddress(p_raqm.raqm, "raqm_get_glyphs");
p_raqm.version = 2;
} else {
p_raqm.version = 1;
p_raqm.get_glyphs_01 =
(t_raqm_get_glyphs_01)GetProcAddress(p_raqm.raqm, "raqm_get_glyphs");
}
if (!(p_raqm.create && p_raqm.set_text && p_raqm.set_text_utf8 &&
p_raqm.set_par_direction && p_raqm.set_language && p_raqm.add_font_feature &&
p_raqm.set_freetype_face && p_raqm.layout &&
(p_raqm.get_glyphs || p_raqm.get_glyphs_01) && p_raqm.destroy)) {
FreeLibrary(p_raqm.raqm);
p_raqm.raqm = NULL;
return 2;
}
#endif
return 0;
}
static PyObject *
getfont(PyObject *self_, PyObject *args, PyObject *kw) {
/* create a font object from a file name and a size (in pixels) */
@ -346,6 +221,8 @@ font_getchar(PyObject *string, int index, FT_ULong *char_out) {
return 0;
}
#ifdef HAVE_RAQM
static size_t
text_layout_raqm(
PyObject *string,
@ -359,10 +236,9 @@ text_layout_raqm(
size_t i = 0, count = 0, start = 0;
raqm_t *rq;
raqm_glyph_t *glyphs = NULL;
raqm_glyph_t_01 *glyphs_01 = NULL;
raqm_direction_t direction;
rq = (*p_raqm.create)();
rq = raqm_create();
if (rq == NULL) {
PyErr_SetString(PyExc_ValueError, "raqm_create() failed.");
goto failed;
@ -376,14 +252,14 @@ text_layout_raqm(
and raqm fails with empty strings */
goto failed;
}
int set_text = (*p_raqm.set_text)(rq, text, size);
int set_text = raqm_set_text(rq, text, size);
PyMem_Free(text);
if (!set_text) {
PyErr_SetString(PyExc_ValueError, "raqm_set_text() failed");
goto failed;
}
if (lang) {
if (!(*p_raqm.set_language)(rq, lang, start, size)) {
if (!raqm_set_language(rq, lang, start, size)) {
PyErr_SetString(PyExc_ValueError, "raqm_set_language() failed");
goto failed;
}
@ -401,12 +277,12 @@ text_layout_raqm(
direction = RAQM_DIRECTION_LTR;
} else if (strcmp(dir, "ttb") == 0) {
direction = RAQM_DIRECTION_TTB;
if (p_raqm.version_atleast == NULL || !(*p_raqm.version_atleast)(0, 7, 0)) {
PyErr_SetString(
PyExc_ValueError,
"libraqm 0.7 or greater required for 'ttb' direction");
goto failed;
}
#if !defined(RAQM_VERSION_ATLEAST) || !RAQM_VERSION_ATLEAST(0, 7, 0)
PyErr_SetString(
PyExc_ValueError,
"libraqm 0.7 or greater required for 'ttb' direction");
goto failed;
#endif
} else {
PyErr_SetString(
PyExc_ValueError, "direction must be either 'rtl', 'ltr' or 'ttb'");
@ -414,7 +290,7 @@ text_layout_raqm(
}
}
if (!(*p_raqm.set_par_direction)(rq, direction)) {
if (!raqm_set_par_direction(rq, direction)) {
PyErr_SetString(PyExc_ValueError, "raqm_set_par_direction() failed");
goto failed;
}
@ -446,37 +322,28 @@ text_layout_raqm(
feature = PyBytes_AS_STRING(bytes);
size = PyBytes_GET_SIZE(bytes);
}
if (!(*p_raqm.add_font_feature)(rq, feature, size)) {
if (!raqm_add_font_feature(rq, feature, size)) {
PyErr_SetString(PyExc_ValueError, "raqm_add_font_feature() failed");
goto failed;
}
}
}
if (!(*p_raqm.set_freetype_face)(rq, self->face)) {
if (!raqm_set_freetype_face(rq, self->face)) {
PyErr_SetString(PyExc_RuntimeError, "raqm_set_freetype_face() failed.");
goto failed;
}
if (!(*p_raqm.layout)(rq)) {
if (!raqm_layout(rq)) {
PyErr_SetString(PyExc_RuntimeError, "raqm_layout() failed.");
goto failed;
}
if (p_raqm.version == 1) {
glyphs_01 = (*p_raqm.get_glyphs_01)(rq, &count);
if (glyphs_01 == NULL) {
PyErr_SetString(PyExc_ValueError, "raqm_get_glyphs() failed.");
count = 0;
goto failed;
}
} else { /* version == 2 */
glyphs = (*p_raqm.get_glyphs)(rq, &count);
if (glyphs == NULL) {
PyErr_SetString(PyExc_ValueError, "raqm_get_glyphs() failed.");
count = 0;
goto failed;
}
glyphs = raqm_get_glyphs(rq, &count);
if (glyphs == NULL) {
PyErr_SetString(PyExc_ValueError, "raqm_get_glyphs() failed.");
count = 0;
goto failed;
}
(*glyph_info) = PyMem_New(GlyphInfo, count);
@ -486,31 +353,22 @@ text_layout_raqm(
goto failed;
}
if (p_raqm.version == 1) {
for (i = 0; i < count; i++) {
(*glyph_info)[i].index = glyphs_01[i].index;
(*glyph_info)[i].x_offset = glyphs_01[i].x_offset;
(*glyph_info)[i].x_advance = glyphs_01[i].x_advance;
(*glyph_info)[i].y_offset = glyphs_01[i].y_offset;
(*glyph_info)[i].y_advance = glyphs_01[i].y_advance;
(*glyph_info)[i].cluster = glyphs_01[i].cluster;
}
} else {
for (i = 0; i < count; i++) {
(*glyph_info)[i].index = glyphs[i].index;
(*glyph_info)[i].x_offset = glyphs[i].x_offset;
(*glyph_info)[i].x_advance = glyphs[i].x_advance;
(*glyph_info)[i].y_offset = glyphs[i].y_offset;
(*glyph_info)[i].y_advance = glyphs[i].y_advance;
(*glyph_info)[i].cluster = glyphs[i].cluster;
}
for (i = 0; i < count; i++) {
(*glyph_info)[i].index = glyphs[i].index;
(*glyph_info)[i].x_offset = glyphs[i].x_offset;
(*glyph_info)[i].x_advance = glyphs[i].x_advance;
(*glyph_info)[i].y_offset = glyphs[i].y_offset;
(*glyph_info)[i].y_advance = glyphs[i].y_advance;
(*glyph_info)[i].cluster = glyphs[i].cluster;
}
failed:
(*p_raqm.destroy)(rq);
raqm_destroy(rq);
return count;
}
#endif
static size_t
text_layout_fallback(
PyObject *string,
@ -606,11 +464,13 @@ text_layout(
int mask,
int color) {
size_t count;
if (p_raqm.raqm && self->layout_engine == LAYOUT_RAQM) {
#ifdef HAVE_RAQM
if (have_raqm && self->layout_engine == LAYOUT_RAQM) {
count = text_layout_raqm(
string, self, dir, features, lang, glyph_info, mask, color);
} else {
string, self, dir, features, lang, glyph_info, mask, color);
} else
#endif
{
count = text_layout_fallback(
string, self, dir, features, lang, glyph_info, mask, color);
}
@ -1490,12 +1350,51 @@ setup_module(PyObject *m) {
v = PyUnicode_FromFormat("%d.%d.%d", major, minor, patch);
PyDict_SetItemString(d, "freetype2_version", v);
setraqm();
v = PyBool_FromLong(!!p_raqm.raqm);
#ifdef HAVE_RAQM
#if defined(HAVE_RAQM_SYSTEM) || defined(HAVE_FRIBIDI_SYSTEM)
have_raqm = 1;
#else
load_fribidi();
have_raqm = !!p_fribidi;
#endif
#else
have_raqm = 0;
#endif
/* if we have Raqm, we have all three (but possibly no version info) */
v = PyBool_FromLong(have_raqm);
PyDict_SetItemString(d, "HAVE_RAQM", v);
if (p_raqm.version_string) {
PyDict_SetItemString(
d, "raqm_version", PyUnicode_FromString(p_raqm.version_string()));
PyDict_SetItemString(d, "HAVE_FRIBIDI", v);
PyDict_SetItemString(d, "HAVE_HARFBUZZ", v);
if (have_raqm) {
#ifdef RAQM_VERSION_MAJOR
v = PyUnicode_FromString(raqm_version_string());
#else
v = Py_None;
#endif
PyDict_SetItemString(d, "raqm_version", v);
#ifdef FRIBIDI_MAJOR_VERSION
{
const char *a = strchr(fribidi_version_info, ')');
const char *b = strchr(fribidi_version_info, '\n');
if (a && b && a + 2 < b) {
v = PyUnicode_FromStringAndSize(a + 2, b - (a + 2));
} else {
v = Py_None;
}
}
#else
v = Py_None;
#endif
PyDict_SetItemString(d, "fribidi_version", v);
#ifdef HB_VERSION_STRING
v = PyUnicode_FromString(hb_version_string());
#else
v = Py_None;
#endif
PyDict_SetItemString(d, "harfbuzz_version", v);
}
return 0;

101
src/thirdparty/fribidi-shim/fribidi.c vendored Normal file
View File

@ -0,0 +1,101 @@
#ifndef _WIN32
#include <dlfcn.h>
#else
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#endif
#define FRIBIDI_SHIM_IMPLEMENTATION
#include "fribidi.h"
/* FriBiDi>=1.0.0 adds bracket_types param, ignore and call legacy function */
FriBidiLevel fribidi_get_par_embedding_levels_ex_compat(
const FriBidiCharType *bidi_types,
const FriBidiBracketType *bracket_types,
const FriBidiStrIndex len,
FriBidiParType *pbase_dir,
FriBidiLevel *embedding_levels)
{
return fribidi_get_par_embedding_levels(
bidi_types, len, pbase_dir, embedding_levels);
}
/* FriBiDi>=1.0.0 gets bracket types here, ignore */
void fribidi_get_bracket_types_compat(
const FriBidiChar *str,
const FriBidiStrIndex len,
const FriBidiCharType *types,
FriBidiBracketType *btypes)
{ /* no-op*/ }
int load_fribidi(void) {
int error = 0;
p_fribidi = 0;
/* Microsoft needs a totally different system */
#ifndef _WIN32
#define LOAD_FUNCTION(func) \
func = (t_##func)dlsym(p_fribidi, #func); \
error = error || (func == 0);
p_fribidi = dlopen("libfribidi.so", RTLD_LAZY);
if (!p_fribidi) {
p_fribidi = dlopen("libfribidi.so.0", RTLD_LAZY);
}
if (!p_fribidi) {
p_fribidi = dlopen("libfribidi.dylib", RTLD_LAZY);
}
#else
#define LOAD_FUNCTION(func) \
func = (t_##func)GetProcAddress(p_fribidi, #func); \
error = error || (func == 0);
p_fribidi = LoadLibrary("fribidi");
/* MSYS2 */
if (!p_fribidi) {
p_fribidi = LoadLibrary("libfribidi-0");
}
#endif
if (!p_fribidi) {
return 1;
}
/* load FriBiDi>=1.0.0 functions first, use error to detect version */
LOAD_FUNCTION(fribidi_get_par_embedding_levels_ex);
LOAD_FUNCTION(fribidi_get_bracket_types);
if (error) {
/* using FriBiDi<1.0.0, ignore new parameters */
error = 0;
fribidi_get_par_embedding_levels_ex = &fribidi_get_par_embedding_levels_ex_compat;
fribidi_get_bracket_types = &fribidi_get_bracket_types_compat;
}
LOAD_FUNCTION(fribidi_unicode_to_charset);
LOAD_FUNCTION(fribidi_charset_to_unicode);
LOAD_FUNCTION(fribidi_get_bidi_types);
LOAD_FUNCTION(fribidi_get_par_embedding_levels);
#ifndef _WIN32
fribidi_version_info = *(const char**)dlsym(p_fribidi, "fribidi_version_info");
if (dlerror() || error || (fribidi_version_info == 0)) {
dlclose(p_fribidi);
p_fribidi = 0;
return 2;
}
#else
fribidi_version_info = *(const char**)GetProcAddress(p_fribidi, "fribidi_version_info");
if (error || (fribidi_version_info == 0)) {
FreeLibrary(p_fribidi);
p_fribidi = 0;
return 2;
}
#endif
return 0;
}

111
src/thirdparty/fribidi-shim/fribidi.h vendored Normal file
View File

@ -0,0 +1,111 @@
#define FRIBIDI_MAJOR_VERSION 1
/* fribidi-types.h */
# if defined (_SVR4) || defined (SVR4) || defined (__OpenBSD__) || \
defined (_sgi) || defined (__sun) || defined (sun) || \
defined (__digital__) || defined (__HP_cc)
# include <inttypes.h>
# elif defined (_AIX)
# include <sys/inttypes.h>
# else
# include <stdint.h>
# endif
typedef uint32_t FriBidiChar;
typedef int FriBidiStrIndex;
typedef FriBidiChar FriBidiBracketType;
/* fribidi-char-sets.h */
typedef enum
{
_FRIBIDI_CHAR_SET_NOT_FOUND,
FRIBIDI_CHAR_SET_UTF8,
FRIBIDI_CHAR_SET_CAP_RTL,
FRIBIDI_CHAR_SET_ISO8859_6,
FRIBIDI_CHAR_SET_ISO8859_8,
FRIBIDI_CHAR_SET_CP1255,
FRIBIDI_CHAR_SET_CP1256,
_FRIBIDI_CHAR_SETS_NUM_PLUS_ONE
}
FriBidiCharSet;
/* fribidi-bidi-types.h */
typedef signed char FriBidiLevel;
#define FRIBIDI_TYPE_LTR_VAL 0x00000110L
#define FRIBIDI_TYPE_RTL_VAL 0x00000111L
#define FRIBIDI_TYPE_ON_VAL 0x00000040L
typedef uint32_t FriBidiCharType;
#define FRIBIDI_TYPE_LTR FRIBIDI_TYPE_LTR_VAL
typedef uint32_t FriBidiParType;
#define FRIBIDI_PAR_LTR FRIBIDI_TYPE_LTR_VAL
#define FRIBIDI_PAR_RTL FRIBIDI_TYPE_RTL_VAL
#define FRIBIDI_PAR_ON FRIBIDI_TYPE_ON_VAL
#define FRIBIDI_LEVEL_IS_RTL(lev) ((lev) & 1)
#define FRIBIDI_DIR_TO_LEVEL(dir) ((FriBidiLevel) (FRIBIDI_IS_RTL(dir) ? 1 : 0))
#define FRIBIDI_IS_RTL(p) ((p) & 0x00000001L)
#define FRIBIDI_IS_EXPLICIT_OR_BN_OR_WS(p) ((p) & 0x00901000L)
/* functions */
#ifdef FRIBIDI_SHIM_IMPLEMENTATION
#define FRIBIDI_ENTRY
#else
#define FRIBIDI_ENTRY extern
#endif
#define FRIBIDI_FUNC(ret, name, ...) \
typedef ret (*t_##name) (__VA_ARGS__); \
FRIBIDI_ENTRY t_##name name;
FRIBIDI_FUNC(FriBidiStrIndex, fribidi_unicode_to_charset,
FriBidiCharSet, const FriBidiChar *, FriBidiStrIndex, char *);
FRIBIDI_FUNC(FriBidiStrIndex, fribidi_charset_to_unicode,
FriBidiCharSet, const char *, FriBidiStrIndex, FriBidiChar *);
FRIBIDI_FUNC(void, fribidi_get_bidi_types,
const FriBidiChar *, const FriBidiStrIndex, FriBidiCharType *);
FRIBIDI_FUNC(FriBidiLevel, fribidi_get_par_embedding_levels,
const FriBidiCharType *, const FriBidiStrIndex, FriBidiParType *,
FriBidiLevel *);
/* FriBiDi>=1.0.0 */
FRIBIDI_FUNC(FriBidiLevel, fribidi_get_par_embedding_levels_ex,
const FriBidiCharType *, const FriBidiBracketType *, const FriBidiStrIndex,
FriBidiParType *, FriBidiLevel *);
/* FriBiDi>=1.0.0 */
FRIBIDI_FUNC(void, fribidi_get_bracket_types,
const FriBidiChar *, const FriBidiStrIndex, const FriBidiCharType *,
FriBidiBracketType *);
#undef FRIBIDI_FUNC
/* constant, not a function */
FRIBIDI_ENTRY const char *fribidi_version_info;
/* shim */
FRIBIDI_ENTRY void *p_fribidi;
FRIBIDI_ENTRY int load_fribidi(void);
#undef FRIBIDI_ENTRY

9
src/thirdparty/raqm/AUTHORS vendored Normal file
View File

@ -0,0 +1,9 @@
Abderraouf Adjal
Ali Yousuf
Anood Almuharbi
Asma Albahanta
Fahad Alsaidi
Ibtisam Almabsali
Khaled Hosny
Mazoon Almaamari
Shamsa Alqassabi

22
src/thirdparty/raqm/COPYING vendored Normal file
View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright © 2015 Information Technology Authority (ITA) <foss@ita.gov.om>
Copyright © 2016 Khaled Hosny <khaledhosny@eglug.org>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

89
src/thirdparty/raqm/NEWS vendored Normal file
View File

@ -0,0 +1,89 @@
Overview of changes leading to 0.7.1
Sunday, November 22, 2020
====================================
Require HarfBuzz >= 2.0.0
Build and documentation fixes.
Overview of changes leading to 0.7.0
Monday, May 27, 2019
====================================
New API:
* raqm_version
* raqm_version_string
* raqm_version_atleast
* RAQM_VERSION_MAJOR
* RAQM_VERSION_MICRO
* RAQM_VERSION_MINOR
* RAQM_VERSION_STRING
* RAQM_VERSION_ATLEAST
Overview of changes leading to 0.6.0
Sunday, May 5, 2019
====================================
Fix TTB direction regression from the previous release.
Correctly detect script of Common and Inherite characters at start of text.
Undef HAVE_CONFIG_H workaround, for older versions of Fribidi.
Drop test suite dependency on GLib.
Port test runner to Python instead of shell script.
New API:
* raqm_set_invisible_glyph()
Overview of changes leading to 0.5.0
Saturday, February 24, 2018
====================================
Use FriBiDi 1.x API when available.
Overview of changes leading to 0.4.0
Sunday, January 21, 2018
====================================
Set begin-of-text and end-of-text HarfBuzz buffer flags.
Dynamically allocate memory instead of using stack allocation for input text.
Accept zero length text and do nothing instead of treating it as error.
Overview of changes leading to 0.3.0
Monday, August 21, 2017
====================================
Fix stack corruption on MSVC.
New API:
* raqm_set_freetype_load_flags
Overview of changes leading to 0.2.0
Wednesday, August 25, 2016
====================================
Fix building with MSVC due to lacking C99 support.
Make multiple fonts support actually work. Start and length now respect the
input encoding.
New API:
* raqm_index_to_position
* raqm_position_to_index
* raqm_set_language
Overview of changes leading to 0.1.1
Sunday, May 1, 2016
====================================
Fix make check on 32-bit systems.
Overview of changes leading to 0.1.0
Wednesday, January 20, 2016
====================================
First release.

85
src/thirdparty/raqm/README vendored Normal file
View File

@ -0,0 +1,85 @@
Raqm
====
[![Linux & macOS build](https://travis-ci.org/HOST-Oman/libraqm.svg?branch=master)](https://travis-ci.org/HOST-Oman/libraqm)
[![Windows build](https://img.shields.io/appveyor/ci/HOSTOman/libraqm/master.svg)](https://ci.appveyor.com/project/HOSTOman/libraqm)
Raqm is a small library that encapsulates the logic for complex text layout and
provides a convenient API.
It currently provides bidirectional text support (using [FriBiDi][1]), shaping
(using [HarfBuzz][2]), and proper script itemization. As a result,
Raqm can support most writing systems covered by Unicode.
The documentation can be accessed on the web at:
> http://host-oman.github.io/libraqm/
Raqm (Arabic: رَقْم) is writing, also number or digit and the Arabic word for
digital (رَقَمِيّ) shares the same root, so it is a play on “digital writing”.
Building
--------
Raqm depends on the following libraries:
* [FreeType][3]
* [HarfBuzz][2]
* [FriBiDi][1]
To build the documentation you will also need:
* [GTK-Doc][4]
To install dependencies on Fedora:
sudo dnf install freetype-devel harfbuzz-devel fribidi-devel gtk-doc
To install dependencies on Ubuntu:
sudo apt-get install libfreetype6-dev libharfbuzz-dev libfribidi-dev \
gtk-doc-tools
On Mac OS X you can use Homebrew:
brew install freetype harfbuzz fribidi gtk-doc
export XML_CATALOG_FILES="/usr/local/etc/xml/catalog" # for the docs
Once you have the source code and the dependencies, you can proceed to build.
To do that, run the customary sequence of commands in the source code
directory:
$ ./configure
$ make
$ make install
To build the documentation, pass `--enable-gtk-doc` to the `configure` script.
To run the tests:
$ make check
Contributing
------------
Once you have made a change that you are happy with, contribute it back, well
be happy to integrate it! Just fork the repository and make a pull request.
Projects using Raqm
-------------------
1. [ImageMagick](https://github.com/ImageMagick/ImageMagick)
2. [LibGD](https://github.com/libgd/libgd)
3. [FontView](https://github.com/googlei18n/fontview)
4. [Pillow](https://github.com/python-pillow)
5. [mplcairo](https://github.com/anntzer/mplcairo)
The following projects have patches to support complex text layout using Raqm:
2. SDL_ttf: https://bugzilla.libsdl.org/show_bug.cgi?id=3211
3. Pygame: https://bitbucket.org/pygame/pygame/pull-requests/52
4. Blender: https://developer.blender.org/D1809
[1]: http://fribidi.org
[2]: http://harfbuzz.org
[3]: https://www.freetype.org
[4]: https://www.gtk.org/gtk-doc

44
src/thirdparty/raqm/raqm-version.h vendored Normal file
View File

@ -0,0 +1,44 @@
/*
* Copyright © 2011 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef _RAQM_H_IN_
#error "Include <raqm.h> instead."
#endif
#ifndef _RAQM_VERSION_H_
#define _RAQM_VERSION_H_
#define RAQM_VERSION_MAJOR 0
#define RAQM_VERSION_MINOR 7
#define RAQM_VERSION_MICRO 1
#define RAQM_VERSION_STRING "0.7.1"
#define RAQM_VERSION_ATLEAST(major,minor,micro) \
((major)*10000+(minor)*100+(micro) <= \
RAQM_VERSION_MAJOR*10000+RAQM_VERSION_MINOR*100+RAQM_VERSION_MICRO)
#endif /* _RAQM_VERSION_H_ */

2074
src/thirdparty/raqm/raqm.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -24,17 +24,14 @@
#ifndef _RAQM_H_
#define _RAQM_H_
#define _RAQM_H_IN_
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifndef bool
typedef int bool;
#endif
#ifndef uint32_t
typedef UINT32 uint32_t;
#endif
#include <stdbool.h>
#include <stdint.h>
#include <ft2build.h>
#include FT_FREETYPE_H
@ -42,6 +39,8 @@ typedef UINT32 uint32_t;
extern "C" {
#endif
#include "raqm-version.h"
/**
* raqm_t:
*
@ -63,7 +62,8 @@ typedef struct _raqm raqm_t;
*
* Since: 0.1
*/
typedef enum {
typedef enum
{
RAQM_DIRECTION_DEFAULT,
RAQM_DIRECTION_RTL,
RAQM_DIRECTION_LTR,
@ -93,64 +93,93 @@ typedef struct raqm_glyph_t {
FT_Face ftface;
} raqm_glyph_t;
/**
* version 0.1 of the raqm_glyph_t structure
*/
typedef struct raqm_glyph_t_01 {
unsigned int index;
int x_advance;
int y_advance;
int x_offset;
int y_offset;
uint32_t cluster;
} raqm_glyph_t_01;
raqm_t *
raqm_create (void);
raqm_t *
raqm_create(void);
raqm_t *
raqm_reference(raqm_t *rq);
raqm_reference (raqm_t *rq);
void
raqm_destroy(raqm_t *rq);
raqm_destroy (raqm_t *rq);
bool
raqm_set_text(raqm_t *rq, const uint32_t *text, size_t len);
raqm_set_text (raqm_t *rq,
const uint32_t *text,
size_t len);
bool
raqm_set_text_utf8(raqm_t *rq, const char *text, size_t len);
raqm_set_text_utf8 (raqm_t *rq,
const char *text,
size_t len);
bool
raqm_set_par_direction(raqm_t *rq, raqm_direction_t dir);
raqm_set_par_direction (raqm_t *rq,
raqm_direction_t dir);
bool
raqm_set_language(raqm_t *rq, const char *lang, size_t start, size_t len);
raqm_set_language (raqm_t *rq,
const char *lang,
size_t start,
size_t len);
bool
raqm_add_font_feature(raqm_t *rq, const char *feature, int len);
raqm_add_font_feature (raqm_t *rq,
const char *feature,
int len);
bool
raqm_set_freetype_face(raqm_t *rq, FT_Face face);
raqm_set_freetype_face (raqm_t *rq,
FT_Face face);
bool
raqm_set_freetype_face_range(raqm_t *rq, FT_Face face, size_t start, size_t len);
raqm_set_freetype_face_range (raqm_t *rq,
FT_Face face,
size_t start,
size_t len);
bool
raqm_set_freetype_load_flags(raqm_t *rq, int flags);
raqm_set_freetype_load_flags (raqm_t *rq,
int flags);
bool
raqm_layout(raqm_t *rq);
raqm_set_invisible_glyph (raqm_t *rq,
int gid);
bool
raqm_layout (raqm_t *rq);
raqm_glyph_t *
raqm_get_glyphs(raqm_t *rq, size_t *length);
raqm_get_glyphs (raqm_t *rq,
size_t *length);
bool
raqm_index_to_position(raqm_t *rq, size_t *index, int *x, int *y);
raqm_index_to_position (raqm_t *rq,
size_t *index,
int *x,
int *y);
bool
raqm_position_to_index(raqm_t *rq, int x, int y, size_t *index);
raqm_position_to_index (raqm_t *rq,
int x,
int y,
size_t *index);
void
raqm_version (unsigned int *major,
unsigned int *minor,
unsigned int *micro);
const char *
raqm_version_string (void);
bool
raqm_version_atleast (unsigned int major,
unsigned int minor,
unsigned int micro);
#ifdef __cplusplus
}
#endif
#undef _RAQM_H_IN_
#endif /* _RAQM_H_ */

View File

@ -296,21 +296,7 @@ deps = {
cmd_nmake(target="clean"),
cmd_nmake(target="fribidi"),
],
"headers": [r"lib\*.h"],
"libs": [r"*.lib"],
},
"libraqm": {
"url": "https://github.com/HOST-Oman/libraqm/archive/v0.7.1.zip",
"filename": "libraqm-0.7.1.zip",
"dir": "libraqm-0.7.1",
"build": [
cmd_copy(r"{winbuild_dir}\raqm.cmake", r"CMakeLists.txt"),
cmd_cmake(),
cmd_nmake(target="clean"),
cmd_nmake(target="libraqm"),
],
"headers": [r"src\*.h"],
"bins": [r"libraqm.dll"],
"bins": [r"*.dll"],
},
}
@ -486,7 +472,7 @@ def build_pillow():
cmd_set("DISTUTILS_USE_SDK", "1"), # use same compiler to build Pillow
cmd_set("MSSdk", "1"), # for PyPy3.6
cmd_set("py_vcruntime_redist", "true"), # use /MD, not /MT
r'"{python_dir}\{python_exe}" setup.py build_ext %*',
r'"{python_dir}\{python_exe}" setup.py build_ext --vendor-raqm --vendor-fribidi %*', # noqa: E501
]
write_script("build_pillow.cmd", lines)
@ -511,8 +497,8 @@ if __name__ == "__main__":
verbose = True
elif arg == "--no-imagequant":
disabled += ["libimagequant"]
elif arg == "--no-raqm":
disabled += ["fribidi", "libraqm"]
elif arg == "--no-raqm" or arg == "--no-fribidi":
disabled += ["fribidi"]
elif arg.startswith("--depends="):
depends_dir = arg[10:]
elif arg.startswith("--python="):

View File

@ -93,10 +93,10 @@ fribidi_tab(brackets-type unidata/BidiBrackets.txt)
file(GLOB FRIBIDI_SOURCES lib/*.c)
file(GLOB FRIBIDI_HEADERS lib/*.h)
add_library(fribidi STATIC
add_library(fribidi SHARED
${FRIBIDI_SOURCES}
${FRIBIDI_HEADERS}
${FRIBIDI_SOURCES_GENERATED})
fribidi_definitions(fribidi)
target_compile_definitions(fribidi
PUBLIC -DFRIBIDI_LIB_STATIC)
PUBLIC "-DFRIBIDI_BUILD")