+MAKE_SCHEME_CALLBACK (Stem_tremolo, pure_height, 3);
+SCM
+Stem_tremolo::pure_height (SCM smob, SCM, SCM)
+{
+ Item *me = unsmob<Item> (smob);
+
+ /*
+ Cannot use the real slope, since it looks at the Beam.
+ */
+ Stencil s1 (untranslated_stencil (me, 0.35));
+ Item *stem = unsmob<Item> (me->get_object ("stem"));
+ if (!stem)
+ return ly_interval2scm (s1.extent (Y_AXIS));
+
+ Direction dir = get_grob_direction (me);
+
+ Spanner *beam = Stem::get_beam (stem);
+
+ if (!beam)
+ return ly_interval2scm (s1.extent (Y_AXIS));
+
+ Interval ph = stem->pure_y_extent (stem, 0, INT_MAX);
+ Stem_info si = Stem::get_stem_info (stem);
+ ph[-dir] = si.shortest_y_;
+ int beam_count = Stem::beam_multiplicity (stem).length () + 1;
+ Real beam_translation = get_beam_translation (me);
+
+ ph = ph - dir * max (beam_count, 1) * beam_translation;
+ ph = ph - ph.center ();
+
+ return ly_interval2scm (ph);
+}
+
+MAKE_SCHEME_CALLBACK (Stem_tremolo, width, 1);
+SCM
+Stem_tremolo::width (SCM smob)
+{
+ Grob *me = unsmob<Grob> (smob);
+
+ /*
+ Cannot use the real slope, since it looks at the Beam.
+ */
+ Stencil s1 (untranslated_stencil (me, 0.35));
+
+ return ly_interval2scm (s1.extent (X_AXIS));
+}
+
+Real
+Stem_tremolo::vertical_length (Grob *me)
+{
+ return untranslated_stencil (me, 0.35).extent (Y_AXIS).length ();
+}
+
+Stencil
+Stem_tremolo::untranslated_stencil (Grob *me, Real slope)
+{
+ Grob *stem = unsmob<Grob> (me->get_object ("stem"));
+ if (!stem)
+ {
+ programming_error ("no stem for stem-tremolo");
+ return Stencil ();
+ }
+
+ Direction dir = get_grob_direction (me);
+
+ bool whole_note = Stem::duration_log (stem) <= 0;
+
+ /* for a whole note, we position relative to the notehead, so we want the
+ stencil aligned on the flag closest to the head */
+ Direction stencil_dir = whole_note ? -dir : dir;
+ return raw_stencil (me, slope, stencil_dir);
+}
+
+MAKE_SCHEME_CALLBACK (Stem_tremolo, calc_y_offset, 1);
+SCM
+Stem_tremolo::calc_y_offset (SCM smob)
+{
+ Grob *me = unsmob<Grob> (smob);
+ return scm_from_double (y_offset (me, false));
+}
+
+MAKE_SCHEME_CALLBACK (Stem_tremolo, pure_calc_y_offset, 3);
+SCM
+Stem_tremolo::pure_calc_y_offset (SCM smob,
+ SCM, /* start */
+ SCM /* end */)
+{
+ Grob *me = unsmob<Grob> (smob);
+ return scm_from_double (y_offset (me, true));
+}
+
+MAKE_SCHEME_CALLBACK (Stem_tremolo, calc_direction, 1);