mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-08-05 13:00:09 +03:00
merge single font and font family code paths
This commit is contained in:
parent
6002b0a49e
commit
3710f2d299
353
src/_imagingft.c
353
src/_imagingft.c
|
@ -67,9 +67,10 @@ static int have_raqm = 0;
|
||||||
#define LAYOUT_RAQM 1
|
#define LAYOUT_RAQM 1
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
FT_Face face;
|
FT_Face *faces;
|
||||||
unsigned char *font_bytes;
|
int font_count;
|
||||||
} FontFamilyFont;
|
int layout_engine;
|
||||||
|
} FontFamily;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
FT_Face face;
|
FT_Face face;
|
||||||
|
@ -96,9 +97,8 @@ typedef struct {
|
||||||
} FontObject;
|
} FontObject;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PyObject_HEAD int font_count;
|
PyObject_HEAD FontFamily data;
|
||||||
FontFamilyFont *fonts;
|
unsigned char **font_bytes;
|
||||||
int layout_engine;
|
|
||||||
} FontFamilyObject;
|
} FontFamilyObject;
|
||||||
|
|
||||||
static PyTypeObject Font_Type;
|
static PyTypeObject Font_Type;
|
||||||
|
@ -256,6 +256,7 @@ getfamily(PyObject *self_, PyObject *args, PyObject *kw) {
|
||||||
/* create a font family object from a list of file names and a sizes (in pixels) */
|
/* create a font family object from a list of file names and a sizes (in pixels) */
|
||||||
|
|
||||||
FontFamilyObject *self;
|
FontFamilyObject *self;
|
||||||
|
FontFamily *family;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
PyTupleObject *fonts_tuple = NULL;
|
PyTupleObject *fonts_tuple = NULL;
|
||||||
|
@ -282,16 +283,23 @@ getfamily(PyObject *self_, PyObject *args, PyObject *kw) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
self->font_count = PyTuple_GET_SIZE(fonts_tuple);
|
family = &self->data;
|
||||||
self->layout_engine = layout_engine;
|
|
||||||
self->fonts = PyMem_New(FontFamilyFont, self->font_count);
|
family->font_count = PyTuple_GET_SIZE(fonts_tuple);
|
||||||
if (!self->fonts) {
|
family->layout_engine = layout_engine;
|
||||||
|
family->faces = PyMem_New(FT_Face, family->font_count);
|
||||||
|
if (!family->faces) {
|
||||||
|
PyObject_Del(self);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
self->font_bytes = PyMem_New(unsigned char *, family->font_count);
|
||||||
|
if (!self->font_bytes) {
|
||||||
|
PyMem_Free(family->faces);
|
||||||
PyObject_Del(self);
|
PyObject_Del(self);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
FontFamilyFont *font = self->fonts;
|
for (int i = 0; i < family->font_count; i++) {
|
||||||
for (int i = 0; i < self->font_count; ++i, ++font) {
|
|
||||||
char *filename;
|
char *filename;
|
||||||
Py_ssize_t size;
|
Py_ssize_t size;
|
||||||
Py_ssize_t index;
|
Py_ssize_t index;
|
||||||
|
@ -312,38 +320,38 @@ getfamily(PyObject *self_, PyObject *args, PyObject *kw) {
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
font->face = NULL;
|
family->faces[i] = NULL;
|
||||||
|
|
||||||
if (filename && font_bytes_size <= 0) {
|
if (filename && font_bytes_size <= 0) {
|
||||||
font->font_bytes = NULL;
|
self->font_bytes[i] = NULL;
|
||||||
error = FT_New_Face(library, filename, index, &font->face);
|
error = FT_New_Face(library, filename, index, &family->faces[i]);
|
||||||
} else {
|
} else {
|
||||||
/* need to have allocated storage for font_bytes for the life of the
|
/* need to have allocated storage for font_bytes for the life of the
|
||||||
* object.*/
|
* object.*/
|
||||||
/* Don't free this before FT_Done_Face */
|
/* Don't free this before FT_Done_Face */
|
||||||
font->font_bytes = PyMem_Malloc(font_bytes_size);
|
self->font_bytes[i] = PyMem_Malloc(font_bytes_size);
|
||||||
if (!font->font_bytes) {
|
if (!self->font_bytes[i]) {
|
||||||
error = FT_Err_Out_Of_Memory;
|
error = FT_Err_Out_Of_Memory;
|
||||||
}
|
}
|
||||||
if (!error) {
|
if (!error) {
|
||||||
memcpy(font->font_bytes, font_bytes, (size_t)font_bytes_size);
|
memcpy(self->font_bytes[i], font_bytes, (size_t)font_bytes_size);
|
||||||
error = FT_New_Memory_Face(
|
error = FT_New_Memory_Face(
|
||||||
library,
|
library,
|
||||||
(FT_Byte *)font->font_bytes,
|
(FT_Byte *)self->font_bytes[i],
|
||||||
font_bytes_size,
|
font_bytes_size,
|
||||||
index,
|
index,
|
||||||
&font->face);
|
&family->faces[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!error) {
|
if (!error) {
|
||||||
error = FT_Set_Pixel_Sizes(font->face, 0, size);
|
error = FT_Set_Pixel_Sizes(family->faces[i], 0, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!error && encoding && strlen((char *)encoding) == 4) {
|
if (!error && encoding && strlen((char *)encoding) == 4) {
|
||||||
FT_Encoding encoding_tag =
|
FT_Encoding encoding_tag =
|
||||||
FT_MAKE_TAG(encoding[0], encoding[1], encoding[2], encoding[3]);
|
FT_MAKE_TAG(encoding[0], encoding[1], encoding[2], encoding[3]);
|
||||||
error = FT_Select_Charmap(font->face, encoding_tag);
|
error = FT_Select_Charmap(family->faces[i], encoding_tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filename) {
|
if (filename) {
|
||||||
|
@ -351,31 +359,33 @@ getfamily(PyObject *self_, PyObject *args, PyObject *kw) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
if (font->font_bytes) {
|
if (self->font_bytes[i]) {
|
||||||
PyMem_Free(font->font_bytes);
|
PyMem_Free(self->font_bytes[i]);
|
||||||
font->font_bytes = NULL;
|
self->font_bytes[i] = NULL;
|
||||||
|
}
|
||||||
|
if (family->faces[i]) {
|
||||||
|
FT_Done_Face(family->faces[i]);
|
||||||
}
|
}
|
||||||
geterror(error);
|
geterror(error);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
|
||||||
|
err:
|
||||||
|
for (int j = 0; j < i; j++) {
|
||||||
|
if (family->faces[j]) {
|
||||||
|
FT_Done_Face(family->faces[j]);
|
||||||
|
}
|
||||||
|
if (self->font_bytes[j]) {
|
||||||
|
PyMem_Free(self->font_bytes[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PyObject_Del(self);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (PyObject *)self;
|
return (PyObject *)self;
|
||||||
|
|
||||||
err:
|
|
||||||
for (FontFamilyFont *f = self->fonts; f != font; ++f) {
|
|
||||||
if (f->font_bytes) {
|
|
||||||
PyMem_Free(f->font_bytes);
|
|
||||||
f->font_bytes = NULL;
|
|
||||||
}
|
|
||||||
if (f->face) {
|
|
||||||
FT_Done_Face(f->face);
|
|
||||||
f->face = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject_Del(self);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_RAQM
|
#ifdef HAVE_RAQM
|
||||||
|
@ -383,7 +393,7 @@ err:
|
||||||
static size_t
|
static size_t
|
||||||
text_layout_raqm(
|
text_layout_raqm(
|
||||||
PyObject *string,
|
PyObject *string,
|
||||||
FontObject *self,
|
FontFamily *family,
|
||||||
const char *dir,
|
const char *dir,
|
||||||
PyObject *features,
|
PyObject *features,
|
||||||
const char *lang,
|
const char *lang,
|
||||||
|
@ -496,7 +506,7 @@ text_layout_raqm(
|
||||||
Py_DECREF(seq);
|
Py_DECREF(seq);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!raqm_set_freetype_face(rq, self->face)) {
|
if (!raqm_set_freetype_face(rq, family->faces[0])) {
|
||||||
PyErr_SetString(PyExc_RuntimeError, "raqm_set_freetype_face() failed.");
|
PyErr_SetString(PyExc_RuntimeError, "raqm_set_freetype_face() failed.");
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
@ -521,7 +531,7 @@ text_layout_raqm(
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
(*glyph_info)[i].face = self->face;
|
(*glyph_info)[i].face = family->faces[0];
|
||||||
(*glyph_info)[i].index = glyphs[i].index;
|
(*glyph_info)[i].index = glyphs[i].index;
|
||||||
(*glyph_info)[i].x_offset = glyphs[i].x_offset;
|
(*glyph_info)[i].x_offset = glyphs[i].x_offset;
|
||||||
(*glyph_info)[i].x_advance = glyphs[i].x_advance;
|
(*glyph_info)[i].x_advance = glyphs[i].x_advance;
|
||||||
|
@ -540,7 +550,7 @@ failed:
|
||||||
static size_t
|
static size_t
|
||||||
text_layout_fallback(
|
text_layout_fallback(
|
||||||
PyObject *string,
|
PyObject *string,
|
||||||
FontObject *self,
|
FontFamily *family,
|
||||||
const char *dir,
|
const char *dir,
|
||||||
PyObject *features,
|
PyObject *features,
|
||||||
const char *lang,
|
const char *lang,
|
||||||
|
@ -553,7 +563,6 @@ text_layout_fallback(
|
||||||
FT_ULong ch;
|
FT_ULong ch;
|
||||||
Py_ssize_t count;
|
Py_ssize_t count;
|
||||||
FT_GlyphSlot glyph;
|
FT_GlyphSlot glyph;
|
||||||
FT_Bool kerning = FT_HAS_KERNING(self->face);
|
|
||||||
FT_UInt last_index = 0;
|
FT_UInt last_index = 0;
|
||||||
|
|
||||||
if (features != Py_None || dir != NULL || lang != NULL) {
|
if (features != Py_None || dir != NULL || lang != NULL) {
|
||||||
|
@ -592,116 +601,27 @@ text_layout_fallback(
|
||||||
} else {
|
} else {
|
||||||
ch = PyUnicode_READ_CHAR(string, i);
|
ch = PyUnicode_READ_CHAR(string, i);
|
||||||
}
|
}
|
||||||
(*glyph_info)[i].face = self->face;
|
|
||||||
(*glyph_info)[i].index = FT_Get_Char_Index(self->face, ch);
|
|
||||||
error = FT_Load_Glyph(self->face, (*glyph_info)[i].index, load_flags);
|
|
||||||
if (error) {
|
|
||||||
geterror(error);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
glyph = self->face->glyph;
|
|
||||||
(*glyph_info)[i].x_offset = 0;
|
|
||||||
(*glyph_info)[i].y_offset = 0;
|
|
||||||
if (kerning && last_index && (*glyph_info)[i].index) {
|
|
||||||
FT_Vector delta;
|
|
||||||
if (FT_Get_Kerning(
|
|
||||||
self->face,
|
|
||||||
last_index,
|
|
||||||
(*glyph_info)[i].index,
|
|
||||||
ft_kerning_default,
|
|
||||||
&delta
|
|
||||||
) == 0) {
|
|
||||||
(*glyph_info)[i - 1].x_advance += PIXEL(delta.x);
|
|
||||||
(*glyph_info)[i - 1].y_advance += PIXEL(delta.y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(*glyph_info)[i].x_advance = glyph->metrics.horiAdvance;
|
|
||||||
// y_advance is only used in ttb, which is not supported by basic layout
|
|
||||||
(*glyph_info)[i].y_advance = 0;
|
|
||||||
last_index = (*glyph_info)[i].index;
|
|
||||||
(*glyph_info)[i].cluster = ch;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t
|
|
||||||
text_layout_family(
|
|
||||||
PyObject *string,
|
|
||||||
FontFamilyObject *self,
|
|
||||||
const char *dir,
|
|
||||||
PyObject *features,
|
|
||||||
const char *lang,
|
|
||||||
GlyphInfo **glyph_info,
|
|
||||||
int mask,
|
|
||||||
int color) {
|
|
||||||
int error, load_flags;
|
|
||||||
FT_ULong ch;
|
|
||||||
Py_ssize_t count;
|
|
||||||
FT_GlyphSlot glyph;
|
|
||||||
FT_UInt last_index = 0;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (features != Py_None || dir != NULL || lang != NULL) {
|
|
||||||
PyErr_SetString(
|
|
||||||
PyExc_KeyError,
|
|
||||||
"setting text direction, language or font features is not supported "
|
|
||||||
"without libraqm");
|
|
||||||
}
|
|
||||||
if (!PyUnicode_Check(string)) {
|
|
||||||
PyErr_SetString(PyExc_TypeError, "expected string");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
count = 0;
|
|
||||||
if (PyUnicode_Check(string)) {
|
|
||||||
count = PyUnicode_GET_LENGTH(string);
|
|
||||||
} else {
|
|
||||||
PyBytes_AsStringAndSize(string, &buffer, &count);
|
|
||||||
}
|
|
||||||
if (count == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
(*glyph_info) = PyMem_New(GlyphInfo, count);
|
|
||||||
if ((*glyph_info) == NULL) {
|
|
||||||
PyErr_SetString(PyExc_MemoryError, "PyMem_New() failed");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
load_flags = FT_LOAD_DEFAULT;
|
|
||||||
if (mask) {
|
|
||||||
load_flags |= FT_LOAD_TARGET_MONO;
|
|
||||||
}
|
|
||||||
#ifdef FT_LOAD_COLOR
|
|
||||||
if (color) {
|
|
||||||
load_flags |= FT_LOAD_COLOR;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
for (i = 0; i < count; i++) {
|
|
||||||
if (buffer) {
|
|
||||||
ch = buffer[i];
|
|
||||||
} else {
|
|
||||||
ch = PyUnicode_READ_CHAR(string, i);
|
|
||||||
}
|
|
||||||
FontFamilyFont *font = self->fonts;
|
|
||||||
int found = 0;
|
int found = 0;
|
||||||
for (int j = 0; !found && j < self->font_count; j++, font++) {
|
for (int j = 0; !found && j < family->font_count; j++) {
|
||||||
(*glyph_info)[i].index = FT_Get_Char_Index(font->face, ch);
|
FT_Face face = family->faces[j];
|
||||||
|
(*glyph_info)[i].index = FT_Get_Char_Index(face, ch);
|
||||||
if ((*glyph_info)[i].index != 0) {
|
if ((*glyph_info)[i].index != 0) {
|
||||||
found = 1;
|
found = 1;
|
||||||
}
|
}
|
||||||
if (j == 0 || found) { /* use first font's missing glyph */
|
/* prefer first font's missing glyph if no font support this codepoint */
|
||||||
(*glyph_info)[i].face = font->face;
|
if (j == 0 || found) {
|
||||||
error = FT_Load_Glyph(font->face, (*glyph_info)[i].index, load_flags);
|
(*glyph_info)[i].face = face;
|
||||||
|
error = FT_Load_Glyph(face, (*glyph_info)[i].index, load_flags);
|
||||||
if (error) {
|
if (error) {
|
||||||
geterror(error);
|
geterror(error);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
glyph = font->face->glyph;
|
glyph = face->glyph;
|
||||||
(*glyph_info)[i].x_offset = 0;
|
(*glyph_info)[i].x_offset = 0;
|
||||||
(*glyph_info)[i].y_offset = 0;
|
(*glyph_info)[i].y_offset = 0;
|
||||||
if (FT_HAS_KERNING(font->face) && last_index &&
|
|
||||||
|
/* This has been broken and had no effect for many years now...
|
||||||
|
if (FT_HAS_KERNING(face) && last_index &&
|
||||||
(*glyph_info)[i].index) {
|
(*glyph_info)[i].index) {
|
||||||
FT_Vector delta;
|
FT_Vector delta;
|
||||||
if (FT_Get_Kerning(
|
if (FT_Get_Kerning(
|
||||||
|
@ -714,9 +634,10 @@ text_layout_family(
|
||||||
(*glyph_info)[i - 1].y_advance += PIXEL(delta.y);
|
(*glyph_info)[i - 1].y_advance += PIXEL(delta.y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
(*glyph_info)[i].x_advance = glyph->metrics.horiAdvance;
|
(*glyph_info)[i].x_advance = glyph->metrics.horiAdvance;
|
||||||
// y_advance is only used in ttb, which is not supported by basic layout
|
/* y_advance is only used in ttb, which is not supported by basic layout */
|
||||||
(*glyph_info)[i].y_advance = 0;
|
(*glyph_info)[i].y_advance = 0;
|
||||||
last_index = (*glyph_info)[i].index;
|
last_index = (*glyph_info)[i].index;
|
||||||
(*glyph_info)[i].cluster = ch;
|
(*glyph_info)[i].cluster = ch;
|
||||||
|
@ -729,7 +650,7 @@ text_layout_family(
|
||||||
static size_t
|
static size_t
|
||||||
text_layout(
|
text_layout(
|
||||||
PyObject *string,
|
PyObject *string,
|
||||||
FontObject *self,
|
FontFamily *family,
|
||||||
const char *dir,
|
const char *dir,
|
||||||
PyObject *features,
|
PyObject *features,
|
||||||
const char *lang,
|
const char *lang,
|
||||||
|
@ -739,20 +660,20 @@ text_layout(
|
||||||
) {
|
) {
|
||||||
size_t count;
|
size_t count;
|
||||||
#ifdef HAVE_RAQM
|
#ifdef HAVE_RAQM
|
||||||
if (have_raqm && self->layout_engine == LAYOUT_RAQM) {
|
if (have_raqm && family->layout_engine == LAYOUT_RAQM) {
|
||||||
count = text_layout_raqm(string, self, dir, features, lang, glyph_info);
|
count = text_layout_raqm(string, family, dir, features, lang, glyph_info);
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
count = text_layout_fallback(
|
count = text_layout_fallback(
|
||||||
string, self, dir, features, lang, glyph_info, mask, color
|
string, family, dir, features, lang, glyph_info, mask, color
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
text_getlength(void *self, int is_font_family, PyObject *args) {
|
text_getlength(FontFamily *family, PyObject *args) {
|
||||||
int length; /* length along primary axis, in 26.6 precision */
|
int length; /* length along primary axis, in 26.6 precision */
|
||||||
GlyphInfo *glyph_info = NULL; /* computed text layout */
|
GlyphInfo *glyph_info = NULL; /* computed text layout */
|
||||||
size_t i, count; /* glyph_info index and length */
|
size_t i, count; /* glyph_info index and length */
|
||||||
|
@ -778,20 +699,8 @@ text_getlength(void *self, int is_font_family, PyObject *args) {
|
||||||
mask = mode && strcmp(mode, "1") == 0;
|
mask = mode && strcmp(mode, "1") == 0;
|
||||||
color = mode && strcmp(mode, "RGBA") == 0;
|
color = mode && strcmp(mode, "RGBA") == 0;
|
||||||
|
|
||||||
if (is_font_family) {
|
count = text_layout(string, family, dir, features, lang, &glyph_info, mask, color);
|
||||||
count = text_layout_family(
|
|
||||||
string,
|
|
||||||
(FontFamilyObject *)self,
|
|
||||||
dir,
|
|
||||||
features,
|
|
||||||
lang,
|
|
||||||
&glyph_info,
|
|
||||||
mask,
|
|
||||||
color);
|
|
||||||
} else {
|
|
||||||
count = text_layout(
|
|
||||||
string, (FontObject *)self, dir, features, lang, &glyph_info, mask, color);
|
|
||||||
}
|
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -815,18 +724,23 @@ text_getlength(void *self, int is_font_family, PyObject *args) {
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
font_getlength(FontObject *self, PyObject *args) {
|
font_getlength(FontObject *self, PyObject *args) {
|
||||||
return text_getlength(self, 0, args);
|
FontFamily family;
|
||||||
|
|
||||||
|
family.faces = &self->face;
|
||||||
|
family.font_count = 1;
|
||||||
|
family.layout_engine = self->layout_engine;
|
||||||
|
|
||||||
|
return text_getlength(&family, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
family_getlength(FontFamilyObject *self, PyObject *args) {
|
family_getlength(FontFamilyObject *self, PyObject *args) {
|
||||||
return text_getlength(self, 1, args);
|
return text_getlength(&self->data, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
bounding_box_and_anchors(
|
bounding_box_and_anchors(
|
||||||
void *self,
|
FontFamily *family,
|
||||||
int is_font_family,
|
|
||||||
const char *anchor,
|
const char *anchor,
|
||||||
int horizontal_dir,
|
int horizontal_dir,
|
||||||
GlyphInfo *glyph_info,
|
GlyphInfo *glyph_info,
|
||||||
|
@ -844,18 +758,9 @@ bounding_box_and_anchors(
|
||||||
int x_anchor, y_anchor; /* offset of point drawn at (0, 0), in pixels */
|
int x_anchor, y_anchor; /* offset of point drawn at (0, 0), in pixels */
|
||||||
int error;
|
int error;
|
||||||
FT_Face face;
|
FT_Face face;
|
||||||
FT_Face primaryFace;
|
|
||||||
FT_Glyph glyph;
|
FT_Glyph glyph;
|
||||||
FT_BBox bbox; /* glyph bounding box */
|
FT_BBox bbox; /* glyph bounding box */
|
||||||
size_t i; /* glyph_info index */
|
size_t i; /* glyph_info index */
|
||||||
|
|
||||||
if (is_font_family) {
|
|
||||||
FontFamilyObject *family = (FontFamilyObject *)self;
|
|
||||||
primaryFace = family->fonts->face;
|
|
||||||
} else {
|
|
||||||
FontObject *font = (FontObject *)self;
|
|
||||||
primaryFace = font->face;
|
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
* text bounds are given by:
|
* text bounds are given by:
|
||||||
* - bounding boxes of individual glyphs
|
* - bounding boxes of individual glyphs
|
||||||
|
@ -946,14 +851,14 @@ bounding_box_and_anchors(
|
||||||
}
|
}
|
||||||
switch (anchor[1]) {
|
switch (anchor[1]) {
|
||||||
case 'a': // ascender
|
case 'a': // ascender
|
||||||
y_anchor = PIXEL(primaryFace->size->metrics.ascender);
|
y_anchor = PIXEL(family->faces[0]->size->metrics.ascender);
|
||||||
break;
|
break;
|
||||||
case 't': // top
|
case 't': // top
|
||||||
y_anchor = y_max;
|
y_anchor = y_max;
|
||||||
break;
|
break;
|
||||||
case 'm': // middle (ascender + descender) / 2
|
case 'm': // middle (ascender + descender) / 2
|
||||||
y_anchor = PIXEL(
|
y_anchor = PIXEL(
|
||||||
(primaryFace->size->metrics.ascender + primaryFace->size->metrics.descender) /
|
(family->faces[0]->size->metrics.ascender + family->faces[0]->size->metrics.descender) /
|
||||||
2
|
2
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
@ -964,7 +869,7 @@ bounding_box_and_anchors(
|
||||||
y_anchor = y_min;
|
y_anchor = y_min;
|
||||||
break;
|
break;
|
||||||
case 'd': // descender
|
case 'd': // descender
|
||||||
y_anchor = PIXEL(primaryFace->size->metrics.descender);
|
y_anchor = PIXEL(family->faces[0]->size->metrics.descender);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
goto bad_anchor;
|
goto bad_anchor;
|
||||||
|
@ -1016,7 +921,7 @@ bad_anchor:
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
text_getsize(void *self, int is_font_family, PyObject *args) {
|
text_getsize(FontFamily *family, PyObject *args) {
|
||||||
int width, height, x_offset, y_offset;
|
int width, height, x_offset, y_offset;
|
||||||
int load_flags; /* FreeType load_flags parameter */
|
int load_flags; /* FreeType load_flags parameter */
|
||||||
int error;
|
int error;
|
||||||
|
@ -1045,15 +950,7 @@ text_getsize(void *self, int is_font_family, PyObject *args) {
|
||||||
mask = mode && strcmp(mode, "1") == 0;
|
mask = mode && strcmp(mode, "1") == 0;
|
||||||
color = mode && strcmp(mode, "RGBA") == 0;
|
color = mode && strcmp(mode, "RGBA") == 0;
|
||||||
|
|
||||||
if (is_font_family) {
|
count = text_layout(string, family, dir, features, lang, &glyph_info, mask, color);
|
||||||
FontFamilyObject *family = (FontFamilyObject *)self;
|
|
||||||
count = text_layout_family(
|
|
||||||
string, family, dir, features, lang, &glyph_info, mask, color);
|
|
||||||
} else {
|
|
||||||
FontObject *font = (FontObject *) self;
|
|
||||||
count = text_layout(
|
|
||||||
string, font, dir, features, lang, &glyph_info, mask, color);
|
|
||||||
}
|
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1067,8 +964,7 @@ text_getsize(void *self, int is_font_family, PyObject *args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
error = bounding_box_and_anchors(
|
error = bounding_box_and_anchors(
|
||||||
self,
|
family,
|
||||||
is_font_family,
|
|
||||||
anchor,
|
anchor,
|
||||||
horizontal_dir,
|
horizontal_dir,
|
||||||
glyph_info,
|
glyph_info,
|
||||||
|
@ -1092,16 +988,22 @@ text_getsize(void *self, int is_font_family, PyObject *args) {
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
font_getsize(FontObject *self, PyObject *args) {
|
font_getsize(FontObject *self, PyObject *args) {
|
||||||
return text_getsize(self, 0, args);
|
FontFamily family;
|
||||||
|
|
||||||
|
family.faces = &self->face;
|
||||||
|
family.font_count = 1;
|
||||||
|
family.layout_engine = self->layout_engine;
|
||||||
|
|
||||||
|
return text_getsize(&family, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
family_getsize(FontFamilyObject *self, PyObject *args) {
|
family_getsize(FontFamilyObject *self, PyObject *args) {
|
||||||
return text_getsize(self, 1, args);
|
return text_getsize(&self->data, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
text_render(void *self, int is_font_family, PyObject *args) {
|
text_render(FontFamily *family, PyObject *args) {
|
||||||
int x, y; /* pen position, in 26.6 precision */
|
int x, y; /* pen position, in 26.6 precision */
|
||||||
int px, py; /* position of current glyph, in pixels */
|
int px, py; /* position of current glyph, in pixels */
|
||||||
int x_min, y_max; /* text offset in 26.6 precision */
|
int x_min, y_max; /* text offset in 26.6 precision */
|
||||||
|
@ -1168,30 +1070,8 @@ text_render(void *self, int is_font_family, PyObject *args) {
|
||||||
|
|
||||||
foreground_ink = foreground_ink_long;
|
foreground_ink = foreground_ink_long;
|
||||||
|
|
||||||
if (is_font_family) {
|
|
||||||
FontFamilyObject *family = (FontFamilyObject *)self;
|
|
||||||
|
|
||||||
#ifdef FT_COLOR_H
|
|
||||||
for (int i = 0; i < family->font_count; i++) {
|
|
||||||
if (color) {
|
|
||||||
FT_Color foreground_color;
|
|
||||||
FT_Byte *ink = (FT_Byte *)&foreground_ink;
|
|
||||||
foreground_color.red = ink[0];
|
|
||||||
foreground_color.green = ink[1];
|
|
||||||
foreground_color.blue = ink[2];
|
|
||||||
foreground_color.alpha =
|
|
||||||
(FT_Byte)255; /* ink alpha is handled in ImageDraw.text */
|
|
||||||
FT_Palette_Set_Foreground_Color(family->fonts[i].face, foreground_color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
count =
|
|
||||||
text_layout_family(string, family, dir, features, lang, &glyph_info, mask, color);
|
|
||||||
} else {
|
|
||||||
FontObject *font = (FontObject *)self;
|
|
||||||
|
|
||||||
#ifdef FT_COLOR_H
|
#ifdef FT_COLOR_H
|
||||||
|
for (int i = 0; i < family->font_count; i++) {
|
||||||
if (color) {
|
if (color) {
|
||||||
FT_Color foreground_color;
|
FT_Color foreground_color;
|
||||||
FT_Byte *ink = (FT_Byte *)&foreground_ink;
|
FT_Byte *ink = (FT_Byte *)&foreground_ink;
|
||||||
|
@ -1200,13 +1080,13 @@ text_render(void *self, int is_font_family, PyObject *args) {
|
||||||
foreground_color.blue = ink[2];
|
foreground_color.blue = ink[2];
|
||||||
foreground_color.alpha =
|
foreground_color.alpha =
|
||||||
(FT_Byte)255; /* ink alpha is handled in ImageDraw.text */
|
(FT_Byte)255; /* ink alpha is handled in ImageDraw.text */
|
||||||
FT_Palette_Set_Foreground_Color(font->face, foreground_color);
|
FT_Palette_Set_Foreground_Color(family->faces[i], foreground_color);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
count =
|
count = text_layout(string, family, dir, features, lang, &glyph_info, mask, color);
|
||||||
text_layout(string, font, dir, features, lang, &glyph_info, mask, color);
|
|
||||||
}
|
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1222,8 +1102,7 @@ text_render(void *self, int is_font_family, PyObject *args) {
|
||||||
horizontal_dir = dir && strcmp(dir, "ttb") == 0 ? 0 : 1;
|
horizontal_dir = dir && strcmp(dir, "ttb") == 0 ? 0 : 1;
|
||||||
|
|
||||||
error = bounding_box_and_anchors(
|
error = bounding_box_and_anchors(
|
||||||
self,
|
family,
|
||||||
is_font_family,
|
|
||||||
anchor,
|
anchor,
|
||||||
horizontal_dir,
|
horizontal_dir,
|
||||||
glyph_info,
|
glyph_info,
|
||||||
|
@ -1544,12 +1423,18 @@ glyph_error:
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
font_render(FontObject *self, PyObject *args) {
|
font_render(FontObject *self, PyObject *args) {
|
||||||
return text_render(self, 0, args);
|
FontFamily family;
|
||||||
|
|
||||||
|
family.faces = &self->face;
|
||||||
|
family.font_count = 1;
|
||||||
|
family.layout_engine = self->layout_engine;
|
||||||
|
|
||||||
|
return text_render(&family, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
family_render(FontFamilyObject *self, PyObject *args) {
|
family_render(FontFamilyObject *self, PyObject *args) {
|
||||||
return text_render(self, 1, args);
|
return text_render(&self->data, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FREETYPE_MAJOR > 2 || (FREETYPE_MAJOR == 2 && FREETYPE_MINOR > 9) || \
|
#if FREETYPE_MAJOR > 2 || (FREETYPE_MAJOR == 2 && FREETYPE_MINOR > 9) || \
|
||||||
|
@ -1885,16 +1770,16 @@ static PyTypeObject Font_Type = {
|
||||||
|
|
||||||
static void
|
static void
|
||||||
family_dealloc(FontFamilyObject *self) {
|
family_dealloc(FontFamilyObject *self) {
|
||||||
FontFamilyFont *font = self->fonts;
|
for (int i = 0; i < self->data.font_count; i++) {
|
||||||
for (int i = 0; i < self->font_count; ++i, ++font) {
|
if (self->data.faces[i]) {
|
||||||
if (font->face) {
|
FT_Done_Face(self->data.faces[i]);
|
||||||
FT_Done_Face(font->face);
|
|
||||||
}
|
}
|
||||||
if (font->font_bytes) {
|
if (self->font_bytes[i]) {
|
||||||
PyMem_Free(font->font_bytes);
|
PyMem_Free(self->font_bytes[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PyMem_Free(self->fonts);
|
PyMem_Free(self->data.faces);
|
||||||
|
PyMem_Free(self->font_bytes);
|
||||||
PyObject_Del(self);
|
PyObject_Del(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user