SourceForge logo
SourceForge logo
Menu

matplotlib-checkins

Revision: 3540
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3540&view=rev
Author: mdboom
Date: 2007年07月16日 08:08:12 -0700 (2007年7月16日)
Log Message:
-----------
Got nested sub/superscripts working. Improved formatting of grammar
to be more readable to newbies (like me).
Modified Paths:
--------------
 branches/mathtext_mgd/lib/matplotlib/mathtext.py
Modified: branches/mathtext_mgd/lib/matplotlib/mathtext.py
===================================================================
--- branches/mathtext_mgd/lib/matplotlib/mathtext.py	2007年07月16日 14:06:59 UTC (rev 3539)
+++ branches/mathtext_mgd/lib/matplotlib/mathtext.py	2007年07月16日 15:08:12 UTC (rev 3540)
@@ -119,7 +119,6 @@
 
 KNOWN ISSUES:
 
- - nested subscripts, eg, x_i_j not working; but you can do x_{i_j}
 - nesting fonts changes in sub/superscript groups not parsing
 - I would also like to add a few more layout commands, like \frac.
 
@@ -136,7 +135,7 @@
 from matplotlib.pyparsing import Literal, Word, OneOrMore, ZeroOrMore, \
 Combine, Group, Optional, Forward, NotAny, alphas, nums, alphanums, \
 StringStart, StringEnd, ParseException, FollowedBy, Regex, \
- operatorPrecedence, opAssoc, ParseResults
+ operatorPrecedence, opAssoc, ParseResults, Or
 
 from matplotlib.afm import AFM
 from matplotlib.cbook import enumerate, iterable, Bunch
@@ -1014,6 +1013,7 @@
 self.dpi = dpi
 for loc, element in self.neighbors.items():
 if loc in ('subscript', 'superscript'):
+ print type(element), element
 element.set_size_info(0.7*self.fontsize, dpi)
 else:
 element.set_size_info(self.fontsize, dpi)
@@ -1257,8 +1257,10 @@
 
 def clear(self):
 self.symbols = []
+ self.subscript_stack = []
 
 def expression(self, s, loc, toks):
+ print "expression", toks
 self.expr = ExpressionElement(toks)
 return [self.expr]
 
@@ -1279,7 +1281,7 @@
 assert(len(toks)==1)
 
 s = toks[0]
- #~ print 'sym', toks[0]
+ print 'sym', toks[0]
 if charOverChars.has_key(s):
 under, over, pad = charOverChars[s]
 font, tok, scale = under
@@ -1360,172 +1362,209 @@
 grp.set_font(name[1:]) # suppress the slash
 return [grp]
 
- def subscript(self, s, loc, toks):
+ _subsuperscript_names = {
+ 'normal': ['subscript', 'superscript'],
+ 'overUnder': ['below', 'above']
+ }
+
+ _subsuperscript_indices = {
+ '_': (0, 1),
+ '^': (1, 0)
+ }
+ 
+ def subsuperscript(self, s, loc, toks):
 assert(len(toks)==1)
- #print 'subsup', toks
- if len(toks[0])==2:
- under, next = toks[0]
- prev = SpaceElement(0)
- else:
- prev, under, next = toks[0]
+ print 'subscript', toks
 
- if self.is_overunder(prev):
- prev.neighbors['below'] = next
- else:
- prev.neighbors['subscript'] = next
+ if len(toks[0])==3:
+ prev, op, next = toks[0]
+ index, other_index = self._subsuperscript_indices[op]
+ if self.is_overunder(prev):
+ names = self._subsuperscript_names['overUnder']
+ else:
+ names = self._subsuperscript_names['normal']
+ 
+ prev.neighbors[names[index]] = next
 
- return loc, [prev]
+ for compound in self._subsuperscript_names.values():
+ if compound[other_index] in next.neighbors:
+ prev.neighbors[names[other_index]] = next.neighbors[compound[other_index]]
+ del next.neighbors[compound[other_index]]
+ return [prev]
+ return toks[0].asList()
 
 def is_overunder(self, prev):
 return isinstance(prev, SymbolElement) and overunder.has_key(prev.sym)
 
- def superscript(self, s, loc, toks):
- assert(len(toks)==1)
- #print 'subsup', toks
- if len(toks[0])==2:
- under, next = toks[0]
- prev = SpaceElement(0,0.6)
- else:
- prev, under, next = toks[0]
- if self.is_overunder(prev):
- prev.neighbors['above'] = next
- else:
- prev.neighbors['superscript'] = next
-
- return [prev]
-
- def subsuperscript(self, s, loc, toks):
- assert(len(toks)==1)
- #print 'subsup', toks
- prev, undersym, down, oversym, up = toks[0]
-
- if self.is_overunder(prev):
- prev.neighbors['below'] = down
- prev.neighbors['above'] = up
- else:
- prev.neighbors['subscript'] = down
- prev.neighbors['superscript'] = up
-
- return [prev]
-
-
-
 handler = Handler()
 
-lbrace = Literal('{').suppress()
-rbrace = Literal('}').suppress()
-lbrack = Literal('[')
-rbrack = Literal(']')
-lparen = Literal('(')
-rparen = Literal(')')
-grouping = lbrack | rbrack | lparen | rparen
+# All forward declarations are here
+font = Forward().setParseAction(handler.font).setName("font")
+subsuper = Forward().setParseAction(handler.subsuperscript).setName("subsuper")
+placeable = Forward().setName("placeable")
 
-bslash = Literal('\\')
 
+lbrace = Literal('{').suppress()
+rbrace = Literal('}').suppress()
+lbrack = Literal('[')
+rbrack = Literal(']')
+lparen = Literal('(')
+rparen = Literal(')')
+grouping =(lbrack 
+ | rbrack 
+ | lparen 
+ | rparen)
 
-langle = Literal('<')
-rangle = Literal('>')
-equals = Literal('=')
-relation = langle | rangle | equals
+subscript = Literal('_')
+superscript = Literal('^')
 
-colon = Literal(':')
-comma = Literal(',')
-period = Literal('.')
-semicolon = Literal(';')
-exclamation = Literal('!')
+bslash = Literal('\\')
 
-punctuation = colon | comma | period | semicolon
+langle = Literal('<')
+rangle = Literal('>')
+equals = Literal('=')
+relation =(langle
+ | rangle
+ | equals)
 
-at = Literal('@')
-percent = Literal('%')
-ampersand = Literal('&')
-misc = exclamation | at | percent | ampersand
+colon = Literal(':')
+comma = Literal(',')
+period = Literal('.')
+semicolon = Literal(';')
+exclamation = Literal('!')
+punctuation =(colon
+ | comma
+ | period
+ | semicolon)
 
-over = Literal('over')
-under = Literal('under')
-#~ composite = over | under
-overUnder = over | under
+at = Literal('@')
+percent = Literal('%')
+ampersand = Literal('&')
+misc =(exclamation
+ | at
+ | percent
+ | ampersand)
 
-accent = Literal('hat') | Literal('check') | Literal('dot') | \
- Literal('breve') | Literal('acute') | Literal('ddot') | \
- Literal('grave') | Literal('tilde') | Literal('bar') | \
- Literal('vec') | Literal('"') | Literal("`") | Literal("'") |\
- Literal('~') | Literal('.') | Literal('^')
+over = Literal('over')
+under = Literal('under')
+overUnder =(over
+ | under)
 
+accent =(Literal('hat') | Literal('check') | Literal('dot') | 
+ Literal('breve') | Literal('acute') | Literal('ddot') | 
+ Literal('grave') | Literal('tilde') | Literal('bar') | 
+ Literal('vec') | Literal('"') | Literal("`") | Literal("'") |
+ Literal('~') | Literal('.') | Literal('^'))
 
+number = Combine(Word(nums) + Optional(Literal('.')) + Optional( Word(nums) ))
 
+plus = Literal('+')
+minus = Literal('-')
+times = Literal('*')
+div = Literal('/')
+binop =(plus 
+ | minus
+ | times
+ | div)
 
-number = Combine(Word(nums) + Optional(Literal('.')) + Optional( Word(nums) ))
+roman = Literal('rm')
+cal = Literal('cal')
+italics = Literal('it')
+typewriter = Literal('tt')
+fontname =(roman 
+ | cal 
+ | italics
+ | typewriter)
 
-plus = Literal('+')
-minus = Literal('-')
-times = Literal('*')
-div = Literal('/')
-binop = plus | minus | times | div
+texsym = Combine(bslash + Word(alphanums) + NotAny("{"))
 
+char = Word(alphanums + ' ', exact=1).leaveWhitespace()
 
-roman = Literal('rm')
-cal = Literal('cal')
-italics = Literal('it')
-typewriter = Literal('tt')
-fontname = roman | cal | italics | typewriter
+space =(FollowedBy(bslash)
+ + (Literal(r'\ ')
+ | Literal(r'\/')
+ | Group(Literal(r'\hspace{') + number + Literal('}'))
+ )
+ ).setParseAction(handler.space).setName('space')
 
-texsym = Combine(bslash + Word(alphanums) + NotAny("{"))
+symbol = Regex("(" + ")|(".join(
+ [
+ r"\\[a-zA-Z0-9]+(?!{)",
+ r"[a-zA-Z0-9 ]",
+ r"[+\-*/]",
+ r"[<>=]",
+ r"[:,.;!]",
+ r"[!@%&]",
+ r"[[\]()]",
+ ])
+ + ")"
+ ).setParseAction(handler.symbol).leaveWhitespace()
 
-char = Word(alphanums + ' ', exact=1).leaveWhitespace()
+_symbol =(texsym
+ | char
+ | binop
+ | relation
+ | punctuation
+ | misc
+ | grouping
+ ).setParseAction(handler.symbol).leaveWhitespace()
 
-space = FollowedBy(bslash) + (Literal(r'\ ') | Literal(r'\/') | Group(Literal(r'\hspace{') + number + Literal('}'))).setParseAction(handler.space).setName('space')
+accent = Group(
+ Combine(bslash + accent)
+ + Optional(lbrace)
+ + symbol
+ + Optional(rbrace)
+ ).setParseAction(handler.accent).setName("accent")
 
-symbol = Regex("("+")|(".join(
- [
- r"\\[a-zA-Z0-9]+(?!{)",
- r"[a-zA-Z0-9 ]",
- r"[+\-*/]",
- r"[<>=]",
- r"[:,.;!]",
- r"[!@%&]",
- r"[[\]()]",
- ])+")"
- ).setParseAction(handler.symbol).leaveWhitespace()
+group = Group(
+ lbrace
+ + OneOrMore(
+ space
+ ^ font
+ ^ subsuper
+ ^ placeable
+ )
+ + rbrace
+ ).setParseAction(handler.group).setName("group")
 
-#~ symbol = (texsym ^ char ^ binop ^ relation ^ punctuation ^ misc ^ grouping ).setParseAction(handler.symbol).leaveWhitespace()
-_symbol = (texsym | char | binop | relation | punctuation | misc | grouping ).setParseAction(handler.symbol).leaveWhitespace()
+composite = Group(
+ Combine(
+ bslash
+ + overUnder
+ )
+ + group
+ + group
+ ).setParseAction(handler.composite).setName("composite")
 
-subscript = Forward().setParseAction(handler.subscript).setName("subscript")
-superscript = Forward().setParseAction(handler.superscript).setName("superscript")
-subsuperscript = Forward().setParseAction(handler.subsuperscript).setName("subsuperscript")
+font << Group(
+ Combine(
+ bslash
+ + fontname)
+ + group)
 
-font = Forward().setParseAction(handler.font).setName("font")
+placeable <<(accent
+ ^ symbol
+ ^ group
+ ^ composite
+ )
 
+subsuper << Group(
+ placeable
+ + ZeroOrMore(
+ ( subscript
+ | superscript
+ )
+ + subsuper
+ )
+ )
 
-accent = Group( Combine(bslash + accent) + Optional(lbrace) + symbol + Optional(rbrace)).setParseAction(handler.accent).setName("accent")
-group = Group( lbrace + OneOrMore(symbol^subscript^superscript^subsuperscript^space^font^accent) + rbrace).setParseAction(handler.group).setName("group")
-#~ group = Group( lbrace + OneOrMore(subsuperscript | subscript | superscript | symbol | space ) + rbrace).setParseAction(handler.group).setName("group")
+expression = OneOrMore(
+ space
+ ^ font
+ ^ subsuper
+ ^ placeable
+ ).setParseAction(handler.expression).setName("expression")
 
-#composite = Group( Combine(bslash + composite) + lbrace + symbol + rbrace + lbrace + symbol + rbrace).setParseAction(handler.composite).setName("composite")
-#~ composite = Group( Combine(bslash + composite) + group + group).setParseAction(handler.composite).setName("composite")
-composite = Group( Combine(bslash + overUnder) + group + group).setParseAction(handler.composite).setName("composite")
-
-
-
-
-
-
-symgroup = font | group | symbol
-
-subscript << Group( Optional(symgroup) + Literal('_') + symgroup )
-superscript << Group( Optional(symgroup) + Literal('^') + symgroup )
-subsuperscript << Group( symgroup + Literal('_') + symgroup + Literal('^') + symgroup )
-
-font << Group( Combine(bslash + fontname) + group)
-
-
-
-expression = OneOrMore(
- space ^ font ^ accent ^ symbol ^ subscript ^ superscript ^ subsuperscript ^ group ^ composite ).setParseAction(handler.expression).setName("expression")
-#~ expression = OneOrMore(
- #~ group | composite | space | font | subsuperscript | subscript | superscript | symbol ).setParseAction(handler.expression).setName("expression")
-
 ####
 
 
