SourceForge logo
SourceForge logo
Menu

matplotlib-checkins

Revision: 3610
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3610&view=rev
Author: mdboom
Date: 2007年07月24日 12:23:37 -0700 (2007年7月24日)
Log Message:
-----------
Back to feature-parity with old mathtext system (plus fractions and no
character clashes).
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月24日 19:22:53 UTC (rev 3609)
+++ branches/mathtext_mgd/lib/matplotlib/mathtext.py	2007年07月24日 19:23:37 UTC (rev 3610)
@@ -141,7 +141,7 @@
 from matplotlib import verbose
 from matplotlib.pyparsing import Literal, Word, OneOrMore, ZeroOrMore, \
 Combine, Group, Optional, Forward, NotAny, alphas, nums, alphanums, \
- StringStart, StringEnd, ParseException, FollowedBy, Regex, \
+ StringStart, StringEnd, ParseFatalException, FollowedBy, Regex, \
 operatorPrecedence, opAssoc, ParseResults, Or, Suppress, oneOf
 
 from matplotlib.afm import AFM
@@ -154,6 +154,16 @@
 from matplotlib.numerix import absolute
 from matplotlib import get_data_path, rcParams
 
+####################
+# MGDTODO: Use rcParams for these
+SHRINK_FACTOR = 0.7
+NUM_SIZE_LEVELS = 3
+SUBDROP = 1.0
+SCRIPT_SPACE = 2.0
+SUP1 = 4.0
+SUB1 = 5.0
+DELTA = 1.0
+
 # symbols that have the sub and superscripts over/under
 overunder_symbols = {
 r'\sum' : 1,
@@ -611,6 +621,9 @@
 self.fonts[basename] = cached_font
 return basename, cached_font
 
+ def get_font(self, font):
+ return self._get_font(font)[1].font
+ 
 def get_fonts(self):
 return [x.font for x in self.fonts.values()]
 
@@ -668,11 +681,10 @@
 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
+ iceberg = glyph.horiBearingY/64.0 + offset
 )
- 
+
+ print glyph.vertBearingY/64.0, glyph.vertAdvance/65536.0
 self.glyphd[key] = basename, font, metrics, symbol_name, num, glyph, offset
 return self.glyphd[key]
 
@@ -694,8 +706,7 @@
 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 - 1, y2 - 1)
+ font.font.draw_rect_filled(x1, y1, max(x2 - 1, x1), max(y2 - 1, y1))
 
 def _old_get_kern(self, font, symleft, symright, fontsize, dpi):
 """
@@ -723,6 +734,22 @@
 basename, cached_font = self._get_font(font)
 pclt = cached_font.font.get_sfnt_table('pclt')
 return pclt['xHeight'] / 64.0 
+
+ def get_underline_thickness(self, font):
+ basename, cached_font = self._get_font(font)
+ return max(1.0, cached_font.font.underline_thickness / 64.0)
+
+ def get_kern(self, fontleft, symleft, fontsizeleft,
+ fontright, symright, fontsizeright, dpi):
+ if fontsizeleft == fontsizeright:
+ basename, font1, metrics, symbol_name, num, glyph1, offset = \
+ self._get_info(fontleft, symleft, fontsizeleft, dpi)
+ basename, font2, metrics, symbol_name, num, glyph2, offset = \
+ self._get_info(fontright, symright, fontsizeright, dpi)
+ if font1 == font2:
+ basename, font = self._get_font(font1)
+ return font.font.get_kerning(glyph1, glyph2) / 64.0
+ return 0.0
 
 class BakomaPSFonts(BakomaFonts):
 """
@@ -929,11 +956,13 @@
 # Typesetting math formulas
 #
 # Many of the docstrings below refer to a numbered "node" in that
-# book, e.g. §123
+# book, e.g. @123
 #
 # Note that (as TeX) y increases downward, unlike many other parts of
 # matplotlib.
 
