+ set<Grob *> support = get_support_set (me);
+
+ Grob *common[2];
+ for (Axis ax = X_AXIS; ax < NO_AXES; incr (ax))
+ common[ax] = common_refpoint_of_array (support,
+ (ax == a
+ ? me->get_parent (ax)
+ : me),
+ ax);
+
+ Grob *staff_symbol = Staff_symbol_referencer::get_staff_symbol (me);
+ bool quantize_position = to_boolean (me->get_maybe_pure_property ("quantize-position", pure, start, end));
+ bool me_cross_staff = to_boolean (me->get_property ("cross-staff"));
+
+ bool include_staff
+ = staff_symbol
+ && a == Y_AXIS
+ && scm_is_number (me->get_maybe_pure_property ("staff-padding", pure, start, end))
+ && !quantize_position;
+
+ if (include_staff)
+ common[Y_AXIS] = staff_symbol->common_refpoint (common[Y_AXIS], Y_AXIS);
+
+ Skyline my_dim;
+ SCM skyp = me->get_maybe_pure_property (a == X_AXIS
+ ? "horizontal-skylines"
+ : "vertical-skylines",
+ pure,
+ start,
+ end);
+ if (unsmob<Skyline_pair> (skyp))
+ {
+ // for spanner pure heights, we don't know horizontal spacing,
+ // so a spanner can never have a meaningful x coordiante
+ // we just give it the parents' coordinate because its
+ // skyline will likely be of infinite width anyway
+ // and we don't want to prematurely trigger H spacing
+ Real xc = a == X_AXIS || (pure && dynamic_cast<Spanner *> (me))
+ ? me->parent_relative (common[X_AXIS], X_AXIS)
+ : me->relative_coordinate (common[X_AXIS], X_AXIS);
+ // same here, for X_AXIS spacing, if it's happening, it should only be
+ // before line breaking. because there is no thing as "pure" x spacing,
+ // we assume that it is all pure
+ Real yc = a == X_AXIS
+ ? me->pure_relative_y_coordinate (common[Y_AXIS], start, end)
+ : me->get_parent (Y_AXIS)->maybe_pure_coordinate (common[Y_AXIS], Y_AXIS, pure, start, end);
+ Skyline_pair copy = *unsmob<Skyline_pair> (skyp);
+ copy.shift (a == X_AXIS ? yc : xc);
+ copy.raise (a == X_AXIS ? xc : yc);
+ my_dim = copy[-dir];
+ }
+ else
+ me->warning ("cannot find skylines - strange alignment will follow");
+
+
+ vector<Box> boxes;
+ vector<Skyline_pair> skyps;
+ set<Grob *>::iterator it;
+
+ for (it = support.begin (); it != support.end (); it++)
+ {
+ Grob *e = *it;
+
+ bool cross_staff = to_boolean (e->get_property ("cross-staff"));
+ if (a == Y_AXIS
+ && !me_cross_staff // 'me' promised not to adapt to staff-spacing
+ && cross_staff) // but 'e' might move based on staff-pacing
+ continue; // so 'me' may not move in response to 'e'
+
+ if (a == Y_AXIS
+ && has_interface<Stem> (e))
+ {
+ // If called as 'pure' we may not force a stem to set its direction,
+ if (pure && !is_direction (e->get_property_data ("direction")))
+ continue;
+ // There is no need to consider stems pointing away.
+ if (dir == -get_grob_direction (e))
+ continue;
+ }
+
+ if (e)
+ {
+ SCM sp = e->get_maybe_pure_property (a == X_AXIS
+ ? "horizontal-skylines"
+ : "vertical-skylines",
+ pure,
+ start,
+ end);
+
+ if (unsmob<Skyline_pair> (sp))
+ {
+ Real xc = pure && dynamic_cast<Spanner *> (e)
+ ? e->parent_relative (common[X_AXIS], X_AXIS)
+ : e->relative_coordinate (common[X_AXIS], X_AXIS);
+ // same logic as above
+ // we assume horizontal spacing is always pure
+ Real yc = a == X_AXIS
+ ? e->pure_relative_y_coordinate (common[Y_AXIS], start, end)
+ : e->maybe_pure_coordinate (common[Y_AXIS], Y_AXIS, pure, start, end);
+ Skyline_pair copy = *unsmob<Skyline_pair> (sp);
+ if (a == Y_AXIS
+ && has_interface<Stem> (e)
+ && to_boolean (me->get_maybe_pure_property ("add-stem-support", pure, start, end)))
+ copy[dir].set_minimum_height (copy[dir].max_height ());
+ copy.shift (a == X_AXIS ? yc : xc);
+ copy.raise (a == X_AXIS ? xc : yc);
+ skyps.push_back (copy);
+ }
+ else { /* no warning*/ }
+ }
+ }
+
+ Skyline dim (boxes, other_axis (a), dir);
+ if (skyps.size ())
+ {
+ Skyline_pair merged (skyps);
+ dim.merge (merged[dir]);
+ }
+
+ if (include_staff)
+ {
+ Interval staff_extents;
+ common[Y_AXIS] = staff_symbol->common_refpoint (common[Y_AXIS], Y_AXIS);
+ staff_extents = staff_symbol->maybe_pure_extent (common[Y_AXIS], Y_AXIS, pure, start, end);
+ dim.set_minimum_height (staff_extents[dir]);
+ }
+
+ // Sometimes, we want to side position for grobs but they
+ // don't position against anything. Some cases where this is true:
+ // - StanzaNumber if the supporting lyrics are hara-kiri'd
+ // SystemStartBracket
+ // InstrumentName
+ // In all these cases, we set the height of the support to 0.
+ // This becomes then like the self-alignment-interface with the
+ // caveat that there is padding added.
+ // TODO: if there is a grob that never has side-support-elements
+ // (like InstrumentName), why are we using this function? Isn't it
+ // overkill? A function like self-alignment-interface with padding
+ // works just fine.
+ // One could even imagine the two interfaces merged, as the only
+ // difference is that in self-alignment-interface we align on the parent
+ // where as here we align on a group of grobs.
+ if (dim.is_empty ())
+ {
+ dim = Skyline (dim.direction ());
+ dim.set_minimum_height (0.0);
+ }
+
+ Real ss = Staff_symbol_referencer::staff_space (me);
+ Real dist = dim.distance (my_dim, robust_scm2double (me->get_maybe_pure_property ("horizon-padding", pure, start, end), 0.0));
+ Real total_off = !isinf (dist) ? dir * dist : 0.0;
+
+ total_off += dir * ss * robust_scm2double (me->get_maybe_pure_property ("padding", pure, start, end), 0.0);
+
+ Real minimum_space = ss * robust_scm2double (me->get_maybe_pure_property ("minimum-space", pure, start, end), -1);
+
+ if (minimum_space >= 0
+ && dir
+ && total_off * dir < minimum_space)
+ total_off = minimum_space * dir;
+
+ if (current_off)
+ total_off = dir * max (dir * total_off,
+ dir * (*current_off));
+
+ /* FIXME: 1000 should relate to paper size. */
+ if (fabs (total_off) > 1000)
+ {
+ string msg
+ = String_convert::form_string ("Improbable offset for grob %s: %f",
+ me->name ().c_str (), total_off);
+
+ programming_error (msg);
+ if (strict_infinity_checking)
+ scm_misc_error (__FUNCTION__, "Improbable offset.", SCM_EOL);
+ }