@@ -1577,7 +1616,9 @@
 expression.parseString( s )
 
 handler.expr.set_size_info(fontsize, dpi)
-
+ print handler.expr
+ print handler.symbols
+ 
 # set the origin once to allow w, h compution
 handler.expr.set_origin(0, 0)
 xmin = min([e.xmin() for e in handler.symbols])
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 3541
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3541&view=rev
Author: mdboom
Date: 2007年07月16日 08:42:25 -0700 (2007年7月16日)
Log Message:
-----------
Minor cleanup and simplifications. Handle sub/superscript as a unary operator.
Modified Paths:
--------------
 branches/mathtext_mgd/lib/matplotlib/mathtext.py
Modified: branches/mathtext_mgd/lib/matplotlib/mathtext.py
===================================================================
--- branches/mathtext_mgd/lib/matplotlib/mathtext.py	2007年07月16日 15:08:12 UTC (rev 3540)
+++ branches/mathtext_mgd/lib/matplotlib/mathtext.py	2007年07月16日 15:42:25 UTC (rev 3541)
@@ -1013,7 +1013,6 @@
 self.dpi = dpi
 for loc, element in self.neighbors.items():
 if loc in ('subscript', 'superscript'):
- print type(element), element
 element.set_size_info(0.7*self.fontsize, dpi)
 else:
 element.set_size_info(self.fontsize, dpi)
@@ -1260,7 +1259,6 @@
 self.subscript_stack = []
 
 def expression(self, s, loc, toks):
- print "expression", toks
 self.expr = ExpressionElement(toks)
 return [self.expr]
 
@@ -1281,7 +1279,6 @@
 assert(len(toks)==1)
 
 s = toks[0]
- print 'sym', toks[0]
 if charOverChars.has_key(s):
 under, over, pad = charOverChars[s]
 font, tok, scale = under
@@ -1374,25 +1371,32 @@
 
 def subsuperscript(self, s, loc, toks):
 assert(len(toks)==1)
- print 'subscript', toks
+ #~ print 'subsuperscript', toks
 
- if len(toks[0])==3:
+ if len(toks[0]) == 1:
+ return toks[0].asList()
+ if len(toks[0]) == 3:
 prev, op, next = toks[0]
- index, other_index = self._subsuperscript_indices[op]
- if self.is_overunder(prev):
- names = self._subsuperscript_names['overUnder']
- else:
- names = self._subsuperscript_names['normal']
- 
- prev.neighbors[names[index]] = next
+ elif len(toks[0]) == 2:
+ prev = SpaceElement(0)
+ op, next = toks[0]
+ else:
+ raise ParseException("Unable to parse subscript/superscript construct.")
 
- for compound in self._subsuperscript_names.values():
- if compound[other_index] in next.neighbors:
- prev.neighbors[names[other_index]] = next.neighbors[compound[other_index]]
- del next.neighbors[compound[other_index]]
- return [prev]
- return toks[0].asList()
+ index, other_index = self._subsuperscript_indices[op]
+ if self.is_overunder(prev):
+ names = self._subsuperscript_names['overUnder']
+ else:
+ names = self._subsuperscript_names['normal']
 
+ prev.neighbors[names[index]] = next
+
+ for compound in self._subsuperscript_names.values():
+ if compound[other_index] in next.neighbors:
+ prev.neighbors[names[other_index]] = next.neighbors[compound[other_index]]
+ del next.neighbors[compound[other_index]]
+ return [prev]
+
 def is_overunder(self, prev):
 return isinstance(prev, SymbolElement) and overunder.has_key(prev.sym)
 
@@ -1522,7 +1526,6 @@
 space
 ^ font
 ^ subsuper
- ^ placeable
 )
 + rbrace
 ).setParseAction(handler.group).setName("group")
@@ -1549,20 +1552,22 @@
 )
 
 subsuper << Group(
- placeable
- + ZeroOrMore(
- ( subscript
- | superscript
- )
- + subsuper
+ (
+ placeable
+ + ZeroOrMore(
+ ( subscript
+ | superscript
+ )
+ + subsuper
+ )
 )
+ | (( subscript | superscript) + placeable)
 )
 
 expression = OneOrMore(
 space
 ^ font
 ^ subsuper
- ^ placeable
 ).setParseAction(handler.expression).setName("expression")
 
 ####
@@ -1616,8 +1621,6 @@
 expression.parseString( s )
 
 handler.expr.set_size_info(fontsize, dpi)
- print handler.expr
- print handler.symbols
 
 # set the origin once to allow w, h compution
 handler.expr.set_origin(0, 0)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 3542
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3542&view=rev
Author: mdboom
Date: 2007年07月16日 10:59:17 -0700 (2007年7月16日)
Log Message:
-----------
Deal with font tags (\cal \it \rm etc.) more like TeX
Modified Paths:
--------------
 branches/mathtext_mgd/lib/matplotlib/mathtext.py
Modified: branches/mathtext_mgd/lib/matplotlib/mathtext.py
===================================================================
--- branches/mathtext_mgd/lib/matplotlib/mathtext.py	2007年07月16日 15:42:25 UTC (rev 3541)
+++ branches/mathtext_mgd/lib/matplotlib/mathtext.py	2007年07月16日 17:59:17 UTC (rev 3542)
@@ -135,7 +135,7 @@
 from matplotlib.pyparsing import Literal, Word, OneOrMore, ZeroOrMore, \
 Combine, Group, Optional, Forward, NotAny, alphas, nums, alphanums, \
 StringStart, StringEnd, ParseException, FollowedBy, Regex, \
- operatorPrecedence, opAssoc, ParseResults, Or
+ operatorPrecedence, opAssoc, ParseResults, Or, Suppress
 
 from matplotlib.afm import AFM
 from matplotlib.cbook import enumerate, iterable, Bunch
@@ -927,7 +927,6 @@
 class Element:
 fontsize = 12
 dpi = 72
- font = 'it'
 _padx, _pady = 2, 2 # the x and y padding in points
 _scale = 1.0
 
@@ -965,10 +964,14 @@
 'get the ymax of ink rect'
 raise NotImplementedError('derived must override')
 
+ def determine_font(self, font_stack):
+ 'a first pass to determine the font of this element (one of tt, it, rm , cal)'
+ raise NotImplementedError('derived must override')
+
 def set_font(self, font):
 'set the font (one of tt, it, rm , cal)'
 raise NotImplementedError('derived must override')
-
+ 
 def render(self):
 'render to the fonts canvas'
 for element in self.neighbors.values():
@@ -1044,6 +1047,45 @@
 def __repr__(self):
 return str(self.__class__) + str(self.neighbors)
 
+class FontElement(Element):
+ def __init__(self, name):
+ Element.__init__(self)
+ self.name = name
+
+ def advance(self):
+ 'get the horiz advance'
+ return 0
+ 
+ def height(self):
+ 'get the element height: ymax-ymin'
+ return 0
+ 
+ def width(self):
+ 'get the element width: xmax-xmin'
+ return 0
+ 
+ def xmin(self):
+ 'get the xmin of ink rect'
+ return 0
+ 
+ def xmax(self):
+ 'get the xmax of ink rect'
+ return 0
+ 
+ def ymin(self):
+ 'get the ymin of ink rect'
+ return 0
+ 
+ def ymax(self):
+ 'get the ymax of ink rect'
+ return 0
+ 
+ def determine_font(self, font_stack):
+ font_stack[-1] = self.name
+
+ def set_font(self, font):
+ return
+ 
 class SpaceElement(Element):
 'blank horizontal space'
 def __init__(self, space, height=0):
@@ -1083,10 +1125,17 @@
 'get the max ink in y'
 return self.oy + self.height()
 
- def set_font(self, f):
+ def determine_font(self, font_stack):
 # space doesn't care about font, only size
+ for neighbor_type in ('above', 'below', 'subscript', 'superscript'):
+ neighbor = self.neighbors.get(neighbor_type)
+ if neighbor is not None:
+ neighbor.determine_font(font_stack)
+
+ def set_font(self, font_stack):
+ # space doesn't care about font, only size
 pass
-
+ 
 class SymbolElement(Element):
 def __init__(self, sym):
 Element.__init__(self)
@@ -1094,10 +1143,19 @@
 self.kern = None
 self.widthm = 1 # the width of an m; will be resized below
 
+ def determine_font(self, font_stack):
+ 'set the font (one of tt, it, rm, cal)'
+ self.set_font(font_stack[-1])
+ for neighbor_type in ('above', 'below', 'subscript', 'superscript'):
+ neighbor = self.neighbors.get(neighbor_type)
+ if neighbor is not None:
+ neighbor.determine_font(font_stack)
+ 
 def set_font(self, font):
- 'set the font (one of tt, it, rm , cal)'
+ # space doesn't care about font, only size
+ assert not hasattr(self, 'font')
 self.font = font
-
+ 
 def set_origin(self, ox, oy):
 Element.set_origin(self, ox, oy)
 
@@ -1163,6 +1221,8 @@
 def __repr__(self):
 return self.sym
 
+class AccentElement(SymbolElement):
+ pass
 
 class GroupElement(Element):
 """
@@ -1174,20 +1234,25 @@
 for i in range(len(elements)-1):
 self.elements[i].neighbors['right'] = self.elements[i+1]
 
- def set_font(self, font):
+ def determine_font(self, font_stack):
 'set the font (one of tt, it, rm , cal)'
+ font_stack.append(font_stack[-1])
 for element in self.elements:
- element.set_font(font)
+ element.determine_font(font_stack)
+ font_stack.pop()
 
-
+ def set_font(self, font):
+ return
+ 
+ # MGDTODO: The code below is probably now broken
 #print 'set fonts'
- for i in range(len(self.elements)-1):
- if not isinstance(self.elements[i], SymbolElement): continue
- if not isinstance(self.elements[i+1], SymbolElement): continue
- symleft = self.elements[i].sym
- symright = self.elements[i+1].sym
- self.elements[i].kern = None
- #self.elements[i].kern = Element.fonts.get_kern(font, symleft, symright, self.fontsize, self.dpi)
+# for i in range(len(self.elements)-1):
+# if not isinstance(self.elements[i], SymbolElement): continue
+# if not isinstance(self.elements[i+1], SymbolElement): continue
+# symleft = self.elements[i].sym
+# symright = self.elements[i+1].sym
+# self.elements[i].kern = None
+# #self.elements[i].kern = Element.fonts.get_kern(font, symleft, symright, self.fontsize, self.dpi)
 
 
 def set_size_info(self, fontsize, dpi):
@@ -1250,6 +1315,9 @@
 def __repr__(self):
 return 'Expression: [ %s ]' % ' '.join([str(e) for e in self.elements])
 
+ def determine_font(self):
+ font_stack = ['it']
+ GroupElement.determine_font(self, font_stack)
 
 class Handler:
 symbols = []
@@ -1275,29 +1343,30 @@
 return [element]
 
 def symbol(self, s, loc, toks):
-
 assert(len(toks)==1)
-
+ #print "symbol", toks
+ 
 s = toks[0]
- if charOverChars.has_key(s):
- under, over, pad = charOverChars[s]
- font, tok, scale = under
- sym = SymbolElement(tok)
- if font is not None:
- sym.set_font(font)
- sym.set_scale(scale)
- sym.set_pady(pad)
+ # MGDTODO: This clause is probably broken due to font changes
+# if charOverChars.has_key(s):
+# under, over, pad = charOverChars[s]
+# font, tok, scale = under
+# sym = SymbolElement(tok)
+# if font is not None:
+# sym.set_font(font)
+# sym.set_scale(scale)
+# sym.set_pady(pad)
 
- font, tok, scale = over
- sym2 = SymbolElement(tok)
- if font is not None:
- sym2.set_font(font)
- sym2.set_scale(scale)
+# font, tok, scale = over
+# sym2 = SymbolElement(tok)
+# if font is not None:
+# sym2.set_font(font)
+# sym2.set_scale(scale)
 
- sym.neighbors['above'] = sym2
- self.symbols.append(sym2)
- else:
- sym = SymbolElement(toks[0])
+# sym.neighbors['above'] = sym2
+# self.symbols.append(sym2)
+# else:
+ sym = SymbolElement(toks[0])
 self.symbols.append(sym)
 
 return [sym]
@@ -1339,7 +1408,7 @@
 r'\.' : r'\combiningdotabove',
 r'\^' : r'\circumflexaccent',
 }
- above = SymbolElement(d[accent])
+ above = AccentElement(d[accent])
 sym.neighbors['above'] = above
 sym.set_pady(1)
 self.symbols.append(above)
@@ -1352,12 +1421,11 @@
 return [grp]
 
 def font(self, s, loc, toks):
-
 assert(len(toks)==1)
- name, grp = toks[0]
+ name = toks[0]
 #print 'fontgrp', toks
- grp.set_font(name[1:]) # suppress the slash
- return [grp]
+ font = FontElement(name)
+ return [font]
 
 _subsuperscript_names = {
 'normal': ['subscript', 'superscript'],
@@ -1524,8 +1592,8 @@
 lbrace
 + OneOrMore(
 space
- ^ font
- ^ subsuper
+ | font
+ | subsuper
 )
 + rbrace
 ).setParseAction(handler.group).setName("group")
@@ -1539,11 +1607,8 @@
 + group
 ).setParseAction(handler.composite).setName("composite")
 
-font << Group(
- Combine(
- bslash
- + fontname)
- + group)
+font <<(Suppress(bslash)
+ + fontname)
 
 placeable <<(accent
 ^ symbol
@@ -1566,8 +1631,8 @@
 
 expression = OneOrMore(
 space
- ^ font
- ^ subsuper
+ | font
+ | subsuper
 ).setParseAction(handler.expression).setName("expression")
 
 ####
@@ -1616,10 +1681,11 @@
 elif self.output == 'PDF':
 self.font_object = BakomaPDFFonts(character_tracker)
 Element.fonts = self.font_object
-
+ 
 handler.clear()
 expression.parseString( s )
 
+ handler.expr.determine_font()
 handler.expr.set_size_info(fontsize, dpi)
 
 # set the origin once to allow w, h compution
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 3548
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3548&view=rev
Author: mdboom
Date: 2007年07月17日 05:21:59 -0700 (2007年7月17日)
Log Message:
-----------
Add support for Latex2e-style math fonts (\mathrm, \mathit etc.)
Add support for function name shortcuts (\sin, \cos etc.)
Raise an exception when encountering double subscript or superscripts
(e.g. x_i_j)
Modified Paths:
--------------
 branches/mathtext_mgd/lib/matplotlib/mathtext.py
Modified: branches/mathtext_mgd/lib/matplotlib/mathtext.py
===================================================================
--- branches/mathtext_mgd/lib/matplotlib/mathtext.py	2007年07月17日 10:09:27 UTC (rev 3547)
+++ branches/mathtext_mgd/lib/matplotlib/mathtext.py	2007年07月17日 12:21:59 UTC (rev 3548)
@@ -135,7 +135,7 @@
 from matplotlib.pyparsing import Literal, Word, OneOrMore, ZeroOrMore, \
 Combine, Group, Optional, Forward, NotAny, alphas, nums, alphanums, \
 StringStart, StringEnd, ParseException, FollowedBy, Regex, \
- operatorPrecedence, opAssoc, ParseResults, Or, Suppress
+ operatorPrecedence, opAssoc, ParseResults, Or, Suppress, oneOf
 
 from matplotlib.afm import AFM
 from matplotlib.cbook import enumerate, iterable, Bunch
@@ -1230,6 +1230,8 @@
 """
 def __init__(self, elements):
 Element.__init__(self)
+ if not isinstance(elements, list):
+ elements = elements.asList()
 self.elements = elements
 for i in range(len(elements)-1):
 self.elements[i].neighbors['right'] = self.elements[i+1]
@@ -1414,6 +1416,15 @@
 self.symbols.append(above)
 return [sym]
 
+ def function(self, s, loc, toks):
+ #~ print "function", toks
+ symbols = [FontElement("rm")]
+ for c in toks[0]:
+ sym = SymbolElement(c)
+ symbols.append(sym)
+ self.symbols.append(sym)
+ return [GroupElement(symbols)]
+ 
 def group(self, s, loc, toks):
 assert(len(toks)==1)
 #print 'grp', toks
@@ -1427,6 +1438,16 @@
 font = FontElement(name)
 return [font]
 
+ def latexfont(self, s, loc, toks):
+ assert(len(toks)==1)
+ name, grp = toks[0]
+ if len(grp.elements):
+ font = FontElement(name[4:])
+ font.neighbors['right'] = grp.elements[0]
+ grp.elements.insert(0, font)
+ return [grp]
+ return []
+ 
 _subsuperscript_names = {
 'normal': ['subscript', 'superscript'],
 'overUnder': ['below', 'above']
@@ -1463,6 +1484,10 @@
 if compound[other_index] in next.neighbors:
 prev.neighbors[names[other_index]] = next.neighbors[compound[other_index]]
 del next.neighbors[compound[other_index]]
+ elif compound[index] in next.neighbors:
+ raise ValueError(
+ "Double %ss" %
+ self._subsuperscript_names['normal'][index])
 return [prev]
 
 def is_overunder(self, prev):
@@ -1472,6 +1497,7 @@
 
 # All forward declarations are here
 font = Forward().setParseAction(handler.font).setName("font")
+latexfont = Forward().setParseAction(handler.latexfont).setName("latexfont")
 subsuper = Forward().setParseAction(handler.subsuperscript).setName("subsuper")
 placeable = Forward().setName("placeable")
 
@@ -1522,12 +1548,13 @@
 overUnder =(over
 | under)
 
-accent =(Literal('hat') | Literal('check') | Literal('dot') | 
- Literal('breve') | Literal('acute') | Literal('ddot') | 
- Literal('grave') | Literal('tilde') | Literal('bar') | 
- Literal('vec') | Literal('"') | Literal("`") | Literal("'") |
- Literal('~') | Literal('.') | Literal('^'))
+accent = oneOf("hat check dot breve acute ddot grave tilde bar vec "
+ "\" ` ' ~ . ^")
 
+function = oneOf("arccos csc ker min arcsin deg lg Pr arctan det lim sec "
+ "arg dim liminf sin cos exp limsup sinh cosh gcd ln sup "
+ "cot hom log tan coth inf max tanh")
+
 number = Combine(Word(nums) + Optional(Literal('.')) + Optional( Word(nums) ))
 
 plus = Literal('+')
@@ -1539,14 +1566,9 @@
 | times
 | div)
 
-roman = Literal('rm')
-cal = Literal('cal')
-italics = Literal('it')
-typewriter = Literal('tt')
-fontname =(roman 
- | cal 
- | italics
- | typewriter)
+fontname = oneOf("rm cal it tt")
+ # mathbf and mathsf not supported yet
+latex2efont = oneOf("mathrm mathcal mathit mathtt")
 
 texsym = Combine(bslash + Word(alphanums) + NotAny("{"))
 
@@ -1588,16 +1610,28 @@
 + Optional(rbrace)
 ).setParseAction(handler.accent).setName("accent")
 
