+void mark_attr_ends(word *words)
+{
+ word *w, *wp;
+
+ wp = NULL;
+ for (w = words; w; w = w->next) {
+ if (isattr(w->type)) {
+ int before = (wp && isattr(wp->type) &&
+ sameattr(wp->type, w->type));
+ int after = (w->next && isattr(w->next->type) &&
+ sameattr(w->next->type, w->type));
+ w->aux |= (before ?
+ (after ? attr_Always : attr_Last) :
+ (after ? attr_First : attr_Only));
+ }
+ wp = w;
+ }
+}
+
+/*
+ * This function implements the optimal paragraph wrapping
+ * algorithm, pretty much as used in TeX. A cost function is
+ * defined for each line of the wrapped paragraph (typically some
+ * convex function of the difference between the line's length and
+ * its desired length), and a dynamic programming approach is used
+ * to optimise globally across all possible layouts of the
+ * paragraph to find the one with the minimum total cost.
+ *
+ * The function as implemented here gives a choice of two options
+ * for the cost function:
+ *
+ * - If `natural_space' is zero, then the algorithm attempts to
+ * make each line the maximum possible width (either `width' or
+ * `subsequentwidth' depending on whether it's the first line of
+ * the paragraph or not), and the cost function is simply the
+ * square of the unused space at the end of each line. This is a
+ * simple mechanism suitable for use in fixed-pitch environments
+ * such as plain text displayed on a terminal.
+ *
+ * - However, if `natural_space' is positive, the algorithm
+ * assumes the medium is fully graphical and that the width of
+ * space characters can be adjusted finely, and it attempts to
+ * make each _space character_ the width given in
+ * `natural_space'. (The provided width function should return
+ * the _minimum_ acceptable width of a space character in this
+ * case.) Therefore, the cost function for a line is dependent
+ * on the number of spaces on that line as well as the amount by
+ * which the line width differs from the optimum.
+ */