+# MGDTODO: scale_factor is a non-TeX hack
+ 
 class MathTextWarning(Warning):
 pass
 
@@ -943,6 +972,7 @@
 """
 def __init__(self):
 self.link = None
+ self.size = 0
 
 def __repr__(self):
 s = self.__internal_repr__()
@@ -955,62 +985,127 @@
 
 def get_kerning(self, next):
 return 0.0
- 
+
 def set_link(self, other):
 self.link = other
- 
+
+ def pack(self):
+ if self.link:
+ self.link.pack()
+
+ def shrink(self):
+ """Shrinks one level smaller. There are only three levels of sizes,
+ after which things will no longer get smaller."""
+ if self.link:
+ self.link.shrink()
+ self.size += 1
+ 
 def render(self, x, y):
 pass
 
 class Box(Node):
 """Represents any node with a physical location.
- §135"""
+ @135"""
 def __init__(self, width, height, depth):
 Node.__init__(self)
 self.width = width
 self.height = height
 self.depth = depth
+
+ def shrink(self):
+ Node.shrink(self)
+ if self.size < NUM_SIZE_LEVELS:
+ if self.width is not None:
+ self.width *= SHRINK_FACTOR
+ if self.height is not None:
+ self.height *= SHRINK_FACTOR
+ if self.depth is not None:
+ self.depth *= SHRINK_FACTOR
+
+ def render(self, x1, y1, x2, y2):
+ pass
+
+class Vbox(Box):
+ def __init__(self, height, depth):
+ Box.__init__(self, 0., height, depth)
+
+class Hbox(Box):
+ def __init__(self, width):
+ Box.__init__(self, width, 0., 0.)
 
-class CharNode(Box):
+class Char(Node):
 """Represents a single character. Unlike TeX, the font
- information and metrics are stored with each CharNode to make it
+ information and metrics are stored with each Char 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"""
+ Char is added to its parent Hlist.
+ @134"""
 def __init__(self, c, state):
+ Node.__init__(self)
 self.c = c
 self.font_manager = state.font_manager
 self.font = state.font
 self.fontsize = state.fontsize
 self.dpi = state.dpi
+ # The real width, height and depth will be set during the
+ # pack phase, after we know the real fontsize
+ self._update_metrics()
+ 
+ def __internal_repr__(self):
+ return repr(self.c)
+
+ def _update_metrics(self):
 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))
+ print self.c, metrics.height, metrics.ymax, metrics.ymin, metrics.iceberg
+ self.width = metrics.width
+ self.height = metrics.iceberg
+ self.depth = -(metrics.iceberg - metrics.height)
 
- def __internal_repr__(self):
- return self.c
-
 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
+ advance = self._metrics.advance - self.width
+ kern = 0.
+ #if isinstance(next, Char):
+ # kern = self.font_manager.get_kern(self.font, self.c, self.fontsize, next.font, next.c, next.fontsize, self.dpi)
+ return advance + kern
 
 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)
+
+ def shrink(self):
+ Node.shrink(self)
+ if self.size < NUM_SIZE_LEVELS:
+ self.fontsize *= SHRINK_FACTOR
+ self._update_metrics()
 
+class Accent(Char):
+ """The font metrics need to be dealt with differently for accents."""
+ def _update_metrics(self):
+ metrics = self._metrics = self.font_manager.get_metrics(
+ self.font, self.c, self.fontsize, self.dpi)
+ self.width = metrics.width
+ self.height = metrics.ymax - metrics.ymin
+ self.depth = 0
+
+ def render(self, x, y):
+ """Render the character to the canvas"""
+ self.font_manager.render(
+ x, y + (self._metrics.ymax - self.height),
+ self.font, self.c, self.fontsize, self.dpi)
+ 
 class List(Box):
 """A list of nodes (either horizontal or vertical).
- §135"""
+ @135"""
 def __init__(self, elements):
 Box.__init__(self, 0., 0., 0.)
 self.shift_amount = 0. # An arbitrary offset