+function =(Suppress(bslash)
+ + function).setParseAction(handler.function).setName("function")
+
 group = Group(
 lbrace
 + OneOrMore(
 space
 | font
+ | latexfont
 | subsuper
 )
 + rbrace
 ).setParseAction(handler.group).setName("group")
 
+font <<(Suppress(bslash)
+ + fontname)
+
+latexfont << Group(
+ Suppress(bslash)
+ + latex2efont
+ + group)
+
 composite = Group(
 Combine(
 bslash
@@ -1607,10 +1641,8 @@
 + group
 ).setParseAction(handler.composite).setName("composite")
 
-font <<(Suppress(bslash)
- + fontname)
-
 placeable <<(accent
+ ^ function 
 ^ symbol
 ^ group
 ^ composite
@@ -1632,6 +1664,7 @@
 expression = OneOrMore(
 space
 | font
+ | latexfont
 | subsuper
 ).setParseAction(handler.expression).setName("expression")
 
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 3550
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3550&view=rev
Author: mdboom
Date: 2007年07月17日 05:55:05 -0700 (2007年7月17日)
Log Message:
-----------
Fix charOverChars (\angstrom)
Modified Paths:
--------------
 branches/mathtext_mgd/lib/matplotlib/mathtext.py
Modified: branches/mathtext_mgd/lib/matplotlib/mathtext.py
===================================================================
--- branches/mathtext_mgd/lib/matplotlib/mathtext.py	2007年07月17日 12:40:56 UTC (rev 3549)
+++ branches/mathtext_mgd/lib/matplotlib/mathtext.py	2007年07月17日 12:55:05 UTC (rev 3550)
@@ -971,11 +971,11 @@
 raise NotImplementedError('derived must override')
 
 def determine_font(self, font_stack):
- 'a first pass to determine the font of this element (one of tt, it, rm , cal)'
+ 'a first pass to determine the font of this element (one of tt, it, rm , cal, bf, sf)'
 raise NotImplementedError('derived must override')
 
 def set_font(self, font):
- 'set the font (one of tt, it, rm , cal)'
+ 'set the font (one of tt, it, rm, cal, bf, sf)'
 raise NotImplementedError('derived must override')
 
 def render(self):
@@ -1143,6 +1143,8 @@
 pass
 
 class SymbolElement(Element):
+ hardcoded_font = False
+
 def __init__(self, sym):
 Element.__init__(self)
 self.sym = sym
@@ -1150,17 +1152,20 @@
 self.widthm = 1 # the width of an m; will be resized below
 
 def determine_font(self, font_stack):
- 'set the font (one of tt, it, rm, cal)'
+ 'set the font (one of tt, it, rm, cal, bf, sf)'
 self.set_font(font_stack[-1])
 for neighbor_type in ('above', 'below', 'subscript', 'superscript'):
 neighbor = self.neighbors.get(neighbor_type)
 if neighbor is not None:
 neighbor.determine_font(font_stack)
 
- def set_font(self, font):
- # space doesn't care about font, only size
- assert not hasattr(self, 'font')
- self.font = font
+ def set_font(self, font, hardcoded=False):
+ if hardcoded:
+ self.hardcoded_font = True
+ self.font = font
+ if not self.hardcoded_font:
+ assert not hasattr(self, 'font')
+ self.font = font
 
 def set_origin(self, ox, oy):
 Element.set_origin(self, ox, oy)
@@ -1355,26 +1360,25 @@
 #print "symbol", toks
 
 s = toks[0]
- # MGDTODO: This clause is probably broken due to font changes
-# if charOverChars.has_key(s):
-# under, over, pad = charOverChars[s]
-# font, tok, scale = under
-# sym = SymbolElement(tok)
-# if font is not None:
-# sym.set_font(font)
-# sym.set_scale(scale)
-# sym.set_pady(pad)
+ if charOverChars.has_key(s):
+ under, over, pad = charOverChars[s]
+ font, tok, scale = under
+ sym = SymbolElement(tok)
+ if font is not None:
+ sym.set_font(font, hardcoded=True)
+ sym.set_scale(scale)
+ sym.set_pady(pad)
 
-# font, tok, scale = over
-# sym2 = SymbolElement(tok)
-# if font is not None:
-# sym2.set_font(font)
-# sym2.set_scale(scale)
+ font, tok, scale = over
+ sym2 = SymbolElement(tok)
+ if font is not None:
+ sym2.set_font(font, hardcoded=True)
+ sym2.set_scale(scale)
 
-# sym.neighbors['above'] = sym2
-# self.symbols.append(sym2)
-# else:
- sym = SymbolElement(toks[0])
+ sym.neighbors['above'] = sym2
+ self.symbols.append(sym2)
+ else:
+ sym = SymbolElement(toks[0])
 self.symbols.append(sym)
 
 return [sym]
@@ -1673,8 +1677,8 @@
 | subsuper
 ).setParseAction(handler.expression).setName("expression")
 
+ 
 
-
 ####
 
 
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 3564
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3564&view=rev
Author: mdboom
Date: 2007年07月18日 10:18:15 -0700 (2007年7月18日)
Log Message:
-----------
Make \under and \over behave as in TeX. (i.e. it's {x \over y} not \over{x}{y})
Modified Paths:
--------------
 branches/mathtext_mgd/lib/matplotlib/mathtext.py
Modified: branches/mathtext_mgd/lib/matplotlib/mathtext.py
===================================================================
--- branches/mathtext_mgd/lib/matplotlib/mathtext.py	2007年07月18日 16:59:39 UTC (rev 3563)
+++ branches/mathtext_mgd/lib/matplotlib/mathtext.py	2007年07月18日 17:18:15 UTC (rev 3564)
@@ -1088,6 +1088,7 @@
 return self.oy + self.height()
 
 def determine_font(self, font_stack):
+ print "Space"
 # space doesn't care about font, only size
 for neighbor_type in ('above', 'below', 'subscript', 'superscript'):
 neighbor = self.neighbors.get(neighbor_type)
@@ -1109,6 +1110,7 @@
 
 def determine_font(self, font_stack):
 'set the font (one of tt, it, rm, cal, bf, sf)'
+ print "sym:", self.sym, self.neighbors.keys()
 self.set_font(font_stack[-1])
 for neighbor_type in ('above', 'below', 'subscript', 'superscript'):
 neighbor = self.neighbors.get(neighbor_type)
@@ -1208,6 +1210,10 @@
 font_stack.append(font_stack[-1])
 for element in self.elements:
 element.determine_font(font_stack)
+ for neighbor_type in ('above', 'below', 'subscript', 'superscript'):
+ neighbor = self.neighbors.get(neighbor_type)
+ if neighbor is not None:
+ neighbor.determine_font(font_stack)
 font_stack.pop()
 
 def set_font(self, font):
@@ -1359,16 +1365,17 @@
 
 return [sym]
 
- def composite(self, s, loc, toks):
-
+ def over_under(self, s, loc, toks):
 assert(len(toks)==1)
 where, sym0, sym1 = toks[0]
 #keys = ('above', 'below', 'subscript', 'superscript', 'right')
+ print "where:", toks[0]
 if where==r'\over':
 sym0.neighbors['above'] = sym1
 elif where==r'\under':
 sym0.neighbors['below'] = sym1
-
+ print sym0.neighbors.keys()
+ 
 self.symbols.append(sym0)
 self.symbols.append(sym1)
 
@@ -1440,8 +1447,10 @@
 }
 
 _subsuperscript_indices = {
- '_': (0, 1),
- '^': (1, 0)
+ '_' : ('normal', (0, 1)),
+ '^' : ('normal', (1, 0)),
+ 'over' : ('overUnder', (0, 1)),
+ 'under' : ('overUnder', (1, 0))
 }
 
 def subsuperscript(self, s, loc, toks):
@@ -1458,17 +1467,17 @@
 else:
 raise ParseException("Unable to parse subscript/superscript construct.")
 
- index, other_index = self._subsuperscript_indices[op]
+ relation_type, (index, other_index) = self._subsuperscript_indices[op]
 if self.is_overunder(prev):
- names = self._subsuperscript_names['overUnder']
- else:
- names = self._subsuperscript_names['normal']
+ relation_type = 'overUnder'
+ names = self._subsuperscript_names[relation_type]
 
 prev.neighbors[names[index]] = next
 
 for compound in self._subsuperscript_names.values():
 if compound[other_index] in next.neighbors:
- prev.neighbors[names[other_index]] = next.neighbors[compound[other_index]]
+ prev.neighbors[names[other_index]] = \
+ next.neighbors[compound[other_index]]
 del next.neighbors[compound[other_index]]
 elif compound[index] in next.neighbors:
 raise ValueError(
@@ -1486,6 +1495,7 @@
 latexfont = Forward().setParseAction(handler.latexfont).setName("latexfont")
 subsuper = Forward().setParseAction(handler.subsuperscript).setName("subsuper")
 placeable = Forward().setName("placeable")
+simple = Forward().setName("simple")
 expression = Forward().setParseAction(handler.expression).setName("expression")
 
 lbrace = Literal('{').suppress()
@@ -1499,9 +1509,6 @@
 | lparen 
 | rparen)
 
-subscript = Literal('_')
-superscript = Literal('^')
-
 bslash = Literal('\\')
 
 langle = Literal('<')
@@ -1529,11 +1536,6 @@
 | percent
 | ampersand)
 
