Stroking geometric paths - not as easy as it seems

In PDF geometric paths are simply described as lines and cubic bézier curves. The filling of a path is straight forward once one understands the even-odd and non-zero-winding rule. The stroking of a path however is not as simple as it seems at the first glance. Let us have a look into stroking and some special cases.

Actually, stroking a path means nothing else than creating a new path and filling it. To do so the graphics engine must interpret the line attributes such as the line width, miter limit, dash array, dash phase, cap and join styles etc. which are stored in the graphics state.

Let's start with some simple cases: a single line is drawn by using a moveto, a lineto and a stroke operator. Obviously, this path is stroked by creating a new path consisting of two caps at the start and end points which are connected by two lines. The form of the caps is given by the cap style and the vertical distance of the lines is given by the line width. Two line segments are stroked in a similar way exept for the point in the middle which forms a join in the given style.

If a path is built of more than two line segments then they can cross earlier line segments. This implies that the newly created path must be filled using the non-zero-winding rule in order to draw the overlapping correctly. Furthermore, the last line segment can end where the first starts. This is different to closing a path using the appropriate operator. Why? Because if a stroked path is closed then a line join is used instead of the start and end caps. If a path is not closed the caps are drawn even if the start and end point are the same.

Now, what if a line segment has zero length? The form of the caps and joins as well as the distance between the connecting lines depend on the direction of the line segement. If the line segment has zero length then the direction cannot be determined. It is therefore safe in general to remove such line segments except for one case. A path containing a single, zero length line segment is allowed. But how is it drawn? If round caps are used then a circle is drawn with a diameter of the line width. If butt caps are used then a square is drawn. The direction of the edges, however, is implementation specific. If no caps are used then a single pixel must be drawn.

How about bézier curves? They are converted to a number of connected line segments before the path is stroked so they need no special treatment.