def render(self, text): # Convert text to UCS2 text_len = len(text) text_ucs2 = str_ucs2(text) # Create layout override handler to extract device advance value. override_spec = ATSULayoutOperationOverrideSpecifier() override_spec.operationSelector = \ kATSULayoutOperationPostLayoutAdjustment override_spec.overrideUPP = \ ATSUDirectLayoutOperationOverrideUPP(self._layout_callback) # Create ATSU text layout for this text and font layout = c_void_p() carbon.ATSUCreateTextLayout(byref(layout)) set_layout_attributes( layout, { kATSUCGContextTag: self._bitmap_context, kATSULayoutOperationOverrideTag: override_spec }) carbon.ATSUSetTextPointerLocation(layout, text_ucs2, kATSUFromTextBeginning, kATSUToTextEnd, text_len) carbon.ATSUSetRunStyle(layout, self.font.atsu_style, kATSUFromTextBeginning, kATSUToTextEnd) # Turning on transient font matching screws up font layout # predictability when strange fonts are installed # <ah> Don't believe this. Can't get foreign/special characters # without transient on. carbon.ATSUSetTransientFontMatching(layout, True) # Get bitmap dimensions required rect = Rect() carbon.ATSUMeasureTextImage(layout, kATSUFromTextBeginning, kATSUToTextEnd, 0, 0, byref(rect)) image_width = rect.right - rect.left + 2 image_height = rect.bottom - rect.top + 2 baseline = rect.bottom + 1 lsb = rect.left # Resize Quartz context if necessary if (image_width > self._bitmap_rect.size.width or image_height > self._bitmap_rect.size.height): self._create_bitmap_context( int(max(image_width, self._bitmap_rect.size.width)), int(max(image_height, self._bitmap_rect.size.height))) set_layout_attributes(layout, {kATSUCGContextTag: self._bitmap_context}) # Draw to the bitmap carbon.CGContextClearRect(self._bitmap_context, self._bitmap_rect) carbon.ATSUDrawText(layout, 0, kATSUToTextEnd, fixed(-lsb + 1), fixed(baseline)) advance = self._glyph_advance # Round advance to nearest int. It actually looks good with sub-pixel # advance as well -- Helvetica at 12pt is more tightly spaced, but # Times New Roman at 12pt is too light. With integer positioning # overall look seems darker and perhaps more uniform. It's also more # similar (programmatically) to Win32 and FreeType. Still, worth # messing around with (comment out next line) if you're interested. advance = int(round(advance)) # Fix advance for zero-width space if text == u'\u200b': advance = 0 # A negative pitch is required, but it is much faster to load the # glyph upside-down and flip the tex_coords. Note region used # to start at top of glyph image. pitch = int(4 * self._bitmap_rect.size.width) image = pyglet.image.ImageData(image_width, self._bitmap_rect.size.height, 'RGBA', self._bitmap, pitch) skip_rows = int(self._bitmap_rect.size.height - image_height) image = image.get_region(0, skip_rows, image.width, image_height) glyph = self.font.create_glyph(image) glyph.set_bearings(baseline, lsb - 1, int(advance)) t = list(glyph.tex_coords) glyph.tex_coords = t[9:12] + t[6:9] + t[3:6] + t[:3] return glyph
def render(self, text): # Convert text to UCS2 text_len = len(text) text = str_ucs2(text) # Create ATSU text layout for this text and font layout = c_void_p() carbon.ATSUCreateTextLayout(byref(layout)) set_layout_attributes(layout, {kATSUCGContextTag: self._bitmap_context}) carbon.ATSUSetTextPointerLocation(layout, text, kATSUFromTextBeginning, kATSUToTextEnd, text_len) carbon.ATSUSetRunStyle(layout, self.font.atsu_style, kATSUFromTextBeginning, kATSUToTextEnd) # Turning on transient font matching screws up font layout # predictability when strange fonts are installed carbon.ATSUSetTransientFontMatching(layout, False) # Get bitmap dimensions required rect = Rect() carbon.ATSUMeasureTextImage(layout, kATSUFromTextBeginning, kATSUToTextEnd, 0, 0, byref(rect)) image_width = rect.right - rect.left + 2 image_height = rect.bottom - rect.top + 2 baseline = rect.bottom + 1 lsb = rect.left # Resize Quartz context if necessary if (image_width > self._bitmap_rect.size.width or image_height > self._bitmap_rect.size.height): self._create_bitmap_context( int(max(image_width, self._bitmap_rect.size.width)), int(max(image_height, self._bitmap_rect.size.height))) set_layout_attributes(layout, {kATSUCGContextTag: self._bitmap_context}) # Get typographic box, which gives advance. bounds_actual = c_uint32() bounds = ATSTrapezoid() carbon.ATSUGetGlyphBounds(layout, 0, 0, kATSUFromTextBeginning, kATSUToTextEnd, kATSUseDeviceOrigins, 1, byref(bounds), byref(bounds_actual)) advance = fix2float(bounds.lowerRight.x) - fix2float( bounds.lowerLeft.x) # Draw to the bitmap carbon.CGContextClearRect(self._bitmap_context, self._bitmap_rect) carbon.ATSUDrawText(layout, 0, kATSUToTextEnd, fixed(-lsb + 1), fixed(baseline)) # A negative pitch is required, but it is much faster to load the # glyph upside-down and flip the tex_coords. Note region used # to start at top of glyph image. pitch = int(4 * self._bitmap_rect.size.width) image = pyglet.image.ImageData(image_width, self._bitmap_rect.size.height, 'RGBA', self._bitmap, pitch) skip_rows = int(self._bitmap_rect.size.height - image_height) image = image.get_region(0, skip_rows, image.width, image_height) glyph = self.font.create_glyph(image) glyph.set_bearings(baseline, lsb - 1, int(advance)) t = list(glyph.tex_coords) glyph.tex_coords = t[9:12] + t[6:9] + t[3:6] + t[:3] return glyph