-over = Literal('over')
-under = Literal('under')
-overUnder =(over
- | under)
-
 accent = oneOf("hat check dot breve acute ddot grave tilde bar vec "
 "\" ` ' ~ . ^")
 
@@ -1602,10 +1604,7 @@
 group = Group(
 lbrace
 + OneOrMore(
- space
- | font
- | latexfont
- | subsuper
+ simple
 )
 + rbrace
 ).setParseAction(handler.group).setName("group")
@@ -1618,40 +1617,36 @@
 + latex2efont
 + group)
 
-composite = Group(
- Combine(
- bslash
- + overUnder
- )
- + group
- + group
- ).setParseAction(handler.composite).setName("composite")
-
 placeable <<(accent
 ^ function 
 ^ symbol
 ^ group
- ^ composite
 )
 
+simple <<(space
+ | font
+ | latexfont
+ | subsuper)
+
+subsuperop =(Literal("_")
+ | Literal("^")
+ | (Suppress(bslash) + Literal("under"))
+ | (Suppress(bslash) + Literal("over"))
+ ) 
+
 subsuper << Group(
 (
 placeable
 + ZeroOrMore(
- ( subscript
- | superscript
- )
+ subsuperop
 + subsuper
 )
 )
- | (( subscript | superscript) + placeable)
+ | (subsuperop + placeable)
 )
 
 math = OneOrMore(
- space
- | font
- | latexfont
- | subsuper
+ simple
 ).setParseAction(handler.math).setName("math")
 
 math_delim =(~bslash
@@ -1669,7 +1664,6 @@
 + non_math
 )
 )
- 
 
 ####
 
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 3565
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3565&view=rev
Author: mdboom
Date: 2007年07月18日 10:21:11 -0700 (2007年7月18日)
Log Message:
-----------
Clean up logging. Remove dead function.
Modified Paths:
--------------
 branches/mathtext_mgd/lib/matplotlib/mathtext.py
Modified: branches/mathtext_mgd/lib/matplotlib/mathtext.py
===================================================================
--- branches/mathtext_mgd/lib/matplotlib/mathtext.py	2007年07月18日 17:18:15 UTC (rev 3564)
+++ branches/mathtext_mgd/lib/matplotlib/mathtext.py	2007年07月18日 17:21:11 UTC (rev 3565)
@@ -1088,7 +1088,6 @@
 return self.oy + self.height()
 
 def determine_font(self, font_stack):
- print "Space"
 # space doesn't care about font, only size
 for neighbor_type in ('above', 'below', 'subscript', 'superscript'):
 neighbor = self.neighbors.get(neighbor_type)
@@ -1110,7 +1109,6 @@
 
 def determine_font(self, font_stack):
 'set the font (one of tt, it, rm, cal, bf, sf)'
- print "sym:", self.sym, self.neighbors.keys()
 self.set_font(font_stack[-1])
 for neighbor_type in ('above', 'below', 'subscript', 'superscript'):
 neighbor = self.neighbors.get(neighbor_type)
@@ -1365,22 +1363,6 @@
 
 return [sym]
 
- def over_under(self, s, loc, toks):
- assert(len(toks)==1)
- where, sym0, sym1 = toks[0]
- #keys = ('above', 'below', 'subscript', 'superscript', 'right')
- print "where:", toks[0]
- if where==r'\over':
- sym0.neighbors['above'] = sym1
- elif where==r'\under':
- sym0.neighbors['below'] = sym1
- print sym0.neighbors.keys()
- 
- self.symbols.append(sym0)
- self.symbols.append(sym1)
-
- return [sym0]
-
 def accent(self, s, loc, toks):
 
 assert(len(toks)==1)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 3559
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3559&view=rev
Author: mdboom
Date: 2007年07月18日 08:41:59 -0700 (2007年7月18日)
Log Message:
-----------
Fix spacing when going from non-math to math.
Modified Paths:
--------------
 branches/mathtext_mgd/lib/matplotlib/mathtext.py
Modified: branches/mathtext_mgd/lib/matplotlib/mathtext.py
===================================================================
--- branches/mathtext_mgd/lib/matplotlib/mathtext.py	2007年07月18日 15:27:58 UTC (rev 3558)
+++ branches/mathtext_mgd/lib/matplotlib/mathtext.py	2007年07月18日 15:41:59 UTC (rev 3559)
@@ -1311,7 +1311,10 @@
 
 def non_math(self, s, loc, toks):
 #~ print "non_math", toks
- symbols = [SymbolElement(c) for c in toks[0]]
+ # This is a hack, but it allows the system to use the
+ # proper amount of advance when going from non-math to math
+ s = toks[0] + ' '
+ symbols = [SymbolElement(c) for c in s]
 self.symbols.extend(symbols)
 non_math = NonMathGroupElement(symbols)
 return [non_math]
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 3590
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3590&view=rev
Author: mdboom
Date: 2007年07月20日 07:19:48 -0700 (2007年7月20日)
Log Message:
-----------
First pass with a real TeX box model. Lots of things broken -- just
want to mark this spot in the revision history.
Modified Paths:
--------------
 branches/mathtext_mgd/lib/matplotlib/mathtext.py
Modified: branches/mathtext_mgd/lib/matplotlib/mathtext.py
===================================================================
--- branches/mathtext_mgd/lib/matplotlib/mathtext.py	2007年07月20日 14:15:29 UTC (rev 3589)
+++ branches/mathtext_mgd/lib/matplotlib/mathtext.py	2007年07月20日 14:19:48 UTC (rev 3590)
@@ -127,6 +127,7 @@
 math text yet. They are most likely broken. -- Michael Droettboom, July 2007
 
 Author : John Hunter <jdh...@ac...>
+ Michael Droettboom <md...@st...> (rewrite based on TeX algorithms)
 Copyright : John Hunter (2004,2005)
 License : matplotlib license (PSF compatible)
 
@@ -135,6 +136,7 @@
 import os, sys
 from cStringIO import StringIO
 from sets import Set
+from warnings import warn
 
 from matplotlib import verbose
 from matplotlib.pyparsing import Literal, Word, OneOrMore, ZeroOrMore, \
@@ -152,11 +154,12 @@
 from matplotlib import get_data_path, rcParams
 
 # symbols that have the sub and superscripts over/under
-overunder = { r'\sum' : 1,
- r'\int' : 1,
- r'\prod' : 1,
- r'\coprod' : 1,
- }
+overunder_symbols = {
+ r'\sum' : 1,
+ r'\int' : 1,
+ r'\prod' : 1,
+ r'\coprod' : 1,
+ }
 # a character over another character
 charOverChars = {
 # The first 2 entires in the tuple are (font, char, sizescale) for
@@ -165,6 +168,8 @@
 r'\angstrom' : ( ('rm', 'A', 1.0), (None, '\circ', 0.5), 0.0 ),
 }
 
+##############################################################################
+# FONTS
 
 def font_open(filename):
 ext = filename.rsplit('.',1)[1]
@@ -269,6 +274,9 @@
 def render(self, ox, oy, facename, sym, fontsize, dpi):
 pass
 
+ def render_rect_filled(self, x1, y1, x2, y2):
+ pass
+ 
 def get_used_characters(self):
 return {}
 
@@ -659,6 +667,9 @@
 xmax = xmax,
 ymin = ymin+offset,
 ymax = ymax+offset,
+ # iceberg is the amount of character that floats above the baseline
+ # This is equivalent to TeX' "height"
+ iceberg = glyph.horiBearingY/64.0
 )
 
 self.glyphd[key] = basename, font, metrics, symbol_name, num, glyph, offset
@@ -673,11 +684,18 @@
 
 def render(self, ox, oy, font, sym, fontsize, dpi):
 basename, font, metrics, symbol_name, num, glyph, offset = \
- self._get_info(font, sym, fontsize, dpi)
+ self._get_info(font, sym, fontsize, dpi)
 
+ font.draw_rect(0, 0, self.width - 1, self.height - 1)
 font.draw_glyph_to_bitmap(
- int(ox), int(self.height - oy - metrics.ymax), glyph)
+ int(ox), int(oy - metrics.ymax), glyph)
 
+ def render_rect_filled(self, x1, y1, x2, y2):
+ assert len(self.fonts)
+ font = self.fonts.values()[0]
+ print "filled rect:", x1, y1, x2, y2
+ font.font.draw_rect_filled(x1, y1, x2, y2)
+ 
 def _old_get_kern(self, font, symleft, symright, fontsize, dpi):
 """
 Get the kerning distance for font between symleft and symright.
@@ -699,6 +717,11 @@
 
 def get_used_characters(self):
 return self.used_characters
+
+ def get_xheight(self, font):
+ basename, cached_font = self._get_font(font)
+ pclt = cached_font.font.get_sfnt_table('pclt')
+ return pclt['xHeight'] / 64.0 
 
 class BakomaPSFonts(BakomaFonts):
 """
@@ -885,443 +908,905 @@
 basename, font = self._get_font(font)
 return font.get_kern_dist(glyph1, glyph2) * 0.001 * fontsize
 return 0
- 
-class Element:
- fontsize = 12
- dpi = 72
- _padx, _pady = 2, 2 # the x and y padding in points
- _scale = 1.0
 
- def __init__(self):
- # a dict mapping the keys above, below, subscript,
- # superscript, right to Elements in that position
- self.neighbors = {}
- self.ox, self.oy = 0, 0
+##############################################################################
+# TeX-LIKE BOX MODEL
 
- def advance(self):
- 'get the horiz advance'
- raise NotImplementedError('derived must override')
+# The following is based directly on the document 'woven' from the
+# TeX82 source code. This information is also available in printed
+# form:
+#
+# Knuth, Donald E.. 1986. Computers and Typesetting, Volume B:
+# TeX: The Program. Addison-Wesley Professional.
+#
+# The most relevant "chapters" are:
+# Data structures for boxes and their friends
+# Shipping pages out (Ship class)
+# Packaging (hpack and vpack)
+# Data structures for math mode
+# Subroutines for math mode
+# Typesetting math formulas
+#
+# Many of the docstrings below refer to a numbered "node" in that
+# book, e.g. §123
+#
+# Note that (as TeX) y increases downward, unlike many other parts of
+# matplotlib.
 
- def height(self):
- 'get the element height: ymax-ymin'
- raise NotImplementedError('derived must override')
+class MathTextWarning(Warning):
+ pass
+ 
+class Node(object):
+ """A node in a linked list.
+ §133
+ """
+ def __init__(self):
+ self.link = None
+ 
+ def __repr__(self):
+ s = self.__internal_repr__()
+ if self.link:
+ s += ' ' + self.link.__repr__()
+ return s
 
- def width(self):
- 'get the element width: xmax-xmin'
- raise NotImplementedError('derived must override')
+ def __internal_repr__(self):
+ return self.__class__.__name__
 
- def xmin(self):
- 'get the xmin of ink rect'
- raise NotImplementedError('derived must override')
+ def get_kerning(self, next):
+ return 0.0
+ 
+ def set_link(self, other):
+ self.link = other
+ 
+ def render(self, x, y):
+ pass
 
- def xmax(self):
- 'get the xmax of ink rect'
- raise NotImplementedError('derived must override')
+class Box(Node):
+ """Represents any node with a physical location.
+ §135"""
+ def __init__(self, width, height, depth):
+ Node.__init__(self)
+ self.width = width
+ self.height = height
+ self.depth = depth
+ 
+class CharNode(Box):
+ """Represents a single character. Unlike TeX, the font
+ information and metrics are stored with each CharNode to make it
+ easier to lookup the font metrics when needed. Note that TeX
+ boxes have a width, height, and depth, unlike Type1 and Truetype
+ which use a full bounding box and an advance in the x-direction.
+ The metrics must be converted to the TeX way, and the advance (if
+ different from width) must be converted into a Kern node when the
+ CharNode is added to its parent Hlist.
+ §134"""
+ def __init__(self, c, state):
+ self.c = c
+ self.font_manager = state.font_manager
+ self.font = state.font
+ self.fontsize = state.fontsize
+ self.dpi = state.dpi
+ metrics = self._metrics = self.font_manager.get_metrics(
+ self.font, self.c, self.fontsize, self.dpi)
+ Box.__init__(self, metrics.width, metrics.iceberg,
+ -(metrics.iceberg - metrics.height))
+ 
+ def __internal_repr__(self):
+ return self.c
 
