From dd567a6b3152a2f58ad159cfd768eedfc03d082c Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Sun, 13 Feb 2022 22:05:29 +0100 Subject: [PATCH 1/4] Turn _mathtext.ship into a plain function. Making it a plain function with two nested mutually recursive functions, instead of a singleton object with methods, makes ship() thread-safe at no cost (otherwise, two threads calling ship() at the same time would overwrite each other's instance variables). --- lib/matplotlib/_mathtext.py | 116 +++++++++++++++++------------------- 1 file changed, 56 insertions(+), 60 deletions(-) diff --git a/lib/matplotlib/_mathtext.py b/lib/matplotlib/_mathtext.py index 06d97bc57171..af415ef42bc2 100644 --- a/lib/matplotlib/_mathtext.py +++ b/lib/matplotlib/_mathtext.py @@ -911,8 +911,8 @@ def get_underline_thickness(self, font, fontsize, dpi): # # The most relevant "chapters" are: # Data structures for boxes and their friends -# Shipping pages out (Ship class) -# Packaging (hpack and vpack) +# Shipping pages out (ship()) +# Packaging (hpack() and vpack()) # Data structures for math mode # Subroutines for math mode # Typesetting math formulas @@ -1690,27 +1690,24 @@ def __init__(self, c, width, state, always=False, char_class=Char): self.width = char.width -class Ship: +def ship(ox, oy, box): """ Ship boxes to output once they have been set up, this sends them to output. - Since boxes can be inside of boxes inside of boxes, the main work of `Ship` + 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 `Hlist` nodes and `Vlist` nodes inside of horizontal and vertical boxes. The global variables used in TeX to store state as it - processes have become member variables here. + processes have become local variables here. """ - 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. - self.off_h = ox - self.off_v = oy + box.height - self.hlist_out(box) + max_push = 0 # Deepest nesting of push commands so far + cur_s = 0 + cur_v = 0. + cur_h = 0. + off_h = ox + off_v = oy + box.height - @staticmethod def clamp(value): if value < -1000000000.: return -1000000000. @@ -1718,37 +1715,38 @@ def clamp(value): return 1000000000. return value - def hlist_out(self, box): + def hlist_out(box): + nonlocal max_push, cur_s, cur_v, cur_h, off_h, off_v + cur_g = 0 cur_glue = 0. glue_order = box.glue_order glue_sign = box.glue_sign - base_line = self.cur_v - left_edge = self.cur_h - self.cur_s += 1 - self.max_push = max(self.cur_s, self.max_push) - clamp = self.clamp + base_line = cur_v + left_edge = cur_h + cur_s += 1 + max_push = max(cur_s, max_push) for p in box.children: if isinstance(p, Char): - p.render(self.cur_h + self.off_h, self.cur_v + self.off_v) - self.cur_h += p.width + p.render(cur_h + off_h, cur_v + off_v) + cur_h += p.width elif isinstance(p, Kern): - self.cur_h += p.width + cur_h += p.width elif isinstance(p, List): # node623 if len(p.children) == 0: - self.cur_h += p.width + cur_h += p.width else: - edge = self.cur_h - self.cur_v = base_line + p.shift_amount + edge = cur_h + cur_v = base_line + p.shift_amount if isinstance(p, Hlist): - self.hlist_out(p) + hlist_out(p) else: # p.vpack(box.height + box.depth, 'exactly') - self.vlist_out(p) - self.cur_h = edge + p.width - self.cur_v = base_line + vlist_out(p) + cur_h = edge + p.width + cur_v = base_line elif isinstance(p, Box): # node624 rule_height = p.height @@ -1759,12 +1757,11 @@ def hlist_out(self, box): if np.isinf(rule_depth): rule_depth = box.depth if rule_height > 0 and rule_width > 0: - self.cur_v = base_line + rule_depth - p.render(self.cur_h + self.off_h, - self.cur_v + self.off_v, + cur_v = base_line + rule_depth + p.render(cur_h + off_h, cur_v + off_v, rule_width, rule_height) - self.cur_v = base_line - self.cur_h += rule_width + cur_v = base_line + cur_h += rule_width elif isinstance(p, Glue): # node625 glue_spec = p.glue_spec @@ -1778,38 +1775,39 @@ def hlist_out(self, box): cur_glue += glue_spec.shrink cur_g = round(clamp(box.glue_set * cur_glue)) rule_width += cur_g - self.cur_h += rule_width - self.cur_s -= 1 + cur_h += rule_width + cur_s -= 1 + + def vlist_out(box): + nonlocal max_push, cur_s, cur_v, cur_h, off_h, off_v - def vlist_out(self, box): cur_g = 0 cur_glue = 0. glue_order = box.glue_order glue_sign = box.glue_sign - 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 - clamp = self.clamp + cur_s += 1 + max_push = max(max_push, cur_s) + left_edge = cur_h + cur_v -= box.height + top_edge = cur_v for p in box.children: if isinstance(p, Kern): - self.cur_v += p.width + cur_v += p.width elif isinstance(p, List): if len(p.children) == 0: - self.cur_v += p.height + p.depth + 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 + cur_v += p.height + cur_h = left_edge + p.shift_amount + save_v = cur_v p.width = box.width if isinstance(p, Hlist): - self.hlist_out(p) + hlist_out(p) else: - self.vlist_out(p) - self.cur_v = save_v + p.depth - self.cur_h = left_edge + vlist_out(p) + cur_v = save_v + p.depth + cur_h = left_edge elif isinstance(p, Box): rule_height = p.height rule_depth = p.depth @@ -1818,9 +1816,8 @@ def vlist_out(self, box): 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, + cur_v += rule_height + p.render(cur_h + off_h, cur_v + off_v, rule_width, rule_height) elif isinstance(p, Glue): glue_spec = p.glue_spec @@ -1834,14 +1831,13 @@ def vlist_out(self, box): cur_glue += glue_spec.shrink cur_g = round(clamp(box.glue_set * cur_glue)) rule_height += cur_g - self.cur_v += rule_height + cur_v += rule_height elif isinstance(p, Char): raise RuntimeError( "Internal mathtext error: Char node found in vlist") - self.cur_s -= 1 - + cur_s -= 1 -ship = Ship() + hlist_out(box) ############################################################################## From a889ec01b5cee261d10380b2d91cf18cf3805b3a Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Sun, 13 Feb 2022 22:09:11 +0100 Subject: [PATCH 2/4] Remove unused recursion depth tracking in ship. --- lib/matplotlib/_mathtext.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/lib/matplotlib/_mathtext.py b/lib/matplotlib/_mathtext.py index af415ef42bc2..21299d247c7b 100644 --- a/lib/matplotlib/_mathtext.py +++ b/lib/matplotlib/_mathtext.py @@ -1701,8 +1701,6 @@ def ship(ox, oy, box): processes have become local variables here. """ - max_push = 0 # Deepest nesting of push commands so far - cur_s = 0 cur_v = 0. cur_h = 0. off_h = ox @@ -1716,7 +1714,7 @@ def clamp(value): return value def hlist_out(box): - nonlocal max_push, cur_s, cur_v, cur_h, off_h, off_v + nonlocal cur_v, cur_h, off_h, off_v cur_g = 0 cur_glue = 0. @@ -1724,8 +1722,6 @@ def hlist_out(box): glue_sign = box.glue_sign base_line = cur_v left_edge = cur_h - cur_s += 1 - max_push = max(cur_s, max_push) for p in box.children: if isinstance(p, Char): @@ -1776,17 +1772,14 @@ def hlist_out(box): cur_g = round(clamp(box.glue_set * cur_glue)) rule_width += cur_g cur_h += rule_width - cur_s -= 1 def vlist_out(box): - nonlocal max_push, cur_s, cur_v, cur_h, off_h, off_v + nonlocal cur_v, cur_h, off_h, off_v cur_g = 0 cur_glue = 0. glue_order = box.glue_order glue_sign = box.glue_sign - cur_s += 1 - max_push = max(max_push, cur_s) left_edge = cur_h cur_v -= box.height top_edge = cur_v @@ -1835,7 +1828,6 @@ def vlist_out(box): elif isinstance(p, Char): raise RuntimeError( "Internal mathtext error: Char node found in vlist") - cur_s -= 1 hlist_out(box) From 375ed004dc06ddf95175967508a42e50702faafd Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Sun, 13 Feb 2022 23:04:09 +0100 Subject: [PATCH 3/4] Unalign equals. --- lib/matplotlib/_mathtext.py | 38 ++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/lib/matplotlib/_mathtext.py b/lib/matplotlib/_mathtext.py index 21299d247c7b..7f52457adcbb 100644 --- a/lib/matplotlib/_mathtext.py +++ b/lib/matplotlib/_mathtext.py @@ -1701,10 +1701,10 @@ def ship(ox, oy, box): processes have become local variables here. """ - cur_v = 0. - cur_h = 0. - off_h = ox - off_v = oy + box.height + cur_v = 0. + cur_h = 0. + off_h = ox + off_v = oy + box.height def clamp(value): if value < -1000000000.: @@ -1716,12 +1716,12 @@ def clamp(value): def hlist_out(box): nonlocal cur_v, cur_h, off_h, off_v - cur_g = 0 - cur_glue = 0. - glue_order = box.glue_order - glue_sign = box.glue_sign - base_line = cur_v - left_edge = cur_h + cur_g = 0 + cur_glue = 0. + glue_order = box.glue_order + glue_sign = box.glue_sign + base_line = cur_v + left_edge = cur_h for p in box.children: if isinstance(p, Char): @@ -1746,8 +1746,8 @@ def hlist_out(box): elif isinstance(p, Box): # node624 rule_height = p.height - rule_depth = p.depth - rule_width = p.width + rule_depth = p.depth + rule_width = p.width if np.isinf(rule_height): rule_height = box.height if np.isinf(rule_depth): @@ -1776,13 +1776,13 @@ def hlist_out(box): def vlist_out(box): nonlocal cur_v, cur_h, off_h, off_v - cur_g = 0 - cur_glue = 0. - glue_order = box.glue_order - glue_sign = box.glue_sign - left_edge = cur_h - cur_v -= box.height - top_edge = cur_v + cur_g = 0 + cur_glue = 0. + glue_order = box.glue_order + glue_sign = box.glue_sign + left_edge = cur_h + cur_v -= box.height + top_edge = cur_v for p in box.children: if isinstance(p, Kern): From 99d481ba818e4ba7dc730a71d048953bf0ae1826 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Thu, 17 Feb 2022 13:48:09 +0100 Subject: [PATCH 4/4] Make clamp use a ternary. --- lib/matplotlib/_mathtext.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/matplotlib/_mathtext.py b/lib/matplotlib/_mathtext.py index 7f52457adcbb..bdba4fe55a12 100644 --- a/lib/matplotlib/_mathtext.py +++ b/lib/matplotlib/_mathtext.py @@ -1707,11 +1707,7 @@ def ship(ox, oy, box): off_v = oy + box.height def clamp(value): - if value < -1000000000.: - return -1000000000. - if value > 1000000000.: - return 1000000000. - return value + return -1e9 if value < -1e9 else +1e9 if value > +1e9 else value def hlist_out(box): nonlocal cur_v, cur_h, off_h, off_v