2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1996--2015 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"
32 Spanner::clone () const
34 return new Spanner (*this);
38 Spanner::do_break_processing ()
41 Item *left = spanned_drul_[LEFT];
42 Item *right = spanned_drul_[RIGHT];
47 if (get_system () || is_broken ())
53 If we have a spanner spanning one column, we must break it
54 anyway because it might provide a parent for another item. */
55 for (LEFT_and_RIGHT (d))
57 Item *bound = left->find_prebroken_piece (d);
59 programming_error ("no broken bound");
60 else if (bound->get_system ())
62 Spanner *span = dynamic_cast<Spanner *> (clone ());
63 span->set_bound (LEFT, bound);
64 span->set_bound (RIGHT, bound);
66 assert (span->get_system ());
67 span->get_system ()->typeset_grob (span);
68 broken_intos_.push_back (span);
74 System *root = get_root_system (this);
75 vector<Item *> break_points = root->broken_col_range (left, right);
77 break_points.insert (break_points.begin () + 0, left);
78 break_points.push_back (right);
80 Slice parent_rank_slice;
81 parent_rank_slice.set_full ();
84 Check if our parent in X-direction spans equally wide
87 for (int a = X_AXIS; a < NO_AXES; a++)
89 if (Spanner *parent = dynamic_cast<Spanner *> (get_parent ((Axis)a)))
90 parent_rank_slice.intersect (parent->spanned_rank_interval ());
93 for (vsize i = 1; i < break_points.size (); i++)
95 Drul_array<Item *> bounds;
96 bounds[LEFT] = break_points[i - 1];
97 bounds[RIGHT] = break_points[i];
98 for (LEFT_and_RIGHT (d))
100 if (!bounds[d]->get_system ())
101 bounds[d] = bounds[d]->find_prebroken_piece (- d);
104 if (!bounds[LEFT] || ! bounds[RIGHT])
106 programming_error ("bounds of this piece aren't breakable.");
110 bool ok = parent_rank_slice.contains (bounds[LEFT]->get_column ()->get_rank ());
111 ok = ok && parent_rank_slice.contains (bounds[RIGHT]->get_column ()->get_rank ());
115 programming_error (to_string ("Spanner `%s' is not fully contained in parent spanner."
116 " Ignoring orphaned part",
121 Spanner *span = dynamic_cast<Spanner *> (clone ());
122 span->set_bound (LEFT, bounds[LEFT]);
123 span->set_bound (RIGHT, bounds[RIGHT]);
125 if (!bounds[LEFT]->get_system ()
126 || !bounds[RIGHT]->get_system ()
127 || bounds[LEFT]->get_system () != bounds[RIGHT]->get_system ())
129 programming_error ("bounds of spanner are invalid");
134 bounds[LEFT]->get_system ()->typeset_grob (span);
135 broken_intos_.push_back (span);
139 vector_sort (broken_intos_, Spanner::less);
140 for (vsize i = broken_intos_.size (); i--;)
141 broken_intos_[i]->break_index_ = i;
145 Spanner::get_break_index () const
151 Spanner::set_my_columns ()
153 for (LEFT_and_RIGHT (d))
155 if (!spanned_drul_[d]->get_system ())
156 set_bound (d, spanned_drul_[d]->find_prebroken_piece ((Direction) - d));
161 Spanner::spanned_rank_interval () const
163 Interval_t<int> iv (0, 0);
165 if (spanned_drul_[LEFT] && spanned_drul_[LEFT]->get_column ())
166 iv[LEFT] = spanned_drul_[LEFT]->get_column ()->get_rank ();
167 if (spanned_drul_[RIGHT] && spanned_drul_[RIGHT]->get_column ())
168 iv[RIGHT] = spanned_drul_[RIGHT]->get_column ()->get_rank ();
173 Spanner::spanned_time () const
175 return spanned_time_interval (spanned_drul_[LEFT],
176 spanned_drul_[RIGHT]);
180 Spanner::get_bound (Direction d) const
182 return spanned_drul_[d];
186 Set the items that this spanner spans. If D == LEFT, we also set the
187 X-axis parent of THIS to S.
189 For example, when a slur crosses a line break, it's broken into two
190 pieces. The second piece shouldn't be positioned relative to the
191 original NoteColumn, but rather to the PaperColumn after the break.
194 Spanner::set_bound (Direction d, Grob *s)
196 Item *i = dynamic_cast<Item *> (s);
199 programming_error ("must have Item for spanner bound of " + name ());
203 spanned_drul_[d] = i;
206 We check for System to prevent the column -> line_of_score
207 -> column -> line_of_score -> etc situation */
208 if (d == LEFT && !dynamic_cast<System *> (this))
210 If the X-parent is a spanner, it will be split across linebreaks, too,
211 so we shouldn't have to overwrite it with the bound. Also, we need
212 original parent for alignment.
213 This happens e.g. for MultiMeasureRestNumbers and PercentRepeatCounters.
215 if (!dynamic_cast <Spanner *> (get_parent (X_AXIS)))
216 set_parent (i, X_AXIS);
219 Signal that this column needs to be kept alive. They need to be
220 kept alive to have meaningful position and linebreaking.
222 [maybe we should try keeping all columns alive?, and perhaps
223 inherit position from their (non-)musical brother]
225 if (dynamic_cast<Paper_column *> (i))
226 Pointer_group_interface::add_grob (i, ly_symbol2scm ("bounded-by-me"), this);
229 Spanner::Spanner (SCM s)
233 spanned_drul_.set (0, 0);
234 pure_property_cache_ = SCM_UNDEFINED;
237 Spanner::Spanner (Spanner const &s)
240 spanned_drul_.set (0, 0);
241 pure_property_cache_ = SCM_UNDEFINED;
245 Certain spanners have pre-computed X values that lie either in
246 X-positions or the X key of the alists returned for left-bound-info
247 and right-bound-info. These are calculated to give the real length
248 of a spanner (which, because of various padding or overhang properties,
249 can extend pass or arrive short of a given bound). If possible, we
250 use these to calculate the spanner's length, and otherwise, we use
253 For those writing a new spanner, DO NOT use both X-positions and
254 left-bound-info/right-bound-info.
257 Spanner::spanner_length () const
259 Interval lr = robust_scm2interval (get_property ("X-positions"),
264 Drul_array<SCM> bounds (get_property ("left-bound-info"),
265 get_property ("right-bound-info"));
267 for (LEFT_and_RIGHT (d))
268 lr[d] = robust_scm2double (ly_assoc_get (ly_symbol2scm ("X"),
269 bounds[d], SCM_BOOL_F), -d);
274 for (LEFT_and_RIGHT (d))
275 lr[d] = spanned_drul_[d]->relative_coordinate (0, X_AXIS);
279 programming_error ("spanner with negative length");
285 Spanner::get_system () const
287 if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
289 if (spanned_drul_[LEFT]->get_system () != spanned_drul_[RIGHT]->get_system ())
291 return spanned_drul_[LEFT]->get_system ();
295 Spanner::find_broken_piece (System *l) const
297 vsize idx = binary_search (broken_intos_, (Spanner *) l, Spanner::less);
299 return broken_intos_ [idx];
304 Spanner::broken_neighbor (Direction d) const
309 vsize k = get_break_index ();
310 Spanner *orig = dynamic_cast<Spanner *> (original_);
312 if (j < 0 || vsize (j) >= orig->broken_intos_.size ())
315 return orig->broken_intos_[j];
319 Spanner::compare (Spanner *const &p1, Spanner *const &p2)
321 return p1->get_system ()->get_rank () - p2->get_system ()->get_rank ();
325 Spanner::less (Spanner *const &a, Spanner *const &b)
327 return a->get_system ()->get_rank () < b->get_system ()->get_rank ();
331 Spanner::is_broken () const
333 return broken_intos_.size ();
337 Spanner::derived_mark () const
339 scm_gc_mark (pure_property_cache_);
341 for (LEFT_and_RIGHT (d))
342 if (spanned_drul_[d])
343 scm_gc_mark (spanned_drul_[d]->self_scm ());
346 for (vsize i = broken_intos_.size (); i--;)
347 scm_gc_mark (broken_intos_[i]->self_scm ());
351 Set left or right bound to IT.
353 Warning: caller should ensure that subsequent calls put in ITems
354 that are left-to-right ordered.
357 add_bound_item (Spanner *sp, Grob *it)
359 if (!sp->get_bound (LEFT))
360 sp->set_bound (LEFT, it);
362 sp->set_bound (RIGHT, it);
365 MAKE_SCHEME_CALLBACK (Spanner, set_spacing_rods, 1);
367 Spanner::set_spacing_rods (SCM smob)
369 Grob *me = unsmob<Grob> (smob);
370 SCM num_length = me->get_property ("minimum-length");
371 SCM broken_length = me->get_property ("minimum-length-after-break");
372 if (scm_is_number (num_length)
373 || scm_is_number (broken_length))
375 Spanner *sp = dynamic_cast<Spanner *> (me);
376 System *root = get_root_system (me);
377 Drul_array<Item *> bounds (sp->get_bound (LEFT),
378 sp->get_bound (RIGHT));
379 if (!bounds[LEFT] || !bounds[RIGHT])
380 return SCM_UNSPECIFIED;
382 vector<Item *> cols (root->broken_col_range (bounds[LEFT]->get_column (),
383 bounds[RIGHT]->get_column ()));
388 r.item_drul_[LEFT] = sp->get_bound (LEFT);
389 r.item_drul_[RIGHT] = cols[0]->find_prebroken_piece (LEFT);
390 r.distance_ = robust_scm2double (num_length, 0);
393 r.item_drul_[LEFT] = cols.back ()->find_prebroken_piece (RIGHT);
394 r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
395 if (scm_is_number (broken_length))
397 r.distance_ may have been modified by add_to_cols ()
398 above. For treatment of minimum-distance-after-break
399 consistent with minimum-distance (which will use the
400 changed value), we cannot directly reset r.distance_ to
403 r.distance_ += robust_scm2double (broken_length, 0) -
404 robust_scm2double (num_length, 0);
410 As r is a fresh rod, we can set distance_ with no complication.
412 r.distance_ = robust_scm2double (num_length, 0);
413 r.item_drul_[LEFT] = sp->get_bound (LEFT);
414 r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
418 We do not know yet if the spanner is going to have a bound that is
419 broken. To account for this uncertainty, we add the rod twice:
420 once for the central column (see above) and once for the left column
421 (see below). As end_rods_ are never used when rods_ are used and vice
422 versa, this rod will only be accessed once for each spacing
423 configuraiton before line breaking. Then, as a grob never exists in
424 both unbroken and broken forms after line breaking, only one of these
425 two rods will be in the column vector used for spacing in
426 simple-spacer.cc get_line_confugration.
428 if (Item *left_pbp = sp->get_bound (RIGHT)->find_prebroken_piece (LEFT))
430 r.item_drul_[RIGHT] = left_pbp;
435 return SCM_UNSPECIFIED;
438 MAKE_SCHEME_CALLBACK (Spanner, calc_normalized_endpoints, 1);
440 Spanner::calc_normalized_endpoints (SCM smob)
442 Spanner *me = unsmob<Spanner> (smob);
443 SCM result = SCM_EOL;
445 Spanner *orig = dynamic_cast<Spanner *> (me->original ());
447 orig = orig ? orig : me;
449 if (orig->is_broken ())
451 Real total_width = 0.0;
452 vector<Real> span_data;
454 if (!orig->is_broken ())
455 span_data.push_back (orig->spanner_length ());
457 for (vsize i = 0; i < orig->broken_intos_.size (); i++)
458 span_data.push_back (orig->broken_intos_[i]->spanner_length ());
460 vector<Interval> unnormalized_endpoints;
462 for (vsize i = 0; i < span_data.size (); i++)
464 unnormalized_endpoints.push_back (Interval (total_width, total_width + span_data[i]));
465 total_width += span_data[i];
468 for (vsize i = 0; i < unnormalized_endpoints.size (); i++)
470 SCM t = ly_interval2scm (1 / total_width * unnormalized_endpoints[i]);
471 orig->broken_intos_[i]->set_property ("normalized-endpoints", t);
472 if (me->get_break_index () == i)
478 result = scm_cons (scm_from_double (0.0), scm_from_double (1.0));
479 orig->set_property ("normalized-endpoints", result);
485 MAKE_SCHEME_CALLBACK (Spanner, bounds_width, 1);
487 Spanner::bounds_width (SCM grob)
489 Spanner *me = unsmob<Spanner> (grob);
491 Grob *common = me->get_bound (LEFT)->common_refpoint (me->get_bound (RIGHT), X_AXIS);
493 Interval w (me->get_bound (LEFT)->relative_coordinate (common, X_AXIS),
494 me->get_bound (RIGHT)->relative_coordinate (common, X_AXIS));
496 w -= me->relative_coordinate (common, X_AXIS);
498 return ly_interval2scm (w);
501 MAKE_SCHEME_CALLBACK (Spanner, kill_zero_spanned_time, 1);
503 Spanner::kill_zero_spanned_time (SCM grob)
505 Spanner *me = unsmob<Spanner> (grob);
507 Remove the line or hairpin at the start of the line. For
508 piano voice indicators, it makes no sense to have them at
509 the start of the line.
511 I'm not sure what the official rules for glissandi are, but
512 usually the 2nd note of the glissando is "exact", so when playing
513 from the start of the line, there is no need to glide.
515 From a typographical p.o.v. this makes sense, since the amount of
516 space left of a note at the start of a line is very small.
521 if (me->get_bound (LEFT)->break_status_dir ())
523 Interval_t<Moment> moments = me->spanned_time ();
524 moments [LEFT].grace_part_ = 0;
525 if (moments.length () == Moment (0, 0))
529 return SCM_UNSPECIFIED;
533 Spanner::get_cached_pure_property (SCM sym, int start, int end)
535 // The pure property cache is indexed by (name start . end), where name is
536 // a symbol, and start and end are numbers referring to the starting and
537 // ending column ranks of the current line.
538 if (scm_is_false (scm_hash_table_p (pure_property_cache_)))
539 return SCM_UNDEFINED;
541 SCM key = scm_cons (sym, scm_cons (scm_from_int (start), scm_from_int (end)));
542 return scm_hash_ref (pure_property_cache_, key, SCM_UNDEFINED);
546 Spanner::cache_pure_property (SCM sym, int start, int end, SCM val)
548 if (scm_is_false (scm_hash_table_p (pure_property_cache_)))
549 pure_property_cache_ = scm_c_make_hash_table (17);
551 SCM key = scm_cons (sym, scm_cons (scm_from_int (start), scm_from_int (end)));
552 scm_hash_set_x (pure_property_cache_, key, val);
555 ADD_INTERFACE (Spanner,
556 "Some objects are horizontally spanned between objects. For"
557 " example, slurs, beams, ties, etc. These grobs form a subtype"
558 " called @code{Spanner}. All spanners have two span points"
559 " (these must be @code{Item} objects), one on the left and one"
560 " on the right. The left bound is also the X@tie{}reference"
561 " point of the spanner.",
564 "normalized-endpoints "
566 "minimum-length-after-break "