+/* We want to avoid situations like this:
+ still more text
+ more text
+ text
+ -------------------
+ staff
+ -------------------
+
+ The point is that "still more text" should be positioned under
+ "more text". In order to achieve this, we place the grobs in several
+ passes. We keep track of the right-most horizontal position that has been
+ affected by the current pass so far (actually we keep track of 2
+ positions, one for above the staff, one for below).
+
+ In each pass, we loop through the unplaced grobs from left to right.
+ If the grob doesn't overlap the right-most affected position, we place it
+ (and then update the right-most affected position to point to the right
+ edge of the just-placed grob). Otherwise, we skip it until the next pass.
+*/
+static void
+add_grobs_of_one_priority (Skyline_pair *const skylines,
+ vector<Grob *> elements,
+ Grob *x_common,
+ Grob *y_common)
+{
+ vector<Box> boxes;
+ Drul_array<Real> last_affected_position;
+
+ reverse (elements);
+ while (!elements.empty ())
+ {
+ last_affected_position[UP] = -infinity_f;
+ last_affected_position[DOWN] = -infinity_f;
+ /* do one pass */
+ for (vsize i = elements.size (); i--;)
+ {
+ Direction dir = get_grob_direction (elements[i]);
+ if (dir == CENTER)
+ {
+ warning (_ ("an outside-staff object should have a direction, defaulting to up"));
+ dir = UP;
+ }
+
+ Box b (elements[i]->extent (x_common, X_AXIS),
+ elements[i]->extent (y_common, Y_AXIS));
+ SCM horizon_padding_scm = elements[i]->get_property ("outside-staff-horizontal-padding");
+ Real horizon_padding = robust_scm2double (horizon_padding_scm, 0.0);
+
+ if (b[X_AXIS][LEFT] - 2 * horizon_padding < last_affected_position[dir])
+ continue;
+
+ if (!b[X_AXIS].is_empty () && !b[Y_AXIS].is_empty ())
+ {
+ boxes.clear ();
+ boxes.push_back (b);
+ Skyline other = Skyline (boxes, horizon_padding, X_AXIS, -dir);
+ Real padding = robust_scm2double (elements[i]->get_property ("outside-staff-padding"), 0.5);
+ Real dist = (*skylines)[dir].distance (other) + padding;
+
+ if (dist > 0)
+ {
+ b.translate (Offset (0, dir * dist));
+ elements[i]->translate_axis (dir * dist, Y_AXIS);
+ }
+ skylines->insert (b, 0, X_AXIS);
+ elements[i]->set_property ("outside-staff-priority", SCM_BOOL_F);
+ last_affected_position[dir] = b[X_AXIS][RIGHT];
+ }
+
+ /*
+ Ugh: quadratic. --hwn
+ */
+ elements.erase (elements.begin () + i);
+ }
+ }
+}
+
+bool
+Axis_group_interface::has_outside_staff_parent (Grob *me)
+{
+ return (me
+ ? (scm_is_number (me->get_property ("outside-staff-priority"))
+ || has_outside_staff_parent (me->get_parent (Y_AXIS)))
+ : false);
+}
+
+// TODO: it is tricky to correctly handle skyline placement of cross-staff grobs.
+// For example, cross-staff beams cannot be formatted until the distance between
+// staves is known and therefore any grobs that depend on the beam cannot be placed
+// until the skylines are known. On the other hand, the distance between staves should
+// really depend on position of the cross-staff grobs that lie between them.
+// Currently, we just leave cross-staff grobs out of the
+// skyline altogether, but this could mean that staves are placed so close together
+// that there is no room for the cross-staff grob. It also means, of course, that
+// we don't get the benefits of skyline placement for cross-staff grobs.
+Skyline_pair
+Axis_group_interface::skyline_spacing (Grob *me, vector<Grob *> elements)