- def ymin(self):
- 'get the ymin of ink rect'
- raise NotImplementedError('derived must override')
+ def get_kerning(self, next):
+ """Return the amount of kerning between this and the given
+ character. Called when characters are strung together into
+ Hlists to create Kern nodes."""
+ # MGDTODO: Actually use kerning pairs
+ return self._metrics.advance - self.width
+ 
+ def render(self, x, y):
+ """Render the character to the canvas"""
+ self.font_manager.render(
+ x, y,
+ self.font, self.c, self.fontsize, self.dpi)
+ 
+class List(Box):
+ """A list of nodes (either horizontal or vertical).
+ §135"""
+ def __init__(self, elements):
+ Box.__init__(self, 0., 0., 0.)
+ self.shift_amount = 0. # An arbitrary offset
+ self.list_head = None # The head of a linked list of Nodes in this box
+ # The following parameters are set in the vpack and hpack functions
+ self.glue_set = 0. # The glue setting of this list
+ self.glue_sign = 0 # 0: normal, -1: shrinking, 1: stretching
+ self.glue_order = 0 # The order of infinity (0 - 3) for the glue
+ 
+ # Convert the Python list to a linked list
+ if len(elements):
+ elem = self.list_head = elements[0]
+ for next in elements[1:]:
+ elem.set_link(next)
+ elem = next
 
- def ymax(self):
- 'get the ymax of ink rect'
- raise NotImplementedError('derived must override')
+ def __repr__(self):
+ s = '[' + self.__internal_repr__()
+ if self.list_head:
+ s += ' ' + self.list_head.__repr__()
+ s += ']'
+ if self.link:
+ s += ' ' + self.link.__repr__()
+ return s
 
- def determine_font(self, font_stack):
- 'a first pass to determine the font of this element (one of tt, it, rm , cal, bf, sf)'
- raise NotImplementedError('derived must override')
-
- def set_font(self, font):
- 'set the font (one of tt, it, rm, cal, bf, sf)'
- raise NotImplementedError('derived must override')
+ def _determine_order(self, totals):
+ """A helper function to determine the highest order of glue
+ used by the members of this list. Used by vpack and hpack."""
+ o = 0
+ for i in range(len(totals), 0, -1):
+ if totals[i] != 0.0:
+ o = i
+ break
+ return o
 
- def render(self):
- 'render to the fonts canvas'
- for element in self.neighbors.values():
- element.render()
+class Hlist(List):
+ """A horizontal list of boxes.
+ §135"""
+ def __init__(self, elements, w=0., m='additional'):
+ List.__init__(self, elements)
+ self.do_kerning()
+ self.hpack(w, m)
 
- def set_origin(self, ox, oy):
- self.ox, self.oy = ox, oy
+ def do_kerning(self):
+ """Insert Kern nodes between CharNodes to set kerning. The
+ CharNodes themselves determine the amount of kerning they need
+ (in get_kerning), and this function just creates the linked
+ list in the correct way."""
+ elem = self.list_head
+ while elem is not None:
+ next = elem.link
+ kerning_distance = elem.get_kerning(next)
+ if kerning_distance != 0.:
+ kern = Kern(kerning_distance)
+ elem.link = kern
+ kern.link = next
+ elem = next
+ 
+ def hpack(self, w=0., m='additional'):
+ """The main duty of hpack is to compute the dimensions of the
+ resulting boxes, and to adjust the glue if one of those dimensions is
+ pre-specified. The computed sizes normally enclose all of the material
+ inside the new box; but some items may stick out if negative glue is
+ used, if the box is overfull, or if a \vbox includes other boxes that
+ have been shifted left.
 
- # order matters! right needs to be evaled last
- keys = ('above', 'below', 'subscript', 'superscript', 'right')
- for loc in keys:
- element = self.neighbors.get(loc)
- if element is None: continue
+ w: specifies a width
+ m: is either 'exactly' or 'additional'.
 
- if loc=='above':
- nx = self.centerx() - element.width()/2.0
- ny = self.ymax() + self.pady() + (element.oy - element.ymax() + element.height())
- #print element, self.ymax(), element.height(), element.ymax(), element.ymin(), ny
- elif loc=='below':
- nx = self.centerx() - element.width()/2.0
- ny = self.ymin() - self.pady() - element.height()
- elif loc=='superscript':
- nx = self.xmax()
- ny = self.ymax() - self.pady()
- elif loc=='subscript':
- nx = self.xmax()
- ny = self.oy - 0.5*element.height()
- elif loc=='right':
- nx = self.ox + self.advance()
- if self.neighbors.has_key('subscript'):
- o = self.neighbors['subscript']
- nx = max(nx, o.ox + o.advance())
- if self.neighbors.has_key('superscript'):
- o = self.neighbors['superscript']
- nx = max(nx, o.ox + o.advance())
+ Thus, hpack(w, exactly) produces a box whose width is exactly w, while
+ hpack (w, additional ) yields a box whose width is the natural width
+ plus w. The default values produce a box with the natural width.
+ §644, §649"""
+ self.shift_amount = 0.
+ h = 0.
+ d = 0.
+ x = 0.
+ total_stretch = [0.] * 4
+ total_shrink = [0.] * 4
+ p = self.list_head
+ while p is not None:
+ # Layout characters in a tight inner loop (common case)
+ while isinstance(p, CharNode):
+ x += p.width
+ h = max(h, p.height)
+ d = max(d, p.depth)
+ p = p.link
+ if p is None:
+ break
+ 
+ if isinstance(p, (List, Rule, Unset)):
+ x += p.width
+ if hasattr(p, 'shift_amount'):
+ s = p.shift_amount
+ else:
+ s = 0.
+ if p.height is not None and p.depth is not None:
+ h = max(h, p.height - s)
+ d = max(d, p.depth + s)
+ elif isinstance(p, Glue):
+ glue_spec = p.glue_spec
+ x += glue_spec.width
+ total_stretch[glue_spec.stretch_order] += glue_spec.stretch
+ total_shrink[glue_spec.shrink_order] += glue_spec.shrink
+ elif isinstance(p, Kern):
+ x += p.width
+ p = p.link
+ self.height = h
+ self.depth = d
 
- ny = self.oy
- element.set_origin(nx, ny)
-
- def set_size_info(self, fontsize, dpi):
- self.fontsize = self._scale*fontsize
- self.dpi = dpi
- for loc, element in self.neighbors.items():
- if loc in ('subscript', 'superscript'):
- element.set_size_info(0.7*self.fontsize, dpi)
+ if m == 'additional':
+ w += x
+ self.width = w
+ x = w - x
+ 
+ if x == 0.:
+ self.glue_sign = 0
+ self.glue_order = 0
+ self.glue_ratio = 0.
+ return
+ if x > 0.:
+ o = self._determine_order(total_stretch)
+ self.glue_order = o
+ self.glue_sign = 1
+ if total_stretch[o] != 0.:
+ self.glue_set = x / total_stretch[o]
 else:
- element.set_size_info(self.fontsize, dpi)
+ self.glue_sign = 0
+ self.glue_ratio = 0.
+ if o == 0:
+ if self.list_head is not None:
+ warn("Overfull hbox: %r" % self, MathTextWarning)
+ else:
+ o = self._determine_order(total_shrink)
+ self.glue_order = o
+ self.glue_sign = -1
+ if total_shrink[o] != 0.:
+ self.glue_set = x / total_shrink[o]
+ else:
+ self.glue_sign = 0
+ self.glue_ratio = 0.
+ if o == 0:
+ if self.list_head is not None:
+ warn("Underfull vbox: %r" % self, MathTextWarning)
 
- def pady(self):
- return self.dpi/72.0*self._pady
+class Vlist(List):
+ """A vertical list of boxes.
+ §137"""
+ def __init__(self, elements, h=0., m='additional'):
+ List.__init__(self, elements)
+ self.vpack(h, m)
 
- def padx(self):
- return self.dpi/72.0*self._padx
+ def vpack(self, h=0., m='additional', l=float('inf')):
+ """The main duty of vpack is to compute the dimensions of the
+ resulting boxes, and to adjust the glue if one of those dimensions is
+ pre-specified.
 
- def set_padx(self, pad):
- 'set the y padding in points'
- self._padx = pad
+ h: specifies a height
+ m: is either 'exactly' or 'additional'.
+ l: a maximum height
 
- def set_pady(self, pad):
- 'set the y padding in points'
- self._pady = pad
+ Thus, vpack(h, exactly) produces a box whose width is exactly w, while
+ hpack (w, additional ) yields a box whose width is the natural width
+ plus w. The default values produce a box with the natural width.
+ §644, §668"""
+ self.shift_amount = 0.
+ w = 0.
+ d = 0.
+ x = 0.
+ total_stretch = [0.] * 4
+ total_shrink = [0.] * 4
+ p = self.list_head
+ while p is not None:
+ if isinstance(p, CharNode):
+ raise RuntimeError("Internal error in mathtext")
+ elif isinstance(p, (List, Rule, Unset)):
+ x += d + p.height
+ d = p.depth
+ if hasattr(p, 'shift_amount'):
+ s = p.shift_amount
+ else:
+ s = 0.
+ if p.width is not None:
+ w = max(w, p.width + s)
+ elif isinstance(p, Glue):
+ x += d
+ d = 0.
+ glue_spec = p.glue_spec
+ x += glue_spec.width
+ total_stretch[glue_spec.stretch_order] += glue_spec.stretch
+ total_shrink[glue_spec.shrink_order] += glue_spec.shrink
+ elif isinstance(p, Kern):
+ x += d + p.width
+ d = 0.
+ p = p.link
 
- def set_scale(self, scale):
- 'scale the element by scale'
- self._scale = scale
+ self.width = w
+ if d > l:
+ x += d - l
+ self.depth = l
+ else:
+ self.depth = d
 
- def centerx(self):
- return 0.5 * (self.xmax() + self.xmin() )
+ if m == 'additional':
+ h += x
+ self.height = h
+ x = h - x
 
- def centery(self):
- return 0.5 * (self.ymax() + self.ymin() )
+ if x == 0:
+ self.glue_sign = 0
+ self.glue_order = 0
+ self.glue_ratio = 0.
+ return
+ if x > 0.:
+ o = self._determine_order(total_stretch)
+ self.glue_order = o
+ self.glue_sign = 1
+ if total_stretch[o] != 0.:
+ self.glue_set = x / total_stretch[o]
+ else:
+ self.glue_sign = 0
+ self.glue_ratio = 0.
+ if o == 0:
+ if self.list_head is not None:
+ warn("Overfull vbox: %r" % self, MathTextWarning)
+ else:
+ o = self._determine_order(total_shrink)
+ self.glue_order = o
+ self.glue_sign = -1
+ if total_shrink[o] != 0.:
+ self.glue_set = x / total_shrink[o]
+ else:
+ self.glue_sign = 0
+ self.glue_ratio = 0.
+ if o == 0:
+ if self.list_head is not None:
+ warn("Underfull vbox: %r" % self, MathTextWarning)
+ 
+class Rule(Box):
+ """A Rule node stands for a solid black rectangle; it has width,
+ depth, and height fields just as in an Hlist. However, if any of these
+ dimensions is None, the actual value will be determined by running the
+ rule up to the boundary of the innermost enclosing box. This is called
+ a "running dimension." The width is never running in an Hlist; the
+ height and depth are never running in a Vlist.
+ §138"""
+ def __init__(self, width, height, depth, state):
+ Box.__init__(self, width, height, depth)
+ self.font_manager = state.font_manager
+ 
+ def render(self, x, y, w, h):
+ self.font_manager.render_rect_filled(x, y, x + w, y + h)
+ 
+class Hrule(Rule):
+ """Convenience class to create a horizontal rule."""
+ def __init__(self, state):
+ # MGDTODO: Get the line width from the font information
+ Rule.__init__(self, None, 0.5, 0.5, state)
 
- def __repr__(self):
- return str(self.__class__) + str(self.neighbors)
+class Vrule(Rule):
+ """Convenience class to create a vertical rule."""
+ def __init__(self, state):
+ # MGDTODO: Get the line width from the font information
+ Rule.__init__(self, 1.0, None, None, state)
+ 
+class Glue(Node):
+ """Most of the information in this object is stored in the underlying
+ GlueSpec class, which is shared between multiple glue objects. (This
+ is a memory optimization which probably doesn't matter anymore, but it's
+ easier to stick to what TeX does.)
+ §149, §152"""
+ def __init__(self, glue_type, copy=False):
+ Node.__init__(self)
+ self.glue_subtype = 'normal'
+ if is_string_like(glue_type):
+ glue_spec = GlueSpec.factory(glue_type)
+ elif isinstance(glue_type, GlueSpec):
+ glue_spec = glue_type
+ else:
+ raise ArgumentError("glue_type must be a glue spec name or instance.")
+ if copy:
+ glue_spec = glue_spec.copy()
+ self.glue_spec = glue_spec
 
-class FontElement(Element):
- def __init__(self, name):
- Element.__init__(self)
- self.name = name
+class GlueSpec(object):
+ """§150, §151"""
+ def __init__(self, width=0., stretch=0., stretch_order=0, shrink=0., shrink_order=0):
+ self.width = width
+ self.stretch = stretch
+ self.stretch_order = stretch_order
+ self.shrink = shrink
+ self.shrink_order = shrink_order
 
- def advance(self):
- 'get the horiz advance'
- return 0
+ def copy(self):
+ return GlueSpec(
+ self.width,
+ self.stretch,
+ self.stretch_order,
+ self.shrink,
+ self.shrink_order)
 
- def height(self):
- 'get the element height: ymax-ymin'
- return 0
+ def factory(glue_type):
+ return self._types[glue_type]
+ factory = staticmethod(factory)
+
+GlueSpec._types = {
+ 'lineskip': GlueSpec(0, 0, 0, 0, 0)
+}
+ 
+class Kern(Node):
+ """A Kern node has a width field to specify a (normally negative)
+ amount of spacing. This spacing correction appears in horizontal lists
+ between letters like A and V when the font designer said that it looks
+ better to move them closer together or further apart. A kern node can
+ also appear in a vertical list, when its ‘width ’ denotes additional
+ spacing in the vertical direction.
+ §155"""
+ def __init__(self, width, subtype='normal'):
+ Node.__init__(self)
+ self.width = width
+ self.subtype = subtype
+
+class Unset(Node):
+ pass
 