@@ -1028,7 +1123,7 @@
 elem = next
 
 def __repr__(self):
- s = '[' + self.__internal_repr__() + "%f %d %d " % (self.glue_set, self.glue_sign, self.glue_order)
+ s = '[' + self.__internal_repr__() + " <%d %d %d %d> " % (self.width, self.height, self.depth, self.shift_amount)
 if self.list_head:
 s += ' ' + self.list_head.__repr__()
 s += ']'
@@ -1045,18 +1140,39 @@
 o = i
 break
 return o
- 
+
+ def _set_glue(self, x, sign, totals, error_type):
+ o = self._determine_order(totals)
+ self.glue_order = o
+ self.glue_sign = sign
+ if totals[o] != 0.:
+ self.glue_set = x / totals[o]
+ else:
+ self.glue_sign = 0
+ self.glue_ratio = 0.
+ if o == 0:
+ if self.list_head is not None:
+ warn("%s %s: %r" % (error_type, self.__class__.__name__, self),
+ MathTextWarning)
+
+ def shrink(self):
+ if self.list_head:
+ self.list_head.shrink()
+ Box.shrink(self)
+ if self.size < NUM_SIZE_LEVELS:
+ self.shift_amount *= SHRINK_FACTOR
+
 class Hlist(List):
 """A horizontal list of boxes.
- §135"""
+ @135"""
 def __init__(self, elements, w=0., m='additional'):
 List.__init__(self, elements)
- self.do_kerning()
- self.hpack(w, m)
+ self.kern()
+ self.hpack()
 
- def do_kerning(self):
- """Insert Kern nodes between CharNodes to set kerning. The
- CharNodes themselves determine the amount of kerning they need
+ def kern(self):
+ """Insert Kern nodes between Chars to set kerning. The
+ Chars 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
@@ -1068,7 +1184,13 @@
 elem.link = kern
 kern.link = next
 elem = next
- 
+
+ def pack(self):
+ if self.list_head:
+ self.list_head.pack()
+ self.hpack()
+ Node.pack(self)
+ 
 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
@@ -1083,8 +1205,10 @@
 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.
+ @644, @649"""
+ # I don't know why these get reset in TeX. Shift_amount is pretty
+ # much useless if we do.
+ #self.shift_amount = 0.
 h = 0.
 d = 0.
 x = 0.
@@ -1093,21 +1217,18 @@
 p = self.list_head
 while p is not None:
 # Layout characters in a tight inner loop (common case)
- while isinstance(p, CharNode):
+ while isinstance(p, Char):
 x += p.width
 h = max(h, p.height)
 d = max(d, p.depth)
- p = p.link
+ p = p.link # Go to next node in list
 if p is None:
 break
 
