34
34
from matplotlib .transforms import Affine2D
35
35
36
36
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
+
37
44
def _append_path (ctx , path , transform , clip = None ):
38
45
for points , code in path .iter_segments (
39
46
transform , remove_nans = True , clip = clip ):
@@ -100,13 +107,11 @@ def set_context(self, ctx):
100
107
self .gc .ctx = ctx
101
108
self .width , self .height = size
102
109
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 ):
104
112
if fill_c is not None :
105
113
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 )
110
115
ctx .fill_preserve ()
111
116
ctx .restore ()
112
117
ctx .stroke ()
@@ -122,8 +127,31 @@ def draw_path(self, gc, path, transform, rgbFace=None):
122
127
+ Affine2D ().scale (1 , - 1 ).translate (0 , self .height ))
123
128
ctx .new_path ()
124
129
_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 ()
127
155
128
156
def draw_markers (self , gc , marker_path , marker_trans , path , transform ,
129
157
rgbFace = None ):
@@ -267,8 +295,13 @@ def get_text_width_height_descent(self, s, prop, ismath):
267
295
def new_gc (self ):
268
296
# docstring inherited
269
297
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.
270
302
self .gc ._alpha = 1
271
303
self .gc ._forced_alpha = False # if True, _alpha overrides A from RGBA
304
+ self .gc ._hatch = None
272
305
return self .gc
273
306
274
307
def points_to_pixels (self , points ):
@@ -298,12 +331,8 @@ def restore(self):
298
331
299
332
def set_alpha (self , alpha ):
300
333
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 ())
307
336
308
337
def set_antialiased (self , b ):
309
338
self .ctx .set_antialias (
0 commit comments