Ensure only a single thread tries to render chars at a time

This commit is contained in:
Kovid Goyal 2016-10-28 15:09:39 +05:30
parent fabdebfd89
commit ed74f8e467

View File

@ -8,6 +8,7 @@ import re
import ctypes import ctypes
from collections import namedtuple from collections import namedtuple
from functools import lru_cache from functools import lru_cache
from threading import Lock
from freetype import ( from freetype import (
Face, FT_LOAD_RENDER, FT_LOAD_TARGET_NORMAL, FT_LOAD_TARGET_LIGHT, Face, FT_LOAD_RENDER, FT_LOAD_TARGET_NORMAL, FT_LOAD_TARGET_LIGHT,
@ -111,6 +112,9 @@ def font_units_to_pixels(x, units_per_em, size_in_pts, dpi):
return int(x * ((size_in_pts * dpi) / (72 * units_per_em))) return int(x * ((size_in_pts * dpi) / (72 * units_per_em)))
freetype_lock = Lock()
def render_char(text, bold=False, italic=False, size_in_pts=None): def render_char(text, bold=False, italic=False, size_in_pts=None):
# TODO: Handle non-normalizable combining chars. Probably need to use # TODO: Handle non-normalizable combining chars. Probably need to use
# harfbuzz for that # harfbuzz for that
@ -123,27 +127,28 @@ def render_char(text, bold=False, italic=False, size_in_pts=None):
key = 'bi' if italic else 'bold' key = 'bi' if italic else 'bold'
elif italic: elif italic:
key = 'italic' key = 'italic'
font = current_font_family.get(key) or current_font_family['regular'] with freetype_lock:
face = font.face font = current_font_family.get(key) or current_font_family['regular']
if not face.get_char_index(ord(text[0])): face = font.face
face = face_for_char(text[0], bold, italic) if not face.get_char_index(ord(text[0])):
face.set_char_size(width=sz, height=sz, hres=dpi[0], vres=dpi[1]) face = face_for_char(text[0], bold, italic)
flags = FT_LOAD_RENDER face.set_char_size(width=sz, height=sz, hres=dpi[0], vres=dpi[1])
if font.hinting: flags = FT_LOAD_RENDER
if font.hintstyle >= 3: if font.hinting:
flags |= FT_LOAD_TARGET_NORMAL if font.hintstyle >= 3:
elif 0 < font.hintstyle < 3: flags |= FT_LOAD_TARGET_NORMAL
flags |= FT_LOAD_TARGET_LIGHT elif 0 < font.hintstyle < 3:
else: flags |= FT_LOAD_TARGET_LIGHT
flags |= FT_LOAD_NO_HINTING else:
face.load_char(text, flags) flags |= FT_LOAD_NO_HINTING
bitmap = face.glyph.bitmap face.load_char(text, flags)
if bitmap.pixel_mode != FT_PIXEL_MODE_GRAY: bitmap = face.glyph.bitmap
raise ValueError( if bitmap.pixel_mode != FT_PIXEL_MODE_GRAY:
'FreeType rendered the glyph for {!r} with an unsupported pixel mode: {}'.format(text, bitmap.pixel_mode)) raise ValueError(
m = face.glyph.metrics 'FreeType rendered the glyph for {!r} with an unsupported pixel mode: {}'.format(text, bitmap.pixel_mode))
return CharBitmap(bitmap.buffer, min(int(abs(m.horiBearingX) / 64), bitmap.width), m = face.glyph.metrics
min(int(abs(m.horiBearingY) / 64), bitmap.rows), int(m.horiAdvance / 64), bitmap.rows, bitmap.width) return CharBitmap(bitmap.buffer, min(int(abs(m.horiBearingX) / 64), bitmap.width),
min(int(abs(m.horiBearingY) / 64), bitmap.rows), int(m.horiAdvance / 64), bitmap.rows, bitmap.width)
def is_wide_char(bitmap_char): def is_wide_char(bitmap_char):