- if isinstance(p, (List, Rule, Unset)):
+ if isinstance(p, (Box, 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:
+ s = getattr(p, 'shift_amount', 0.)
 h = max(h, p.height - s)
 d = max(d, p.depth + s)
 elif isinstance(p, Glue):
@@ -1117,7 +1238,7 @@
 total_shrink[glue_spec.shrink_order] += glue_spec.shrink
 elif isinstance(p, Kern):
 x += p.width
- p = p.link
+ p = p.link # Go to next node in list
 self.height = h
 self.depth = d
 
@@ -1126,44 +1247,29 @@
 self.width = w
 x = w - x
 
- print "total_stretch:", total_stretch
 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 hbox: %r" % self, MathTextWarning)
+ self._set_glue(x, 1, total_stretch, "Overfull")
 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)
+ self._set_glue(x, -1, total_shrink, "Underfull")
 
 class Vlist(List):
 """A vertical list of boxes.
- §137"""
+ @137"""
 def __init__(self, elements, h=0., m='additional'):
 List.__init__(self, elements)
- self.vpack(h, m)
+ self.vpack()
 
+ def pack(self):
+ if self.list_head:
+ self.list_head.pack()
+ self.vpack()
+ Node.pack(self)
+ 
 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
@@ -1174,10 +1280,12 @@
 l: a maximum height
 
 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
+ vpack(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.
+ @644, @668"""
+ # I don't know why these get reset in TeX. Shift_amount is pretty
+ # much useless if we do.
+ # self.shift_amount = 0.
 w = 0.
 d = 0.
 x = 0.
@@ -1185,16 +1293,13 @@
 total_shrink = [0.] * 4
 p = self.list_head
 while p is not None:
- if isinstance(p, CharNode):
+ if isinstance(p, Char):
 raise RuntimeError("Internal error in mathtext")
- elif isinstance(p, (List, Rule, Unset)):
+ elif isinstance(p, (Box, 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:
+ s = getattr(p, 'shift_amount', 0.)
 w = max(w, p.width + s)
 elif isinstance(p, Glue):
 x += d
@@ -1225,30 +1330,11 @@
 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)
+ self._set_glue(x, 1, total_stretch, "Overfull")
 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)
+ self._set_glue(x, -1, total_shrink, "Underfull")
 
 class Rule(Box):
 """A Rule node stands for a solid black rectangle; it has width,
@@ -1257,7 +1343,7 @@
 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"""
+ @138"""
 def __init__(self, width, height, depth, state):
 Box.__init__(self, width, height, depth)
 self.font_manager = state.font_manager
@@ -1268,21 +1354,22 @@
 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)
+ thickness = state.font_manager.get_underline_thickness(state.font)
+ height = depth = thickness * 0.5
+ Rule.__init__(self, None, height, depth, state)
 
 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)
+ thickness = state.font_manager.get_underline_thickness(state.font)
+ Rule.__init__(self, thickness, 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"""
+ @149, @152"""
 def __init__(self, glue_type, copy=False):
 Node.__init__(self)
 self.glue_subtype = 'normal'
@@ -1297,7 +1384,7 @@
 self.glue_spec = glue_spec
 
 class GlueSpec(object):
- """§150, §151"""
+ """@150, @151"""
 def __init__(self, width=0., stretch=0., stretch_order=0, shrink=0., shrink_order=0):
 self.width = width
 self.stretch = stretch
@@ -1318,9 +1405,14 @@
 factory = classmethod(factory)
 
 GlueSpec._types = {
- 'fil': GlueSpec(0., 1., 1, 0., 0),
- 'fill': GlueSpec(0., 1., 2, 0., 0),
- 'filll': GlueSpec(0., 1., 3, 0., 0)
+ 'fil': GlueSpec(0., 1., 1, 0., 0),
+ 'fill': GlueSpec(0., 1., 2, 0., 0),
+ 'filll': GlueSpec(0., 1., 3, 0., 0),
+ 'neg_fil': GlueSpec(0., 0., 0, 1., 1),
+ 'neg_fill': GlueSpec(0., 0., 0, 1., 2),
+ 'neg_filll': GlueSpec(0., 0., 0, 1., 3),
+ 'empty': GlueSpec(0., 0., 0, 0., 0),
+ 'ss': GlueSpec(0., 1., 1, -1., 1)
 }
 
 # Some convenient ways to get common kinds of glue
@@ -1337,11 +1429,38 @@
 def __init__(self):
 Glue.__init__(self, 'filll')
 
+class NegFil(Glue):
+ def __init__(self):
+ Glue.__init__(self, 'neg_fil')
+
+class NegFill(Glue):
+ def __init__(self):
+ Glue.__init__(self, 'neg_fill')
+
+class NegFilll(Glue):
+ def __init__(self):
+ Glue.__init__(self, 'neg_filll')
+ 
+class FixedGlue(Glue):
+ def __init__(self, width):
+ Glue.__init__(self, 'empty', copy=True)
+ self.glue_spec.width = width
+
+class SsGlue(Glue):
+ def __init__(self):
+ Glue.__init__(self, 'ss')
+ 
 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()])
+ Hlist.__init__(self, [SsGlue()] + elements + [SsGlue()])
+
+class VCentered(Hlist):
+ """A convenience class to create an Hlist whose contents are centered
+ within its enclosing box."""
+ def __init__(self, elements):
+ Vlist.__init__(self, [Fill()] + elements + [Fill()])
 
 class Kern(Node):
 """A Kern node has a width field to specify a (normally negative)
@@ -1350,28 +1469,123 @@
 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'):
+ @155"""
+ def __init__(self, width):
 Node.__init__(self)
 self.width = width
- self.subtype = subtype
 
+ def shrink(self):
+ Node.shrink(self)
+ if self.size < NUM_SIZE_LEVELS:
+ self.width *= SHRINK_FACTOR
+ 
 class Unset(Node):
 pass
 
+class SubSuperCluster(Hlist):
+ """This class is a sort of hack to get around that fact that this
+ code doesn't parse to an mlist and then an hlist, but goes directly
+ to hlists. This lets us store enough information in the hlist itself,
+ namely the nucleas, sub- and super-script, such that if another script
+ follows that needs to be attached, it can be reconfigured on the fly."""
+ def __init__(self):
+ self.nucleus = None
+ self.sub = None
+ self.super = None
+ Hlist.__init__(self, [])
+
+ def is_overunder(self):
+ if isinstance(self.nucleus, Char):
+ return overunder_symbols.has_key(self.nucleus.c)
+ return False
+ 
+ def reconfigure(self, state):
+ """Lays out the nucleus, subscript and superscript, with
+ either the subscript or superscript being optional.
+ @756"""
+ rule_thickness = state.font_manager.get_underline_thickness(state.font)
+ xHeight = state.font_manager.get_xheight(state.font)
+
+ if self.nucleus is None:
+ raise ParseError("Internal mathtext error. No nucleus in sub/superscript cluster.")
+ 
+ if self.super is None and self.sub is None:
+ self.list_head = self.nucleus
+ return
+
+ if self.is_overunder():
+ vlist = []
+ shift = 0.
+ width = max(self.super.width, self.nucleus.width, self.sub.width)
+ if self.super is not None:
+ hlist = HCentered([self.super])
+ hlist.hpack(width, 'exactly')
+ vlist.extend([hlist, FixedGlue(rule_thickness * 2.0)])
+ hlist = HCentered([self.nucleus])
+ hlist.hpack(width, 'exactly')
+ vlist.append(hlist)
+ if self.sub is not None:
+ hlist = HCentered([self.sub])
+ hlist.hpack(width, 'exactly')
+ vlist.extend([FixedGlue(rule_thickness), hlist])
+ shift = hlist.height + hlist.depth + rule_thickness * 2.0
+ x = Vlist(vlist)
+ x.shift_amount = shift
+ self.list_head = x
+ self.hpack()
+ return
+ 
+ p = Hlist([self.nucleus])
+ p.hpack()
+ shift_up = p.height - SUBDROP
+ shift_down = p.depth + SUBDROP
+ if self.super is None:
+ # @757
+ x = Hlist([self.sub])
+ x.width += SCRIPT_SPACE
+ shift_down = max(shift_down, SUB1)
+ clr = x.height - (abs(xHeight * 4.0) / 5.0)
+ shift_down = max(shift_down, clr)
+ x.shift_amount = shift_down
+ else:
+ x = Hlist([self.super])
+ x.width += SCRIPT_SPACE
+ clr = SUP1
+ shift_up = max(shift_up, SUP1)
+ clr = x.depth + (abs(xHeight) / 4.0)
+ shift_up = max(shift_up, clr)
+ if self.sub is None:
+ x.shift_amount = -shift_up
+ else: # Both sub and superscript
+ y = Hlist([self.sub])
+ y.width += SCRIPT_SPACE
+ shift_down = max(shift_down, SUB1)
+ clr = 4.0 * rule_thickness - ((shift_up - x.depth) - (y.height - shift_down))
+ if clr > 0.:
+ shift_up += clr
+ shift_down += clr
+ x.shift_amount = DELTA
+ x = Vlist([x,
+ Kern((shift_up - x.depth) - (y.height - shift_down)),
+ y])
+ x.shift_amount = shift_down
+
+ self.list_head = p
+ p.link = x
+ self.hpack()
+ 
 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."""
+ @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)
@@ -1396,7 +1610,7 @@
 self.max_push = max(self.cur_s, self.max_push)
 
 while p:
