On Fri, Jan 13, 2006 at 11:34:16AM +1100, Rene Dudfield wrote: > I tried changing PyUnicode_AsEncodedObject to PyUnicode_AsEncodedString. > > I think it works... but haven't really tested it fully. I think this > should be ok. > > If someone is using unicode fonts, that can test pygame cvs please do! > Also a little example that tests unicode fonts would be very handy. Here's a little app (attached, unless I forget) that lets you select any of the system fonts returned by pygame.fonts.get_fonts, and display the first 1023 Unicode characters in that font. It is very easy to crash the application by just moving around and rendering different fonts. There appears to be some memory corruption going on, as the C library complains about its malloc arena being corrupted: *** glibc detected *** free(): invalid next size (fast): 0x08254c28 *** Aborted The crashes are not very deterministic: if the first font I choose to render is 'arial', I get the crash right away, but if I render a couple of other fonts first, I can then 'render' arial just fine, and get a crash some time later. I can crash both PyGame 1.6.2 from Ubuntu, and 1.7.2pre that I checked out from CVS today. Another, smaller problem is that not all of the fonts returned by pygame.fonts.get_fonts() can be actually used. pygame.fonts.match_font( fontname) returns None for those fonts. It seems that all of the unavailable fonts have commas in their names (e.g., "padmaa,padmmaa"). fc-list mentions them like this: /usr/share/fonts/truetype/ttf-gujarati-fonts/padmaa-Medium-0.5.ttf: padmaa,padmmaa:style=regular,Medium /usr/share/fonts/truetype/ttf-gujarati-fonts/padmaa-Bold-0.5.ttf: padmaa,padmmaa:style=Bold,medium Marius Gedminas -- "What's the name of the new OO COBOL -- an equivalent of C++?" "ADD 1 TO COBOL GIVING COBOL"
#!/usr/bin/env pytho
"""
System font browser for PyGame, version 0.1.
On the left you see a list of all system fonts found by PyGame. Select
a font using arrow keys, then press Enter to see a list of characters
(from the Unicode range U+0001 to U+0400) on the right. Alphanumeric
characters are shown brighter than punctuation or control characters.
Esc quits.
This appliction seems to be just the things to identify bugs in PyGame (or
maybe SDL_ttf): rendering some fonts on my system apparently overwrites random
memory locations and causes the application to crash with messages like
*** glibc detected *** free(): invalid next size (fast): 0x08254358 ***
Aborted
Written by Marius Gedminas <mgedmin@xxxxxxxx>. This program can be distributed
with the same licence as PyGame itself, which is the GNU LGPL 2.1.
"""
import sys
import pygame
from pygame.locals import *
MODE = (800, 600)
class ListBox:
bgcolor = (0, 0, 0)
fgcolor = (255, 255, 255)
selected_bgcolor = (127, 127, 255)
selected_fgcolor = (255, 255, 255)
padding = (2, 1)
def __init__(self, rect, font, items):
self.rect = rect
self.font = font
self.items = items
self.top = 0
self.selected = 0
self.itemheight = self.font.get_linesize() + 2 * self.padding[1]
self.pagesize = max(1, self.rect.height / self.itemheight)
self.buf = pygame.Surface(self.rect.size)
self.render()
def render(self):
self.buf.fill(self.bgcolor)
x, y = self.padding
for n in range(self.top, len(self.items)):
item = self.items[n]
if n == self.selected:
self.buf.fill(self.selected_bgcolor,
(x - self.padding[0], y - self.padding[1],
self.buf.get_width(), self.itemheight))
img = self.font.render(item, True, self.selected_fgcolor)
else:
img = self.font.render(item, True, self.fgcolor)
self.buf.blit(img, (x, y))
y += self.itemheight
if y >= self.buf.get_height():
break
def draw(self, surface):
surface.blit(self.buf, self.rect)
def select_next(self):
if self.selected + 1 < len(self.items):
self.selected += 1
if self.selected >= self.top + self.pagesize:
self.top = self.selected - self.pagesize + 1
self.render()
def select_prev(self):
if self.selected > 0:
self.selected -= 1
if self.selected < self.top:
self.top = self.selected
self.render()
def select_first(self):
self.selected = 0
self.top = 0
self.render()
def select_last(self):
self.selected = len(self.items) - 1
self.top = max(0, self.selected - self.pagesize + 1)
self.render()
def page_up(self):
self.selected = max(0, self.selected - self.pagesize + 1)
self.top = max(0, self.top - self.pagesize + 1)
self.render()
def page_down(self):
self.selected = min(len(self.items) - 1,
self.selected + self.pagesize - 1)
self.top = min(self.selected, self.top + self.pagesize - 1)
self.render()
class FontBox:
font_size = 12
bgcolor = (0, 20, 0)
fgcolor = (200, 250, 255)
nonalnum_fgcolor = (100, 150, 155)
errorcolor = (200, 50, 50)
padding = (2, 1)
# Range of characters to display
minchar = 1
maxchar = 0x0400-1
# How many characters to examine to determine bounding box limits
chars_to_determine_font_size = 254
def __init__(self, rect, fontname=None):
self.rect = rect
self.buf = pygame.Surface(self.rect.size)
self.set_font(fontname)
def set_font(self, fontname):
self.font = None
self.fontname = fontname
if self.fontname is not None:
self.filename = pygame.font.match_font(fontname)
if self.filename:
# Intentionally not using SysFont here: I want no fallback
self.font = pygame.font.Font(self.filename, self.font_size)
if self.font is not None:
self.itemheight = self.font.get_linesize() + 2 * self.padding[1]
self.itemwidth = (max([self.font.size(unichr(self.minchar + c))[0]
for c in range(self.chars_to_determine_font_size)])
+ 2 * self.padding[0])
self.render()
def render(self):
self.buf.fill(self.bgcolor)
if self.fontname is None:
return
if self.font is None:
return
width = self.rect.width - 2 * self.padding[0]
items_per_row = max(width / self.itemwidth, 1)
origin_x = self.padding[0] + width % self.itemwidth / 2
innerwidth = self.itemwidth - 2 * self.padding[0]
for row, y in enumerate(range(self.padding[1], self.rect.height,
self.itemheight)):
x = origin_x
for col in range(items_per_row):
chr = unichr(row * items_per_row + col)
if self.minchar <= ord(chr) <= self.maxchar:
if chr.isalnum():
color = self.fgcolor
else:
color = self.nonalnum_fgcolor
try:
img = self.font.render(chr, True, color)
except pygame.error:
self.buf.fill(self.errorcolor,
(x, y,
self.itemwidth - self.padding[0] * 2,
self.itemheight - self.padding[1] * 2))
else:
self.buf.blit(img,
(x + (innerwidth - img.get_width()) / 2,
y))
x += self.itemwidth
def draw(self, surface):
surface.blit(self.buf, self.rect)
class FontBrowser:
default_font = 'Verdana'
def __init__(self, screen):
self.screen = screen
default_font = pygame.font.SysFont(self.default_font, 24)
fontnames = pygame.font.get_fonts()
fontnames.sort()
rect = screen.get_rect()
rect.width /= 2
rect.inflate_ip(-8, -8)
self.fonts = ListBox(rect, default_font, fontnames)
rect = rect.move(screen.get_width() / 2, 0)
self.chars = FontBox(rect)
self.draw()
self.draw_chars()
def draw(self):
self.fonts.draw(self.screen)
pygame.display.update(self.fonts.rect)
def draw_chars(self):
self.chars.draw(self.screen)
pygame.display.update(self.chars.rect)
def process_events(self, events):
for e in events:
if e.type == QUIT:
sys.exit(0)
if e.type == KEYDOWN:
if e.key == K_ESCAPE:
sys.exit(0)
elif e.key == K_UP:
self.fonts.select_prev()
self.draw()
elif e.key == K_DOWN:
self.fonts.select_next()
self.draw()
elif e.key == K_HOME:
self.fonts.select_first()
self.draw()
elif e.key == K_END:
self.fonts.select_last()
self.draw()
elif e.key == K_PAGEUP:
self.fonts.page_up()
self.draw()
elif e.key == K_PAGEDOWN:
self.fonts.page_down()
self.draw()
elif e.key == K_RETURN:
self.chars.set_font(self.fonts.items[self.fonts.selected])
self.draw_chars()
def main():
pygame.init()
pygame.display.set_caption("PyGame Font Browser")
screen = pygame.display.set_mode(MODE)
pygame.key.set_repeat(250, 1000/30)
browser = FontBrowser(screen)
while True:
browser.process_events([pygame.event.wait()])
if __name__ == '__main__':
main()
Attachment:
signature.asc
Description: Digital signature