- def width(self):
- 'get the element width: xmax-xmin'
- return 0
+# MGDTODO: Move this to cbook 
+def clamp(value, min, max):
+ if value < min:
+ return min
+ if value > max:
+ return max
+ return value
 
- def xmin(self):
- 'get the xmin of ink rect'
- return 0
+class Ship(object):
+ """Since boxes can be inside of boxes inside of boxes, the main
+ work of Ship is done by two mutually recursive routines, hlist_out
+ and vlist_out , which traverse the Hlists and Vlists inside of
+ horizontal and vertical boxes. The global variables used in TeX to
+ store state as it processes have become member variables here.
+ §592."""
+ def __call__(self, ox, oy, box):
+ self.max_push = 0 # Deepest nesting of push commands so far
+ self.cur_s = 0
+ self.cur_v = 0.
+ self.cur_h = 0.
+ print box
+ self.off_h = ox
+ self.off_v = oy + box.height
+ self.hlist_out(box)
 
- def xmax(self):
- 'get the xmax of ink rect'
- return 0
- 
- def ymin(self):
- 'get the ymin of ink rect'
- return 0
- 
- def ymax(self):
- 'get the ymax of ink rect'
- return 0
- 
- def determine_font(self, font_stack):
- font_stack[-1] = self.name
+ def hlist_out(self, box):
+ cur_g = 0
+ cur_glue = 0.
+ glue_order = box.glue_order
+ glue_sign = box.glue_sign
+ p = box.list_head
+ base_line = self.cur_v
+ left_edge = self.cur_h
+ self.cur_s += 1
+ self.max_push = max(self.cur_s, self.max_push)
 
- def set_font(self, font):
- return
+ while p:
+ while isinstance(p, CharNode):
+ p.render(self.cur_h + self.off_h, self.cur_v + self.off_v)
+ self.cur_h += p.width
+ p = p.link
+ if p is None:
+ break
+ 
+ if isinstance(p, List):
+ # §623
+ if p.list_head is None:
+ self.cur_h += p.width
+ else:
+ edge = self.cur_h
+ self.cur_v = base_line + p.shift_amount
+ if isinstance(p, Hlist):
+ self.hlist_out(p)
+ else:
+ self.vlist_out(p)
+ self.cur_h = edge + p.width
+ self.cur_v = base_line
+ elif isinstance(p, Rule):
+ # §624
+ rule_height = p.height
+ rule_depth = p.depth
+ rule_width = p.width
+ if rule_height is None:
+ rule_height = box.height
+ if rule_depth is None:
+ rule_depth = box.depth
+ if rule_height > 0 and rule_width > 0:
+ self.cur_v = baseline + rule_depth
+ p.render(self.cur_h + self.off_h,
+ self.cur_v + self.off_v,
+ rule_width, rule_height)
+ self.cur_v = baseline
+ self.cur_h += rule_width
+ elif isinstance(p, Glue):
+ # §625
+ glue_spec = p.glue_spec
+ rule_width = glue_spec.width - cur_g
+ if g_sign != 0: # normal
+ if g_sign == 1: # stretching
+ if glue_spec.stretch_order == glue_order:
+ cur_glue += glue_spec.stretch
+ glue_temp = clamp(float(box.glue_set) * cur_glue,
+ 1000000000., -10000000000.)
+ cur_g = round(glue_temp)
+ elif glue_spec.shrink_order == glue_order:
+ cur_glue += glue_spec.shrink
+ glue_temp = clamp(float(box.glue_set) * cur_glue,
+ 1000000000., -10000000000.)
+ cur_g = round(glue_temp)
+ rule_width += cur_g
+ self.cur_h += rule_width
+ elif isinstance(p, Kern):
+ self.cur_h += p.width
+ p = p.link
+ self.cur_s -= 1
+
+ def vlist_out(self, box):
+ cur_g = 0
+ cur_glue = 0.
+ glue_order = box.glue_order
+ glue_sign = box.glue_sign
+ p = box.list_head
+ self.cur_s += 1
+ self.max_push = max(self.max_push, self.cur_s)
+ left_edge = self.cur_h
+ self.cur_v -= box.height
+ top_edge = self.cur_v
+
+ while p:
+ if isinstance(p, CharNode):
+ raise RuntimeError("Internal error in mathtext")
+ elif isinstance(p, List):
+ if p.list_head is None:
+ self.cur_v += p.height + p.depth
+ else:
+ self.cur_v += p.height
+ self.cur_h = left_edge + p.shift_amount
+ save_v = self.cur_v
+ if isinstance(p, Hlist):
+ self.hlist_out(p)
+ else:
+ self.vlist_out(p)
+ self.cur_v = save_v + p.depth
+ self.cur_h = left_edge
+ elif isinstance(p, Rule):
+ rule_height = p.height
+ rule_depth = p.depth
+ rule_width = p.width
+ if rule_width is None:
+ rule_width = box.width
+ rule_height += rule_depth
+ if rule_height > 0 and rule_depth > 0:
+ self.cur_v += rule_height
+ p.render(self.cur_h + self.off_h,
+ self.cur_v + self.off_v,
+ rule_width, rule_height)
+ elif isinstance(p, Glue):
+ glue_spec = p.glue_spec
+ rule_height = glue_spec.width - cur_g
+ if g_sign != 0: # normal
+ if g_sign == 1: # stretching
+ if glue_spec.stretch_order == glue_order:
+ cur_glue += glue_spec.stretch
+ glue_temp = clamp(float(box.glue_set) * cur_glue,
+ 1000000000., -10000000000.)
+ cur_g = round(glue_temp)
+ elif glue_spec.shrink_order == glue_order: # shrinking
+ cur_glue += glue_spec.shrink
+ glue_temp = clamp(float(box.glue_set) * cur_glue,
+ 1000000000., -10000000000.)
+ cur_g = round(glue_temp)
+ rule_height += cur_g
+ self.cur_v += rule_height
+ elif isinstance(p, Kern):
+ self.cur_v += p.width
+ 
+ p = p.link
+ self.cur_s -= 1
 
-class SpaceElement(Element):
- 'blank horizontal space'
- def __init__(self, space, height=0):
- """
- space is the amount of blank space in fraction of fontsize
- height is the height of the space in fraction of fontsize
- """
- Element.__init__(self)
- self.space = space
- self._height = height
+ship = Ship()
 
- def advance(self):
- 'get the horiz advance'
- return self.dpi/72.0*self.space*self.fontsize
+# TODO: Ligature nodes? (143)
 
- def height(self):
- 'get the element height: ymax-ymin'
- return self._height*self.dpi/72.0*self.fontsize
+# TODO: Unset box?
 
- def width(self):
- 'get the element width: xmax-xmin'
- return self.advance()
+##############################################################################
+# NOADS
 
- def xmin(self):
- 'get the minimum ink in x'
- return self.ox
+class Noad:
+ def __init__(self, nucleus=None, subscr=None, superscr=None):
+ self.link = None
+ self.nucleus = nucleus
+ self.subscr = subscr
+ self.superscr = superscr
 
- def xmax(self):
- 'get the max ink in x'
- return self.ox + self.advance()
+class OrdNoad(Noad):
+ pass
 
- def ymin(self):
- 'get the minimum ink in y'
- return self.oy
+class OpNoad(Noad):
+ pass
 
- def ymax(self):
- 'get the max ink in y'
- return self.oy + self.height()
+class BinNoad(Noad):
+ pass
 
- def determine_font(self, font_stack):
- # space doesn't care about font, only size
- for neighbor_type in ('above', 'below', 'subscript', 'superscript'):
- neighbor = self.neighbors.get(neighbor_type)
- if neighbor is not None:
- neighbor.determine_font(font_stack)
+class RelNoad(Noad):
+ pass
 
- def set_font(self, font_stack):
- # space doesn't care about font, only size
- pass
- 
-class SymbolElement(Element):
- hardcoded_font = False
+class OpenNoad(Noad):
+ pass
 
- def __init__(self, sym):
- Element.__init__(self)
- self.sym = sym
- self.kern = None
- self.widthm = 1 # the width of an m; will be resized below
+class CloseNoad(Noad):
+ pass
 
- def determine_font(self, font_stack):
- 'set the font (one of tt, it, rm, cal, bf, sf)'
- self.set_font(font_stack[-1])
- for neighbor_type in ('above', 'below', 'subscript', 'superscript'):
- neighbor = self.neighbors.get(neighbor_type)
- if neighbor is not None:
- neighbor.determine_font(font_stack)
- 
- def set_font(self, font, hardcoded=False):
- if hardcoded:
- self.hardcoded_font = True
- self.font = font
- if not self.hardcoded_font:
- assert not hasattr(self, 'font')
- self.font = font
- 
- def set_origin(self, ox, oy):
- Element.set_origin(self, ox, oy)
+class PunctNoad(Noad):
+ pass
 
- def set_size_info(self, fontsize, dpi):
- Element.set_size_info(self, fontsize, dpi)
- self.metrics = Element.fonts.get_metrics(
- self.font, self.sym, self.fontsize, dpi)
+class InnerNoad(Noad):
+ pass
 
- mmetrics = Element.fonts.get_metrics(
- self.font, 'm', self.fontsize, dpi)
- self.widthm = mmetrics.width
- #print self.widthm
+class RadicalNoad(Noad):
+ def __init__(self, nucleus=None, subscr=None, superscr=None, left_delim_font=None, left_delim_char=None):
+ Noad.__init__(self, nucleus, subscr, superscr)
+ self.left_delim = left_delim
 
- def advance(self):
- 'get the horiz advance'
- if self.kern is None:
- self.kern = 0
- if self.neighbors.has_key('right'):
- sym = None
- o = self.neighbors['right']
- if hasattr(o, 'sym'):
- sym = o.sym
- elif isinstance(o, SpaceElement):
- sym = ' '
- if sym is not None:
- self.kern = Element.fonts.get_kern(
- self.font, self.sym, sym, self.fontsize, self.dpi)
- return self.metrics.advance + self.kern
- #return self.metrics.advance # how to handle cm units?+ self.kern*self.widthm
+class NoadField:
+ def __init__(self):
+ pass
 
+class MathChar(NoadField):
+ def __init__(self, char, font):
+ self.char = char
+ self.font = font
 
- def height(self):
- 'get the element height: ymax-ymin'
- return self.metrics.height
+class SubMlist(NoadField):
+ def __init__(self):
+ pass
 
- def width(self):
- 'get the element width: xmax-xmin'
- return self.metrics.width
+##############################################################################
+# PARSER
+ 
+class Parser:
+ class State:
+ def __init__(self, font_manager, font, fontsize, dpi):
+ self.font_manager = font_manager
+ self.font = font
+ self.fontsize = fontsize
+ self.dpi = dpi
 
- def xmin(self):
- 'get the minimum ink in x'
- return self.ox + self.metrics.xmin
+ def copy(self):
+ return Parser.State(
+ self.font_manager,
+ self.font,
+ self.fontsize,
+ self.dpi)
+ 
+ def __init__(self):
+ # All forward declarations are here
+ font = Forward().setParseAction(self.font).setName("font")
+ latexfont = Forward().setParseAction(self.latexfont).setName("latexfont")
+ subsuper = Forward().setParseAction(self.subsuperscript).setName("subsuper")
+ overunder = Forward().setParseAction(self.overunder).setName("overunder")
+ placeable = Forward().setName("placeable")
+ simple = Forward().setName("simple")
+ self._expression = Forward().setParseAction(self.finish).setName("finish")
 
- def xmax(self):
- 'get the max ink in x'
- return self.ox + self.metrics.xmax
+ lbrace = Literal('{').suppress().setParseAction(self.start_group).setName("start_group")
+ rbrace = Literal('}').suppress().setParseAction(self.end_group).setName("end_group")
+ lbrack = Literal('[')
+ rbrack = Literal(']')
+ lparen = Literal('(')
+ rparen = Literal(')')
+ grouping =(lbrack 
+ | rbrack 
+ | lparen 
+ | rparen)
 
- def ymin(self):
- 'get the minimum ink in y'
- return self.oy + self.metrics.ymin
+ bslash = Literal('\\')
 
- def ymax(self):
- 'get the max ink in y'
- return self.oy + self.metrics.ymax
+ langle = Literal('<')
+ rangle = Literal('>')
+ equals = Literal('=')
+ relation =(langle
+ | rangle
+ | equals)
 
- def render(self):
- 'render to the fonts canvas'
- Element.fonts.render(
- self.ox, self.oy,
- self.font, self.sym, self.fontsize, self.dpi)
- Element.render(self)
+ colon = Literal(':')
+ comma = Literal(',')
+ period = Literal('.')
+ semicolon = Literal(';')
+ exclamation = Literal('!')
+ punctuation =(colon
+ | comma
+ | period
+ | semicolon)
 
- def __repr__(self):
- return self.sym
+ at = Literal('@')
+ percent = Literal('%')
+ ampersand = Literal('&')
+ misc =(exclamation
+ | at
+ | percent
+ | ampersand)
 
-class AccentElement(SymbolElement):
- pass
+ accent = oneOf("hat check dot breve acute ddot grave tilde bar vec "
+ "\" ` ' ~ . ^")
 
