1
0
Fork 0
ProjektAI/kelner/venv/Lib/site-packages/pygame/tests/freetype_test.py

1555 lines
59 KiB
Python

import os
if os.environ.get('SDL_VIDEODRIVER') == 'dummy':
__tags__ = ('ignore', 'subprocess_ignore')
import unittest
import sys
import ctypes
import weakref
import gc
import platform
IS_PYPY = 'PyPy' == platform.python_implementation()
try:
from pygame.tests.test_utils import arrinter
except NameError:
pass
import pygame
try:
import pygame.freetype as ft
except ImportError:
ft = None
from pygame.compat import as_unicode, bytes_, unichr_, unicode_
FONTDIR = os.path.join(os.path.dirname (os.path.abspath (__file__)),
'fixtures', 'fonts')
def nullfont():
"""return an uninitialized font instance"""
return ft.Font.__new__(ft.Font)
max_point_size_FX6 = 0x7FFFFFFF
max_point_size = max_point_size_FX6 >> 6
max_point_size_f = max_point_size_FX6 * 0.015625
def surf_same_image(a, b):
"""Return True if a's pixel buffer is identical to b's"""
a_sz = a.get_height() * a.get_pitch()
b_sz = b.get_height() * b.get_pitch()
if a_sz != b_sz:
return False
a_bytes = ctypes.string_at(a._pixels_address, a_sz)
b_bytes = ctypes.string_at(b._pixels_address, b_sz)
return a_bytes == b_bytes
class FreeTypeFontTest(unittest.TestCase):
_fixed_path = os.path.join(FONTDIR, 'test_fixed.otf')
_sans_path = os.path.join(FONTDIR, 'test_sans.ttf')
_mono_path = os.path.join(FONTDIR, 'PyGameMono.otf')
_bmp_8_75dpi_path = os.path.join(FONTDIR, 'PyGameMono-8.bdf')
_bmp_18_75dpi_path = os.path.join(FONTDIR, 'PyGameMono-18-75dpi.bdf')
_bmp_18_100dpi_path = os.path.join(FONTDIR, 'PyGameMono-18-100dpi.bdf')
_TEST_FONTS = {}
@classmethod
def setUpClass(cls):
ft.init()
# Setup the test fonts.
# Inconsolata is an open-source font designed by Raph Levien.
# Licensed under the Open Font License.
# http://www.levien.com/type/myfonts/inconsolata.html
cls._TEST_FONTS['fixed'] = ft.Font(cls._fixed_path)
# Liberation Sans is an open-source font designed by Steve Matteson.
# Licensed under the GNU GPL.
# https://fedorahosted.org/liberation-fonts/
cls._TEST_FONTS['sans'] = ft.Font(cls._sans_path)
# A scalable mono test font made for pygame. It contains only
# a few glyphs: '\0', 'A', 'B', 'C', and U+13079.
# It also contains two bitmap sizes: 8.0 X 8.0 and 19.0 X 19.0.
cls._TEST_FONTS['mono'] = ft.Font(cls._mono_path)
# A fixed size bitmap mono test font made for pygame.
# It contains only a few glyphs: '\0', 'A', 'B', 'C', and U+13079.
# The size is 8.0 X 8.0.
cls._TEST_FONTS['bmp-8-75dpi'] = ft.Font(cls._bmp_8_75dpi_path)
# A fixed size bitmap mono test font made for pygame.
# It contains only a few glyphs: '\0', 'A', 'B', 'C', and U+13079.
# The size is 8.0 X 8.0.
cls._TEST_FONTS['bmp-18-75dpi'] = ft.Font(cls._bmp_18_75dpi_path)
# A fixed size bitmap mono test font made for pygame.
# It contains only a few glyphs: '\0', 'A', 'B', 'C', and U+13079.
# The size is 8.0 X 8.0.
cls._TEST_FONTS['bmp-18-100dpi'] = ft.Font(cls._bmp_18_100dpi_path)
@classmethod
def tearDownClass(cls):
ft.quit()
def test_freetype_defaultfont(self):
font = ft.Font(None)
self.assertEqual(font.name, "FreeSans")
def test_freetype_Font_init(self):
self.assertRaises(IOError, ft.Font, os.path.join (FONTDIR, 'nonexistant.ttf'))
f = self._TEST_FONTS['sans']
self.assertIsInstance(f, ft.Font)
f = self._TEST_FONTS['fixed']
self.assertIsInstance(f, ft.Font)
# Test keyword arguments
f = ft.Font(size=22, file=None)
self.assertEqual(f.size, 22)
f = ft.Font(font_index=0, file=None)
self.assertNotEqual(ft.get_default_resolution(), 100)
f = ft.Font(resolution=100, file=None)
self.assertEqual(f.resolution, 100)
f = ft.Font(ucs4=True, file=None)
self.assertTrue(f.ucs4)
self.assertRaises(OverflowError, ft.Font, file=None,
size=(max_point_size + 1))
self.assertRaises(OverflowError, ft.Font, file=None, size=-1)
f = ft.Font(None, size=24)
self.assertTrue(f.height > 0)
self.assertRaises(IOError, f.__init__,
os.path.join(FONTDIR, 'nonexistant.ttf'))
# Test attribute preservation during reinitalization
f = ft.Font(self._sans_path, size=24, ucs4=True)
self.assertEqual(f.name, 'Liberation Sans')
self.assertTrue(f.scalable)
self.assertFalse(f.fixed_width)
self.assertTrue(f.antialiased)
self.assertFalse(f.oblique)
self.assertTrue(f.ucs4)
f.antialiased = False
f.oblique = True
f.__init__(self._mono_path)
self.assertEqual(f.name, 'PyGameMono')
self.assertTrue(f.scalable)
self.assertTrue(f.fixed_width)
self.assertFalse(f.antialiased)
self.assertTrue(f.oblique)
self.assertTrue(f.ucs4)
# For a bitmap font, the size is automatically set to the first
# size in the available sizes list.
f = ft.Font(self._bmp_8_75dpi_path)
sizes = f.get_sizes()
self.assertEqual(len(sizes), 1)
size_pt, width_px, height_px, x_ppem, y_ppem = sizes[0]
self.assertEqual(f.size, (x_ppem, y_ppem))
f.__init__(self._bmp_8_75dpi_path, size=12)
self.assertEqual(f.size, 12.0)
@unittest.skipIf(IS_PYPY, "PyPy doesn't use refcounting")
def test_freetype_Font_dealloc(self):
import sys
handle = open(self._sans_path, 'rb')
def load_font():
tempFont = ft.Font(handle)
try:
load_font()
self.assertEqual(sys.getrefcount(handle), 2)
finally:
# Ensures file is closed even if test fails.
handle.close()
def test_freetype_Font_scalable(self):
f = self._TEST_FONTS['sans']
self.assertTrue(f.scalable)
self.assertRaises(RuntimeError, lambda : nullfont().scalable)
def test_freetype_Font_fixed_width(self):
f = self._TEST_FONTS['sans']
self.assertFalse(f.fixed_width)
f = self._TEST_FONTS['mono']
self.assertTrue(f.fixed_width)
self.assertRaises(RuntimeError, lambda : nullfont().fixed_width)
def test_freetype_Font_fixed_sizes(self):
f = self._TEST_FONTS['sans']
self.assertEqual(f.fixed_sizes, 0)
f = self._TEST_FONTS['bmp-8-75dpi']
self.assertEqual(f.fixed_sizes, 1)
f = self._TEST_FONTS['mono']
self.assertEqual(f.fixed_sizes, 2)
def test_freetype_Font_get_sizes(self):
f = self._TEST_FONTS['sans']
szlist = f.get_sizes()
self.assertIsInstance(szlist, list)
self.assertEqual(len(szlist), 0)
f = self._TEST_FONTS['bmp-8-75dpi']
szlist = f.get_sizes()
self.assertIsInstance(szlist, list)
self.assertEqual(len(szlist), 1)
size8 = szlist[0]
self.assertIsInstance(size8[0], int)
self.assertEqual(size8[0], 8)
self.assertIsInstance(size8[1], int)
self.assertIsInstance(size8[2], int)
self.assertIsInstance(size8[3], float)
self.assertEqual(int(size8[3] * 64.0 + 0.5), 8 * 64)
self.assertIsInstance(size8[4], float)
self.assertEqual(int(size8[4] * 64.0 + 0.5), 8 * 64)
f = self._TEST_FONTS['mono']
szlist = f.get_sizes()
self.assertIsInstance(szlist, list)
self.assertEqual(len(szlist), 2)
size8 = szlist[0]
self.assertEqual(size8[3], 8)
self.assertEqual(int(size8[3] * 64.0 + 0.5), 8 * 64)
self.assertEqual(int(size8[4] * 64.0 + 0.5), 8 * 64)
size19 = szlist[1]
self.assertEqual(size19[3], 19)
self.assertEqual(int(size19[3] * 64.0 + 0.5), 19 * 64)
self.assertEqual(int(size19[4] * 64.0 + 0.5), 19 * 64)
def test_freetype_Font_use_bitmap_strikes(self):
f = self._TEST_FONTS['mono']
try:
# use_bitmap_strikes == True
#
self.assertTrue(f.use_bitmap_strikes)
# bitmap compatible properties
s_strike, sz = f.render_raw('A', size=19)
try:
f.vertical = True
s_strike_vert, sz = f.render_raw('A', size=19)
finally:
f.vertical = False
try:
f.wide = True
s_strike_wide, sz = f.render_raw('A', size=19)
finally:
f.wide = False
try:
f.underline = True
s_strike_underline, sz = f.render_raw('A', size=19)
finally:
f.underline = False
# bitmap incompatible properties
s_strike_rot45, sz = f.render_raw('A', size=19, rotation=45)
try:
f.strong = True
s_strike_strong, sz = f.render_raw('A', size=19)
finally:
f.strong = False
try:
f.oblique = True
s_strike_oblique, sz = f.render_raw('A', size=19)
finally:
f.oblique = False
# compare with use_bitmap_strikes == False
#
f.use_bitmap_strikes = False
self.assertFalse(f.use_bitmap_strikes)
# bitmap compatible properties
s_outline, sz = f.render_raw('A', size=19)
self.assertNotEqual(s_outline, s_strike)
try:
f.vertical = True
s_outline, sz = f.render_raw('A', size=19)
self.assertNotEqual(s_outline, s_strike_vert)
finally:
f.vertical = False
try:
f.wide = True
s_outline, sz = f.render_raw('A', size=19)
self.assertNotEqual(s_outline, s_strike_wide)
finally:
f.wide = False
try:
f.underline = True
s_outline, sz = f.render_raw('A', size=19)
self.assertNotEqual(s_outline, s_strike_underline)
finally:
f.underline = False
# bitmap incompatible properties
s_outline, sz = f.render_raw('A', size=19, rotation=45)
self.assertEqual(s_outline, s_strike_rot45)
try:
f.strong = True
s_outline, sz = f.render_raw('A', size=19)
self.assertEqual(s_outline, s_strike_strong)
finally:
f.strong = False
try:
f.oblique = True
s_outline, sz = f.render_raw('A', size=19)
self.assertEqual(s_outline, s_strike_oblique)
finally:
f.oblique = False
finally:
f.use_bitmap_strikes = True
def test_freetype_Font_bitmap_files(self):
"""Ensure bitmap file restrictions are caught"""
f = self._TEST_FONTS['bmp-8-75dpi']
f_null = nullfont()
s = pygame.Surface((10, 10), 0, 32)
a = s.get_view('3')
exception = AttributeError
self.assertRaises(exception, setattr, f, 'strong', True)
self.assertRaises(exception, setattr, f, 'oblique', True)
self.assertRaises(exception, setattr, f, 'style', ft.STYLE_STRONG)
self.assertRaises(exception, setattr, f, 'style', ft.STYLE_OBLIQUE)
exception = RuntimeError
self.assertRaises(exception, setattr, f_null, 'strong', True)
self.assertRaises(exception, setattr, f_null, 'oblique', True)
self.assertRaises(exception, setattr, f_null, 'style', ft.STYLE_STRONG)
self.assertRaises(exception, setattr, f_null, 'style', ft.STYLE_OBLIQUE)
exception = ValueError
self.assertRaises(exception, f.render,
'A', (0, 0, 0), size=8, rotation=1)
self.assertRaises(exception, f.render,
'A', (0, 0, 0), size=8, style=ft.STYLE_OBLIQUE)
self.assertRaises(exception, f.render,
'A', (0, 0, 0), size=8, style=ft.STYLE_STRONG)
self.assertRaises(exception, f.render_raw, 'A', size=8, rotation=1)
self.assertRaises(exception, f.render_raw,
'A', size=8, style=ft.STYLE_OBLIQUE)
self.assertRaises(exception, f.render_raw,
'A', size=8, style=ft.STYLE_STRONG)
self.assertRaises(exception, f.render_to,
s, (0, 0), 'A', (0, 0, 0), size=8, rotation=1)
self.assertRaises(exception, f.render_to,
s, (0, 0), 'A', (0, 0, 0), size=8,
style=ft.STYLE_OBLIQUE)
self.assertRaises(exception, f.render_to,
s, (0, 0), 'A', (0, 0, 0), size=8,
style=ft.STYLE_STRONG)
self.assertRaises(exception, f.render_raw_to,
a, 'A', size=8, rotation=1)
self.assertRaises(exception, f.render_raw_to,
a, 'A', size=8, style=ft.STYLE_OBLIQUE)
self.assertRaises(exception, f.render_raw_to,
a, 'A', size=8, style=ft.STYLE_STRONG)
self.assertRaises(exception, f.get_rect, 'A', size=8, rotation=1)
self.assertRaises(exception, f.get_rect,
'A', size=8, style=ft.STYLE_OBLIQUE)
self.assertRaises(exception, f.get_rect,
'A', size=8, style=ft.STYLE_STRONG)
# Unsupported point size
exception = pygame.error
self.assertRaises(exception, f.get_rect, 'A', size=42)
self.assertRaises(exception, f.get_metrics, 'A', size=42)
self.assertRaises(exception, f.get_sized_ascender, 42)
self.assertRaises(exception, f.get_sized_descender, 42)
self.assertRaises(exception, f.get_sized_height, 42)
self.assertRaises(exception, f.get_sized_glyph_height, 42)
def test_freetype_Font_get_metrics(self):
font = self._TEST_FONTS['sans']
metrics = font.get_metrics('ABCD', size=24)
self.assertEqual(len(metrics), len('ABCD'))
self.assertIsInstance(metrics, list)
for metrics_tuple in metrics:
self.assertIsInstance(metrics_tuple, tuple, metrics_tuple)
self.assertEqual(len(metrics_tuple), 6)
for m in metrics_tuple[:4]:
self.assertIsInstance(m, int)
for m in metrics_tuple[4:]:
self.assertIsInstance(m, float)
# test for empty string
metrics = font.get_metrics('', size=24)
self.assertEqual(metrics, [])
# test for invalid string
self.assertRaises(TypeError, font.get_metrics, 24, 24)
# raises exception when uninitalized
self.assertRaises(RuntimeError, nullfont().get_metrics,
'a', size=24)
def test_freetype_Font_get_rect(self):
font = self._TEST_FONTS['sans']
def test_rect(r):
self.assertIsInstance(r, pygame.Rect)
rect_default = font.get_rect("ABCDabcd", size=24)
test_rect(rect_default)
self.assertTrue(rect_default.size > (0, 0))
self.assertTrue(rect_default.width > rect_default.height)
rect_bigger = font.get_rect("ABCDabcd", size=32)
test_rect(rect_bigger)
self.assertTrue(rect_bigger.size > rect_default.size)
rect_strong = font.get_rect("ABCDabcd", size=24, style=ft.STYLE_STRONG)
test_rect(rect_strong)
self.assertTrue(rect_strong.size > rect_default.size)
font.vertical = True
rect_vert = font.get_rect("ABCDabcd", size=24)
test_rect(rect_vert)
self.assertTrue(rect_vert.width < rect_vert.height)
font.vertical = False
rect_oblique = font.get_rect("ABCDabcd", size=24, style=ft.STYLE_OBLIQUE)
test_rect(rect_oblique)
self.assertTrue(rect_oblique.width > rect_default.width)
self.assertTrue(rect_oblique.height == rect_default.height)
rect_under = font.get_rect("ABCDabcd", size=24, style=ft.STYLE_UNDERLINE)
test_rect(rect_under)
self.assertTrue(rect_under.width == rect_default.width)
self.assertTrue(rect_under.height > rect_default.height)
# Rect size should change if UTF surrogate pairs are treated as
# one code point or two.
ufont = self._TEST_FONTS['mono']
rect_utf32 = ufont.get_rect(as_unicode(r'\U00013079'), size=24)
rect_utf16 = ufont.get_rect(as_unicode(r'\uD80C\uDC79'), size=24)
self.assertEqual(rect_utf16, rect_utf32);
ufont.ucs4 = True
try:
rect_utf16 = ufont.get_rect(as_unicode(r'\uD80C\uDC79'), size=24)
finally:
ufont.ucs4 = False
self.assertNotEqual(rect_utf16, rect_utf32);
self.assertRaises(RuntimeError,
nullfont().get_rect, 'a', size=24)
# text stretching
rect12 = font.get_rect('A', size=12.0)
rect24 = font.get_rect('A', size=24.0)
rect_x = font.get_rect('A', size=(24.0, 12.0))
self.assertEqual(rect_x.width, rect24.width)
self.assertEqual(rect_x.height, rect12.height)
rect_y = font.get_rect('A', size=(12.0, 24.0))
self.assertEqual(rect_y.width, rect12.width)
self.assertEqual(rect_y.height, rect24.height)
def test_freetype_Font_height(self):
f = self._TEST_FONTS['sans']
self.assertEqual(f.height, 2355)
f = self._TEST_FONTS['fixed']
self.assertEqual(f.height, 1100)
self.assertRaises(RuntimeError, lambda : nullfont().height)
def test_freetype_Font_name(self):
f = self._TEST_FONTS['sans']
self.assertEqual(f.name, 'Liberation Sans')
f = self._TEST_FONTS['fixed']
self.assertEqual(f.name, 'Inconsolata')
nf = nullfont()
self.assertEqual(nf.name, repr(nf))
def test_freetype_Font_size(self):
f = ft.Font(None, size=12)
self.assertEqual(f.size, 12)
f.size = 22
self.assertEqual(f.size, 22)
f.size = 0
self.assertEqual(f.size, 0)
f.size = max_point_size
self.assertEqual(f.size, max_point_size)
f.size = 6.5
self.assertEqual(f.size, 6.5)
f.size = max_point_size_f
self.assertEqual(f.size, max_point_size_f)
self.assertRaises(OverflowError, setattr, f, 'size', -1)
self.assertRaises(OverflowError, setattr, f, 'size',
(max_point_size + 1))
f.size = 24.0, 0
size = f.size
self.assertIsInstance(size, float)
self.assertEqual(size, 24.0)
f.size = 16, 16
size = f.size
self.assertIsInstance(size, tuple)
self.assertEqual(len(size), 2)
x, y = size
self.assertIsInstance(x, float)
self.assertEqual(x, 16.0)
self.assertIsInstance(y, float)
self.assertEqual(y, 16.0)
f.size = 20.5, 22.25
x, y = f.size
self.assertEqual(x, 20.5)
self.assertEqual(y, 22.25)
f.size = 0, 0
size = f.size
self.assertIsInstance(size, float)
self.assertEqual(size, 0.0)
self.assertRaises(ValueError, setattr, f, 'size', (0, 24.0))
self.assertRaises(TypeError, setattr, f, 'size', (24.0,))
self.assertRaises(TypeError, setattr, f, 'size', (24.0, 0, 0))
self.assertRaises(TypeError, setattr, f, 'size', (24.0j, 24.0))
self.assertRaises(TypeError, setattr, f, 'size', (24.0, 24.0j))
self.assertRaises(OverflowError, setattr, f, 'size', (-1, 16))
self.assertRaises(OverflowError, setattr, f, 'size',
(max_point_size + 1, 16))
self.assertRaises(OverflowError, setattr, f, 'size', (16, -1))
self.assertRaises(OverflowError, setattr, f, 'size',
(16, max_point_size + 1))
# bitmap files with identical point size but differing ppems.
f75 = self._TEST_FONTS['bmp-18-75dpi']
sizes = f75.get_sizes()
self.assertEqual(len(sizes), 1)
size_pt, width_px, height_px, x_ppem, y_ppem = sizes[0]
self.assertEqual(size_pt, 18)
self.assertEqual(x_ppem, 19.0)
self.assertEqual(y_ppem, 19.0)
rect = f75.get_rect('A', size=18)
rect = f75.get_rect('A', size=19)
rect = f75.get_rect('A', size=(19.0, 19.0))
self.assertRaises(pygame.error, f75.get_rect, 'A', size=17)
f100 = self._TEST_FONTS['bmp-18-100dpi']
sizes = f100.get_sizes()
self.assertEqual(len(sizes), 1)
size_pt, width_px, height_px, x_ppem, y_ppem = sizes[0]
self.assertEqual(size_pt, 18)
self.assertEqual(x_ppem, 25.0)
self.assertEqual(y_ppem, 25.0)
rect = f100.get_rect('A', size=18)
rect = f100.get_rect('A', size=25)
rect = f100.get_rect('A', size=(25.0, 25.0))
self.assertRaises(pygame.error, f100.get_rect, 'A', size=17)
def test_freetype_Font_rotation(self):
test_angles = [(30, 30),
(360, 0), (390, 30),
(720, 0), (764, 44),
(-30, 330),
(-360, 0), (-390, 330),
(-720, 0), (-764, 316)]
f = ft.Font(None)
self.assertEqual(f.rotation, 0)
for r, r_reduced in test_angles:
f.rotation = r
self.assertEqual(f.rotation, r_reduced,
"for angle %d: %d != %d" %
(r, f.rotation, r_reduced))
self.assertRaises(TypeError, setattr, f, 'rotation', '12')
def test_freetype_Font_render_to(self):
# Rendering to an existing target surface is equivalent to
# blitting a surface returned by Font.render with the target.
font = self._TEST_FONTS['sans']
surf = pygame.Surface((800, 600))
color = pygame.Color(0, 0, 0)
rrect = font.render_to(surf, (32, 32),
'FoobarBaz', color, None, size=24)
self.assertIsInstance(rrect, pygame.Rect)
self.assertEqual(rrect.top, rrect.height)
## self.assertEqual(rrect.left, something or other)
rcopy = rrect.copy()
rcopy.topleft = (32, 32)
self.assertTrue(surf.get_rect().contains(rcopy))
rect = pygame.Rect(20, 20, 2, 2)
rrect = font.render_to(surf, rect, 'FoobarBax', color, None, size=24)
self.assertEqual(rrect.top, rrect.height)
self.assertNotEqual(rrect.size, rect.size)
rrect = font.render_to(surf, (20.1, 18.9), 'FoobarBax',
color, None, size=24)
## self.assertEqual(tuple(rend[1].topleft), (20, 18))
rrect = font.render_to(surf, rect, '', color, None, size=24)
self.assertFalse(rrect)
self.assertEqual(rrect.height, font.get_sized_height(24))
# invalid surf test
self.assertRaises(TypeError, font.render_to,
"not a surface", "text", color)
self.assertRaises(TypeError, font.render_to,
pygame.Surface, "text", color)
# invalid dest test
for dest in [None, 0, 'a', 'ab',
(), (1,), ('a', 2), (1, 'a'), (1+2j, 2), (1, 1+2j),
(1, int), (int, 1)]:
self.assertRaises(TypeError, font.render,
surf, dest, 'foobar', color, size=24)
# misc parameter test
self.assertRaises(ValueError, font.render_to, surf, (0, 0),
'foobar', color)
self.assertRaises(TypeError, font.render_to, surf, (0, 0),
'foobar', color, "", size=24)
self.assertRaises(ValueError, font.render_to, surf, (0, 0),
'foobar', color, None, style=42, size=24)
self.assertRaises(TypeError, font.render_to, surf, (0, 0),
'foobar', color, None, style=None, size=24)
self.assertRaises(ValueError, font.render_to, surf, (0, 0),
'foobar', color, None, style=97, size=24)
def test_freetype_Font_render(self):
font = self._TEST_FONTS['sans']
surf = pygame.Surface((800, 600))
color = pygame.Color(0, 0, 0)
rend = font.render('FoobarBaz', pygame.Color(0, 0, 0), None, size=24)
self.assertIsInstance(rend, tuple)
self.assertEqual(len(rend), 2)
self.assertIsInstance(rend[0], pygame.Surface)
self.assertIsInstance(rend[1], pygame.Rect)
self.assertEqual(rend[0].get_rect().size, rend[1].size)
s, r = font.render('', pygame.Color(0, 0, 0), None, size=24)
self.assertEqual(r.width, 1)
self.assertEqual(r.height, font.get_sized_height(24))
self.assertEqual(s.get_size(), r.size)
self.assertEqual(s.get_bitsize(), 32)
# misc parameter test
self.assertRaises(ValueError, font.render, 'foobar', color)
self.assertRaises(TypeError, font.render, 'foobar', color, "",
size=24)
self.assertRaises(ValueError, font.render, 'foobar', color, None,
style=42, size=24)
self.assertRaises(TypeError, font.render, 'foobar', color, None,
style=None, size=24)
self.assertRaises(ValueError, font.render, 'foobar', color, None,
style=97, size=24)
# valid surrogate pairs
font2 = self._TEST_FONTS['mono']
ucs4 = font2.ucs4
try:
font2.ucs4 = False
rend1 = font2.render(as_unicode(r'\uD80C\uDC79'), color, size=24)
rend2 = font2.render(as_unicode(r'\U00013079'), color, size=24)
self.assertEqual(rend1[1], rend2[1])
font2.ucs4 = True
rend1 = font2.render(as_unicode(r'\uD80C\uDC79'), color, size=24)
self.assertNotEqual(rend1[1], rend2[1])
finally:
font2.ucs4 = ucs4
# malformed surrogate pairs
self.assertRaises(UnicodeEncodeError, font.render,
as_unicode(r'\uD80C'), color, size=24)
self.assertRaises(UnicodeEncodeError, font.render,
as_unicode(r'\uDCA7'), color, size=24)
self.assertRaises(UnicodeEncodeError, font.render,
as_unicode(r'\uD7FF\uDCA7'), color, size=24)
self.assertRaises(UnicodeEncodeError, font.render,
as_unicode(r'\uDC00\uDCA7'), color, size=24)
self.assertRaises(UnicodeEncodeError, font.render,
as_unicode(r'\uD80C\uDBFF'), color, size=24)
self.assertRaises(UnicodeEncodeError, font.render,
as_unicode(r'\uD80C\uE000'), color, size=24)
# raises exception when uninitalized
self.assertRaises(RuntimeError, nullfont().render,
'a', (0, 0, 0), size=24)
# Confirm the correct glpyhs are returned for a couple of
# unicode code points, 'A' and '\U00023079'. For each code point
# the rendered glyph is compared with an image of glyph bitmap
# as exported by FontForge.
path = os.path.join(FONTDIR, 'A_PyGameMono-8.png')
A = pygame.image.load(path)
path = os.path.join(FONTDIR, 'u13079_PyGameMono-8.png')
u13079 = pygame.image.load(path)
font = self._TEST_FONTS['mono']
font.ucs4 = False
A_rendered, r = font.render('A', bgcolor=pygame.Color('white'), size=8)
u13079_rendered, r = font.render(as_unicode(r'\U00013079'),
bgcolor=pygame.Color('white'), size=8)
## before comparing the surfaces, make sure they are the same
## pixel format. Use 32-bit SRCALPHA to avoid row padding and
## undefined bytes (the alpha byte will be set to 255.)
bitmap = pygame.Surface(A.get_size(), pygame.SRCALPHA, 32)
bitmap.blit(A, (0, 0))
rendering = pygame.Surface(A_rendered.get_size(), pygame.SRCALPHA, 32)
rendering.blit(A_rendered, (0, 0))
self.assertTrue(surf_same_image(rendering, bitmap))
bitmap = pygame.Surface(u13079.get_size(), pygame.SRCALPHA, 32)
bitmap.blit(u13079, (0, 0))
rendering = pygame.Surface(u13079_rendered.get_size(),
pygame.SRCALPHA, 32)
rendering.blit(u13079_rendered, (0, 0))
self.assertTrue(surf_same_image(rendering, bitmap))
def test_freetype_Font_render_mono(self):
font = self._TEST_FONTS['sans']
color = pygame.Color('black')
colorkey = pygame.Color('white')
text = "."
save_antialiased = font.antialiased
font.antialiased = False
try:
surf, r = font.render(text, color, size=24)
self.assertEqual(surf.get_bitsize(), 8)
flags = surf.get_flags()
self.assertTrue(flags & pygame.SRCCOLORKEY)
self.assertFalse(flags & (pygame.SRCALPHA | pygame.HWSURFACE))
self.assertEqual(surf.get_colorkey(), colorkey)
self.assertIsNone(surf.get_alpha())
translucent_color = pygame.Color(*color)
translucent_color.a = 55
surf, r = font.render(text, translucent_color, size=24)
self.assertEqual(surf.get_bitsize(), 8)
flags = surf.get_flags()
self.assertTrue(flags & (pygame.SRCCOLORKEY | pygame.SRCALPHA))
self.assertFalse(flags & pygame.HWSURFACE)
self.assertEqual(surf.get_colorkey(), colorkey)
self.assertEqual(surf.get_alpha(), translucent_color.a)
surf, r = font.render(text, color, colorkey, size=24)
self.assertEqual(surf.get_bitsize(), 32)
finally:
font.antialiased = save_antialiased
@unittest.skipIf(pygame.get_sdl_version()[0] == 2, "skipping due to blending issue (#864)")
def test_freetype_Font_render_to_mono(self):
# Blitting is done in two stages. First the target is alpha filled
# with the background color, if any. Second, the foreground
# color is alpha blitted to the background.
font = self._TEST_FONTS['sans']
text = " ."
rect = font.get_rect(text, size=24)
size = rect.size
fg = pygame.Surface((1, 1), pygame.SRCALPHA, 32)
bg = pygame.Surface((1, 1), pygame.SRCALPHA, 32)
surrogate = pygame.Surface((1, 1), pygame.SRCALPHA, 32)
surfaces = [pygame.Surface(size, 0, 8),
pygame.Surface(size, 0, 16),
pygame.Surface(size, pygame.SRCALPHA, 16),
pygame.Surface(size, 0, 24),
pygame.Surface(size, 0, 32),
pygame.Surface(size, pygame.SRCALPHA, 32)]
fg_colors = [
surfaces[0].get_palette_at(2),
surfaces[1].unmap_rgb(surfaces[1].map_rgb((128, 64, 200))),
surfaces[2].unmap_rgb(surfaces[2].map_rgb((99, 0, 100, 64))),
(128, 97, 213),
(128, 97, 213),
(128, 97, 213, 60)]
fg_colors = [pygame.Color(*c) for c in fg_colors]
self.assertEqual(len(surfaces), len(fg_colors)) # integrity check
bg_colors = [
surfaces[0].get_palette_at(4),
surfaces[1].unmap_rgb(surfaces[1].map_rgb((220, 20, 99))),
surfaces[2].unmap_rgb(surfaces[2].map_rgb((55, 200, 0, 86))),
(255, 120, 13),
(255, 120, 13),
(255, 120, 13, 180)]
bg_colors = [pygame.Color(*c) for c in bg_colors]
self.assertEqual(len(surfaces), len(bg_colors)) # integrity check
save_antialiased = font.antialiased
font.antialiased = False
try:
fill_color = pygame.Color('black')
for i, surf in enumerate(surfaces):
surf.fill(fill_color)
fg_color = fg_colors[i]
fg.set_at((0, 0), fg_color)
surf.blit(fg, (0, 0))
r_fg_color = surf.get_at((0, 0))
surf.set_at((0, 0), fill_color)
rrect = font.render_to(surf, (0, 0), text, fg_color,
size=24)
bottomleft = 0, rrect.height - 1
self.assertEqual(surf.get_at(bottomleft), fill_color,
"Position: {}. Depth: {}."
" fg_color: {}.".format(bottomleft,
surf.get_bitsize(), fg_color))
bottomright = rrect.width - 1, rrect.height - 1
self.assertEqual(surf.get_at(bottomright), r_fg_color,
"Position: {}. Depth: {}."
" fg_color: {}.".format(bottomright,
surf.get_bitsize(), fg_color))
for i, surf in enumerate(surfaces):
surf.fill(fill_color)
fg_color = fg_colors[i]
bg_color = bg_colors[i]
bg.set_at((0, 0), bg_color)
fg.set_at((0, 0), fg_color)
if surf.get_bitsize() == 24:
# For a 24 bit target surface test against Pygame's alpha
# blit as there appears to be a problem with SDL's alpha
# blit:
#
# self.assertEqual(surf.get_at(bottomright), r_fg_color)
#
# raises
#
# AssertionError: (128, 97, 213, 255) != (129, 98, 213, 255)
#
surrogate.set_at((0, 0), fill_color)
surrogate.blit(bg, (0, 0))
r_bg_color = surrogate.get_at((0, 0))
surrogate.blit(fg, (0, 0))
r_fg_color = surrogate.get_at((0, 0))
else:
# Surface blit values for comparison.
surf.blit(bg, (0, 0))
r_bg_color = surf.get_at((0, 0))
surf.blit(fg, (0, 0))
r_fg_color = surf.get_at((0, 0))
surf.set_at((0, 0), fill_color)
rrect = font.render_to(surf, (0, 0), text, fg_color,
bg_color, size=24)
bottomleft = 0, rrect.height - 1
self.assertEqual(surf.get_at(bottomleft), r_bg_color)
bottomright = rrect.width - 1, rrect.height - 1
self.assertEqual(surf.get_at(bottomright), r_fg_color)
finally:
font.antialiased = save_antialiased
def test_freetype_Font_render_raw(self):
font = self._TEST_FONTS['sans']
text = "abc"
size = font.get_rect(text, size=24).size
rend = font.render_raw(text, size=24)
self.assertIsInstance(rend, tuple)
self.assertEqual(len(rend), 2)
r, s = rend
self.assertIsInstance(r, bytes_)
self.assertIsInstance(s, tuple)
self.assertTrue(len(s), 2)
w, h = s
self.assertIsInstance(w, int)
self.assertIsInstance(h, int)
self.assertEqual(s, size)
self.assertEqual(len(r), w * h)
r, (w, h) = font.render_raw('', size=24)
self.assertEqual(w, 0)
self.assertEqual(h, font.height)
self.assertEqual(len(r), 0)
# bug with decenders: this would crash
rend = font.render_raw('render_raw', size=24)
# bug with non-printable characters: this would cause a crash
# because the text length was not adjusted for skipped characters.
text = unicode_("").join([unichr_(i) for i in range(31, 64)])
rend = font.render_raw(text, size=10)
def test_freetype_Font_render_raw_to(self):
# This only checks that blits do not crash. It needs to check:
# - int values
# - invert option
#
font = self._TEST_FONTS['sans']
text = "abc"
# No frills antialiased render to int1 (__render_glyph_INT)
srect = font.get_rect(text, size=24)
surf = pygame.Surface(srect.size, 0, 8)
rrect = font.render_raw_to(surf.get_view('2'), text, size=24)
self.assertEqual(rrect, srect)
for bpp in [24, 32]:
surf = pygame.Surface(srect.size, 0, bpp)
rrect = font.render_raw_to(surf.get_view('r'), text, size=24)
self.assertEqual(rrect, srect)
# Underlining to int1 (__fill_glyph_INT)
srect = font.get_rect(text, size=24, style=ft.STYLE_UNDERLINE)
surf = pygame.Surface(srect.size, 0, 8)
rrect = font.render_raw_to(surf.get_view('2'), text, size=24,
style=ft.STYLE_UNDERLINE)
self.assertEqual(rrect, srect)
for bpp in [24, 32]:
surf = pygame.Surface(srect.size, 0, bpp)
rrect = font.render_raw_to(surf.get_view('r'), text, size=24,
style=ft.STYLE_UNDERLINE)
self.assertEqual(rrect, srect)
# Unaliased (mono) rendering to int1 (__render_glyph_MONO_as_INT)
font.antialiased = False
try:
srect = font.get_rect(text, size=24)
surf = pygame.Surface(srect.size, 0, 8)
rrect = font.render_raw_to(surf.get_view('2'), text, size=24)
self.assertEqual(rrect, srect)
for bpp in [24, 32]:
surf = pygame.Surface(srect.size, 0, bpp)
rrect = font.render_raw_to(surf.get_view('r'), text, size=24)
self.assertEqual(rrect, srect)
finally:
font.antialiased = True
# Antialiased render to ints sized greater than 1 byte
# (__render_glyph_INT)
srect = font.get_rect(text, size=24)
for bpp in [16, 24, 32]:
surf = pygame.Surface(srect.size, 0, bpp)
rrect = font.render_raw_to(surf.get_view('2'), text, size=24)
self.assertEqual(rrect, srect)
# Underline render to ints sized greater than 1 byte
# (__fill_glyph_INT)
srect = font.get_rect(text, size=24, style=ft.STYLE_UNDERLINE)
for bpp in [16, 24, 32]:
surf = pygame.Surface(srect.size, 0, bpp)
rrect = font.render_raw_to(surf.get_view('2'), text, size=24,
style=ft.STYLE_UNDERLINE)
self.assertEqual(rrect, srect)
# Unaliased (mono) rendering to ints greater than 1 byte
# (__render_glyph_MONO_as_INT)
font.antialiased = False
try:
srect = font.get_rect(text, size=24)
for bpp in [16, 24, 32]:
surf = pygame.Surface(srect.size, 0, bpp)
rrect = font.render_raw_to(surf.get_view('2'),
text, size=24)
self.assertEqual(rrect, srect)
finally:
font.antialiased = True
def test_freetype_Font_text_is_None(self):
f = ft.Font(self._sans_path, 36)
f.style = ft.STYLE_NORMAL
f.rotation = 0
text = 'ABCD'
# reference values
get_rect = f.get_rect(text)
f.vertical = True
get_rect_vert = f.get_rect(text)
self.assertTrue(get_rect_vert.width < get_rect.width)
self.assertTrue(get_rect_vert.height > get_rect.height)
f.vertical = False
render_to_surf = pygame.Surface(get_rect.size, pygame.SRCALPHA, 32)
if IS_PYPY:
return
arr = arrinter.Array(get_rect.size, 'u', 1)
render = f.render(text, (0, 0, 0))
render_to = f.render_to(render_to_surf, (0, 0), text, (0, 0, 0))
render_raw = f.render_raw(text)
render_raw_to = f.render_raw_to(arr, text)
# comparisons
surf = pygame.Surface(get_rect.size, pygame.SRCALPHA, 32)
self.assertEqual(f.get_rect(None), get_rect)
s, r = f.render(None, (0, 0, 0))
self.assertEqual(r, render[1])
self.assertTrue(surf_same_image(s, render[0]))
r = f.render_to(surf, (0, 0), None, (0, 0, 0))
self.assertEqual(r, render_to)
self.assertTrue(surf_same_image(surf, render_to_surf))
px, sz = f.render_raw(None)
self.assertEqual(sz, render_raw[1])
self.assertEqual(px, render_raw[0])
sz = f.render_raw_to(arr, None)
self.assertEqual(sz, render_raw_to)
def test_freetype_Font_text_is_None(self):
f = ft.Font(self._sans_path, 36)
f.style = ft.STYLE_NORMAL
f.rotation = 0
text = 'ABCD'
# reference values
get_rect = f.get_rect(text)
f.vertical = True
get_rect_vert = f.get_rect(text)
# vertical: trigger glyph positioning.
f.vertical = True
r = f.get_rect(None)
self.assertEqual(r, get_rect_vert)
f.vertical = False
# wide style: trigger glyph reload
r = f.get_rect(None, style=ft.STYLE_WIDE)
self.assertEqual(r.height, get_rect.height)
self.assertTrue(r.width > get_rect.width)
r = f.get_rect(None)
self.assertEqual(r, get_rect)
# rotated: trigger glyph reload
r = f.get_rect(None, rotation=90)
self.assertEqual(r.width, get_rect.height)
self.assertEqual(r.height, get_rect.width)
# this method will not support None text
self.assertRaises(TypeError, f.get_metrics, None)
def test_freetype_Font_fgcolor(self):
f = ft.Font(self._bmp_8_75dpi_path)
notdef = '\0' # the PyGameMono .notdef glyph has a pixel at (0, 0)
f.origin = False
f.pad = False
black = pygame.Color('black') # initial color
green = pygame.Color('green')
alpha128 = pygame.Color(10, 20, 30, 128)
c = f.fgcolor
self.assertIsInstance(c, pygame.Color)
self.assertEqual(c, black)
s, r = f.render(notdef)
self.assertEqual(s.get_at((0, 0)), black)
f.fgcolor = green
self.assertEqual(f.fgcolor, green)
s, r = f.render(notdef)
self.assertEqual(s.get_at((0, 0)), green)
f.fgcolor = alpha128
s, r = f.render(notdef)
self.assertEqual(s.get_at((0, 0)), alpha128)
surf = pygame.Surface(f.get_rect(notdef).size, pygame.SRCALPHA, 32)
f.render_to(surf, (0, 0), None)
self.assertEqual(surf.get_at((0, 0)), alpha128)
self.assertRaises(AttributeError, setattr, f, 'fgcolor', None)
@unittest.skipIf(not pygame.HAVE_NEWBUF, 'newbuf not implemented')
def test_newbuf(self):
from pygame.tests.test_utils import buftools
Exporter = buftools.Exporter
font = self._TEST_FONTS['sans']
srect = font.get_rect("Hi", size=12)
for format in ['b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q',
'x', '1x', '2x', '3x', '4x', '5x', '6x', '7x',
'8x', '9x', '<h', '>h', '=h', '@h', '!h', '1h', '=1h']:
newbuf = Exporter(srect.size, format=format)
rrect = font.render_raw_to(newbuf, "Hi", size=12)
self.assertEqual(rrect, srect)
# Some unsupported formats
for format in ['f', 'd', '2h', '?', 'hh']:
newbuf = Exporter(srect.size, format=format, itemsize=4)
self.assertRaises(ValueError, font.render_raw_to,
newbuf, "Hi", size=12)
def test_freetype_Font_style(self):
font = self._TEST_FONTS['sans']
# make sure STYLE_NORMAL is the default value
self.assertEqual(ft.STYLE_NORMAL, font.style)
# make sure we check for style type
with self.assertRaises(TypeError):
font.style = "None"
with self.assertRaises(TypeError):
font.style = None
# make sure we only accept valid constants
with self.assertRaises(ValueError):
font.style = 112
# make assure no assignements happened
self.assertEqual(ft.STYLE_NORMAL, font.style)
# test assignement
font.style = ft.STYLE_UNDERLINE
self.assertEqual(ft.STYLE_UNDERLINE, font.style)
# test complex styles
st = ( ft.STYLE_STRONG | ft.STYLE_UNDERLINE |
ft.STYLE_OBLIQUE )
font.style = st
self.assertEqual(st, font.style)
# and that STYLE_DEFAULT has no effect (continued from above)
self.assertNotEqual(st, ft.STYLE_DEFAULT)
font.style = ft.STYLE_DEFAULT
self.assertEqual(st, font.style)
# revert changes
font.style = ft.STYLE_NORMAL
self.assertEqual(ft.STYLE_NORMAL, font.style)
def test_freetype_Font_resolution(self):
text = "|" # Differs in width and height
resolution = ft.get_default_resolution()
new_font = ft.Font(self._sans_path, resolution=2 * resolution)
self.assertEqual(new_font.resolution, 2 * resolution)
size_normal = self._TEST_FONTS['sans'].get_rect(text, size=24).size
size_scaled = new_font.get_rect(text, size=24).size
size_by_2 = size_normal[0] * 2
self.assertTrue(size_by_2 + 2 >= size_scaled[0] >= size_by_2 - 2,
"%i not equal %i" % (size_scaled[1], size_by_2))
size_by_2 = size_normal[1] * 2
self.assertTrue(size_by_2 + 2 >= size_scaled[1] >= size_by_2 - 2,
"%i not equal %i" % (size_scaled[1], size_by_2))
new_resolution = resolution + 10
ft.set_default_resolution(new_resolution)
try:
new_font = ft.Font(self._sans_path, resolution=0)
self.assertEqual(new_font.resolution, new_resolution)
finally:
ft.set_default_resolution()
def test_freetype_Font_path(self):
self.assertEqual(self._TEST_FONTS['sans'].path, self._sans_path)
self.assertRaises(AttributeError, getattr, nullfont(), 'path')
# This Font cache test is conditional on freetype being built by a debug
# version of Python or with the C macro PGFT_DEBUG_CACHE defined.
def test_freetype_Font_cache(self):
glyphs = "abcde"
glen = len(glyphs)
other_glyphs = "123"
oglen = len(other_glyphs)
uempty = unicode_("")
## many_glyphs = (uempty.join([unichr_(i) for i in range(32,127)] +
## [unichr_(i) for i in range(161,172)] +
## [unichr_(i) for i in range(174,239)]))
many_glyphs = uempty.join([unichr_(i) for i in range(32,127)])
mglen = len(many_glyphs)
count = 0
access = 0
hit = 0
miss = 0
f = ft.Font(None, size=24, font_index=0, resolution=72, ucs4=False)
f.style = ft.STYLE_NORMAL
f.antialiased = True
# Ensure debug counters are zero
self.assertEqual(f._debug_cache_stats, (0, 0, 0, 0, 0))
# Load some basic glyphs
count = access = miss = glen
f.render_raw(glyphs)
self.assertEqual(f._debug_cache_stats, (count, 0, access, hit, miss))
# Vertical should not affect the cache
access += glen
hit += glen
f.vertical = True
f.render_raw(glyphs)
f.vertical = False
self.assertEqual(f._debug_cache_stats, (count, 0, access, hit, miss))
# New glyphs will
count += oglen
access += oglen
miss += oglen
f.render_raw(other_glyphs)
self.assertEqual(f._debug_cache_stats, (count, 0, access, hit, miss))
# Point size does
count += glen
access += glen
miss += glen
f.render_raw(glyphs, size=12)
self.assertEqual(f._debug_cache_stats, (count, 0, access, hit, miss))
# Underline style does not
access += oglen
hit += oglen
f.underline = True
f.render_raw(other_glyphs)
f.underline = False
self.assertEqual(f._debug_cache_stats, (count, 0, access, hit, miss))
# Oblique style does
count += glen
access += glen
miss += glen
f.oblique = True
f.render_raw(glyphs)
f.oblique = False
self.assertEqual(f._debug_cache_stats, (count, 0, access, hit, miss))
# Strong style does; by this point cache clears can happen
count += glen
access += glen
miss += glen
f.strong = True
f.render_raw(glyphs)
f.strong = False
ccount, cdelete_count, caccess, chit, cmiss = f._debug_cache_stats
self.assertEqual((ccount + cdelete_count, caccess, chit, cmiss),
(count, access, hit, miss))
# Rotation does
count += glen
access += glen
miss += glen
f.render_raw(glyphs, rotation=10)
ccount, cdelete_count, caccess, chit, cmiss = f._debug_cache_stats
self.assertEqual((ccount + cdelete_count, caccess, chit, cmiss),
(count, access, hit, miss))
# aliased (mono) glyphs do
count += oglen
access += oglen
miss += oglen
f.antialiased = False
f.render_raw(other_glyphs)
f.antialiased = True
ccount, cdelete_count, caccess, chit, cmiss = f._debug_cache_stats
self.assertEqual((ccount + cdelete_count, caccess, chit, cmiss),
(count, access, hit, miss))
# Trigger a cleanup for sure.
count += 2 * mglen
access += 2 * mglen
miss += 2 * mglen
f.get_metrics(many_glyphs, size=8)
f.get_metrics(many_glyphs, size=10)
ccount, cdelete_count, caccess, chit, cmiss = f._debug_cache_stats
self.assertTrue(ccount < count)
self.assertEqual((ccount + cdelete_count, caccess, chit, cmiss),
(count, access, hit, miss))
try:
ft.Font._debug_cache_stats
except AttributeError:
del test_freetype_Font_cache
def test_undefined_character_code(self):
# To be consistent with pygame.font.Font, undefined codes
# are rendered as the undefined character, and has metrics
# of None.
font = self._TEST_FONTS['sans']
img, size1 = font.render(unichr_(1), (0, 0, 0), size=24)
img, size0 = font.render("", (0, 0, 0), size=24)
self.assertTrue(size1.width > size0.width )
metrics = font.get_metrics(unichr_(1) + unichr_(48), size=24)
self.assertEqual(len(metrics), 2)
self.assertIsNone(metrics[0])
self.assertIsInstance(metrics[1], tuple)
@unittest.skipIf(pygame.get_sdl_version()[0] == 2, "SDL2 surfaces are only limited by memory")
def test_issue_144(self):
"""Issue #144: unable to render text"""
# The bug came in two parts. The first was a convertion bug from
# FT_Fixed to integer in for an Intel x86_64 Pygame build. The second
# was to have the raised exception disappear before Font.render
# returned to Python level.
#
font = ft.Font(None, size=64)
s = 'M' * 100000 # Way too long for an SDL surface
self.assertRaises(pygame.error, font.render, s, (0, 0, 0))
def test_issue_242(self):
"""Issue #242: get_rect() uses 0 as default style"""
# Issue #242: freetype.Font.get_rect() ignores style defaults when
# the style argument is not given
#
# The text boundary rectangle returned by freetype.Font.get_rect()
# should match the boundary of the same text rendered directly to a
# surface. This permits accurate text positioning. To work properly,
# get_rect() should calculate the text boundary to reflect text style,
# such as underline. Instead, it ignores the style settings for the
# Font object when the style argument is omitted.
#
# When the style argument is not given, freetype.get_rect() uses
# unstyled text when calculating the boundary rectangle. This is
# because _ftfont_getrect(), in _freetype.c, set the default
# style to 0 rather than FT_STYLE_DEFAULT.
#
font = self._TEST_FONTS['sans']
# Try wide style on a wide character.
prev_style = font.wide
font.wide = True
try:
rect = font.get_rect('M', size=64)
surf, rrect = font.render(None, size=64)
self.assertEqual(rect, rrect)
finally:
font.wide = prev_style
# Try strong style on several wide characters.
prev_style = font.strong
font.strong = True
try:
rect = font.get_rect('Mm_', size=64)
surf, rrect = font.render(None, size=64)
self.assertEqual(rect, rrect)
finally:
font.strong = prev_style
# Try oblique style on a tall, narrow character.
prev_style = font.oblique
font.oblique = True
try:
rect = font.get_rect('|', size=64)
surf, rrect = font.render(None, size=64)
self.assertEqual(rect, rrect)
finally:
font.oblique = prev_style
# Try underline style on a glyphless character.
prev_style = font.underline
font.underline = True
try:
rect = font.get_rect(' ', size=64)
surf, rrect = font.render(None, size=64)
self.assertEqual(rect, rrect)
finally:
font.underline = prev_style
def test_issue_237(self):
"""Issue #237: Memory overrun when rendered with underlining"""
# Issue #237: Memory overrun when text without descenders is rendered
# with underlining
#
# The bug crashes the Python interpreter. The bug is caught with C
# assertions in ft_render_cb.c when the Pygame module is compiled
# for debugging. So far it is only known to affect Times New Roman.
#
name = "Times New Roman"
font = ft.SysFont(name, 19)
if font.name != name:
# The font is unavailable, so skip the test.
return
font.underline = True
s, r = font.render("Amazon", size=19)
# Some other checks to make sure nothing else broke.
for adj in [-2, -1.9, -1, 0, 1.9, 2]:
font.underline_adjustment = adj
s, r = font.render("Amazon", size=19)
def test_issue_243(self):
"""Issue Y: trailing space ignored in boundary calculation"""
# Issue #243: For a string with trailing spaces, freetype ignores the
# last space in boundary calculations
#
font = self._TEST_FONTS['fixed']
r1 = font.get_rect(" ", size=64)
self.assertTrue(r1.width > 1)
r2 = font.get_rect(" ", size=64)
self.assertEqual(r2.width, 2 * r1.width)
def test_garbage_collection(self):
"""Check reference counting on returned new references"""
def ref_items(seq):
return [weakref.ref(o) for o in seq]
font = self._TEST_FONTS['bmp-8-75dpi']
font.size = font.get_sizes()[0][0]
text = 'A'
rect = font.get_rect(text)
surf = pygame.Surface(rect.size, pygame.SRCALPHA, 32)
refs = []
refs.extend(ref_items(font.render(text, (0, 0, 0))))
refs.append(weakref.ref(font.render_to(surf, (0, 0), text, (0, 0, 0))))
refs.append(weakref.ref(font.get_rect(text)))
n = len(refs)
self.assertTrue(n > 0)
# for pypy we garbage collection twice.
for i in range(2):
gc.collect()
for i in range(n):
self.assertIsNone(refs[i](), "ref %d not collected" % i)
try:
from sys import getrefcount
except ImportError:
pass
else:
array = arrinter.Array(rect.size, 'u', 1)
o = font.render_raw(text)
self.assertEqual(getrefcount(o), 2)
self.assertEqual(getrefcount(o[0]), 2)
self.assertEqual(getrefcount(o[1]), 2)
self.assertEqual(getrefcount(font.render_raw_to(array, text)), 1)
o = font.get_metrics('AB')
self.assertEqual(getrefcount(o), 2)
for i in range(len(o)):
self.assertEqual(getrefcount(o[i]), 2,
"refcount fail for item %d" % i)
o = font.get_sizes()
self.assertEqual(getrefcount(o), 2)
for i in range(len(o)):
self.assertEqual(getrefcount(o[i]), 2,
"refcount fail for item %d" % i)
def test_display_surface_quit(self):
"""Font.render_to() on a closed display surface"""
# The Font.render_to() method checks that PySurfaceObject.surf is NULL
# and raise a exception if it is. This fixes a bug in Pygame revision
# 0600ea4f1cfb and earlier where Pygame segfaults instead.
null_surface = pygame.Surface.__new__(pygame.Surface)
f = self._TEST_FONTS['sans']
self.assertRaises(pygame.error, f.render_to,
null_surface, (0, 0), "Crash!", size=12)
def test_issue_565(self):
"""get_metrics supporting rotation/styles/size"""
tests = [
{'method': 'size', 'value': 36, 'msg': 'metrics same for size'},
{'method': 'rotation', 'value': 90, 'msg': 'metrics same for rotation'},
{'method': 'oblique', 'value': True, 'msg': 'metrics same for oblique'}
]
text = "|"
def run_test(method, value, msg):
font = ft.Font(self._sans_path, size=24)
before = font.get_metrics(text)
font.__setattr__(method, value)
after = font.get_metrics(text)
self.assertNotEqual(before, after, msg)
for test in tests:
run_test(test['method'], test['value'], test['msg'])
class FreeTypeTest(unittest.TestCase):
def setUp(self):
ft.init()
def tearDown(self):
ft.quit()
def test_resolution(self):
try:
ft.set_default_resolution()
resolution = ft.get_default_resolution()
self.assertEqual(resolution, 72)
new_resolution = resolution + 10
ft.set_default_resolution(new_resolution)
self.assertEqual(ft.get_default_resolution(), new_resolution)
ft.init(resolution=resolution+20)
self.assertEqual(ft.get_default_resolution(), new_resolution)
finally:
ft.set_default_resolution()
def test_autoinit_and_autoquit(self):
pygame.init()
self.assertTrue(ft.get_init())
pygame.quit()
self.assertFalse(ft.get_init())
# Ensure autoquit is replaced at init time
pygame.init()
self.assertTrue(ft.get_init())
pygame.quit()
self.assertFalse(ft.get_init())
def test_init(self):
# Test if module initialized after calling init().
ft.quit()
ft.init()
self.assertTrue(ft.get_init())
def test_init__multiple(self):
# Test if module initialized after multiple init() calls.
ft.init()
ft.init()
self.assertTrue(ft.get_init())
def test_quit(self):
# Test if module uninitialized after calling quit().
ft.quit()
self.assertFalse(ft.get_init())
def test_quit__multiple(self):
# Test if module initialized after multiple quit() calls.
ft.quit()
ft.quit()
self.assertFalse(ft.get_init())
def test_get_init(self):
# Test if get_init() gets the init state.
self.assertTrue(ft.get_init())
def test_cache_size(self):
DEFAULT_CACHE_SIZE = 64
self.assertEqual(ft.get_cache_size(), DEFAULT_CACHE_SIZE)
ft.quit()
self.assertEqual(ft.get_cache_size(), 0)
new_cache_size = DEFAULT_CACHE_SIZE * 2
ft.init(cache_size=new_cache_size)
self.assertEqual(ft.get_cache_size(), new_cache_size)
if __name__ == '__main__':
unittest.main()