2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1996--2014 Han-Wen Nienhuys <hanwen@xs4all.nl>
6 LilyPond is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 LilyPond is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
20 #include "libc-extension.hh"
22 #include "paper-column.hh"
23 #include "paper-score.hh"
24 #include "pointer-group-interface.hh"
30 Spanner::clone () const
32 return new Spanner (*this);
36 Spanner::do_break_processing ()
39 Item *left = spanned_drul_[LEFT];
40 Item *right = spanned_drul_[RIGHT];
45 if (get_system () || is_broken ())
51 If we have a spanner spanning one column, we must break it
52 anyway because it might provide a parent for another item. */
53 for (LEFT_and_RIGHT (d))
55 Item *bound = left->find_prebroken_piece (d);
57 programming_error ("no broken bound");
58 else if (bound->get_system ())
60 Spanner *span = dynamic_cast<Spanner *> (clone ());
61 span->set_bound (LEFT, bound);
62 span->set_bound (RIGHT, bound);
64 assert (span->get_system ());
65 span->get_system ()->typeset_grob (span);
66 broken_intos_.push_back (span);
72 System *root = get_root_system (this);
73 vector<Item *> break_points = root->broken_col_range (left, right);
75 break_points.insert (break_points.begin () + 0, left);
76 break_points.push_back (right);
78 Slice parent_rank_slice;
79 parent_rank_slice.set_full ();
82 Check if our parent in X-direction spans equally wide
85 for (int a = X_AXIS; a < NO_AXES; a++)
87 if (Spanner *parent = dynamic_cast<Spanner *> (get_parent ((Axis)a)))
88 parent_rank_slice.intersect (parent->spanned_rank_interval ());
91 for (vsize i = 1; i < break_points.size (); i++)
93 Drul_array<Item *> bounds;
94 bounds[LEFT] = break_points[i - 1];
95 bounds[RIGHT] = break_points[i];
96 for (LEFT_and_RIGHT (d))
98 if (!bounds[d]->get_system ())
99 bounds[d] = bounds[d]->find_prebroken_piece (- d);
102 if (!bounds[LEFT] || ! bounds[RIGHT])
104 programming_error ("bounds of this piece aren't breakable.");
108 bool ok = parent_rank_slice.contains (bounds[LEFT]->get_column ()->get_rank ());
109 ok = ok && parent_rank_slice.contains (bounds[RIGHT]->get_column ()->get_rank ());
113 programming_error (to_string ("Spanner `%s' is not fully contained in parent spanner."
114 " Ignoring orphaned part",
119 Spanner *span = dynamic_cast<Spanner *> (clone ());
120 span->set_bound (LEFT, bounds[LEFT]);
121 span->set_bound (RIGHT, bounds[RIGHT]);
123 if (!bounds[LEFT]->get_system ()
124 || !bounds[RIGHT]->get_system ()
125 || bounds[LEFT]->get_system () != bounds[RIGHT]->get_system ())
127 programming_error ("bounds of spanner are invalid");
132 bounds[LEFT]->get_system ()->typeset_grob (span);
133 broken_intos_.push_back (span);
137 vector_sort (broken_intos_, Spanner::less);
138 for (vsize i = broken_intos_.size (); i--;)
139 broken_intos_[i]->break_index_ = i;
143 Spanner::get_break_index () const
149 Spanner::set_my_columns ()
151 for (LEFT_and_RIGHT (d))
153 if (!spanned_drul_[d]->get_system ())
154 set_bound (d, spanned_drul_[d]->find_prebroken_piece ((Direction) - d));
159 Spanner::spanned_rank_interval () const
161 Interval_t<int> iv (0, 0);
163 if (spanned_drul_[LEFT] && spanned_drul_[LEFT]->get_column ())
164 iv[LEFT] = spanned_drul_[LEFT]->get_column ()->get_rank ();
165 if (spanned_drul_[RIGHT] && spanned_drul_[RIGHT]->get_column ())
166 iv[RIGHT] = spanned_drul_[RIGHT]->get_column ()->get_rank ();
171 Spanner::spanned_time () const
173 return spanned_time_interval (spanned_drul_[LEFT],
174 spanned_drul_[RIGHT]);
178 Spanner::get_bound (Direction d) const
180 return spanned_drul_[d];
184 Set the items that this spanner spans. If D == LEFT, we also set the
185 X-axis parent of THIS to S.
187 For example, when a slur crosses a line break, it's broken into two
188 pieces. The second piece shouldn't be positioned relative to the
189 original NoteColumn, but rather to the PaperColumn after the break.
192 Spanner::set_bound (Direction d, Grob *s)
194 Item *i = dynamic_cast<Item *> (s);
197 programming_error ("must have Item for spanner bound of " + name ());
201 spanned_drul_[d] = i;
204 We check for System to prevent the column -> line_of_score
205 -> column -> line_of_score -> etc situation */
206 if (d == LEFT && !dynamic_cast<System *> (this))
208 If the X-parent is a spanner, it will be split across linebreaks, too,
209 so we shouldn't have to overwrite it with the bound. Also, we need
210 original parent for alignment.
211 This happens e.g. for MultiMeasureRestNumbers and PercentRepeatCounters.
213 if (!dynamic_cast <Spanner *> (this->get_parent (X_AXIS)))
214 set_parent (i, X_AXIS);
217 Signal that this column needs to be kept alive. They need to be
218 kept alive to have meaningful position and linebreaking.
220 [maybe we should try keeping all columns alive?, and perhaps
221 inherit position from their (non-)musical brother]
223 if (dynamic_cast<Paper_column *> (i))
224 Pointer_group_interface::add_grob (i, ly_symbol2scm ("bounded-by-me"), this);
227 Spanner::Spanner (SCM s)
231 spanned_drul_.set (0, 0);
232 pure_property_cache_ = SCM_UNDEFINED;
235 Spanner::Spanner (Spanner const &s)
238 spanned_drul_.set (0, 0);
239 pure_property_cache_ = SCM_UNDEFINED;
243 Certain spanners have pre-computed X values that lie either in
244 X-positions or the X key of the alists returned for left-bound-info
245 and right-bound-info. These are calculated to give the real length
246 of a spanner (which, because of various padding or overhang properties,
247 can extend pass or arrive short of a given bound). If possible, we
248 use these to calculate the spanner's length, and otherwise, we use
251 For those writing a new spanner, DO NOT use both X-positions and
252 left-bound-info/right-bound-info.
255 Spanner::spanner_length () const
257 Interval lr = robust_scm2interval (get_property ("X-positions"),
262 Drul_array<SCM> bounds (get_property ("left-bound-info"),
263 get_property ("right-bound-info"));
265 for (LEFT_and_RIGHT (d))
266 lr[d] = robust_scm2double (ly_assoc_get (ly_symbol2scm ("X"),
267 bounds[d], SCM_BOOL_F), -d);
272 for (LEFT_and_RIGHT (d))
273 lr[d] = spanned_drul_[d]->relative_coordinate (0, X_AXIS);
277 programming_error ("spanner with negative length");
283 Spanner::get_system () const
285 if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
287 if (spanned_drul_[LEFT]->get_system () != spanned_drul_[RIGHT]->get_system ())
289 return spanned_drul_[LEFT]->get_system ();
293 Spanner::find_broken_piece (System *l) const
295 vsize idx = binary_search (broken_intos_, (Spanner *) l, Spanner::less);
297 return broken_intos_ [idx];
302 Spanner::broken_neighbor (Direction d) const
307 vsize k = get_break_index ();
308 Spanner *orig = dynamic_cast<Spanner *> (original_);
310 if (j < 0 || vsize (j) >= orig->broken_intos_.size ())
313 return orig->broken_intos_[j];
317 Spanner::compare (Spanner *const &p1, Spanner *const &p2)
319 return p1->get_system ()->get_rank () - p2->get_system ()->get_rank ();
323 Spanner::less (Spanner *const &a, Spanner *const &b)
325 return a->get_system ()->get_rank () < b->get_system ()->get_rank ();
329 Spanner::is_broken () const
331 return broken_intos_.size ();
335 Spanner::derived_mark () const
337 scm_gc_mark (pure_property_cache_);
339 for (LEFT_and_RIGHT (d))
340 if (spanned_drul_[d])
341 scm_gc_mark (spanned_drul_[d]->self_scm ());
344 for (vsize i = broken_intos_.size (); i--;)
345 scm_gc_mark (broken_intos_[i]->self_scm ());
349 Set left or right bound to IT.
351 Warning: caller should ensure that subsequent calls put in ITems
352 that are left-to-right ordered.
355 add_bound_item (Spanner *sp, Grob *it)
357 if (!sp->get_bound (LEFT))
358 sp->set_bound (LEFT, it);
360 sp->set_bound (RIGHT, it);
363 MAKE_SCHEME_CALLBACK (Spanner, set_spacing_rods, 1);
365 Spanner::set_spacing_rods (SCM smob)
367 Grob *me = Grob::unsmob (smob);
368 SCM num_length = me->get_property ("minimum-length");
369 if (scm_is_number (num_length))
372 Spanner *sp = dynamic_cast<Spanner *> (me);
373 System *root = get_root_system (me);
374 Drul_array<Item *> bounds (sp->get_bound (LEFT),
375 sp->get_bound (RIGHT));
376 if (!bounds[LEFT] || !bounds[RIGHT])
377 return SCM_UNSPECIFIED;
379 vector<Item *> cols (root->broken_col_range (bounds[LEFT]->get_column (),
380 bounds[RIGHT]->get_column ()));
385 r.item_drul_[LEFT] = sp->get_bound (LEFT);
386 r.item_drul_[RIGHT] = cols[0]->find_prebroken_piece (LEFT);
387 r.distance_ = robust_scm2double (num_length, 0);
390 r.item_drul_[LEFT] = cols.back ()->find_prebroken_piece (RIGHT);
391 r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
395 r.distance_ = robust_scm2double (num_length, 0);
396 r.item_drul_[LEFT] = sp->get_bound (LEFT);
397 r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
401 We do not know yet if the spanner is going to have a bound that is
402 broken. To account for this uncertainty, we add the rod twice:
403 once for the central column (see above) and once for the left column
404 (see below). As end_rods_ are never used when rods_ are used and vice
405 versa, this rod will only be accessed once for each spacing
406 configuraiton before line breaking. Then, as a grob never exists in
407 both unbroken and broken forms after line breaking, only one of these
408 two rods will be in the column vector used for spacing in
409 simple-spacer.cc get_line_confugration.
411 if (Item *left_pbp = sp->get_bound (RIGHT)->find_prebroken_piece (LEFT))
413 r.item_drul_[RIGHT] = left_pbp;
418 return SCM_UNSPECIFIED;
421 MAKE_SCHEME_CALLBACK (Spanner, calc_normalized_endpoints, 1);
423 Spanner::calc_normalized_endpoints (SCM smob)
425 Spanner *me = Spanner::unsmob (smob);
426 SCM result = SCM_EOL;
428 Spanner *orig = dynamic_cast<Spanner *> (me->original ());
430 orig = orig ? orig : me;
432 if (orig->is_broken ())
434 Real total_width = 0.0;
435 vector<Real> span_data;
437 if (!orig->is_broken ())
438 span_data.push_back (orig->spanner_length ());
440 for (vsize i = 0; i < orig->broken_intos_.size (); i++)
441 span_data.push_back (orig->broken_intos_[i]->spanner_length ());
443 vector<Interval> unnormalized_endpoints;
445 for (vsize i = 0; i < span_data.size (); i++)
447 unnormalized_endpoints.push_back (Interval (total_width, total_width + span_data[i]));
448 total_width += span_data[i];
451 for (vsize i = 0; i < unnormalized_endpoints.size (); i++)
453 SCM t = ly_interval2scm (1 / total_width * unnormalized_endpoints[i]);
454 orig->broken_intos_[i]->set_property ("normalized-endpoints", t);
455 if (me->get_break_index () == i)
461 result = scm_cons (scm_from_double (0.0), scm_from_double (1.0));
462 orig->set_property ("normalized-endpoints", result);
468 MAKE_SCHEME_CALLBACK (Spanner, bounds_width, 1);
470 Spanner::bounds_width (SCM grob)
472 Spanner *me = Spanner::unsmob (grob);
474 Grob *common = me->get_bound (LEFT)->common_refpoint (me->get_bound (RIGHT), X_AXIS);
476 Interval w (me->get_bound (LEFT)->relative_coordinate (common, X_AXIS),
477 me->get_bound (RIGHT)->relative_coordinate (common, X_AXIS));
479 w -= me->relative_coordinate (common, X_AXIS);
481 return ly_interval2scm (w);
484 MAKE_SCHEME_CALLBACK (Spanner, kill_zero_spanned_time, 1);
486 Spanner::kill_zero_spanned_time (SCM grob)
488 Spanner *me = Spanner::unsmob (grob);
490 Remove the line or hairpin at the start of the line. For
491 piano voice indicators, it makes no sense to have them at
492 the start of the line.
494 I'm not sure what the official rules for glissandi are, but
495 usually the 2nd note of the glissando is "exact", so when playing
496 from the start of the line, there is no need to glide.
498 From a typographical p.o.v. this makes sense, since the amount of
499 space left of a note at the start of a line is very small.
504 if (me->get_bound (LEFT)->break_status_dir ())
506 Interval_t<Moment> moments = me->spanned_time ();
507 moments [LEFT].grace_part_ = 0;
508 if (moments.length () == Moment (0, 0))
512 return SCM_UNSPECIFIED;
516 Spanner::get_cached_pure_property (SCM sym, int start, int end)
518 // The pure property cache is indexed by (name start . end), where name is
519 // a symbol, and start and end are numbers referring to the starting and
520 // ending column ranks of the current line.
521 if (scm_hash_table_p (pure_property_cache_) == SCM_BOOL_F)
522 return SCM_UNDEFINED;
524 SCM key = scm_cons (sym, scm_cons (scm_from_int (start), scm_from_int (end)));
525 return scm_hash_ref (pure_property_cache_, key, SCM_UNDEFINED);
529 Spanner::cache_pure_property (SCM sym, int start, int end, SCM val)
531 if (scm_hash_table_p (pure_property_cache_) == SCM_BOOL_F)
532 pure_property_cache_ = scm_c_make_hash_table (17);
534 SCM key = scm_cons (sym, scm_cons (scm_from_int (start), scm_from_int (end)));
535 scm_hash_set_x (pure_property_cache_, key, val);
538 ADD_INTERFACE (Spanner,
539 "Some objects are horizontally spanned between objects. For"
540 " example, slurs, beams, ties, etc. These grobs form a subtype"
541 " called @code{Spanner}. All spanners have two span points"
542 " (these must be @code{Item} objects), one on the left and one"
543 " on the right. The left bound is also the X@tie{}reference"
544 " point of the spanner.",
547 "normalized-endpoints "