- while isinstance(p, CharNode):
+ while isinstance(p, Char):
 p.render(self.cur_h + self.off_h, self.cur_v + self.off_v)
 self.cur_h += p.width
 p = p.link
@@ -1404,7 +1618,7 @@
 break
 
 if isinstance(p, List):
- # §623
+ # @623
 if p.list_head is None:
 self.cur_h += p.width
 else:
@@ -1413,12 +1627,12 @@
 if isinstance(p, Hlist):
 self.hlist_out(p)
 else:
- p.vpack(box.height, 'exactly')
+ # p.vpack(box.height + box.depth, 'exactly')
 self.vlist_out(p)
 self.cur_h = edge + p.width
 self.cur_v = base_line
- elif isinstance(p, Rule):
- # §624
+ elif isinstance(p, Box):
+ # @624
 rule_height = p.height
 rule_depth = p.depth
 rule_width = p.width
@@ -1434,7 +1648,7 @@
 self.cur_v = baseline
 self.cur_h += rule_width
 elif isinstance(p, Glue):
- # §625
+ # @625
 glue_spec = p.glue_spec
 rule_width = glue_spec.width - cur_g
 if glue_sign != 0: # normal
@@ -1465,7 +1679,7 @@
 top_edge = self.cur_v
 
 while p:
