From ccaa75f4b4160954c394261feecf74c819ad5ec1 Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Wed, 3 Jul 2019 22:56:08 +0200 Subject: [PATCH] Make shapes more robust w.r.t pre-existing paths (#2806) A call to cairo_close_path() adds a straight line to the beginning of the current sub-path. This is used in some of the shapes to, well, close the shapes. Sub-paths can be created explicitly via cairo_new_sub_path(), but also implicitly via cairo_move_to(). When a new sub-path is started, there is no current point on the path. This means that e.g. cairo_line_to() is in this start equivalent to cairo_move_to() (= no line is created) and that cairo_curve_to() first does a cairo_move_to() to the beginning of the curve. Similarly, cairo_arc() and cairo_arc_negative() first do a line_to() to the beginning of the arc, and this line_to() can be implicitly turned into a curve_to(). The problem with the code in gears.shape is that parts of the code (implicitly) assume that there is not yet any path when the shape function is called. If this assumption is broken, the call to close_path() could go to the wrong point, because the path did not start at the expected position. Most of the functions in gears.shape already implicitly start a new sub-path via a call to cairo_move_to(). Those that do not (necessarily) begin with a call to cairo_move_to() are handled in this commit: They get an explicit call to cairo_new_sub_path(). This change fixes the issue reported at https://github.com/awesomeWM/awesome/pull/2804, because the shapes will no longer be influenced by the pre-existing path. The move_to() that was left around and caused that issue turns into a degenerate part (it only has a move_to(), so nothing can be drawn) and is then discarded by cairo. Signed-off-by: Uli Schlachter --- lib/gears/shape.lua | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/gears/shape.lua b/lib/gears/shape.lua index c051a011..f13278a9 100644 --- a/lib/gears/shape.lua +++ b/lib/gears/shape.lua @@ -113,6 +113,10 @@ function module.partially_rounded_rect(cr, width, height, tl, tr, br, bl, rad) rad = height / 2 end + -- In case there is already some other path on the cairo context: + -- Make sure the close_path() below goes to the right position. + cr:new_sub_path() + -- Top left if tl then cr:arc( rad, rad, rad, math.pi, 3*(math.pi/2)) @@ -431,6 +435,10 @@ function module.pie(cr, width, height, start_angle, end_angle, radius) radius = radius or math.floor(math.min(width, height)/2) start_angle, end_angle = start_angle or 0, end_angle or math.pi/2 + -- In case there is already some other path on the cairo context: + -- Make sure the close_path() below goes to the right position. + cr:new_sub_path() + -- If the shape is a circle, then avoid the lines if math.abs(start_angle + end_angle - 2*math.pi) <= 0.01 then cr:arc(width/2, height/2, radius, 0, 2*math.pi) @@ -465,6 +473,10 @@ function module.arc(cr, width, height, thickness, start_angle, end_angle, start_ start_angle = start_angle or 0 end_angle = end_angle or math.pi/2 + -- In case there is already some other path on the cairo context: + -- Make sure the close_path() below goes to the right position. + cr:new_sub_path() + -- This shape is a partial circle local radius = math.min(width, height)/2