-class GroupElement(Element):
- """
- A group is a collection of elements
- """
- def __init__(self, elements):
- Element.__init__(self)
- if not isinstance(elements, list):
- elements = elements.asList()
- self.elements = elements
- for i in range(len(elements)-1):
- self.elements[i].neighbors['right'] = self.elements[i+1]
+ function = oneOf("arccos csc ker min arcsin deg lg Pr arctan det lim sec "
+ "arg dim liminf sin cos exp limsup sinh cosh gcd ln sup "
+ "cot hom log tan coth inf max tanh")
 
- def determine_font(self, font_stack):
- 'set the font (one of tt, it, rm , cal)'
- font_stack.append(font_stack[-1])
- for element in self.elements:
- element.determine_font(font_stack)
- for neighbor_type in ('above', 'below', 'subscript', 'superscript'):
- neighbor = self.neighbors.get(neighbor_type)
- if neighbor is not None:
- neighbor.determine_font(font_stack)
- font_stack.pop()
+ number = Combine(Word(nums) + Optional(Literal('.')) + Optional( Word(nums) ))
 
- def set_font(self, font):
- return
+ plus = Literal('+')
+ minus = Literal('-')
+ times = Literal('*')
+ div = Literal('/')
+ binop =(plus 
+ | minus
+ | times
+ | div)
 
- def set_size_info(self, fontsize, dpi):
- if len(self.elements):
- self.elements[0].set_size_info(self._scale*fontsize, dpi)
- Element.set_size_info(self, fontsize, dpi)
- #print 'set size'
+ fontname = oneOf("rm cal it tt sf bf")
+ latex2efont = oneOf("mathrm mathcal mathit mathtt mathsf mathbf")
 
+ texsym = Combine(bslash + Word(alphanums) + NotAny("{"))
 
- def set_origin(self, ox, oy):
- if len(self.elements):
- self.elements[0].set_origin(ox, oy)
- Element.set_origin(self, ox, oy)
+ char = Word(alphanums + ' ', exact=1).leaveWhitespace()
 
+ space =(FollowedBy(bslash)
+ + (Literal(r'\ ')
+ | Literal(r'\/')
+ | Group(Literal(r'\hspace{') + number + Literal('}'))
+ )
+ ).setParseAction(self.space).setName('space')
 
- def advance(self):
- 'get the horiz advance'
- if len(self.elements):
- return self.elements[-1].xmax() - self.elements[0].ox
- return 0
+ symbol = Regex("(" + ")|(".join(
+ [
+ r"\\[a-zA-Z0-9]+(?!{)",
+ r"[a-zA-Z0-9 ]",
+ r"[+\-*/]",
+ r"[<>=]",
+ r"[:,.;!]",
+ r"[!@%&]",
+ r"[[\]()]",
+ r"\\\$"
+ ])
+ + ")"
+ ).setParseAction(self.symbol).leaveWhitespace()
 
+ _symbol =(texsym
+ | char
+ | binop
+ | relation
+ | punctuation
+ | misc
+ | grouping
+ ).setParseAction(self.symbol).leaveWhitespace()
 
- def height(self):
- 'get the element height: ymax-ymin'
- ymax = max([e.ymax() for e in self.elements])
- ymin = min([e.ymin() for e in self.elements])
- return ymax-ymin
+ accent = Group(
+ Combine(bslash + accent)
+ + Optional(lbrace)
+ + symbol
+ + Optional(rbrace)
+ ).setParseAction(self.accent).setName("accent")
 
- def width(self):
- 'get the element width: xmax-xmin'
- xmax = max([e.xmax() for e in self.elements])
- xmin = min([e.xmin() for e in self.elements])
- return xmax-xmin
+ function =(Suppress(bslash)
+ + function).setParseAction(self.function).setName("function")
 
- def render(self):
- 'render to the fonts canvas'
- if len(self.elements):
- self.elements[0].render()
- Element.render(self)
+ group = Group(
+ lbrace
+ + OneOrMore(
+ simple
+ )
+ + rbrace
+ ).setParseAction(self.group).setName("group")
 
- def xmin(self):
- 'get the minimum ink in x'
- return min([e.xmin() for e in self.elements])
+ font <<(Suppress(bslash)
+ + fontname)
 
- def xmax(self):
- 'get the max ink in x'
- return max([e.xmax() for e in self.elements])
+ latexfont << Group(
+ Suppress(bslash)
+ + latex2efont
+ + group)
 
- def ymin(self):
- 'get the minimum ink in y'
- return max([e.ymin() for e in self.elements])
+ frac = Group(
+ Suppress(
+ bslash
+ + Literal("frac")
+ )
+ + group
+ + group
+ ).setParseAction(self.frac).setName("frac")
 
- def ymax(self):
- 'get the max ink in y'
- return max([e.ymax() for e in self.elements])
+ placeable <<(accent
+ ^ function 
+ ^ symbol
+ ^ group
+ ^ frac
+ )
 
- def __repr__(self):
- return 'Group: [ %s ]' % ' '.join([str(e) for e in self.elements])
+ simple <<(space
+ | font
+ | latexfont
+ | overunder)
 
-class MathGroupElement(GroupElement):
- def determine_font(self, font_stack):
- font_stack.append('it')
- for element in self.elements:
- element.determine_font(font_stack)
- font_stack.pop()
+ subsuperop =(Literal("_")
+ | Literal("^")
+ ) 
 
-class NonMathGroupElement(GroupElement):
- def determine_font(self, font_stack):
- for element in self.elements:
- element.determine_font(font_stack)
- 
-class ExpressionElement(GroupElement):
- """
- The entire mathtext expression
- """
+ subsuper << Group(
+ (
+ placeable
+ + ZeroOrMore(
+ subsuperop
+ + subsuper
+ )
+ )
+ | (subsuperop + placeable)
+ )
 
- def __repr__(self):
- return 'Expression: [ %s ]' % ' '.join([str(e) for e in self.elements])
+ overunderop =(
+ ( Suppress(bslash)
+ + Literal(r"over")
+ )
+ | ( Suppress(bslash)
+ + Literal(r"under")
+ )
+ ) 
 
- def determine_font(self, font_stack):
- GroupElement.determine_font(self, font_stack)
+ overunder << Group(
+ (
+ subsuper
+ + ZeroOrMore(
+ overunderop
+ + overunder
+ )
+ )
+ )
 
-class Handler:
- symbols = []
+ math = OneOrMore(
+ simple
+ ).setParseAction(self.math).setName("math")
 
- def clear(self):
- self.symbols = []
+ math_delim =(~bslash
+ + Literal('$'))
 
- def expression(self, s, loc, toks):
- #~ print "expr", toks
- self.expr = ExpressionElement(toks)
- return [self.expr]
+ non_math = Regex(r"(?:[^$]|(?:\\\$))*"
+ ).setParseAction(self.non_math).setName("non_math").leaveWhitespace()
 
+ self._expression <<(
+ non_math
+ + ZeroOrMore(
+ Suppress(math_delim)
+ + math
+ + Suppress(math_delim)
+ + non_math
+ )
+ )
+
+ def parse(self, s, fonts_object, default_font, fontsize, dpi):
+ self._state_stack = [self.State(fonts_object, default_font, fontsize, dpi)]
+ self._expression.parseString(s)
+ return self._expr
+ 
+ def get_state(self):
+ return self._state_stack[-1]
+
+ def pop_state(self):
+ self._state_stack.pop()
+
+ def push_state(self):
+ self._state_stack.append(self.get_state().copy())
+ 
+ def finish(self, s, loc, toks):
+ self._expr = Hlist(toks)
+ return [self._expr]
+ 
 def math(self, s, loc, toks):
- #~ print "math", toks
- math = MathGroupElement(toks)
- return [math]
+ hlist = Hlist(toks)
+ self.pop_state()
+ return [hlist]
 
 def non_math(self, s, loc, toks):
 #~ print "non_math", toks
 # This is a hack, but it allows the system to use the
 # proper amount of advance when going from non-math to math
 s = toks[0] + ' '
- symbols = [SymbolElement(c) for c in s]
- self.symbols.extend(symbols)
- non_math = NonMathGroupElement(symbols)
- return [non_math]
+ symbols = [CharNode(c, self.get_state()) for c in s]
+ hlist = Hlist(symbols)
+ self.push_state()
+ self.get_state().font = 'it'
+ return [hlist]
 
 def space(self, s, loc, toks):
 assert(len(toks)==1)
@@ -1335,36 +1820,40 @@
 self.symbols.append(element)
 return [element]
 
- def symbol(self, s, loc, toks):
- assert(len(toks)==1)
- #print "symbol", toks
+# def symbol(self, s, loc, toks):
+# assert(len(toks)==1)
+# #print "symbol", toks
 
- s = toks[0]
- if charOverChars.has_key(s):
- under, over, pad = charOverChars[s]
- font, tok, scale = under
- sym = SymbolElement(tok)
- if font is not None:
- sym.set_font(font, hardcoded=True)
- sym.set_scale(scale)
- sym.set_pady(pad)
+# s = toks[0]
+# if charOverChars.has_key(s):
+# under, over, pad = charOverChars[s]
+# font, tok, scale = under
+# sym = SymbolElement(tok)
+# if font is not None:
+# sym.set_font(font, hardcoded=True)
+# sym.set_scale(scale)
+# sym.set_pady(pad)
 
- font, tok, scale = over
- sym2 = SymbolElement(tok)
- if font is not None:
- sym2.set_font(font, hardcoded=True)
- sym2.set_scale(scale)
+# font, tok, scale = over
+# sym2 = SymbolElement(tok)
+# if font is not None:
+# sym2.set_font(font, hardcoded=True)
+# sym2.set_scale(scale)
 
- sym.neighbors['above'] = sym2
- self.symbols.append(sym2)
- else:
- sym = SymbolElement(toks[0])
- self.symbols.append(sym)
+# sym.neighbors['above'] = sym2
+# self.symbols.append(sym2)
+# else:
+# sym = SymbolElement(toks[0], self.current_font)
+# self.symbols.append(sym)
 
- return [sym]
+# return [sym]
 
+ def symbol(self, s, loc, toks):
+ return [CharNode(toks[0], self.get_state())]
+
+ space = symbol
+ 
 def accent(self, s, loc, toks):
-
 assert(len(toks)==1)
 accent, sym = toks[0]
 
@@ -1399,19 +1888,22 @@
 symbols.append(sym)
 self.symbols.append(sym)
 return [GroupElement(symbols)]
+
+ def start_group(self, s, loc, toks):
+ self.push_state()
 
 def group(self, s, loc, toks):
- assert(len(toks)==1)
- #print 'grp', toks
- grp = GroupElement(toks[0])
+ grp = Hlist(toks[0])
 return [grp]
 
+ def end_group(self, s, loc, toks):
+ self.pop_state()
+ 
 def font(self, s, loc, toks):
 assert(len(toks)==1)
 name = toks[0]
- #print 'fontgrp', toks
- font = FontElement(name)
- return [font]
+ self.get_state().font = name
+ return []
 
 def latexfont(self, s, loc, toks):
 assert(len(toks)==1)
@@ -1468,189 +1960,26 @@
 return [prev]
 
 def is_overunder(self, prev):
- return isinstance(prev, SymbolElement) and overunder.has_key(prev.sym)
+ return isinstance(prev, SymbolElement) and overunder_symbols.has_key(prev.sym)
 
-handler = Handler()
+ def frac(self, s, loc, toks):
+ assert(len(toks)==1)
+ assert(len(toks[0])==2)
+ #~ print 'subsuperscript', toks
+ 
+ top, bottom = toks[0]
+ vlist = Vlist([bottom, Hrule(self.get_state()), top])
+ # vlist.shift_amount = 8
+ return [vlist]
 
-# All forward declarations are here
-font = Forward().setParseAction(handler.font).setName("font")
-latexfont = Forward().setParseAction(handler.latexfont).setName("latexfont")
-subsuper = Forward().setParseAction(handler.subsuperscript).setName("subsuper")
-placeable = Forward().setName("placeable")
-simple = Forward().setName("simple")
-expression = Forward().setParseAction(handler.expression).setName("expression")
+ overunder = subsuperscript
+ 
 