- if isinstance(p, CharNode):
+ if isinstance(p, Char):
 raise RuntimeError("Internal error in mathtext")
 elif isinstance(p, List):
 if p.list_head is None:
@@ -1476,13 +1690,12 @@
 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)
 self.cur_v = save_v + p.depth
 self.cur_h = left_edge
- elif isinstance(p, Rule):
+ elif isinstance(p, Box):
 rule_height = p.height
 rule_depth = p.depth
 rule_width = p.width
@@ -1523,7 +1736,7 @@
 # NOADS
 
 class Noad:
- def __init__(self, nucleus=None, subscr=None, superscr=None):
+ def __init__(self):
 self.link = None
 self.nucleus = nucleus
 self.subscr = subscr
@@ -1554,26 +1767,46 @@
 pass
 
 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 __init__(self):
+ Noad.__init__(self)
+ self.left_delim = None
 
-class NoadField:
+class FractionNoad(Noad):
 def __init__(self):
- pass
+ Noad.__init__(self)
+ self.num = None
+ self.denom = None
+ self.thickness = None
+ self.left_delim = None
+ self.right_delim = None
+ 
+class UnderNoad(Noad):
+ pass
 
-class MathChar(NoadField):
- def __init__(self, char, font):
- self.char = char
- self.font = font
+class OverNoad(Noad):
+ pass
 
-class SubMlist(NoadField):
+class AccentNoad(Noad):
 def __init__(self):
- pass
+ Noad__init__(self)
+ self.accent = None
 
+class VCenterNoad(Noad):
+ pass
+
+class LeftNoad(Noad):
+ pass
+
+class RightNoad(Noad):
+ pass
+
+class StyleNoad(Noad):
+ def __init__(self, subtype):
+ self.subtype = subtype
+
 ##############################################################################
 # PARSER
- 
+
 class Parser:
 class State:
 def __init__(self, font_manager, font, fontsize, dpi):
