Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ae5945f

Browse files
authored
Merge pull request #13042 from lazka/cairo-remove-fast-path
cairo: remove the append_path() fast path
2 parents 9e7650e + d6ce849 commit ae5945f

File tree

1 file changed

+15
-86
lines changed

1 file changed

+15
-86
lines changed

lib/matplotlib/backends/backend_cairo.py

Lines changed: 15 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -71,93 +71,22 @@ def buffer_info(self):
7171
return (self.__data, self.__size)
7272

7373

74-
# Mapping from Matplotlib Path codes to cairo path codes.
75-
_MPL_TO_CAIRO_PATH_TYPE = np.zeros(80, dtype=int) # CLOSEPOLY = 79.
76-
_MPL_TO_CAIRO_PATH_TYPE[Path.MOVETO] = cairo.PATH_MOVE_TO
77-
_MPL_TO_CAIRO_PATH_TYPE[Path.LINETO] = cairo.PATH_LINE_TO
78-
_MPL_TO_CAIRO_PATH_TYPE[Path.CURVE4] = cairo.PATH_CURVE_TO
79-
_MPL_TO_CAIRO_PATH_TYPE[Path.CLOSEPOLY] = cairo.PATH_CLOSE_PATH
80-
# Sizes in cairo_path_data_t of each cairo path element.
81-
_CAIRO_PATH_TYPE_SIZES = np.zeros(4, dtype=int)
82-
_CAIRO_PATH_TYPE_SIZES[cairo.PATH_MOVE_TO] = 2
83-
_CAIRO_PATH_TYPE_SIZES[cairo.PATH_LINE_TO] = 2
84-
_CAIRO_PATH_TYPE_SIZES[cairo.PATH_CURVE_TO] = 4
85-
_CAIRO_PATH_TYPE_SIZES[cairo.PATH_CLOSE_PATH] = 1
86-
87-
88-
def _append_paths_slow(ctx, paths, transforms, clip=None):
89-
for path, transform in zip(paths, transforms):
90-
for points, code in path.iter_segments(
91-
transform, remove_nans=True, clip=clip):
92-
if code == Path.MOVETO:
93-
ctx.move_to(*points)
94-
elif code == Path.CLOSEPOLY:
95-
ctx.close_path()
96-
elif code == Path.LINETO:
97-
ctx.line_to(*points)
98-
elif code == Path.CURVE3:
99-
cur = np.asarray(ctx.get_current_point())
100-
a = points[:2]
101-
b = points[-2:]
102-
ctx.curve_to(*(cur / 3 + a * 2 / 3), *(a * 2 / 3 + b / 3), *b)
103-
elif code == Path.CURVE4:
104-
ctx.curve_to(*points)
105-
106-
107-
def _append_paths_fast(ctx, paths, transforms, clip=None):
108-
# We directly convert to the internal representation used by cairo, for
109-
# which ABI compatibility is guaranteed. The layout for each item is
110-
# --CODE(4)-- -LENGTH(4)- ---------PAD(8)---------
111-
# ----------X(8)---------- ----------Y(8)----------
112-
# with the size in bytes in parentheses, and (X, Y) repeated as many times
113-
# as there are points for the current code.
114-
ffi = cairo.ffi
115-
116-
# Convert curves to segment, so that 1. we don't have to handle
117-
# variable-sized CURVE-n codes, and 2. we don't have to implement degree
118-
# elevation for quadratic Beziers.
119-
cleaneds = [path.cleaned(transform, remove_nans=True, clip=clip)
120-
for path, transform in zip(paths, transforms)]
121-
vertices = np.concatenate([cleaned.vertices for cleaned in cleaneds])
122-
codes = np.concatenate([cleaned.codes for cleaned in cleaneds])
123-
124-
# Remove unused vertices and convert to cairo codes. Note that unlike
125-
# cairo_close_path, we do not explicitly insert an extraneous MOVE_TO after
126-
# CLOSE_PATH, so our resulting buffer may be smaller.
127-
vertices = vertices[(codes != Path.STOP) & (codes != Path.CLOSEPOLY)]
128-
codes = codes[codes != Path.STOP]
129-
codes = _MPL_TO_CAIRO_PATH_TYPE[codes]
130-
131-
# Where are the headers of each cairo portions?
132-
cairo_type_sizes = _CAIRO_PATH_TYPE_SIZES[codes]
133-
cairo_type_positions = np.insert(np.cumsum(cairo_type_sizes), 0, 0)
134-
cairo_num_data = cairo_type_positions[-1]
135-
cairo_type_positions = cairo_type_positions[:-1]
136-
137-
# Fill the buffer.
138-
buf = np.empty(cairo_num_data * 16, np.uint8)
139-
as_int = np.frombuffer(buf.data, np.int32)
140-
as_int[::4][cairo_type_positions] = codes
141-
as_int[1::4][cairo_type_positions] = cairo_type_sizes
142-
as_float = np.frombuffer(buf.data, np.float64)
143-
mask = np.ones_like(as_float, bool)
144-
mask[::2][cairo_type_positions] = mask[1::2][cairo_type_positions] = False
145-
as_float[mask] = vertices.ravel()
146-
147-
# Construct the cairo_path_t, and pass it to the context.
148-
ptr = ffi.new("cairo_path_t *")
149-
ptr.status = cairo.STATUS_SUCCESS
150-
ptr.data = ffi.cast("cairo_path_data_t *", ffi.from_buffer(buf))
151-
ptr.num_data = cairo_num_data
152-
cairo.cairo.cairo_append_path(ctx._pointer, ptr)
153-
154-
155-
_append_paths = (_append_paths_fast if cairo.__name__ == "cairocffi"
156-
else _append_paths_slow)
157-
158-
15974
def _append_path(ctx, path, transform, clip=None):
160-
return _append_paths(ctx, [path], [transform], clip)
75+
for points, code in path.iter_segments(
76+
transform, remove_nans=True, clip=clip):
77+
if code == Path.MOVETO:
78+
ctx.move_to(*points)
79+
elif code == Path.CLOSEPOLY:
80+
ctx.close_path()
81+
elif code == Path.LINETO:
82+
ctx.line_to(*points)
83+
elif code == Path.CURVE3:
84+
cur = np.asarray(ctx.get_current_point())
85+
a = points[:2]
86+
b = points[-2:]
87+
ctx.curve_to(*(cur / 3 + a * 2 / 3), *(a * 2 / 3 + b / 3), *b)
88+
elif code == Path.CURVE4:
89+
ctx.curve_to(*points)
16190

16291

16392
class RendererCairo(RendererBase):

0 commit comments

Comments
 (0)