Scale font size by screen DPI on OS X

There seems to be no way to pass a custom DPI to CoreText
This commit is contained in:
Kovid Goyal 2017-01-11 05:53:55 +05:30
parent 70719d37fd
commit 282d6faa5f
3 changed files with 50 additions and 7 deletions

View File

@ -16,7 +16,7 @@ typedef struct {
PyObject_HEAD
unsigned int units_per_em;
float ascent, descent, leading, underline_position, underline_thickness;
float ascent, descent, leading, underline_position, underline_thickness, point_sz, scaled_point_sz;
CTFontRef font;
PyObject *family_name, *full_name;
} Face;
@ -35,20 +35,22 @@ convert_cfstring(CFStringRef src) {
static PyObject*
new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
Face *self;
int bold, italic;
int bold, italic, monospace;
char *cfamily;
float point_sz;
if(!PyArg_ParseTuple(args, "sppf", &cfamily, &bold, &italic, &point_sz)) return NULL;
float point_sz, dpi;
if(!PyArg_ParseTuple(args, "spppff", &cfamily, &bold, &italic, &monospace, &point_sz, &dpi)) return NULL;
NSString *family = [[NSString alloc] initWithCString:cfamily encoding:NSUTF8StringEncoding];
if (family == NULL) return PyErr_NoMemory();
self = (Face *)type->tp_alloc(type, 0);
if (self) {
CTFontSymbolicTraits symbolic_traits = (bold ? kCTFontBoldTrait : 0) | (italic ? kCTFontItalicTrait : 0);
CTFontSymbolicTraits symbolic_traits = (bold ? kCTFontBoldTrait : 0) | (italic ? kCTFontItalicTrait : 0) | (monospace ? kCTFontMonoSpaceTrait : 0);
NSDictionary *font_traits = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:symbolic_traits] forKey:(NSString *)kCTFontSymbolicTrait];
NSDictionary *font_attributes = [NSDictionary dictionaryWithObjectsAndKeys:family, kCTFontFamilyNameAttribute, font_traits, kCTFontTraitsAttribute, nil];
CTFontDescriptorRef descriptor = CTFontDescriptorCreateWithAttributes((CFDictionaryRef)font_attributes);
if (descriptor) {
self->font = CTFontCreateWithFontDescriptor(descriptor, point_sz, NULL);
self->point_sz = point_sz;
self->scaled_point_sz = (dpi / 72.0) * point_sz;
self->font = CTFontCreateWithFontDescriptor(descriptor, self->scaled_point_sz, NULL);
CFRelease(descriptor);
if (!self->font) { Py_CLEAR(self); PyErr_SetString(PyExc_ValueError, "Failed to create CTFont object"); }
else {
@ -107,6 +109,8 @@ has_char(Face *self, PyObject *args) {
static PyMemberDef members[] = {
#define MEM(name, type) {#name, type, offsetof(Face, name), READONLY, #name}
MEM(units_per_em, T_UINT),
MEM(point_sz, T_FLOAT),
MEM(scaled_point_sz, T_FLOAT),
MEM(ascent, T_FLOAT),
MEM(descent, T_FLOAT),
MEM(leading, T_FLOAT),

34
kitty/fonts/core_text.py Normal file
View File

@ -0,0 +1,34 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
from kitty.fast_data_types import CTFace as Face
from kitty.utils import get_dpi
main_font = {}
def set_font_family(family, size_in_pts):
dpi = get_dpi()['logical']
dpi = sum(dpi) / 2.0
if family.lower() == 'monospace':
family = 'Menlo'
for bold in (False, True):
for italic in (False, True):
main_font[(bold, italic)] = Face(family, bold, italic, True, size_in_pts, dpi)
def render_cell(text=' ', bold=False, italic=False, underline=0, strikethrough=False):
pass
def develop():
from kitty.fast_data_types import glfw_init
glfw_init()
set_font_family('monospace', 12.0)
for (bold, italic), face in main_font.items():
print('bold: {} italic: {} family:{} full name: {}'.format(bold, italic, face.family_name, face.full_name))
f = main_font[(False, False)]
for attr in 'units_per_em ascent descent leading underline_position underline_thickness scaled_point_sz'.split():
print(attr, getattr(f, attr))

View File

@ -2,4 +2,9 @@
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
from .freetype import set_font_family, render_cell # noqa
from kitty.constants import isosx
if isosx:
from .core_text import set_font_family, render_cell # noqa
else:
from .freetype import set_font_family, render_cell # noqa