@@ -1820,94 +2053,73 @@
 #~ 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 = [CharNode(c, self.get_state()) for c in s]
+ symbols = [Char(c, self.get_state()) for c in toks[0]]
 hlist = Hlist(symbols)
 self.push_state()
+ # We're going into math now, so set font to 'it'
 self.get_state().font = 'it'
 return [hlist]
 
 def space(self, s, loc, toks):
 assert(len(toks)==1)
-
+ state = self.get_state()
+ metrics = state.font_manager.get_metrics(
+ state.font, 'm', state.fontsize, state.dpi)
+ em = metrics.width
+ 
 if toks[0]==r'\ ': num = 0.30 # 30% of fontsize
 elif toks[0]==r'\/': num = 0.1 # 10% of fontsize
 else: # vspace
 num = float(toks[0][1]) # get the num out of \hspace{num}
 
- element = SpaceElement(num)
- self.symbols.append(element)
- return [element]
+ box = Hbox(num * em)
+ return [box]
 
-# 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)
-
-# 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.current_font)
-# self.symbols.append(sym)
-
-# return [sym]
-
 def symbol(self, s, loc, toks):
- return [CharNode(toks[0], self.get_state())]
+ return [Char(toks[0], self.get_state())]
 
- space = symbol
+ _accent_map = {
+ r'\hat' : r'\circumflexaccent',
+ r'\breve' : r'\combiningbreve',
+ r'\bar' : r'\combiningoverline',
+ r'\grave' : r'\combininggraveaccent',
+ r'\acute' : r'\combiningacuteaccent',
+ r'\ddot' : r'\combiningdiaeresis',
+ r'\tilde' : r'\combiningtilde',
+ r'\dot' : r'\combiningdotabove',
+ r'\vec' : r'\combiningrightarrowabove',
+ r'\"' : r'\combiningdiaeresis',
+ r"\`" : r'\combininggraveaccent',
+ r"\'" : r'\combiningacuteaccent',
+ r'\~' : r'\combiningtilde',
+ r'\.' : r'\combiningdotabove',
+ r'\^' : r'\circumflexaccent',
+ }
 
 def accent(self, s, loc, toks):
 assert(len(toks)==1)
+ state = self.get_state()
+ thickness = state.font_manager.get_underline_thickness(state.font)
 accent, sym = toks[0]
+ accent = Accent(self._accent_map[accent], self.get_state())
+ centered = HCentered([accent])
+ centered.hpack(sym.width, 'exactly')
+ centered.shift_amount = accent._metrics.xmin
+ return Vlist([
+ centered,
+ FixedGlue(thickness * 2.0),
+ Hlist([sym])
+ ])
 
- d = {
- r'\hat' : r'\circumflexaccent',
- r'\breve' : r'\combiningbreve',
- r'\bar' : r'\combiningoverline',
- r'\grave' : r'\combininggraveaccent',
- r'\acute' : r'\combiningacuteaccent',
- r'\ddot' : r'\combiningdiaeresis',
- r'\tilde' : r'\combiningtilde',
- r'\dot' : r'\combiningdotabove',
- r'\vec' : r'\combiningrightarrowabove',
- r'\"' : r'\combiningdiaeresis',
- r"\`" : r'\combininggraveaccent',
- r"\'" : r'\combiningacuteaccent',
- r'\~' : r'\combiningtilde',
- r'\.' : r'\combiningdotabove',
- r'\^' : r'\circumflexaccent',
- }
- above = AccentElement(d[accent])
- sym.neighbors['above'] = above
- sym.set_pady(1)
- 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)]
-
+ self.push_state()
+ state = self.get_state()
+ state.font = 'rm'
+ hlist = Hlist([Char(c, state) for c in toks[0]])
+ self.pop_state()
+ return hlist
+ 
 def start_group(self, s, loc, toks):
 self.push_state()
 
