mirror of
https://github.com/kovidgoyal/kitty
synced 2026-06-08 22:28:24 +02:00
Add support for font features when rendering sample text
This commit is contained in:
@@ -624,7 +624,7 @@ new(PyTypeObject *type UNUSED, PyObject *args, PyObject *kw) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PyObject*
|
PyObject*
|
||||||
specialize_font_descriptor(PyObject *base_descriptor, FONTS_DATA_HANDLE fg UNUSED) {
|
specialize_font_descriptor(PyObject *base_descriptor, double font_sz_in_pts UNUSED, double dpi_x UNUSED, double dpi_y UNUSED) {
|
||||||
Py_INCREF(base_descriptor);
|
Py_INCREF(base_descriptor);
|
||||||
return base_descriptor;
|
return base_descriptor;
|
||||||
}
|
}
|
||||||
@@ -742,6 +742,8 @@ render_simple_text_impl(PyObject *s, const char *text, unsigned int baseline) {
|
|||||||
return ans;
|
return ans;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void destroy_hb_buffer(hb_buffer_t **x) { if (*x) hb_buffer_destroy(*x); }
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
render_sample_text(CTFace *self, PyObject *args) {
|
render_sample_text(CTFace *self, PyObject *args) {
|
||||||
unsigned long canvas_width, canvas_height;
|
unsigned long canvas_width, canvas_height;
|
||||||
@@ -756,35 +758,48 @@ render_sample_text(CTFace *self, PyObject *args) {
|
|||||||
canvas_height = MIN(canvas_height, num_of_lines * cell_height);
|
canvas_height = MIN(canvas_height, num_of_lines * cell_height);
|
||||||
RAII_PyObject(pbuf, PyBytes_FromStringAndSize(NULL, sizeof(pixel) * canvas_width * canvas_height));
|
RAII_PyObject(pbuf, PyBytes_FromStringAndSize(NULL, sizeof(pixel) * canvas_width * canvas_height));
|
||||||
if (!pbuf) return NULL;
|
if (!pbuf) return NULL;
|
||||||
RAII_ALLOC(unichar, chars, calloc(sizeof(unichar), num_chars));
|
|
||||||
if (!chars) return PyErr_NoMemory();
|
__attribute__((cleanup(destroy_hb_buffer))) hb_buffer_t *hb_buffer = hb_buffer_create();
|
||||||
for (size_t i = 0; i < num_chars; i++) chars[i] = PyUnicode_READ_CHAR(ptext, i);
|
if (!hb_buffer_pre_allocate(hb_buffer, 4*num_chars)) { PyErr_NoMemory(); return NULL; }
|
||||||
RAII_ALLOC(CGSize, local_advances, calloc(sizeof(CGSize), num_chars));
|
for (size_t n = 0; n < num_chars; n++) {
|
||||||
if (!local_advances) return PyErr_NoMemory();
|
Py_UCS4 codep = PyUnicode_READ_CHAR(ptext, n);
|
||||||
ensure_render_space(0, 0, num_chars);
|
hb_buffer_add_utf32(hb_buffer, &codep, 1, 0, 1);
|
||||||
CTFontGetGlyphsForCharacters(font, chars, buffers.glyphs, num_chars);
|
|
||||||
CTFontGetAdvancesForGlyphs(font, kCTFontOrientationDefault, buffers.glyphs, local_advances, num_chars);
|
|
||||||
CTFontGetBoundingRectsForGlyphs(font, kCTFontOrientationDefault, buffers.glyphs, buffers.boxes, num_chars);
|
|
||||||
CGFloat x = 0, y = 0;
|
|
||||||
memset(PyByteArray_AS_STRING(pbuf), 0, PyBytes_GET_SIZE(pbuf));
|
|
||||||
if (cell_width > canvas_width) goto end;
|
|
||||||
for (size_t i = 0; i < num_chars; i++) {
|
|
||||||
if (local_advances[i].width + x > canvas_width) {
|
|
||||||
x = 0;
|
|
||||||
y += cell_height;
|
|
||||||
}
|
|
||||||
if (y + cell_height > canvas_height) {
|
|
||||||
num_chars = i - 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
buffers.positions[i] = CGPointMake(x, -y);
|
|
||||||
x += cell_width;
|
|
||||||
}
|
}
|
||||||
unsigned long height = MIN((int)ceil(y) + cell_height, canvas_height);
|
hb_buffer_guess_segment_properties(hb_buffer);
|
||||||
ensure_render_space(canvas_width, height, num_chars);
|
if (!HB_DIRECTION_IS_HORIZONTAL(hb_buffer_get_direction(hb_buffer))) goto end;
|
||||||
render_glyphs(font, canvas_width, height, baseline, num_chars);
|
hb_shape(harfbuzz_font_for_face((PyObject*)self), hb_buffer, self->font_features.features, self->font_features.count);
|
||||||
|
unsigned int len = hb_buffer_get_length(hb_buffer);
|
||||||
|
hb_glyph_info_t *info = hb_buffer_get_glyph_infos(hb_buffer, NULL);
|
||||||
|
hb_glyph_position_t *positions = hb_buffer_get_glyph_positions(hb_buffer, NULL);
|
||||||
|
|
||||||
|
memset(PyBytes_AS_STRING(pbuf), 0, PyBytes_GET_SIZE(pbuf));
|
||||||
|
if (cell_width > canvas_width) goto end;
|
||||||
|
|
||||||
|
ensure_render_space(canvas_width, canvas_height, len);
|
||||||
|
float pen_x = 0, pen_y = 0;
|
||||||
|
unsigned num_glyphs = 0;
|
||||||
|
CGFloat scale = CTFontGetSize(self->ct_font) / CTFontGetUnitsPerEm(self->ct_font);
|
||||||
|
for (unsigned int i = 0; i < len; i++) {
|
||||||
|
float advance = (float)positions[i].x_advance * scale;
|
||||||
|
if (pen_x + advance > canvas_width) {
|
||||||
|
pen_y += cell_height;
|
||||||
|
pen_x = 0;
|
||||||
|
if (pen_y >= canvas_height) break;
|
||||||
|
}
|
||||||
|
double x = pen_x + (double)positions[i].x_offset * scale;
|
||||||
|
double y = pen_y + (double)positions[i].y_offset * scale;
|
||||||
|
pen_x += advance;
|
||||||
|
buffers.positions[i] = CGPointMake(x, -y);
|
||||||
|
buffers.glyphs[i] = info[i].codepoint;
|
||||||
|
num_glyphs++;
|
||||||
|
}
|
||||||
|
render_glyphs(font, canvas_width, canvas_height, baseline, num_glyphs);
|
||||||
uint8_t r = (fg >> 16) & 0xff, g = (fg >> 8) & 0xff, b = fg & 0xff;
|
uint8_t r = (fg >> 16) & 0xff, g = (fg >> 8) & 0xff, b = fg & 0xff;
|
||||||
for (uint8_t *p = (uint8_t*)PyBytes_AS_STRING(pbuf), *s = buffers.render_buf; p < (uint8_t*)PyBytes_AS_STRING(pbuf) + sizeof(pixel) * canvas_width * height; p += 4, s++) {
|
for (
|
||||||
|
uint8_t *p = (uint8_t*)PyBytes_AS_STRING(pbuf), *s = buffers.render_buf;
|
||||||
|
p < (uint8_t*)PyBytes_AS_STRING(pbuf) + sizeof(pixel) * canvas_width * canvas_height;
|
||||||
|
p += 4, s++
|
||||||
|
) {
|
||||||
p[0] = r; p[1] = g; p[2] = b; p[3] = s[0];
|
p[0] = r; p[1] = g; p[2] = b; p[3] = s[0];
|
||||||
}
|
}
|
||||||
end:
|
end:
|
||||||
|
|||||||
@@ -402,7 +402,7 @@ end:
|
|||||||
}
|
}
|
||||||
|
|
||||||
PyObject*
|
PyObject*
|
||||||
specialize_font_descriptor(PyObject *base_descriptor, FONTS_DATA_HANDLE fg) {
|
specialize_font_descriptor(PyObject *base_descriptor, double font_sz_in_pts, double dpi_x, double dpi_y) {
|
||||||
ensure_initialized();
|
ensure_initialized();
|
||||||
PyObject *p = PyDict_GetItemString(base_descriptor, "path");
|
PyObject *p = PyDict_GetItemString(base_descriptor, "path");
|
||||||
PyObject *idx = PyDict_GetItemString(base_descriptor, "index");
|
PyObject *idx = PyDict_GetItemString(base_descriptor, "index");
|
||||||
@@ -416,8 +416,8 @@ specialize_font_descriptor(PyObject *base_descriptor, FONTS_DATA_HANDLE fg) {
|
|||||||
RAII_PyObject(ans, NULL);
|
RAII_PyObject(ans, NULL);
|
||||||
AP(FcPatternAddString, FC_FILE, (const FcChar8*)PyUnicode_AsUTF8(p), "path");
|
AP(FcPatternAddString, FC_FILE, (const FcChar8*)PyUnicode_AsUTF8(p), "path");
|
||||||
AP(FcPatternAddInteger, FC_INDEX, face_idx, "index");
|
AP(FcPatternAddInteger, FC_INDEX, face_idx, "index");
|
||||||
AP(FcPatternAddDouble, FC_SIZE, fg->font_sz_in_pts, "size");
|
AP(FcPatternAddDouble, FC_SIZE, font_sz_in_pts, "size");
|
||||||
AP(FcPatternAddDouble, FC_DPI, (fg->logical_dpi_x + fg->logical_dpi_y) / 2.0, "dpi");
|
AP(FcPatternAddDouble, FC_DPI, (dpi_x + dpi_y) / 2.0, "dpi");
|
||||||
ans = _fc_match(pat);
|
ans = _fc_match(pat);
|
||||||
FcPatternDestroy(pat); pat = NULL;
|
FcPatternDestroy(pat); pat = NULL;
|
||||||
|
|
||||||
|
|||||||
@@ -283,7 +283,7 @@ sprite_tracker_set_layout(GPUSpriteTracker *sprite_tracker, unsigned int cell_wi
|
|||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
desc_to_face(PyObject *desc, FONTS_DATA_HANDLE fg) {
|
desc_to_face(PyObject *desc, FONTS_DATA_HANDLE fg) {
|
||||||
PyObject *d = specialize_font_descriptor(desc, fg);
|
PyObject *d = specialize_font_descriptor(desc, fg->font_sz_in_pts, fg->logical_dpi_x, fg->logical_dpi_y);
|
||||||
if (d == NULL) return NULL;
|
if (d == NULL) return NULL;
|
||||||
PyObject *ans = face_from_descriptor(d, fg);
|
PyObject *ans = face_from_descriptor(d, fg);
|
||||||
Py_DECREF(d);
|
Py_DECREF(d);
|
||||||
@@ -1829,7 +1829,12 @@ PyTypeObject ParsedFontFeature_Type = {
|
|||||||
.tp_call = parsed_font_feature_call,
|
.tp_call = parsed_font_feature_call,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
pyspecialize_font_descriptor(PyObject *self UNUSED, PyObject *args) {
|
||||||
|
PyObject *desc; double font_sz, dpi_x, dpi_y;
|
||||||
|
if (!PyArg_ParseTuple(args, "Offf", &desc, &font_sz, &dpi_x, &dpi_y)) return NULL;
|
||||||
|
return specialize_font_descriptor(desc, font_sz, dpi_x, dpi_y);
|
||||||
|
}
|
||||||
|
|
||||||
static PyMethodDef module_methods[] = {
|
static PyMethodDef module_methods[] = {
|
||||||
METHODB(set_font_data, METH_VARARGS),
|
METHODB(set_font_data, METH_VARARGS),
|
||||||
@@ -1843,6 +1848,7 @@ static PyMethodDef module_methods[] = {
|
|||||||
METHODB(current_fonts, METH_VARARGS),
|
METHODB(current_fonts, METH_VARARGS),
|
||||||
METHODB(test_render_line, METH_VARARGS),
|
METHODB(test_render_line, METH_VARARGS),
|
||||||
METHODB(get_fallback_font, METH_VARARGS),
|
METHODB(get_fallback_font, METH_VARARGS),
|
||||||
|
{"specialize_font_descriptor", (PyCFunction)pyspecialize_font_descriptor, METH_VARARGS, ""},
|
||||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ bool set_size_for_face(PyObject*, unsigned int, bool, FONTS_DATA_HANDLE);
|
|||||||
void cell_metrics(PyObject*, unsigned int*, unsigned int*, unsigned int*, unsigned int*, unsigned int*, unsigned int*, unsigned int*);
|
void cell_metrics(PyObject*, unsigned int*, unsigned int*, unsigned int*, unsigned int*, unsigned int*, unsigned int*, unsigned int*);
|
||||||
bool render_glyphs_in_cells(PyObject *f, bool bold, bool italic, hb_glyph_info_t *info, hb_glyph_position_t *positions, unsigned int num_glyphs, pixel *canvas, unsigned int cell_width, unsigned int cell_height, unsigned int num_cells, unsigned int baseline, bool *was_colored, FONTS_DATA_HANDLE, bool center_glyph);
|
bool render_glyphs_in_cells(PyObject *f, bool bold, bool italic, hb_glyph_info_t *info, hb_glyph_position_t *positions, unsigned int num_glyphs, pixel *canvas, unsigned int cell_width, unsigned int cell_height, unsigned int num_cells, unsigned int baseline, bool *was_colored, FONTS_DATA_HANDLE, bool center_glyph);
|
||||||
PyObject* create_fallback_face(PyObject *base_face, CPUCell* cell, bool bold, bool italic, bool emoji_presentation, FONTS_DATA_HANDLE fg);
|
PyObject* create_fallback_face(PyObject *base_face, CPUCell* cell, bool bold, bool italic, bool emoji_presentation, FONTS_DATA_HANDLE fg);
|
||||||
PyObject* specialize_font_descriptor(PyObject *base_descriptor, FONTS_DATA_HANDLE);
|
PyObject* specialize_font_descriptor(PyObject *base_descriptor, double, double, double);
|
||||||
PyObject* face_from_path(const char *path, int index, FONTS_DATA_HANDLE);
|
PyObject* face_from_path(const char *path, int index, FONTS_DATA_HANDLE);
|
||||||
PyObject* face_from_descriptor(PyObject*, FONTS_DATA_HANDLE);
|
PyObject* face_from_descriptor(PyObject*, FONTS_DATA_HANDLE);
|
||||||
PyObject* iter_fallback_faces(FONTS_DATA_HANDLE fgh, ssize_t *idx);
|
PyObject* iter_fallback_faces(FONTS_DATA_HANDLE fgh, ssize_t *idx);
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ if TYPE_CHECKING:
|
|||||||
prefer_variable: bool = False,
|
prefer_variable: bool = False,
|
||||||
) -> Descriptor: ...
|
) -> Descriptor: ...
|
||||||
def find_last_resort_text_font(bold: bool = False, italic: bool = False, monospaced: bool = True) -> Descriptor: ...
|
def find_last_resort_text_font(bold: bool = False, italic: bool = False, monospaced: bool = True) -> Descriptor: ...
|
||||||
def face_from_descriptor(descriptor: Descriptor) -> Face: ...
|
def face_from_descriptor(descriptor: Descriptor, font_sz_in_pts: Optional[float] = None, dpi_x: Optional[float] = None, dpi_y: Optional[float] = None
|
||||||
|
) -> Face: ...
|
||||||
def is_monospace(descriptor: Descriptor) -> bool: ...
|
def is_monospace(descriptor: Descriptor) -> bool: ...
|
||||||
def is_variable(descriptor: Descriptor) -> bool: ...
|
def is_variable(descriptor: Descriptor) -> bool: ...
|
||||||
def set_named_style(name: str, font: Descriptor, vd: VariableData) -> bool: ...
|
def set_named_style(name: str, font: Descriptor, vd: VariableData) -> bool: ...
|
||||||
@@ -29,6 +30,7 @@ if TYPE_CHECKING:
|
|||||||
def get_axis_values(font: Descriptor, vd: VariableData) -> Dict[str, float]: ...
|
def get_axis_values(font: Descriptor, vd: VariableData) -> Dict[str, float]: ...
|
||||||
else:
|
else:
|
||||||
FontCollectionMapType = FontMap = None
|
FontCollectionMapType = FontMap = None
|
||||||
|
from kitty.fast_data_types import specialize_font_descriptor
|
||||||
if is_macos:
|
if is_macos:
|
||||||
from kitty.fast_data_types import CTFace as Face
|
from kitty.fast_data_types import CTFace as Face
|
||||||
from kitty.fonts.core_text import (
|
from kitty.fonts.core_text import (
|
||||||
@@ -55,7 +57,10 @@ else:
|
|||||||
set_axis_values,
|
set_axis_values,
|
||||||
set_named_style,
|
set_named_style,
|
||||||
)
|
)
|
||||||
def face_from_descriptor(descriptor: Descriptor) -> Face: return Face(descriptor=descriptor)
|
def face_from_descriptor(descriptor, font_sz_in_pts = None, dpi_x = None, dpi_y = None):
|
||||||
|
if font_sz_in_pts is not None:
|
||||||
|
descriptor = specialize_font_descriptor(descriptor, font_sz_in_pts, dpi_x, dpi_y)
|
||||||
|
return Face(descriptor=descriptor)
|
||||||
|
|
||||||
|
|
||||||
cache_for_variable_data_by_path: Dict[str, VariableData] = {}
|
cache_for_variable_data_by_path: Dict[str, VariableData] = {}
|
||||||
|
|||||||
@@ -316,7 +316,9 @@ new(PyTypeObject *type UNUSED, PyObject *args, PyObject *kw) {
|
|||||||
|
|
||||||
static char *kwds[] = {"descriptor", "path", "index", NULL};
|
static char *kwds[] = {"descriptor", "path", "index", NULL};
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "|Osi", kwds, &descriptor, &path, &index)) return NULL;
|
if (!PyArg_ParseTupleAndKeywords(args, kw, "|Osi", kwds, &descriptor, &path, &index)) return NULL;
|
||||||
if (descriptor) return face_from_descriptor(descriptor, NULL);
|
if (descriptor) {
|
||||||
|
return face_from_descriptor(descriptor, NULL);
|
||||||
|
}
|
||||||
if (path) return face_from_path(path, index, NULL);
|
if (path) return face_from_path(path, index, NULL);
|
||||||
PyErr_SetString(PyExc_TypeError, "Must specify either path or descriptor");
|
PyErr_SetString(PyExc_TypeError, "Must specify either path or descriptor");
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -958,9 +960,11 @@ render_simple_text_impl(PyObject *s, const char *text, unsigned int baseline) {
|
|||||||
return ans;
|
return ans;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void destroy_hb_buffer(hb_buffer_t **x) { if (*x) hb_buffer_destroy(*x); }
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
render_sample_text(Face *self, PyObject *args) {
|
render_sample_text(Face *self, PyObject *args) {
|
||||||
unsigned long canvas_width, canvas_height, pen_x = 0, pen_y = 0;
|
unsigned long canvas_width, canvas_height;
|
||||||
unsigned long fg = 0xffffff;
|
unsigned long fg = 0xffffff;
|
||||||
PyObject *ptext;
|
PyObject *ptext;
|
||||||
if (!PyArg_ParseTuple(args, "Ukk|k", &ptext, &canvas_width, &canvas_height, &fg)) return NULL;
|
if (!PyArg_ParseTuple(args, "Ukk|k", &ptext, &canvas_width, &canvas_height, &fg)) return NULL;
|
||||||
@@ -970,30 +974,46 @@ render_sample_text(Face *self, PyObject *args) {
|
|||||||
canvas_height = MIN(canvas_height, num_of_lines * cell_height);
|
canvas_height = MIN(canvas_height, num_of_lines * cell_height);
|
||||||
RAII_PyObject(pbuf, PyBytes_FromStringAndSize(NULL, sizeof(pixel) * canvas_width * canvas_height));
|
RAII_PyObject(pbuf, PyBytes_FromStringAndSize(NULL, sizeof(pixel) * canvas_width * canvas_height));
|
||||||
if (!pbuf) return NULL;
|
if (!pbuf) return NULL;
|
||||||
pixel *canvas = (pixel*)PyBytes_AS_STRING(pbuf);
|
memset(PyBytes_AS_STRING(pbuf), 0, PyBytes_GET_SIZE(pbuf));
|
||||||
memset(canvas, 0, PyBytes_GET_SIZE(pbuf));
|
|
||||||
if (cell_width > canvas_width) goto end;
|
|
||||||
|
|
||||||
|
__attribute__((cleanup(destroy_hb_buffer))) hb_buffer_t *hb_buffer = hb_buffer_create();
|
||||||
|
if (!hb_buffer_pre_allocate(hb_buffer, 4*PyUnicode_GET_LENGTH(ptext))) { PyErr_NoMemory(); return NULL; }
|
||||||
for (ssize_t n = 0; n < PyUnicode_GET_LENGTH(ptext); n++) {
|
for (ssize_t n = 0; n < PyUnicode_GET_LENGTH(ptext); n++) {
|
||||||
if (pen_x + cell_width > canvas_width) {
|
Py_UCS4 codep = PyUnicode_READ_CHAR(ptext, n);
|
||||||
|
hb_buffer_add_utf32(hb_buffer, &codep, 1, 0, 1);
|
||||||
|
}
|
||||||
|
hb_buffer_guess_segment_properties(hb_buffer);
|
||||||
|
if (!HB_DIRECTION_IS_HORIZONTAL(hb_buffer_get_direction(hb_buffer))) goto end;
|
||||||
|
hb_shape(harfbuzz_font_for_face((PyObject*)self), hb_buffer, self->font_features.features, self->font_features.count);
|
||||||
|
unsigned int len = hb_buffer_get_length(hb_buffer);
|
||||||
|
hb_glyph_info_t *info = hb_buffer_get_glyph_infos(hb_buffer, NULL);
|
||||||
|
hb_glyph_position_t *positions = hb_buffer_get_glyph_positions(hb_buffer, NULL);
|
||||||
|
|
||||||
|
if (cell_width > canvas_width) goto end;
|
||||||
|
pixel *canvas = (pixel*)PyBytes_AS_STRING(pbuf);
|
||||||
|
int load_flags = get_load_flags(self->hinting, self->hintstyle, FT_LOAD_RENDER);
|
||||||
|
int error;
|
||||||
|
|
||||||
|
float pen_x = 0, pen_y = 0;
|
||||||
|
for (unsigned int i = 0; i < len; i++) {
|
||||||
|
float advance = (float)positions[i].x_advance / 64.0f;
|
||||||
|
if (pen_x + advance > canvas_width) {
|
||||||
pen_y += cell_height;
|
pen_y += cell_height;
|
||||||
pen_x = 0;
|
pen_x = 0;
|
||||||
|
if (pen_y >= canvas_height) break;
|
||||||
}
|
}
|
||||||
if (pen_y + cell_height > canvas_height) break;
|
size_t x = (size_t)round(pen_x + (float)positions[i].x_offset / 64.0f);
|
||||||
Py_UCS4 ch = PyUnicode_READ_CHAR(ptext, n);
|
size_t y = (size_t)round(pen_y + (float)positions[i].y_offset / 64.0f);
|
||||||
FT_UInt glyph_index = FT_Get_Char_Index(self->face, ch);
|
pen_x += advance;
|
||||||
if (!glyph_index) continue;
|
if ((error = FT_Load_Glyph(self->face, info[i].codepoint, load_flags))) continue;
|
||||||
int error = FT_Load_Glyph(self->face, glyph_index, FT_LOAD_DEFAULT);
|
if ((error = FT_Render_Glyph(self->face->glyph, FT_RENDER_MODE_NORMAL))) continue;
|
||||||
if (error) continue;
|
|
||||||
error = FT_Render_Glyph(self->face->glyph, FT_RENDER_MODE_NORMAL);
|
|
||||||
if (error) continue;
|
|
||||||
FT_Bitmap *bitmap = &self->face->glyph->bitmap;
|
FT_Bitmap *bitmap = &self->face->glyph->bitmap;
|
||||||
ProcessedBitmap pbm = EMPTY_PBM;
|
ProcessedBitmap pbm = EMPTY_PBM;
|
||||||
populate_processed_bitmap(self->face->glyph, bitmap, &pbm, false);
|
populate_processed_bitmap(self->face->glyph, bitmap, &pbm, false);
|
||||||
place_bitmap_in_canvas(canvas, &pbm, canvas_width, canvas_height, 0, 0, baseline, 99999, fg, pen_x, pen_y);
|
place_bitmap_in_canvas(canvas, &pbm, canvas_width, canvas_height, 0, 0, baseline, 99999, fg, x, y);
|
||||||
pen_x += self->face->glyph->advance.x >> 6;
|
|
||||||
}
|
}
|
||||||
for (uint8_t *p = (uint8_t*)PyBytes_AS_STRING(pbuf); p < (uint8_t*)PyBytes_AS_STRING(pbuf) + sizeof(pixel) * canvas_width * (MIN(canvas_height, pen_y + cell_height)); p += 4) {
|
|
||||||
|
for (uint8_t *p = (uint8_t*)PyBytes_AS_STRING(pbuf); p < (uint8_t*)PyBytes_AS_STRING(pbuf) + sizeof(pixel) * canvas_width * canvas_height; p += 4) {
|
||||||
uint8_t a = p[0], b = p[1], g = p[2], r = p[3];
|
uint8_t a = p[0], b = p[1], g = p[2], r = p[3];
|
||||||
p[0] = r; p[1] = g; p[2] = b; p[3] = a;
|
p[0] = r; p[1] = g; p[2] = b; p[3] = a;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user