|
7 | 7 | // From Python
|
8 | 8 | #include <structmember.h>
|
9 | 9 |
|
| 10 | +#include <set> |
| 11 | +#include <algorithm> |
| 12 | + |
10 | 13 | #define STRINGIFY(s) XSTRINGIFY(s)
|
11 | 14 | #define XSTRINGIFY(s) #s
|
12 | 15 |
|
@@ -552,6 +555,76 @@ static PyObject *PyFT2Font_get_kerning(PyFT2Font *self, PyObject *args)
|
552 | 555 | return PyLong_FromLong(result);
|
553 | 556 | }
|
554 | 557 |
|
| 558 | +const char *PyFT2Font_get_fontmap__doc__ = |
| 559 | + "_get_fontmap(self, string)\n" |
| 560 | + "--\n\n" |
| 561 | + "Get a mapping between characters and the font that includes them.\n" |
| 562 | + "A dictionary mapping unicode characters to PyFT2Font objects."; |
| 563 | +static PyObject *PyFT2Font_get_fontmap(PyFT2Font *self, PyObject *args, PyObject *kwds) |
| 564 | +{ |
| 565 | + PyObject *textobj; |
| 566 | + const char *names[] = { "string", NULL }; |
| 567 | + |
| 568 | + if (!PyArg_ParseTupleAndKeywords( |
| 569 | + args, kwds, "O:_get_fontmap", (char **)names, &textobj)) { |
| 570 | + return NULL; |
| 571 | + } |
| 572 | + |
| 573 | + std::set<FT_ULong> codepoints; |
| 574 | + size_t size; |
| 575 | + |
| 576 | + if (PyUnicode_Check(textobj)) { |
| 577 | + size = PyUnicode_GET_LENGTH(textobj); |
| 578 | +#if defined(PYPY_VERSION) && (PYPY_VERSION_NUM < 0x07040000) |
| 579 | + // PyUnicode_ReadChar is available from PyPy 7.3.2, but wheels do not |
| 580 | + // specify the micro-release version, so put the version bound at 7.4 |
| 581 | + // to prevent generating wheels unusable on PyPy 7.3.{0,1}. |
| 582 | + Py_UNICODE *unistr = PyUnicode_AsUnicode(textobj); |
| 583 | + for (size_t i = 0; i < size; ++i) { |
| 584 | + codepoints.insert(unistr[i]); |
| 585 | + } |
| 586 | +#else |
| 587 | + for (size_t i = 0; i < size; ++i) { |
| 588 | + codepoints.insert(PyUnicode_ReadChar(textobj, i)); |
| 589 | + } |
| 590 | +#endif |
| 591 | + } else { |
| 592 | + PyErr_SetString(PyExc_TypeError, "String must be str"); |
| 593 | + return NULL; |
| 594 | + } |
| 595 | + PyObject *char_to_font; |
| 596 | + if (!(char_to_font = PyDict_New())) { |
| 597 | + return NULL; |
| 598 | + } |
| 599 | + for (auto it = codepoints.begin(); it != codepoints.end(); ++it) { |
| 600 | + auto x = *it; |
| 601 | + PyObject* target_font; |
| 602 | + int index; |
| 603 | + if (self->x->get_char_fallback_index(x, index)) { |
| 604 | + if (index >= 0) { |
| 605 | + target_font = self->fallbacks[index]; |
| 606 | + } else { |
| 607 | + target_font = (PyObject *)self; |
| 608 | + } |
| 609 | + } else { |
| 610 | + // TODO Handle recursion! |
| 611 | + target_font = (PyObject *)self; |
| 612 | + } |
| 613 | + |
| 614 | + PyObject *key = NULL; |
| 615 | + bool error = (!(key = PyUnicode_FromFormat("%c", x)) |
| 616 | + || (PyDict_SetItem(char_to_font, key, target_font) == -1)); |
| 617 | + Py_XDECREF(key); |
| 618 | + if (error) { |
| 619 | + Py_DECREF(char_to_font); |
| 620 | + PyErr_SetString(PyExc_ValueError, "Something went very wrong"); |
| 621 | + return NULL; |
| 622 | + } |
| 623 | + } |
| 624 | + return char_to_font; |
| 625 | +} |
| 626 | + |
| 627 | + |
555 | 628 | const char *PyFT2Font_set_text__doc__ =
|
556 | 629 | "set_text(self, string, angle, flags=32)\n"
|
557 | 630 | "--\n\n"
|
@@ -1525,6 +1598,7 @@ static PyTypeObject *PyFT2Font_init_type()
|
1525 | 1598 | {"select_charmap", (PyCFunction)PyFT2Font_select_charmap, METH_VARARGS, PyFT2Font_select_charmap__doc__},
|
1526 | 1599 | {"get_kerning", (PyCFunction)PyFT2Font_get_kerning, METH_VARARGS, PyFT2Font_get_kerning__doc__},
|
1527 | 1600 | {"set_text", (PyCFunction)PyFT2Font_set_text, METH_VARARGS|METH_KEYWORDS, PyFT2Font_set_text__doc__},
|
| 1601 | + {"_get_fontmap", (PyCFunction)PyFT2Font_get_fontmap, METH_VARARGS|METH_KEYWORDS, PyFT2Font_get_fontmap__doc__}, |
1528 | 1602 | {"get_num_glyphs", (PyCFunction)PyFT2Font_get_num_glyphs, METH_NOARGS, PyFT2Font_get_num_glyphs__doc__},
|
1529 | 1603 | {"load_char", (PyCFunction)PyFT2Font_load_char, METH_VARARGS|METH_KEYWORDS, PyFT2Font_load_char__doc__},
|
1530 | 1604 | {"load_glyph", (PyCFunction)PyFT2Font_load_glyph, METH_VARARGS|METH_KEYWORDS, PyFT2Font_load_glyph__doc__},
|
|
0 commit comments