3434from matplotlib .transforms import Affine2D
3535
3636
37+ def _set_rgba (ctx , color , alpha , forced_alpha ):
38+ if len (color ) == 3 or forced_alpha :
39+ ctx .set_source_rgba (* color [:3 ], alpha )
40+ else :
41+ ctx .set_source_rgba (* color )
42+
43+
3744def _append_path (ctx , path , transform , clip = None ):
3845 for points , code in path .iter_segments (
3946 transform , remove_nans = True , clip = clip ):
@@ -100,13 +107,11 @@ def set_context(self, ctx):
100107 self .gc .ctx = ctx
101108 self .width , self .height = size
102109
103- def _fill_and_stroke (self , ctx , fill_c , alpha , alpha_overrides ):
110+ @staticmethod
111+ def _fill_and_stroke (ctx , fill_c , alpha , alpha_overrides ):
104112 if fill_c is not None :
105113 ctx .save ()
106- if len (fill_c ) == 3 or alpha_overrides :
107- ctx .set_source_rgba (fill_c [0 ], fill_c [1 ], fill_c [2 ], alpha )
108- else :
109- ctx .set_source_rgba (fill_c [0 ], fill_c [1 ], fill_c [2 ], fill_c [3 ])
114+ _set_rgba (ctx , fill_c , alpha , alpha_overrides )
110115 ctx .fill_preserve ()
111116 ctx .restore ()
112117 ctx .stroke ()
@@ -122,8 +127,31 @@ def draw_path(self, gc, path, transform, rgbFace=None):
122127 + Affine2D ().scale (1 , - 1 ).translate (0 , self .height ))
123128 ctx .new_path ()
124129 _append_path (ctx , path , transform , clip )
125- self ._fill_and_stroke (
126- ctx , rgbFace , gc .get_alpha (), gc .get_forced_alpha ())
130+ if rgbFace is not None :
131+ ctx .save ()
132+ _set_rgba (ctx , rgbFace , gc .get_alpha (), gc .get_forced_alpha ())
133+ ctx .fill_preserve ()
134+ ctx .restore ()
135+ hatch_path = gc .get_hatch_path ()
136+ if hatch_path :
137+ dpi = int (self .dpi )
138+ hatch_surface = ctx .get_target ().create_similar (
139+ cairo .Content .COLOR_ALPHA , dpi , dpi )
140+ hatch_ctx = cairo .Context (hatch_surface )
141+ _append_path (hatch_ctx , hatch_path ,
142+ Affine2D ().scale (dpi , - dpi ).translate (0 , dpi ),
143+ None )
144+ hatch_ctx .set_line_width (self .points_to_pixels (gc .get_hatch_linewidth ()))
145+ hatch_ctx .set_source_rgba (* gc .get_hatch_color ())
146+ hatch_ctx .fill_preserve ()
147+ hatch_ctx .stroke ()
148+ hatch_pattern = cairo .SurfacePattern (hatch_surface )
149+ hatch_pattern .set_extend (cairo .Extend .REPEAT )
150+ ctx .save ()
151+ ctx .set_source (hatch_pattern )
152+ ctx .fill_preserve ()
153+ ctx .restore ()
154+ ctx .stroke ()
127155
128156 def draw_markers (self , gc , marker_path , marker_trans , path , transform ,
129157 rgbFace = None ):
@@ -267,8 +295,13 @@ def get_text_width_height_descent(self, s, prop, ismath):
267295 def new_gc (self ):
268296 # docstring inherited
269297 self .gc .ctx .save ()
298+ # FIXME: The following doesn't properly implement a stack-like behavior
299+ # and relies instead on the (non-guaranteed) fact that artists never
300+ # rely on nesting gc states, so directly resetting the attributes (IOW
301+ # a single-level stack) is enough.
270302 self .gc ._alpha = 1
271303 self .gc ._forced_alpha = False # if True, _alpha overrides A from RGBA
304+ self .gc ._hatch = None
272305 return self .gc
273306
274307 def points_to_pixels (self , points ):
@@ -298,12 +331,8 @@ def restore(self):
298331
299332 def set_alpha (self , alpha ):
300333 super ().set_alpha (alpha )
301- _alpha = self .get_alpha ()
302- rgb = self ._rgb
303- if self .get_forced_alpha ():
304- self .ctx .set_source_rgba (rgb [0 ], rgb [1 ], rgb [2 ], _alpha )
305- else :
306- self .ctx .set_source_rgba (rgb [0 ], rgb [1 ], rgb [2 ], rgb [3 ])
334+ _set_rgba (
335+ self .ctx , self ._rgb , self .get_alpha (), self .get_forced_alpha ())
307336
308337 def set_antialiased (self , b ):
309338 self .ctx .set_antialias (
0 commit comments