Mercurial > enso_core
comparison enso/graphics/font.py @ 29:47bcdb1de2e8
Added implementation for enso.graphics.font.
author | Atul Varma <varmaa@toolness.com> |
---|---|
date | Sat, 23 Feb 2008 10:33:54 -0600 |
parents | 203d6a15652c |
children | 605d8cb2728c |
comparison
equal
deleted
inserted
replaced
28:cff69f571315 | 29:47bcdb1de2e8 |
---|---|
1 # Copyright (c) 2008, Humanized, Inc. | |
2 # All rights reserved. | |
3 # | |
4 # Redistribution and use in source and binary forms, with or without | |
5 # modification, are permitted provided that the following conditions are met: | |
6 # | |
7 # 1. Redistributions of source code must retain the above copyright | |
8 # notice, this list of conditions and the following disclaimer. | |
9 # | |
10 # 2. Redistributions in binary form must reproduce the above copyright | |
11 # notice, this list of conditions and the following disclaimer in the | |
12 # documentation and/or other materials provided with the distribution. | |
13 # | |
14 # 3. Neither the name of Enso nor the names of its contributors may | |
15 # be used to endorse or promote products derived from this | |
16 # software without specific prior written permission. | |
17 # | |
18 # THIS SOFTWARE IS PROVIDED BY Humanized, Inc. ``AS IS'' AND ANY | |
19 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
20 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
21 # DISCLAIMED. IN NO EVENT SHALL Humanized, Inc. BE LIABLE FOR ANY | |
22 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
23 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
24 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
25 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
27 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
28 | |
29 # ---------------------------------------------------------------------------- | |
30 # | |
31 # enso.graphics.font | |
32 # | |
33 # ---------------------------------------------------------------------------- | |
34 | |
35 """ | |
36 This module provides a high-level interface for registering and | |
37 accessing fonts, including their font metrics information, their | |
38 glyphs, and their rendering. | |
39 | |
40 This module requires no initialization or shutdown. | |
41 """ | |
42 | |
43 # ---------------------------------------------------------------------------- | |
44 # Imports | |
45 # ---------------------------------------------------------------------------- | |
46 | |
47 import cairo | |
48 | |
49 | |
50 # ---------------------------------------------------------------------------- | |
51 # Fonts | |
52 # ---------------------------------------------------------------------------- | |
53 | |
54 class Font: | |
55 """ | |
56 Encapsulates a font face, which describes both a given typeface | |
57 and style. | |
58 """ | |
59 | |
60 def __init__( self, fileName, size, cairoContext ): | |
61 """ | |
62 Creates a Font from the given filename pointing to a TrueType | |
63 font file, at the given size (in points). | |
64 """ | |
65 | |
66 import os | |
67 | |
68 if not os.path.exists( fileName ): | |
69 raise IOError( "file not found: %s" % fileName ) | |
70 | |
71 self.fileName = fileName | |
72 self.size = size | |
73 self.cairoContext = cairoContext | |
74 | |
75 cairoContext.save() | |
76 | |
77 self.loadInto( cairoContext ) | |
78 | |
79 # Make our font metrics information visible to the client. | |
80 | |
81 ( self.ascent, | |
82 self.descent, | |
83 self.height, | |
84 self.maxXAdvance, | |
85 self.maxYAdvance ) = cairoContext.font_extents() | |
86 | |
87 cairoContext.restore() | |
88 | |
89 def getGlyph( self, char ): | |
90 """ | |
91 Returns a glyph of the font corresponding to the given Unicode | |
92 character. | |
93 """ | |
94 | |
95 # TODO: Memoize this function. | |
96 | |
97 return FontGlyph( char, self, self.cairoContext ) | |
98 | |
99 def getKerningDistance( self, charLeft, charRight ): | |
100 """ | |
101 Returns the kerning distance (in points) between the two | |
102 Unicode characters for this font face. | |
103 """ | |
104 | |
105 # LONGTERM TODO: Get this to work. This may involve modifying | |
106 # the source code of Cairo. | |
107 return 0.0 | |
108 | |
109 def loadInto( self, cairoContext ): | |
110 """ | |
111 Sets the cairo context's current font to this font. | |
112 """ | |
113 | |
114 # Note that we are using our own modified 'interpretation' of | |
115 # the select_font_face() function here, as outlined in our | |
116 # modified version of the Cairo FreeType 2 Font Module; see | |
117 # the file 'cairo-ft-font.c' in our modified version of the | |
118 # Cairo library for more information. | |
119 | |
120 # TODO: Note also that our modified interpretation of the | |
121 # function takes an 8-bit string, so we need to do any | |
122 # necessary encoding/transformation from unicode file-paths | |
123 # here. | |
124 | |
125 cairoContext.select_font_face( | |
126 self.fileName, | |
127 cairo.FONT_SLANT_NORMAL, | |
128 cairo.FONT_WEIGHT_NORMAL | |
129 ) | |
130 cairoContext.set_font_size( self.size ) | |
131 | |
132 | |
133 # ---------------------------------------------------------------------------- | |
134 # Font Glyphs | |
135 # ---------------------------------------------------------------------------- | |
136 | |
137 class FontGlyph: | |
138 """ | |
139 Encapsulates a glyph of a font face. | |
140 """ | |
141 | |
142 def __init__( self, char, font, cairoContext ): | |
143 """ | |
144 Creates the font glyph corresponding to the given Unicode | |
145 character, using the font specified by the given Font object | |
146 and the given cairo context. | |
147 """ | |
148 | |
149 # Encode the character to UTF-8 because that's what the cairo | |
150 # API uses. | |
151 self.charAsUtf8 = char.encode("UTF-8") | |
152 self.char = char | |
153 self.font = font | |
154 | |
155 cairoContext.save() | |
156 | |
157 self.font.loadInto( cairoContext ) | |
158 | |
159 # Make our font glyph metrics information visible to the client. | |
160 | |
161 ( xBearing, | |
162 yBearing, | |
163 width, | |
164 height, | |
165 xAdvance, | |
166 yAdvance ) = cairoContext.text_extents( self.charAsUtf8 ) | |
167 | |
168 # The xMin, xMax, yMin, yMax, and advance attributes are used | |
169 # here to correspond to their values in this image: | |
170 # http://freetype.sourceforge.net/freetype2/docs/glyphs/Image3.png | |
171 | |
172 self.xMin = xBearing | |
173 self.xMax = xBearing + width | |
174 self.yMin = -yBearing + height | |
175 self.yMax = -yBearing | |
176 self.advance = xAdvance | |
177 | |
178 cairoContext.restore() | |
179 | |
180 | |
181 # ---------------------------------------------------------------------------- | |
182 # The Font Registry | |
183 # ---------------------------------------------------------------------------- | |
184 | |
185 class FontRegistry: | |
186 """ | |
187 This singleton represents a registry of font faces, allowing for a | |
188 client to simply retrieve a Font object in a particular size and | |
189 style rather without having to know the location of a specific | |
190 TrueType file. | |
191 """ | |
192 | |
193 def __init__( self ): | |
194 """ | |
195 Initializes the font registry. | |
196 """ | |
197 | |
198 self._registry = {} | |
199 | |
200 dummySurface = cairo.ImageSurface( cairo.FORMAT_ARGB32, 1, 1 ) | |
201 self.cairoContext = cairo.Context( dummySurface ) | |
202 | |
203 | |
204 def register( self, fileName, name, italic=False ): | |
205 """ | |
206 Registers the given TrueType font filename as representing the | |
207 given font name with the given style. | |
208 """ | |
209 | |
210 registryKey = (name, italic) | |
211 | |
212 if self._registry.has_key( registryKey ): | |
213 raise FontAlreadyRegisteredError( registryKey ) | |
214 else: | |
215 self._registry[registryKey] = fileName | |
216 | |
217 def get( self, name, size, italic=False ): | |
218 """ | |
219 Retrieves a Font object corresponding to the given font name | |
220 at the given size and style. | |
221 """ | |
222 | |
223 # TODO: Memoize this function. | |
224 | |
225 registryKey = (name, italic) | |
226 | |
227 fileName = self._registry[registryKey] | |
228 return Font( fileName, size, self.cairoContext ) | |
229 | |
230 | |
231 class FontAlreadyRegisteredError( Exception ): | |
232 """ | |
233 Exception raised when the client attempts to register a font when | |
234 that font has already been registered. | |
235 """ | |
236 | |
237 pass | |
238 | |
239 | |
240 # ---------------------------------------------------------------------------- | |
241 # Singleton Instance | |
242 # ---------------------------------------------------------------------------- | |
243 | |
244 # The font registry singleton instance. | |
245 theFontRegistry = FontRegistry() |