New upstream version 2.5.2
Michael Fladischer
2 years ago
0 | 0 | ====== |
1 | 1 | News |
2 | 2 | ====== |
3 | ||
4 | ||
5 | Version 2.5.2 released on 2021-03-06 | |
6 | ==================================== | |
7 | ||
8 | * Fix marker path scale | |
9 | ||
10 | Version 2.5.1 released on 2021-01-06 | |
11 | ==================================== | |
12 | ||
13 | **WARNING:** this is a security update. | |
14 | ||
15 | When processing SVG files, CairoSVG was using two regular expressions which are | |
16 | vulnerable to Regular Expression Denial of Service (REDoS). | |
17 | ||
18 | If an attacker provided a malicious SVG, it could make CairoSVG get stuck | |
19 | processing the file for a very long time. | |
20 | ||
21 | Other bug fixes: | |
22 | ||
23 | * Fix marker positions for unclosed paths | |
24 | * Follow hint when only output_width or output_height is set | |
25 | * Handle opacity on raster images | |
26 | * Don’t crash when use tags reference unknown tags | |
27 | * Take care of the next letter when A/a is replaced by l | |
28 | * Fix misalignment in node.vertices | |
3 | 29 | |
4 | 30 | |
5 | 31 | Version 2.5.0 released on 2020-10-29 |
186 | 186 | 'transparent': (0, 0, 0, 0), |
187 | 187 | } |
188 | 188 | |
189 | RGBA = re.compile(r'rgba\([ \n\r\t]*(.+?)[ \n\r\t]*\)') | |
190 | RGB = re.compile(r'rgb\([ \n\r\t]*(.+?)[ \n\r\t]*\)') | |
189 | RGBA = re.compile(r'rgba\((.+?)\)') | |
190 | RGB = re.compile(r'rgb\((.+?)\)') | |
191 | 191 | HEX_RRGGBB = re.compile('#[0-9a-f]{6}') |
192 | 192 | HEX_RGB = re.compile('#[0-9a-f]{3}') |
193 | 193 | |
211 | 211 | if match: |
212 | 212 | r, g, b, a = tuple( |
213 | 213 | float(i.strip(' %')) / 100 if '%' in i else float(i) / 255 |
214 | for i in match.group(1).split(',')) | |
214 | for i in match.group(1).strip().split(',')) | |
215 | 215 | return (r, g, b, a * 255 * opacity) |
216 | 216 | |
217 | 217 | match = RGB.search(string) |
218 | 218 | if match: |
219 | 219 | r, g, b = tuple( |
220 | 220 | float(i.strip(' %')) / 100 if '%' in i else float(i) / 255 |
221 | for i in match.group(1).split(',')) | |
221 | for i in match.group(1).strip().split(',')) | |
222 | 222 | return (r, g, b, opacity) |
223 | 223 | |
224 | 224 | match = HEX_RRGGBB.search(string) |
345 | 345 | if 'mask' in node: |
346 | 346 | del node['mask'] |
347 | 347 | href = parse_url(node.get_href()).geturl() |
348 | tree = Tree( | |
349 | url=href, url_fetcher=node.url_fetcher, parent=node, | |
350 | tree_cache=surface.tree_cache, unsafe=node.unsafe) | |
348 | try: | |
349 | tree = Tree( | |
350 | url=href, url_fetcher=node.url_fetcher, parent=node, | |
351 | tree_cache=surface.tree_cache, unsafe=node.unsafe) | |
352 | except TypeError: | |
353 | surface.context.restore() | |
354 | return | |
351 | 355 | |
352 | 356 | if not match_features(tree.xml_tree): |
353 | 357 | surface.context.restore() |
101 | 101 | surface.context.clip() |
102 | 102 | |
103 | 103 | # Paint raster image |
104 | opacity = float(node.get('opacity', 1)) | |
104 | 105 | surface.context.save() |
105 | 106 | surface.context.translate(x, y) |
106 | 107 | surface.context.scale(scale_x, scale_y) |
107 | 108 | surface.context.translate(translate_x, translate_y) |
108 | 109 | surface.context.set_source(image_surface.pattern) |
109 | surface.context.paint() | |
110 | surface.context.paint_with_alpha(opacity) | |
110 | 111 | surface.context.restore() |
111 | 112 | |
112 | 113 |
185 | 185 | |
186 | 186 | # rx=0 or ry=0 means straight line |
187 | 187 | if not rx or not ry: |
188 | string = 'l {} {} {}'.format(x3, y3, string) | |
188 | if string and string[0] not in PATH_LETTERS: | |
189 | # As we replace the current operation by l, we must be sure | |
190 | # that the next letter is set to the real current letter (a | |
191 | # or A) in case it’s omitted | |
192 | next_letter = '{} '.format(letter) | |
193 | else: | |
194 | next_letter = '' | |
195 | string = 'l {} {} {}{}'.format(x3, y3, next_letter, string) | |
189 | 196 | continue |
190 | 197 | |
191 | 198 | radii_ratio = ry / rx |
305 | 312 | elif letter == 'm': |
306 | 313 | # Current point relative move |
307 | 314 | x, y, string = point(surface, string) |
315 | if last_letter and last_letter not in 'zZ': | |
316 | node.vertices.append(None) | |
308 | 317 | surface.context.rel_move_to(x, y) |
309 | 318 | current_point = current_point[0] + x, current_point[1] + y |
310 | 319 | |
311 | 320 | elif letter == 'M': |
312 | 321 | # Current point move |
313 | 322 | x, y, string = point(surface, string) |
323 | if last_letter and last_letter not in 'zZ': | |
324 | node.vertices.append(None) | |
314 | 325 | surface.context.move_to(x, y) |
315 | 326 | current_point = x, y |
316 | 327 | |
421 | 432 | # Vertical line |
422 | 433 | y, string = (string + ' ').split(' ', 1) |
423 | 434 | old_x, old_y = current_point |
424 | angle = pi / 2 if size(surface, y, 'y') > 0 else -pi / 2 | |
435 | angle = pi / 2 if size(surface, y, 'y') > old_y else -pi / 2 | |
425 | 436 | node.vertices.append((-angle, angle)) |
426 | 437 | y = size(surface, y, 'y') |
427 | 438 | surface.context.line_to(old_x, y) |
183 | 183 | |
184 | 184 | if output_width and output_height: |
185 | 185 | width, height = output_width, output_height |
186 | elif output_width: | |
187 | if width: | |
188 | # Keep the aspect ratio | |
189 | height *= output_width / width | |
190 | width = output_width | |
191 | elif output_height: | |
192 | if height: | |
193 | # Keep the aspect ratio | |
194 | width *= output_height / height | |
195 | height = output_height | |
186 | 196 | else: |
187 | 197 | width *= scale |
188 | 198 | height *= scale |