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