-lbrace = Literal('{').suppress()
-rbrace = Literal('}').suppress()
-lbrack = Literal('[')
-rbrack = Literal(']')
-lparen = Literal('(')
-rparen = Literal(')')
-grouping =(lbrack 
- | rbrack 
- | lparen 
- | rparen)
-
-bslash = Literal('\\')
-
-langle = Literal('<')
-rangle = Literal('>')
-equals = Literal('=')
-relation =(langle
- | rangle
- | equals)
-
-colon = Literal(':')
-comma = Literal(',')
-period = Literal('.')
-semicolon = Literal(';')
-exclamation = Literal('!')
-punctuation =(colon
- | comma
- | period
- | semicolon)
-
-at = Literal('@')
-percent = Literal('%')
-ampersand = Literal('&')
-misc =(exclamation
- | at
- | percent
- | ampersand)
-
-accent = oneOf("hat check dot breve acute ddot grave tilde bar vec "
- "\" ` ' ~ . ^")
-
-function = oneOf("arccos csc ker min arcsin deg lg Pr arctan det lim sec "
- "arg dim liminf sin cos exp limsup sinh cosh gcd ln sup "
- "cot hom log tan coth inf max tanh")
-
-number = Combine(Word(nums) + Optional(Literal('.')) + Optional( Word(nums) ))
-
-plus = Literal('+')
-minus = Literal('-')
-times = Literal('*')
-div = Literal('/')
-binop =(plus 
- | minus
- | times
- | div)
-
-fontname = oneOf("rm cal it tt sf bf")
-latex2efont = oneOf("mathrm mathcal mathit mathtt mathsf mathbf")
-
-texsym = Combine(bslash + Word(alphanums) + NotAny("{"))
-
-char = Word(alphanums + ' ', exact=1).leaveWhitespace()
-
-space =(FollowedBy(bslash)
- + (Literal(r'\ ')
- | Literal(r'\/')
- | Group(Literal(r'\hspace{') + number + Literal('}'))
- )
- ).setParseAction(handler.space).setName('space')
-
-symbol = Regex("(" + ")|(".join(
- [
- r"\\[a-zA-Z0-9]+(?!{)",
- r"[a-zA-Z0-9 ]",
- r"[+\-*/]",
- r"[<>=]",
- r"[:,.;!]",
- r"[!@%&]",
- r"[[\]()]",
- r"\\\$"
- ])
- + ")"
- ).setParseAction(handler.symbol).leaveWhitespace()
-
-_symbol =(texsym
- | char
- | binop
- | relation
- | punctuation
- | misc
- | grouping
- ).setParseAction(handler.symbol).leaveWhitespace()
-
-accent = Group(
- Combine(bslash + accent)
- + Optional(lbrace)
- + symbol
- + Optional(rbrace)
- ).setParseAction(handler.accent).setName("accent")
-
-function =(Suppress(bslash)
- + function).setParseAction(handler.function).setName("function")
-
-group = Group(
- lbrace
- + OneOrMore(
- simple
- )
- + rbrace
- ).setParseAction(handler.group).setName("group")
-
-font <<(Suppress(bslash)
- + fontname)
-
-latexfont << Group(
- Suppress(bslash)
- + latex2efont
- + group)
-
-placeable <<(accent
- ^ function 
- ^ symbol
- ^ group
- )
-
-simple <<(space
- | font
- | latexfont
- | subsuper)
-
-subsuperop =(Literal("_")
- | Literal("^")
- | (Suppress(bslash) + Literal("under"))
- | (Suppress(bslash) + Literal("over"))
- ) 
-
-subsuper << Group(
- (
- placeable
- + ZeroOrMore(
- subsuperop
- + subsuper
- )
- )
- | (subsuperop + placeable)
- )
-
-math = OneOrMore(
- simple
- ).setParseAction(handler.math).setName("math")
-
-math_delim =(~bslash
- + Literal('$'))
-
-non_math = Regex(r"(?:[^$]|(?:\\\$))*"
- ).setParseAction(handler.non_math).setName("non_math").leaveWhitespace()
-
-expression <<(
- non_math
- + ZeroOrMore(
- Suppress(math_delim)
- + math
- + Suppress(math_delim)
- + non_math
- )
- )
-
 ####
 
+##############################################################################
+# MAIN
 
-
 class math_parse_s_ft2font_common:
 """
 Parse the math expression s, return the (bbox, fonts) tuple needed
@@ -1664,6 +1993,8 @@
 if major==2 and minor1==2:
 raise SystemExit('mathtext broken on python2.2. We hope to get this fixed soon')
 
+ parser = None
+ 
 def __init__(self, output):
 self.output = output
 self.cache = {}
@@ -1676,27 +2007,20 @@
 
 use_afm = False
 if self.output == 'SVG':
- self.font_object = BakomaSVGFonts()
- #self.font_object = MyUnicodeFonts(output='SVG')
+ font_manager = BakomaSVGFonts()
 elif self.output == 'Agg':
- self.font_object = BakomaFonts()
- #self.font_object = MyUnicodeFonts()
+ font_manager = BakomaFonts()
 elif self.output == 'PS':
 if rcParams['ps.useafm']:
- self.font_object = StandardPSFonts()
+ font_manager = StandardPSFonts()
 use_afm = True
 else:
- self.font_object = BakomaPSFonts()
- #self.font_object = MyUnicodeFonts(output='PS')
+ font_manager = BakomaPSFonts()
 elif self.output == 'PDF':
- self.font_object = BakomaPDFFonts()
- Element.fonts = self.font_object
+ font_manager = BakomaPDFFonts()
 
 fontsize = prop.get_size_in_points()
 
- handler.clear()
- expression.parseString( s )
-
 if use_afm:
 fname = fontManager.findfont(prop, fontext='afm')
 default_font = AFM(file(fname, 'r'))
@@ -1704,49 +2028,29 @@
 else:
 fname = fontManager.findfont(prop)
 default_font = FT2Font(fname)
+
+ if self.parser is None:
+ self.__class__.parser = Parser()
+ box = self.parser.parse(s, font_manager, default_font, fontsize, dpi)
+ w, h = box.width, box.height + box.depth
+ w += 4
+ h += 4
+ font_manager.set_canvas_size(w,h)
 
- handler.expr.determine_font([default_font])
- handler.expr.set_size_info(fontsize, dpi)
+ ship(2, 2, box)
 
- # set the origin once to allow w, h compution
- handler.expr.set_origin(0, 0)
- xmin = min([e.xmin() for e in handler.symbols])
- xmax = max([e.xmax() for e in handler.symbols])
- ymin = min([e.ymin() for e in handler.symbols])
- ymax = max([e.ymax() for e in handler.symbols])
- 
- # now set the true origin - doesn't affect with and height
- w, h = xmax-xmin, ymax-ymin
- # a small pad for the canvas size
- w += 2
- h += 2
-
- handler.expr.set_origin(0, h-ymax)
-
- if self.output in ('SVG', 'Agg'):
- Element.fonts.set_canvas_size(w,h)
- elif self.output == 'PS':
- pswriter = StringIO()
...
 
[truncated message content]
Revision: 3594
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3594&view=rev
Author: mdboom
Date: 2007年07月20日 08:47:53 -0700 (2007年7月20日)
Log Message:
-----------
Got glue working, as demonstrated by frac
Modified Paths:
--------------
 branches/mathtext_mgd/lib/matplotlib/mathtext.py
Modified: branches/mathtext_mgd/lib/matplotlib/mathtext.py
===================================================================
--- branches/mathtext_mgd/lib/matplotlib/mathtext.py	2007年07月20日 15:47:00 UTC (rev 3593)
+++ branches/mathtext_mgd/lib/matplotlib/mathtext.py	2007年07月20日 15:47:53 UTC (rev 3594)
@@ -145,7 +145,8 @@
 operatorPrecedence, opAssoc, ParseResults, Or, Suppress, oneOf
 
 from matplotlib.afm import AFM
-from matplotlib.cbook import enumerate, iterable, Bunch, get_realpath_and_stat
+from matplotlib.cbook import enumerate, iterable, Bunch, get_realpath_and_stat, \
+ is_string_like
 from matplotlib.ft2font import FT2Font
 from matplotlib.font_manager import fontManager, FontProperties
 from matplotlib._mathtext_data import latex_to_bakoma, cmkern, \
@@ -694,7 +695,7 @@
 assert len(self.fonts)
 font = self.fonts.values()[0]
 print "filled rect:", x1, y1, x2, y2
- font.font.draw_rect_filled(x1, y1, x2, y2)
+ font.font.draw_rect_filled(x1, y1, x2 - 1, y2 - 1)
 
 def _old_get_kern(self, font, symleft, symright, fontsize, dpi):
 """
@@ -1027,7 +1028,7 @@
 elem = next
 
 def __repr__(self):
- s = '[' + self.__internal_repr__()
+ s = '[' + self.__internal_repr__() + "%f %d %d " % (self.glue_set, self.glue_sign, self.glue_order)
 if self.list_head:
 s += ' ' + self.list_head.__repr__()
 s += ']'
@@ -1039,7 +1040,7 @@
 """A helper function to determine the highest order of glue
 used by the members of this list. Used by vpack and hpack."""
 o = 0
- for i in range(len(totals), 0, -1):
+ for i in range(len(totals) - 1, 0, -1):
 if totals[i] != 0.0:
 o = i
 break
@@ -1124,7 +1125,8 @@
 w += x
 self.width = w
 x = w - x
- 
+
+ print "total_stretch:", total_stretch
 if x == 0.:
 self.glue_sign = 0
 self.glue_order = 0
@@ -1154,7 +1156,7 @@
 if o == 0:
 if self.list_head is not None:
 warn("Underfull vbox: %r" % self, MathTextWarning)
-
+ 
 class Vlist(List):
 """A vertical list of boxes.
 §137"""
@@ -1311,14 +1313,36 @@
 self.shrink,
 self.shrink_order)
 
- def factory(glue_type):
- return self._types[glue_type]
- factory = staticmethod(factory)
+ def factory(cls, glue_type):
+ return cls._types[glue_type]
+ factory = classmethod(factory)
 
 GlueSpec._types = {
- 'lineskip': GlueSpec(0, 0, 0, 0, 0)
+ 'fil': GlueSpec(0., 1., 1, 0., 0),
+ 'fill': GlueSpec(0., 1., 2, 0., 0),
+ 'filll': GlueSpec(0., 1., 3, 0., 0)
 }
- 
+
+# Some convenient ways to get common kinds of glue
+
+class Fil(Glue):
+ def __init__(self):
+ Glue.__init__(self, 'fil')
+
+class Fill(Glue):
+ def __init__(self):
+ Glue.__init__(self, 'fill')
+
+class Filll(Glue):
+ def __init__(self):
+ Glue.__init__(self, 'filll')
+
+class HCentered(Hlist):
+ """A convenience class to create an Hlist whose contents are centered
+ within its enclosing box."""
+ def __init__(self, elements):
+ Hlist.__init__(self, [Fill()] + elements + [Fill()])
+ 
 class Kern(Node):
 """A Kern node has a width field to specify a (normally negative)
 amount of spacing. This spacing correction appears in horizontal lists
@@ -1334,15 +1358,7 @@
 
 class Unset(Node):
 pass
- 
-# MGDTODO: Move this to cbook 
-def clamp(value, min, max):
- if value < min:
- return min
- if value > max:
- return max
- return value
- 
+
 class Ship(object):
 """Since boxes can be inside of boxes inside of boxes, the main
 work of Ship is done by two mutually recursive routines, hlist_out
@@ -1359,6 +1375,14 @@
 self.off_h = ox
 self.off_v = oy + box.height
 self.hlist_out(box)
+
+ def clamp(value):
+ if value < -1000000000.:
+ return -1000000000.
+ if value > 1000000000.:
+ return 1000000000.
+ return value
+ clamp = staticmethod(clamp)
 
 def hlist_out(self, box):
 cur_g = 0
@@ -1389,6 +1413,7 @@
 if isinstance(p, Hlist):
 self.hlist_out(p)
 else:
+ p.vpack(box.height, 'exactly')
 self.vlist_out(p)
 self.cur_h = edge + p.width
 self.cur_v = base_line
@@ -1412,18 +1437,14 @@
 # §625
 glue_spec = p.glue_spec
 rule_width = glue_spec.width - cur_g
- if g_sign != 0: # normal
- if g_sign == 1: # stretching
+ if glue_sign != 0: # normal
+ if glue_sign == 1: # stretching
 if glue_spec.stretch_order == glue_order:
 cur_glue += glue_spec.stretch
- glue_temp = clamp(float(box.glue_set) * cur_glue,
- 1000000000., -10000000000.)
- cur_g = round(glue_temp)
+ cur_g = round(self.clamp(float(box.glue_set) * cur_glue))
 elif glue_spec.shrink_order == glue_order:
 cur_glue += glue_spec.shrink
- glue_temp = clamp(float(box.glue_set) * cur_glue,
- 1000000000., -10000000000.)
- cur_g = round(glue_temp)
+ cur_g = round(self.clamp(float(box.glue_set) * cur_glue))
 rule_width += cur_g
 self.cur_h += rule_width
 elif isinstance(p, Kern):
@@ -1453,7 +1474,9 @@
 self.cur_v += p.height
 self.cur_h = left_edge + p.shift_amount
 save_v = self.cur_v
+ p.width = box.width
 if isinstance(p, Hlist):
+ p.hpack(box.width, 'exactly')
 self.hlist_out(p)
 else:
 self.vlist_out(p)
@@ -1474,18 +1497,14 @@
 elif isinstance(p, Glue):
 glue_spec = p.glue_spec
 rule_height = glue_spec.width - cur_g
- if g_sign != 0: # normal
- if g_sign == 1: # stretching
+ if glue_sign != 0: # normal
+ if glue_sign == 1: # stretching
 if glue_spec.stretch_order == glue_order:
 cur_glue += glue_spec.stretch
- glue_temp = clamp(float(box.glue_set) * cur_glue,
- 1000000000., -10000000000.)
- cur_g = round(glue_temp)
+ cur_g = round(self.clamp(float(box.glue_set) * cur_glue))
 elif glue_spec.shrink_order == glue_order: # shrinking
 cur_glue += glue_spec.shrink
- glue_temp = clamp(float(box.glue_set) * cur_glue,
- 1000000000., -10000000000.)
- cur_g = round(glue_temp)
+ cur_g = round(self.clamp(float(box.glue_set) * cur_glue))
 rule_height += cur_g
 self.cur_v += rule_height
 elif isinstance(p, Kern):
@@ -1968,7 +1987,12 @@
 #~ print 'subsuperscript', toks
 
 top, bottom = toks[0]
- vlist = Vlist([bottom, Hrule(self.get_state()), top])
+ vlist = Vlist([HCentered([top]),
+ Kern(4.0),
+ Hrule(self.get_state()),
+ Kern(4.0),
+ HCentered([bottom])
+ ])
 # vlist.shift_amount = 8
 return [vlist]
 
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.
Thanks for helping keep SourceForge clean.
X





Briefly describe the problem (required):
Upload screenshot of ad (required):
Select a file, or drag & drop file here.
Screenshot instructions:

Click URL instructions:
Right-click on the ad, choose "Copy Link", then paste here →
(This may not be possible with some types of ads)

More information about our ad policies

Ad destination/click URL:

AltStyle によって変換されたページ (->オリジナル) /