~ubuntu-branches/ubuntu/feisty/fonttools/feisty

« back to all changes in this revision

Viewing changes to Lib/fontTools/ttLib/test/ttBrowser.py

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Fok
  • Date: 2003-11-18 00:53:59 UTC
  • Revision ID: james.westby@ubuntu.com-20031118005359-pqirsxbgdz0f0xmx
Tags: upstream-1.99+2.0b1+cvs20031014
Import upstream version 1.99+2.0b1+cvs20031014

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""Mac-only TrueType browser window."""
 
2
 
 
3
from fontTools import ttLib
 
4
from fontTools.ttLib import macUtils
 
5
import macfs
 
6
import PyBrowser
 
7
import W, Lists
 
8
import os
 
9
import ATM
 
10
import Numeric
 
11
import Qd
 
12
from rf.views.wGlyphList import GlyphList
 
13
 
 
14
 
 
15
class TableBrowser:
 
16
        
 
17
        def __init__(self, path=None, ttFont=None, res_index=None):
 
18
                W.SetCursor('watch')
 
19
                if path is None:
 
20
                        self.ttFont = ttFont
 
21
                        self.filename = "????"
 
22
                else:
 
23
                        self.ttFont = ttLib.TTFont(path, res_index)
 
24
                        if res_index is None:
 
25
                                self.filename = os.path.basename(path)
 
26
                        else:
 
27
                                self.filename = os.path.basename(path) + " - " + str(res_index)
 
28
                self.currentglyph = None
 
29
                self.glyphs = {}
 
30
                self.buildinterface()
 
31
        
 
32
        def buildinterface(self):
 
33
                buttonwidth = 120
 
34
                glyphlistwidth = 150
 
35
                hmargin = 10
 
36
                vmargin = 8
 
37
                title = self.filename
 
38
                tables = self.ttFont.keys()
 
39
                tables.sort()
 
40
                self.w = w = W.Window((500, 300), title, minsize = (400, 200))
 
41
                w.browsetablebutton = W.Button((hmargin, 32, buttonwidth, 16), "Browse table�", 
 
42
                                self.browsetable)
 
43
                w.browsefontbutton = W.Button((hmargin, vmargin, buttonwidth, 16), "Browse font�", 
 
44
                                self.browsefont)
 
45
                w.tablelist = W.List((hmargin, 56, buttonwidth, -128), tables, self.tablelisthit)
 
46
                
 
47
                w.divline1 = W.VerticalLine((buttonwidth + 2 * hmargin, vmargin, 1, -vmargin))
 
48
                
 
49
                gleft = buttonwidth + 3 * hmargin + 1
 
50
                
 
51
                hasGlyfTable = self.ttFont.has_key('glyf')
 
52
                
 
53
                glyphnames = self.ttFont.getGlyphNames2()  # caselessly sorted glyph names
 
54
                
 
55
                if hasGlyfTable:
 
56
                        w.glyphlist = GlyphList((gleft, 56, glyphlistwidth, -vmargin), 
 
57
                                        glyphnames, self.glyphlisthit)
 
58
                        
 
59
                        w.divline2 = W.VerticalLine((buttonwidth + glyphlistwidth + 4 * hmargin + 2, 
 
60
                                        vmargin, 1, -vmargin))
 
61
                        
 
62
                        yMin = self.ttFont['head'].yMin
 
63
                        yMax = self.ttFont['head'].yMax
 
64
                        w.gviewer = GlyphViewer((buttonwidth + glyphlistwidth + 5 * hmargin + 3, 
 
65
                                        vmargin, -hmargin, -vmargin), yMin, yMax)
 
66
                        
 
67
                        w.showpoints = W.CheckBox((gleft, vmargin, glyphlistwidth, 16), "Show points", 
 
68
                                        self.w.gviewer.toggleshowpoints)
 
69
                        w.showpoints.set(self.w.gviewer.showpoints)
 
70
                        w.showlines = W.CheckBox((gleft, vmargin + 24, glyphlistwidth, 16), "Show lines",
 
71
                                        self.w.gviewer.toggleshowlines)
 
72
                        w.showlines.set(self.w.gviewer.showlines)
 
73
                else:
 
74
                        w.glyphlist = GlyphList((gleft, 56, glyphlistwidth, -vmargin), 
 
75
                                        glyphnames)
 
76
                        w.noGlyphTable = W.TextBox((gleft, vmargin, -20, 20), "no 'glyf' table found")
 
77
                
 
78
                
 
79
                w.setdefaultbutton(w.browsetablebutton)
 
80
                
 
81
                w.tocurrentfont = W.Button((hmargin, -120, buttonwidth, 16), "Copy to current font", self.copytocurrentfont)
 
82
                w.fromcurrentfont = W.Button((hmargin, -96, buttonwidth, 16), "Copy from current font", self.copyfromcurrentfont)
 
83
                w.saveflat = W.Button((hmargin, -72, buttonwidth, 16), "Save as flat file�", self.saveflat)
 
84
                w.savesuitcasebutton = W.Button((hmargin, -48, buttonwidth, 16), "Save as suitcase�", self.savesuitcase)
 
85
                w.savexmlbutton = W.Button((hmargin, -24, buttonwidth, 16), "Save as XML�", self.saveXML)
 
86
                
 
87
                w.open()
 
88
                w.browsetablebutton.enable(0)
 
89
        
 
90
        def browsetable(self):
 
91
                self.tablelisthit(1)
 
92
        
 
93
        def browsefont(self):
 
94
                PyBrowser.Browser(self.ttFont)
 
95
        
 
96
        def copytocurrentfont(self):
 
97
                pass
 
98
                
 
99
        def copyfromcurrentfont(self):
 
100
                pass
 
101
                
 
102
        def saveflat(self):
 
103
                path = putfile("Save font as flat file:", self.filename, ".TTF")
 
104
                if path:
 
105
                        W.SetCursor('watch')
 
106
                        self.ttFont.save(path)
 
107
        
 
108
        def savesuitcase(self):
 
109
                path = putfile("Save font as suitcase:", self.filename, ".suit")
 
110
                if path:
 
111
                        W.SetCursor('watch')
 
112
                        self.ttFont.save(path, 1)
 
113
        
 
114
        def saveXML(self):
 
115
                path = putfile("Save font as XML text file:", self.filename, ".ttx")
 
116
                if path:
 
117
                        W.SetCursor('watch')
 
118
                        pb = macUtils.ProgressBar("Saving %s as XML�" % self.filename)
 
119
                        try:
 
120
                                self.ttFont.saveXML(path, pb)
 
121
                        finally:
 
122
                                pb.close()
 
123
        
 
124
        def glyphlisthit(self, isDbl):
 
125
                sel = self.w.glyphlist.getselectedobjects()
 
126
                if not sel or sel[0] == self.currentglyph:
 
127
                        return
 
128
                self.currentglyph = sel[0]
 
129
                if self.glyphs.has_key(self.currentglyph):
 
130
                        g = self.glyphs[self.currentglyph]
 
131
                else:
 
132
                        g = Glyph(self.ttFont, self.currentglyph)
 
133
                        self.glyphs[self.currentglyph] = g
 
134
                self.w.gviewer.setglyph(g)
 
135
        
 
136
        def tablelisthit(self, isdbl):
 
137
                if isdbl:
 
138
                        for tag in self.w.tablelist.getselectedobjects():
 
139
                                table = self.ttFont[tag]
 
140
                                if tag == 'glyf':
 
141
                                        W.SetCursor('watch')
 
142
                                        for glyphname in self.ttFont.getGlyphOrder():
 
143
                                                try:
 
144
                                                        glyph = table[glyphname]
 
145
                                                except KeyError:
 
146
                                                        pass # incomplete font, oh well.
 
147
                                PyBrowser.Browser(table)
 
148
                else:
 
149
                        sel = self.w.tablelist.getselection()
 
150
                        if sel:
 
151
                                self.w.browsetablebutton.enable(1)
 
152
                        else:
 
153
                                self.w.browsetablebutton.enable(0)
 
154
 
 
155
 
 
156
class Glyph:
 
157
        
 
158
        def __init__(self, ttFont, glyphName):
 
159
                ttglyph = ttFont['glyf'][glyphName]
 
160
                self.iscomposite = ttglyph.numberOfContours == -1
 
161
                self.width, self.lsb = ttFont['hmtx'][glyphName]
 
162
                if ttglyph.numberOfContours == 0:
 
163
                        self.xMin = 0
 
164
                        self.contours = []
 
165
                        return
 
166
                self.xMin = ttglyph.xMin
 
167
                coordinates, endPts, flags = ttglyph.getCoordinates(ttFont['glyf'])
 
168
                self.contours = []
 
169
                self.flags = []
 
170
                startpt = 0
 
171
                for endpt in endPts:
 
172
                        self.contours.append(Numeric.array(coordinates[startpt:endpt+1]))
 
173
                        self.flags.append(flags[startpt:endpt+1])
 
174
                        startpt = endpt + 1
 
175
        
 
176
        def getcontours(self, scale, move):
 
177
                contours = []
 
178
                for i in range(len(self.contours)):
 
179
                        contours.append(((self.contours[i] * Numeric.array(scale) + move), self.flags[i]))
 
180
                return contours
 
181
 
 
182
 
 
183
class GlyphViewer(W.Widget):
 
184
        
 
185
        def __init__(self, possize, yMin, yMax):
 
186
                W.Widget.__init__(self, possize)
 
187
                self.glyph = None
 
188
                extra = 0.02 * (yMax-yMin)
 
189
                self.yMin, self.yMax = yMin - extra, yMax + extra
 
190
                self.showpoints = 1
 
191
                self.showlines = 1
 
192
        
 
193
        def toggleshowpoints(self, onoff):
 
194
                self.showpoints = onoff
 
195
                self.SetPort()
 
196
                self.draw()
 
197
        
 
198
        def toggleshowlines(self, onoff):
 
199
                self.showlines = onoff
 
200
                self.SetPort()
 
201
                self.draw()
 
202
        
 
203
        def setglyph(self, glyph):
 
204
                self.glyph = glyph
 
205
                self.SetPort()
 
206
                self.draw()
 
207
                
 
208
        def draw(self, visRgn=None):
 
209
                # This a HELL of a routine, but it's pretty damn fast...
 
210
                import Qd
 
211
                if not self._visible:
 
212
                        return
 
213
                Qd.EraseRect(Qd.InsetRect(self._bounds, 1, 1))
 
214
                cliprgn = Qd.NewRgn()
 
215
                savergn = Qd.NewRgn()
 
216
                Qd.RectRgn(cliprgn, self._bounds)
 
217
                Qd.GetClip(savergn)
 
218
                Qd.SetClip(cliprgn)
 
219
                try:
 
220
                        if self.glyph:
 
221
                                l, t, r, b = Qd.InsetRect(self._bounds, 1, 1)
 
222
                                height = b - t
 
223
                                scale = float(height) / (self.yMax - self.yMin)
 
224
                                topoffset = t + scale * self.yMax
 
225
                                width = scale * self.glyph.width
 
226
                                lsb = scale * self.glyph.lsb
 
227
                                xMin = scale * self.glyph.xMin
 
228
                                # XXXX this is not correct when USE_MY_METRICS is set in component!
 
229
                                leftoffset = l + 0.5 * (r - l - width)
 
230
                                gleftoffset = leftoffset - xMin + lsb
 
231
                                if self.showlines:
 
232
                                        Qd.RGBForeColor((0xafff, 0xafff, 0xafff))
 
233
                                        # left sidebearing
 
234
                                        Qd.MoveTo(leftoffset, t)
 
235
                                        Qd.LineTo(leftoffset, b - 1)
 
236
                                        # right sidebearing
 
237
                                        Qd.MoveTo(leftoffset + width, t)
 
238
                                        Qd.LineTo(leftoffset + width, b - 1)
 
239
                                        # baseline
 
240
                                        Qd.MoveTo(l, topoffset)
 
241
                                        Qd.LineTo(r - 1, topoffset)
 
242
                                        
 
243
                                        # origin
 
244
                                        Qd.RGBForeColor((0x5fff, 0, 0))
 
245
                                        Qd.MoveTo(gleftoffset, topoffset - 16)
 
246
                                        Qd.LineTo(gleftoffset, topoffset + 16)
 
247
                                        # reset color
 
248
                                        Qd.RGBForeColor((0, 0, 0))
 
249
                                
 
250
                                if self.glyph.iscomposite:
 
251
                                        Qd.RGBForeColor((0x7fff, 0x7fff, 0x7fff))
 
252
                                
 
253
                                ATM.startFillATM()
 
254
                                contours = self.glyph.getcontours((scale, -scale), (gleftoffset, topoffset))
 
255
                                for contour, flags in contours:
 
256
                                        currentpoint = None
 
257
                                        done_moveto = 0
 
258
                                        i = 0
 
259
                                        nPoints = len(contour)
 
260
                                        while i < nPoints:
 
261
                                                pt = contour[i]
 
262
                                                if flags[i]:
 
263
                                                        # onCurve
 
264
                                                        currentpoint = lineto(pt, done_moveto)
 
265
                                                else:
 
266
                                                        if not currentpoint:
 
267
                                                                if not flags[i-1]:
 
268
                                                                        currentpoint = 0.5 * (contour[i-1] + pt)
 
269
                                                                else:
 
270
                                                                        currentpoint = contour[i-1]
 
271
                                                        if not flags[(i+1) % nPoints]:
 
272
                                                                endPt = 0.5 * (pt + contour[(i+1) % nPoints])
 
273
                                                        else:
 
274
                                                                endPt = contour[(i+1) % nPoints]
 
275
                                                                i = i + 1
 
276
                                                        # offCurve
 
277
                                                        currentpoint = qcurveto(currentpoint, 
 
278
                                                                        pt, endPt, done_moveto)
 
279
                                                done_moveto = 1
 
280
                                                i = i + 1
 
281
                                        ATM.fillClosePathATM()
 
282
                                ATM.endFillATM()
 
283
                                # draw point markers
 
284
                                if self.showpoints:
 
285
                                        for contour, flags in contours:
 
286
                                                Qd.RGBForeColor((0, 0xffff, 0))
 
287
                                                for i in range(len(contour)):
 
288
                                                        (x, y) = contour[i]
 
289
                                                        onCurve = flags[i] & 0x1
 
290
                                                        if onCurve:
 
291
                                                                Qd.PaintRect(Qd.InsetRect((x, y, x, y), -2, -2))
 
292
                                                        else:
 
293
                                                                Qd.PaintOval(Qd.InsetRect((x, y, x, y), -2, -2))
 
294
                                                        Qd.RGBForeColor((0xffff, 0, 0))
 
295
                                                Qd.RGBForeColor((0, 0, 0))
 
296
                        Qd.FrameRect(self._bounds)
 
297
                finally:
 
298
                        Qd.SetClip(savergn)
 
299
                        Qd.DisposeRgn(cliprgn)
 
300
                        Qd.DisposeRgn(savergn)
 
301
 
 
302
 
 
303
extensions = [".suit", ".xml", ".ttx", ".TTF", ".ttf"]
 
304
 
 
305
def putfile(prompt, filename, newextension):
 
306
        for ext in extensions:
 
307
                if filename[-len(ext):] == ext:
 
308
                        filename = filename[:-len(ext)] + newextension
 
309
                        break
 
310
        else:
 
311
                filename = filename + newextension
 
312
        fss, ok = macfs.StandardPutFile(prompt, filename)
 
313
        if ok:
 
314
                return fss.as_pathname()
 
315
 
 
316
 
 
317
def lineto(pt, done_moveto):
 
318
        x, y = pt
 
319
        if done_moveto:
 
320
                ATM.fillLineToATM((x, y))
 
321
        else:
 
322
                ATM.fillMoveToATM((x, y))
 
323
        return pt
 
324
 
 
325
def qcurveto(pt0, pt1, pt2, done_moveto):
 
326
        if not done_moveto:
 
327
                x0, y0 = pt0
 
328
                ATM.fillMoveToATM((x0, y0))
 
329
        x1a, y1a = pt0 + 0.6666666666667 * (pt1 - pt0)
 
330
        x1b, y1b = pt2 + 0.6666666666667 * (pt1 - pt2)
 
331
        x2, y2 = pt2
 
332
        ATM.fillCurveToATM((x1a, y1a), (x1b, y1b), (x2, y2))
 
333
        return pt2
 
334
 
 
335
 
 
336
def browseTTFont():
 
337
        fss, ok = macfs.StandardGetFile()
 
338
        if not ok:
 
339
                return
 
340
        path = fss.as_pathname()
 
341
        indices = macUtils.getSFNTResIndices(path)
 
342
        if indices:
 
343
                for i in indices:
 
344
                        TableBrowser(path, res_index=i)
 
345
        else:
 
346
                TableBrowser(path)
 
347
 
 
348
 
 
349
if __name__ == "__main__":
 
350
        browseTTFont()
 
351