@@ -292,25 +292,113 @@ def _math_to_rgba(self, s, prop, rgb):
292292 rgba = plt .imread (buf )
293293 return rgba , depth
294294
295- def _draw_math_text (self , gc , x , y , s , prop , angle ):
296- # Get color from graphics context
297- rgb = gc .get_rgb ()
295+ def _draw_math_text_path (self , gc , x , y , s , prop , angle ):
296+ """Draw mathematical text using paths directly on the canvas.
298297
299- # Get RGBA array using the new method
300- rgba , depth = self . _math_to_rgba ( s , prop , rgb )
298+ This method renders math text by drawing the actual glyph paths
299+ onto the canvas, rather than creating a temporary image.
301300
302- angle = math .radians (angle )
301+ Parameters
302+ ----------
303+ gc : GraphicsContextHTMLCanvas
304+ The graphics context to use for drawing
305+ x, y : float
306+ The position of the text baseline in pixels
307+ s : str
308+ The text string to render
309+ prop : FontProperties
310+ The font properties to use for rendering
311+ angle : float
312+ The rotation angle in degrees
313+ """
314+ # Parse the math text to get paths and metrics
315+ width , height , depth , glyphs , rects = self .mathtext_parser .parse (
316+ s , dpi = self .dpi , prop = prop
317+ )
318+
319+ # Save the canvas state
320+ self .ctx .save ()
321+
322+ # Move to text position and apply rotation if needed
323+ self .ctx .translate (x , self .height - y )
303324 if angle != 0 :
325+ self .ctx .rotate (- math .radians (angle ))
326+
327+ # Set up text rendering style
328+ self .ctx .fillStyle = self ._matplotlib_color_to_CSS (
329+ gc .get_rgb (), gc .get_alpha (), gc .get_forced_alpha ()
330+ )
331+
332+ # Draw each glyph in the mathematical expression
333+ for font , fontsize , _ , ox , oy in glyphs :
334+ # Move to glyph position
304335 self .ctx .save ()
305- self .ctx .translate (x , y )
306- self .ctx .rotate (- angle )
307- self .ctx .translate (- x , - y )
336+ self .ctx .translate (ox , - oy )
308337
309- self .draw_image (gc , x , - y - depth , np .flipud (rgba ))
338+ # Get the glyph's path data
339+ font .set_size (fontsize , self .dpi )
340+ verts , codes = font .get_path ()
341+
342+ verts = verts * fontsize / font .units_per_EM
343+
344+ # Convert the glyph to a Path object
345+ path = Path (verts , codes )
346+
347+ # Draw the path
348+ transform = Affine2D ().scale (1.0 , - 1.0 )
349+ self ._path_helper (self .ctx , path , transform )
350+ self .ctx .fill ()
310351
311- if angle != 0 :
312352 self .ctx .restore ()
313353
354+ # Draw rectangles (fraction bars, roots, etc.)
355+ for x1 , y1 , x2 , y2 in rects :
356+ self .ctx .fillRect (x1 , - y2 , x2 - x1 , y2 - y1 )
357+
358+ # Restore the canvas state
359+ self .ctx .restore ()
360+
361+ def _draw_math_text (self , gc , x , y , s , prop , angle ):
362+ """Draw mathematical text using the most appropriate method.
363+
364+ This method tries direct path rendering first, and falls back to
365+ the image-based approach if needed.
366+
367+ Parameters
368+ ----------
369+ gc : GraphicsContextHTMLCanvas
370+ The graphics context to use for drawing
371+ x, y : float
372+ The position of the text baseline in pixels
373+ s : str
374+ The text string to render
375+ prop : FontProperties
376+ The font properties to use for rendering
377+ angle : float
378+ The rotation angle in degrees
379+ """
380+ try :
381+ # Try rendering directly with paths first
382+ self ._draw_math_text_path (gc , x , y , s , prop , angle )
383+ except Exception as e :
384+ # If path rendering fails, fall back to image-based approach
385+ print (f"Path rendering failed, falling back to image: { str (e )} " )
386+
387+ # Get RGBA array using the existing image-based method
388+ rgba , depth = self ._math_to_rgba (s , prop , gc .get_rgb ())
389+
390+ angle = math .radians (angle )
391+ if angle != 0 :
392+ self .ctx .save ()
393+ self .ctx .translate (x , y )
394+ self .ctx .rotate (- angle )
395+ self .ctx .translate (- x , - y )
396+
397+ self .draw_image (gc , x , - y - depth , np .flipud (rgba ))
398+
399+ if angle != 0 :
400+ self .ctx .restore ()
401+
314402 def _set_style (self , gc , rgbFace = None ):
315403 if rgbFace is not None :
316404 self .ctx .fillStyle = self ._matplotlib_color_to_CSS (
@@ -404,6 +492,7 @@ def _get_font(self, prop):
404492 def get_text_width_height_descent (self , s , prop , ismath ):
405493 w : float
406494 h : float
495+ d : float
407496 if ismath :
408497 # Use the path parser to get exact metrics
409498 width , height , depth , _ , _ = self .mathtext_parser .parse (
0 commit comments