3030 from sets import Set as set
3131import unicodedata
3232from warnings import warn
33- import weakref
3433
3534from numpy import inf , isinf
3635import numpy as np
5756 latex_to_standard , tex2uni , latex_to_cmex , stix_virtual_fonts
5857from matplotlib import get_data_path , rcParams
5958
60-
61-
6259import matplotlib .colors as mcolors
6360import matplotlib ._png as _png
6461####################
@@ -119,7 +116,9 @@ class MathtextBackend(object):
119116 - :meth:`get_hinting_type`
120117 """
121118 def __init__ (self ):
122- self .fonts_object = None
119+ self .width = 0
120+ self .height = 0
121+ self .depth = 0
123122
124123 def set_canvas_size (self , w , h , d ):
125124 'Dimension the drawing canvas'
@@ -154,111 +153,84 @@ def get_hinting_type(self):
154153 """
155154 return LOAD_NO_HINTING
156155
157- class MathtextBackendBbox (MathtextBackend ):
156+ class MathtextBackendAgg (MathtextBackend ):
158157 """
159- A backend whose only purpose is to get a precise bounding box.
160- Only required for the Agg backend.
158+ Render glyphs and rectangles to an FTImage buffer, which is later
159+ transferred to the Agg image by the Agg backend.
161160 """
162-
163- def __init__ (self , real_backend ):
164- MathtextBackend .__init__ (self )
161+ def __init__ (self ):
162+ self .ox = 0
163+ self .oy = 0
164+ self .image = None
165+ self .mode = 'bbox'
165166 self .bbox = [0 , 0 , 0 , 0 ]
166- self . real_backend = real_backend
167+ MathtextBackend . __init__ ( self )
167168
168169 def _update_bbox (self , x1 , y1 , x2 , y2 ):
169170 self .bbox = [min (self .bbox [0 ], x1 ),
170171 min (self .bbox [1 ], y1 ),
171172 max (self .bbox [2 ], x2 ),
172173 max (self .bbox [3 ], y2 )]
173174
175+ def set_canvas_size (self , w , h , d ):
176+ MathtextBackend .set_canvas_size (self , w , h , d )
177+ if self .mode != 'bbox' :
178+ self .image = FT2Image (ceil (w ), ceil (h + d ))
179+
174180 def render_glyph (self , ox , oy , info ):
175- self ._update_bbox (ox + info .metrics .xmin ,
176- oy - info .metrics .ymax ,
177- ox + info .metrics .xmax ,
178- oy - info .metrics .ymin )
181+ if self .mode == 'bbox' :
182+ self ._update_bbox (ox + info .metrics .xmin ,
183+ oy - info .metrics .ymax ,
184+ ox + info .metrics .xmax ,
185+ oy - info .metrics .ymin )
186+ else :
187+ info .font .draw_glyph_to_bitmap (
188+ self .image , ox , oy - info .metrics .iceberg , info .glyph )
179189
180190 def render_rect_filled (self , x1 , y1 , x2 , y2 ):
181- self ._update_bbox (x1 , y1 , x2 , y2 )
191+ if self .mode == 'bbox' :
192+ self ._update_bbox (x1 , y1 , x2 , y2 )
193+ else :
194+ height = max (int (y2 - y1 ) - 1 , 0 )
195+ if height == 0 :
196+ center = (y2 + y1 ) / 2.0
197+ y = int (center - (height + 1 ) / 2.0 )
198+ else :
199+ y = int (y1 )
200+ self .image .draw_rect_filled (int (x1 ), y , ceil (x2 ), y + height )
182201
183- def get_results (self , box ):
202+ def get_results (self , box , used_characters ):
203+ self .mode = 'bbox'
184204 orig_height = box .height
185205 orig_depth = box .depth
186206 ship (0 , 0 , box )
187207 bbox = self .bbox
188208 bbox = [bbox [0 ] - 1 , bbox [1 ] - 1 , bbox [2 ] + 1 , bbox [3 ] + 1 ]
189- self ._switch_to_real_backend ()
190- self .fonts_object (). set_canvas_size (
209+ self .mode = 'render'
210+ self .set_canvas_size (
191211 bbox [2 ] - bbox [0 ],
192212 (bbox [3 ] - bbox [1 ]) - orig_depth ,
193213 (bbox [3 ] - bbox [1 ]) - orig_height )
194214 ship (- bbox [0 ], - bbox [1 ], box )
195- return self .fonts_object ().get_results (box )
196-
197- def get_hinting_type (self ):
198- return self .real_backend .get_hinting_type ()
199-
200- def _switch_to_real_backend (self ):
201- self .fonts_object ().mathtext_backend = weakref .ref (self .real_backend )
202- self .real_backend .fonts_object = self .fonts_object
203- self .real_backend .ox = self .bbox [0 ]
204- self .real_backend .oy = self .bbox [1 ]
205-
206- class MathtextBackendAggRender (MathtextBackend ):
207- """
208- Render glyphs and rectangles to an FTImage buffer, which is later
209- transferred to the Agg image by the Agg backend.
210- """
211- def __init__ (self ):
212- self .ox = 0
213- self .oy = 0
214- self .image = None
215- MathtextBackend .__init__ (self )
216-
217- def set_canvas_size (self , w , h , d ):
218- MathtextBackend .set_canvas_size (self , w , h , d )
219- self .image = FT2Image (ceil (w ), ceil (h + d ))
220-
221- def render_glyph (self , ox , oy , info ):
222- info .font .draw_glyph_to_bitmap (
223- self .image , ox , oy - info .metrics .iceberg , info .glyph )
224-
225- def render_rect_filled (self , x1 , y1 , x2 , y2 ):
226- height = max (int (y2 - y1 ) - 1 , 0 )
227- if height == 0 :
228- center = (y2 + y1 ) / 2.0
229- y = int (center - (height + 1 ) / 2.0 )
230- else :
231- y = int (y1 )
232- self .image .draw_rect_filled (int (x1 ), y , ceil (x2 ), y + height )
233-
234- def get_results (self , box ):
235215 return (self .ox ,
236216 self .oy ,
237217 self .width ,
238218 self .height + self .depth ,
239219 self .depth ,
240220 self .image ,
241- self . fonts_object (). get_used_characters () )
221+ used_characters )
242222
243223 def get_hinting_type (self ):
244224 if rcParams ['text.hinting' ]:
245225 return LOAD_FORCE_AUTOHINT
246226 else :
247227 return LOAD_NO_HINTING
248228
249- def MathtextBackendAgg ():
250- return MathtextBackendBbox (MathtextBackendAggRender ())
251-
252- class MathtextBackendBitmapRender (MathtextBackendAggRender ):
253- def get_results (self , box ):
254- return self .image , self .depth
255-
256- def MathtextBackendBitmap ():
257- """
258- A backend to generate standalone mathtext images. No additional
259- matplotlib backend is required.
260- """
261- return MathtextBackendBbox (MathtextBackendBitmapRender ())
229+ class MathtextBackendBitmap (MathtextBackendAgg ):
230+ def get_results (self , box , used_characters ):
231+ ox , oy , width , height , depth , image , characters = \
232+ MathtextBackendAgg (self , box , used_characters )
233+ return image , depth
262234
263235class MathtextBackendPs (MathtextBackend ):
264236 """
@@ -292,14 +264,14 @@ def render_rect_filled(self, x1, y1, x2, y2):
292264 ps = "%f %f %f %f rectfill\n " % (x1 , self .height - y2 , x2 - x1 , y2 - y1 )
293265 self .pswriter .write (ps )
294266
295- def get_results (self , box ):
267+ def get_results (self , box , used_characters ):
296268 ship (0 , - self .depth , box )
297269 #print self.depth
298270 return (self .width ,
299271 self .height + self .depth ,
300272 self .depth ,
301273 self .pswriter ,
302- self . fonts_object (). get_used_characters () )
274+ used_characters )
303275
304276class MathtextBackendPdf (MathtextBackend ):
305277 """
@@ -320,14 +292,14 @@ def render_glyph(self, ox, oy, info):
320292 def render_rect_filled (self , x1 , y1 , x2 , y2 ):
321293 self .rects .append ((x1 , self .height - y2 , x2 - x1 , y2 - y1 ))
322294
323- def get_results (self , box ):
295+ def get_results (self , box , used_characters ):
324296 ship (0 , - self .depth , box )
325297 return (self .width ,
326298 self .height + self .depth ,
327299 self .depth ,
328300 self .glyphs ,
329301 self .rects ,
330- self . fonts_object (). get_used_characters () )
302+ used_characters )
331303
332304class MathtextBackendSvg (MathtextBackend ):
333305 """
@@ -348,15 +320,15 @@ def render_rect_filled(self, x1, y1, x2, y2):
348320 self .svg_rects .append (
349321 (x1 , self .height - y1 + 1 , x2 - x1 , y2 - y1 ))
350322
351- def get_results (self , box ):
323+ def get_results (self , box , used_characters ):
352324 ship (0 , - self .depth , box )
353325 svg_elements = Bunch (svg_glyphs = self .svg_glyphs ,
354326 svg_rects = self .svg_rects )
355327 return (self .width ,
356328 self .height + self .depth ,
357329 self .depth ,
358330 svg_elements ,
359- self . fonts_object (). get_used_characters () )
331+ used_characters )
360332
361333class MathtextBackendPath (MathtextBackend ):
362334 """
@@ -378,7 +350,7 @@ def render_rect_filled(self, x1, y1, x2, y2):
378350 self .rects .append (
379351 (x1 , self .height - y2 , x2 - x1 , y2 - y1 ))
380352
381- def get_results (self , box ):
353+ def get_results (self , box , used_characters ):
382354 ship (0 , - self .depth , box )
383355 return (self .width ,
384356 self .height + self .depth ,
@@ -406,7 +378,7 @@ def render_rect_filled(self, x1, y1, x2, y2):
406378 self .rects .append (
407379 (x1 , y1 - self .height , x2 - x1 , y2 - y1 ))
408380
409- def get_results (self , box ):
381+ def get_results (self , box , used_characters ):
410382 ship (0 , - self .depth , box )
411383 return (self .width ,
412384 self .height + self .depth ,
@@ -434,9 +406,7 @@ def __init__(self, default_font_prop, mathtext_backend):
434406 used to delegate the actual rendering.
435407 """
436408 self .default_font_prop = default_font_prop
437- self .mathtext_backend = weakref .ref (mathtext_backend )
438- # Make these classes doubly-linked
439- mathtext_backend .fonts_object = weakref .ref (self )
409+ self .mathtext_backend = mathtext_backend
440410 self .used_characters = {}
441411
442412 def destroy (self ):
@@ -502,7 +472,7 @@ def set_canvas_size(self, w, h, d):
502472 Only really necessary for the bitmap backends.
503473 """
504474 self .width , self .height , self .depth = ceil (w ), ceil (h ), ceil (d )
505- self .mathtext_backend () .set_canvas_size (self .width , self .height , self .depth )
475+ self .mathtext_backend .set_canvas_size (self .width , self .height , self .depth )
506476
507477 def render_glyph (self , ox , oy , facename , font_class , sym , fontsize , dpi ):
508478 """
@@ -525,13 +495,13 @@ def render_glyph(self, ox, oy, facename, font_class, sym, fontsize, dpi):
525495 used_characters = self .used_characters .setdefault (
526496 stat_key , (realpath , set ()))
527497 used_characters [1 ].add (info .num )
528- self .mathtext_backend () .render_glyph (ox , oy , info )
498+ self .mathtext_backend .render_glyph (ox , oy , info )
529499
530500 def render_rect_filled (self , x1 , y1 , x2 , y2 ):
531501 """
532502 Draw a filled rectangle from (*x1*, *y1*) to (*x2*, *y2*).
533503 """
534- self .mathtext_backend () .render_rect_filled (x1 , y1 , x2 , y2 )
504+ self .mathtext_backend .render_rect_filled (x1 , y1 , x2 , y2 )
535505
536506 def get_xheight (self , font , fontsize , dpi ):
537507 """
@@ -559,7 +529,7 @@ def get_results(self, box):
559529 Get the data needed by the backend to render the math
560530 expression. The return value is backend-specific.
561531 """
562- return self .mathtext_backend () .get_results (box )
532+ return self .mathtext_backend .get_results (box , self . get_used_characters () )
563533
564534 def get_sized_alternatives_for_symbol (self , fontname , sym ):
565535 """
@@ -632,7 +602,7 @@ def _get_info(self, fontname, font_class, sym, fontsize, dpi):
632602 font .set_size (fontsize , dpi )
633603 glyph = font .load_char (
634604 num ,
635- flags = self .mathtext_backend () .get_hinting_type ())
605+ flags = self .mathtext_backend .get_hinting_type ())
636606
637607 xmin , ymin , xmax , ymax = [val / 64.0 for val in glyph .bbox ]
638608 offset = self ._get_offset (cached_font , glyph , fontsize , dpi )
0 commit comments