@@ -1925,27 +2137,17 @@
 return []
 
 def latexfont(self, s, loc, toks):
+ # MGDTODO: Not really working
 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']
- }
-
- _subsuperscript_indices = {
- '_' : ('normal', (0, 1)),
- '^' : ('normal', (1, 0)),
- 'over' : ('overUnder', (0, 1)),
- 'under' : ('overUnder', (1, 0))
- }
- 
 def subsuperscript(self, s, loc, toks):
 assert(len(toks)==1)
 #~ print 'subsuperscript', toks
@@ -1955,45 +2157,68 @@
 if len(toks[0]) == 3:
 prev, op, next = toks[0]
 elif len(toks[0]) == 2:
- prev = SpaceElement(0)
+ prev = Hbox(0.)
 op, next = toks[0]
 else:
- raise ParseException("Unable to parse subscript/superscript construct.")
+ raise ParseFatalException("Unable to parse subscript/superscript construct.")
 
- relation_type, (index, other_index) = self._subsuperscript_indices[op]
- if self.is_overunder(prev):
- relation_type = 'overUnder'
- names = self._subsuperscript_names[relation_type]
+ # Handle the case of double scripts
+ if isinstance(next, SubSuperCluster):
+ x = next
+ if op == '_':
+ if next.sub is not None:
+ raise ParseFatalException("Double subscript")
+ x.sub = x.nucleus
+ x.sub.shrink()
+ x.sub.pack()
+ x.nucleus = prev
+ elif op == '^':
+ if next.super is not None:
+ raise ParseFatalException("Double superscript")
+ x.super = x.nucleus
+ x.super.shrink()
+ x.super.pack()
+ x.nucleus = prev
+ else:
+ x = SubSuperCluster()
+ x.nucleus = prev
+ if op == '_':
+ x.sub = next
+ x.sub.shrink()
+ x.sub.pack()
+ else:
+ x.super = next
+ x.super.shrink()
+ x.super.pack()
+ x.reconfigure(self.get_state())
 
- prev.neighbors[names[index]] = next
+ return [x]
 
- 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]]
- elif compound[index] in next.neighbors:
- raise ValueError(
- "Double %ss" %
- self._subsuperscript_names['normal'][index])
- return [prev]
-
- def is_overunder(self, prev):
- return isinstance(prev, SymbolElement) and overunder_symbols.has_key(prev.sym)
-
 def frac(self, s, loc, toks):
 assert(len(toks)==1)
 assert(len(toks[0])==2)
- #~ print 'subsuperscript', toks
- 
- top, bottom = toks[0]
- vlist = Vlist([HCentered([top]),
- Kern(4.0),
+ num, den = toks[0]
+ num.shrink()
+ den.shrink()
+ cnum = HCentered([num])
+ cden = HCentered([den])
+ width = max(num.width, den.height)
+ cnum.hpack(width, 'exactly')
+ cden.hpack(width, 'exactly')
+ state = self.get_state()
+ thickness = state.font_manager.get_underline_thickness(state.font)
+ space = thickness * 3.0
+ vlist = Vlist([cnum,
+ FixedGlue(thickness * 2.0),
 Hrule(self.get_state()),
- Kern(4.0),
- HCentered([bottom])
+ FixedGlue(thickness * 3.0),
+ cden
 ])
- # vlist.shift_amount = 8
+
+ metrics = state.font_manager.get_metrics(
+ state.font, '=', state.fontsize, state.dpi)
+ shift = cden.height - (metrics.ymax + metrics.ymin) / 2 + thickness * 2.5
+ vlist.shift_amount = shift
 return [vlist]
 
 overunder = subsuperscript
@@ -2060,7 +2285,6 @@
 w += 4
 h += 4
 font_manager.set_canvas_size(w,h)
- 
 ship(2, 2, box)
 
 if self.output == 'SVG':
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 によって変換されたページ (->オリジナル) /