changeset 29:47bcdb1de2e8

Added implementation for enso.graphics.font.
author Atul Varma <varmaa@toolness.com>
date Sat, 23 Feb 2008 10:33:54 -0600
parents cff69f571315
children 7a16edc5b579
files enso/graphics/font.py
diffstat 1 files changed, 245 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/enso/graphics/font.py	Sat Feb 23 09:21:00 2008 -0600
+++ b/enso/graphics/font.py	Sat Feb 23 10:33:54 2008 -0600
@@ -0,0 +1,245 @@
+# Copyright (c) 2008, Humanized, Inc.
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+#    1. Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#    2. Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in the
+#       documentation and/or other materials provided with the distribution.
+#
+#    3. Neither the name of Enso nor the names of its contributors may
+#       be used to endorse or promote products derived from this
+#       software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY Humanized, Inc. ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL Humanized, Inc. BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# ----------------------------------------------------------------------------
+#
+#   enso.graphics.font
+#
+# ----------------------------------------------------------------------------
+
+"""
+    This module provides a high-level interface for registering and
+    accessing fonts, including their font metrics information, their
+    glyphs, and their rendering.
+
+    This module requires no initialization or shutdown.
+"""
+
+# ----------------------------------------------------------------------------
+# Imports
+# ----------------------------------------------------------------------------
+
+import cairo
+
+
+# ----------------------------------------------------------------------------
+# Fonts
+# ----------------------------------------------------------------------------
+
+class Font:
+    """
+    Encapsulates a font face, which describes both a given typeface
+    and style.
+    """
+    
+    def __init__( self, fileName, size, cairoContext ):
+        """
+        Creates a Font from the given filename pointing to a TrueType
+        font file, at the given size (in points).
+        """
+        
+        import os
+
+        if not os.path.exists( fileName ):
+            raise IOError( "file not found: %s" % fileName )
+
+        self.fileName = fileName
+        self.size = size
+        self.cairoContext = cairoContext
+
+        cairoContext.save()
+
+        self.loadInto( cairoContext )
+
+        # Make our font metrics information visible to the client.
+        
+        ( self.ascent,
+          self.descent,
+          self.height,
+          self.maxXAdvance,
+          self.maxYAdvance ) = cairoContext.font_extents()
+        
+        cairoContext.restore()
+
+    def getGlyph( self, char ):
+        """
+        Returns a glyph of the font corresponding to the given Unicode
+        character.
+        """
+
+        # TODO: Memoize this function.
+
+        return FontGlyph( char, self, self.cairoContext )
+
+    def getKerningDistance( self, charLeft, charRight ):
+        """
+        Returns the kerning distance (in points) between the two
+        Unicode characters for this font face.
+        """
+
+        # LONGTERM TODO: Get this to work. This may involve modifying
+        # the source code of Cairo.
+        return 0.0
+
+    def loadInto( self, cairoContext ):
+        """
+        Sets the cairo context's current font to this font.
+        """
+
+        # Note that we are using our own modified 'interpretation' of
+        # the select_font_face() function here, as outlined in our
+        # modified version of the Cairo FreeType 2 Font Module; see
+        # the file 'cairo-ft-font.c' in our modified version of the
+        # Cairo library for more information.
+
+        # TODO: Note also that our modified interpretation of the
+        # function takes an 8-bit string, so we need to do any
+        # necessary encoding/transformation from unicode file-paths
+        # here.
+
+        cairoContext.select_font_face(
+            self.fileName,
+            cairo.FONT_SLANT_NORMAL,
+            cairo.FONT_WEIGHT_NORMAL
+            )
+        cairoContext.set_font_size( self.size )
+
+
+# ----------------------------------------------------------------------------
+# Font Glyphs
+# ----------------------------------------------------------------------------
+
+class FontGlyph:
+    """
+    Encapsulates a glyph of a font face.
+    """
+    
+    def __init__( self, char, font, cairoContext ):
+        """
+        Creates the font glyph corresponding to the given Unicode
+        character, using the font specified by the given Font object
+        and the given cairo context.
+        """
+        
+        # Encode the character to UTF-8 because that's what the cairo
+        # API uses.
+        self.charAsUtf8 = char.encode("UTF-8")
+        self.char = char
+        self.font = font
+
+        cairoContext.save()
+        
+        self.font.loadInto( cairoContext )
+
+        # Make our font glyph metrics information visible to the client.
+
+        ( xBearing,
+          yBearing,
+          width,
+          height,
+          xAdvance,
+          yAdvance ) = cairoContext.text_extents( self.charAsUtf8 )
+
+        # The xMin, xMax, yMin, yMax, and advance attributes are used
+        # here to correspond to their values in this image:
+        # http://freetype.sourceforge.net/freetype2/docs/glyphs/Image3.png
+
+        self.xMin = xBearing
+        self.xMax = xBearing + width
+        self.yMin = -yBearing + height
+        self.yMax = -yBearing
+        self.advance = xAdvance
+        
+        cairoContext.restore()
+
+
+# ----------------------------------------------------------------------------
+# The Font Registry
+# ----------------------------------------------------------------------------
+
+class FontRegistry:
+    """
+    This singleton represents a registry of font faces, allowing for a
+    client to simply retrieve a Font object in a particular size and
+    style rather without having to know the location of a specific
+    TrueType file.
+    """
+    
+    def __init__( self ):
+        """
+        Initializes the font registry.
+        """
+        
+        self._registry = {}
+
+        dummySurface = cairo.ImageSurface( cairo.FORMAT_ARGB32, 1, 1 )
+        self.cairoContext = cairo.Context( dummySurface )
+
+
+    def register( self, fileName, name, italic=False ):
+        """
+        Registers the given TrueType font filename as representing the
+        given font name with the given style.
+        """
+        
+        registryKey = (name, italic)
+
+        if self._registry.has_key( registryKey ):
+            raise FontAlreadyRegisteredError( registryKey )
+        else:
+            self._registry[registryKey] = fileName
+
+    def get( self, name, size, italic=False ):
+        """
+        Retrieves a Font object corresponding to the given font name
+        at the given size and style.
+        """
+
+        # TODO: Memoize this function.
+        
+        registryKey = (name, italic)
+
+        fileName = self._registry[registryKey]
+        return Font( fileName, size, self.cairoContext )
+
+
+class FontAlreadyRegisteredError( Exception ):
+    """
+    Exception raised when the client attempts to register a font when
+    that font has already been registered.
+    """
+
+    pass
+
+
+# ----------------------------------------------------------------------------
+# Singleton Instance
+# ----------------------------------------------------------------------------
+
+# The font registry singleton instance.
+theFontRegistry = FontRegistry()