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"
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 *> (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);
230 break_index_ = (vsize)-1;
231 // This is stupid, but derived_mark may be run before broken_into_
232 // has run its constructor and has a recognizable array size.
233 // So we use break_index_ == -1 as a sentinel.
234 spanned_drul_.set (0, 0);
235 pure_property_cache_ = SCM_UNDEFINED;
238 Spanner::Spanner (SCM s)
244 Spanner::Spanner (Spanner const &s)
251 Certain spanners have pre-computed X values that lie either in
252 X-positions or the X key of the alists returned for left-bound-info
253 and right-bound-info. These are calculated to give the real length
254 of a spanner (which, because of various padding or overhang properties,
255 can extend pass or arrive short of a given bound). If possible, we
256 use these to calculate the spanner's length, and otherwise, we use
259 For those writing a new spanner, DO NOT use both X-positions and
260 left-bound-info/right-bound-info.
263 Spanner::spanner_length () const
265 Interval lr = robust_scm2interval (get_property ("X-positions"),
270 Drul_array<SCM> bounds (get_property ("left-bound-info"),
271 get_property ("right-bound-info"));
273 for (LEFT_and_RIGHT (d))
274 lr[d] = robust_scm2double (ly_assoc_get (ly_symbol2scm ("X"),
275 bounds[d], SCM_BOOL_F), -d);
280 for (LEFT_and_RIGHT (d))
281 lr[d] = spanned_drul_[d]->relative_coordinate (0, X_AXIS);
285 programming_error ("spanner with negative length");
291 Spanner::get_system () const
293 if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
295 if (spanned_drul_[LEFT]->get_system () != spanned_drul_[RIGHT]->get_system ())
297 return spanned_drul_[LEFT]->get_system ();
301 Spanner::find_broken_piece (System *l) const
303 vsize idx = binary_search (broken_intos_, (Spanner *) l, Spanner::less);
305 return broken_intos_ [idx];
310 Spanner::broken_neighbor (Direction d) const
315 vsize k = get_break_index ();
316 Spanner *orig = dynamic_cast<Spanner *> (original_);
318 if (j < 0 || vsize (j) >= orig->broken_intos_.size ())
321 return orig->broken_intos_[j];
325 Spanner::compare (Spanner *const &p1, Spanner *const &p2)
327 return p1->get_system ()->get_rank () - p2->get_system ()->get_rank ();
331 Spanner::less (Spanner *const &a, Spanner *const &b)
333 return a->get_system ()->get_rank () < b->get_system ()->get_rank ();
337 Spanner::is_broken () const
339 return broken_intos_.size ();
343 Spanner::derived_mark () const
345 scm_gc_mark (pure_property_cache_);
347 for (LEFT_and_RIGHT (d))
348 if (spanned_drul_[d])
349 scm_gc_mark (spanned_drul_[d]->self_scm ());
352 // If break_index_ is -1, broken_intos_ might not yet have run its
353 // constructor and any access might break things.
354 if (break_index_ != (vsize)-1)
355 for (vsize i = broken_intos_.size (); i--;)
356 scm_gc_mark (broken_intos_[i]->self_scm ());
360 Set left or right bound to IT.
362 Warning: caller should ensure that subsequent calls put in ITems
363 that are left-to-right ordered.
366 add_bound_item (Spanner *sp, Grob *it)
368 if (!sp->get_bound (LEFT))
369 sp->set_bound (LEFT, it);
371 sp->set_bound (RIGHT, it);
374 MAKE_SCHEME_CALLBACK (Spanner, set_spacing_rods, 1);
376 Spanner::set_spacing_rods (SCM smob)
378 Grob *me = unsmob<Grob> (smob);
379 SCM num_length = me->get_property ("minimum-length");
380 SCM broken_length = me->get_property ("minimum-length-after-break");
381 if (scm_is_number (num_length)
382 || scm_is_number (broken_length))
384 Spanner *sp = dynamic_cast<Spanner *> (me);
385 System *root = get_root_system (me);
386 Drul_array<Item *> bounds (sp->get_bound (LEFT),
387 sp->get_bound (RIGHT));
388 if (!bounds[LEFT] || !bounds[RIGHT])
389 return SCM_UNSPECIFIED;
391 vector<Item *> cols (root->broken_col_range (bounds[LEFT]->get_column (),
392 bounds[RIGHT]->get_column ()));
397 r.item_drul_[LEFT] = sp->get_bound (LEFT);
398 r.item_drul_[RIGHT] = cols[0]->find_prebroken_piece (LEFT);
399 r.distance_ = robust_scm2double (num_length, 0);
402 r.item_drul_[LEFT] = cols.back ()->find_prebroken_piece (RIGHT);
403 r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
404 if (scm_is_number (broken_length))
406 r.distance_ may have been modified by add_to_cols ()
407 above. For treatment of minimum-distance-after-break
408 consistent with minimum-distance (which will use the
409 changed value), we cannot directly reset r.distance_ to
412 r.distance_ += robust_scm2double (broken_length, 0) -
413 robust_scm2double (num_length, 0);
419 As r is a fresh rod, we can set distance_ with no complication.
421 r.distance_ = robust_scm2double (num_length, 0);
422 r.item_drul_[LEFT] = sp->get_bound (LEFT);
423 r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
427 We do not know yet if the spanner is going to have a bound that is
428 broken. To account for this uncertainty, we add the rod twice:
429 once for the central column (see above) and once for the left column
430 (see below). As end_rods_ are never used when rods_ are used and vice
431 versa, this rod will only be accessed once for each spacing
432 configuraiton before line breaking. Then, as a grob never exists in
433 both unbroken and broken forms after line breaking, only one of these
434 two rods will be in the column vector used for spacing in
435 simple-spacer.cc get_line_confugration.
437 if (Item *left_pbp = sp->get_bound (RIGHT)->find_prebroken_piece (LEFT))
439 r.item_drul_[RIGHT] = left_pbp;
444 return SCM_UNSPECIFIED;
447 MAKE_SCHEME_CALLBACK (Spanner, calc_normalized_endpoints, 1);
449 Spanner::calc_normalized_endpoints (SCM smob)
451 Spanner *me = unsmob<Spanner> (smob);
452 SCM result = SCM_EOL;
454 Spanner *orig = dynamic_cast<Spanner *> (me->original ());
456 orig = orig ? orig : me;
458 if (orig->is_broken ())
460 Real total_width = 0.0;
461 vector<Real> span_data;
463 if (!orig->is_broken ())
464 span_data.push_back (orig->spanner_length ());
466 for (vsize i = 0; i < orig->broken_intos_.size (); i++)
467 span_data.push_back (orig->broken_intos_[i]->spanner_length ());
469 vector<Interval> unnormalized_endpoints;
471 for (vsize i = 0; i < span_data.size (); i++)
473 unnormalized_endpoints.push_back (Interval (total_width, total_width + span_data[i]));
474 total_width += span_data[i];
477 for (vsize i = 0; i < unnormalized_endpoints.size (); i++)
479 SCM t = ly_interval2scm (1 / total_width * unnormalized_endpoints[i]);
480 orig->broken_intos_[i]->set_property ("normalized-endpoints", t);
481 if (me->get_break_index () == i)
487 result = scm_cons (scm_from_double (0.0), scm_from_double (1.0));
488 orig->set_property ("normalized-endpoints", result);
494 MAKE_SCHEME_CALLBACK (Spanner, bounds_width, 1);
496 Spanner::bounds_width (SCM grob)
498 Spanner *me = unsmob<Spanner> (grob);
500 Grob *common = me->get_bound (LEFT)->common_refpoint (me->get_bound (RIGHT), X_AXIS);
502 Interval w (me->get_bound (LEFT)->relative_coordinate (common, X_AXIS),
503 me->get_bound (RIGHT)->relative_coordinate (common, X_AXIS));
505 w -= me->relative_coordinate (common, X_AXIS);
507 return ly_interval2scm (w);
510 MAKE_SCHEME_CALLBACK (Spanner, kill_zero_spanned_time, 1);
512 Spanner::kill_zero_spanned_time (SCM grob)
514 Spanner *me = unsmob<Spanner> (grob);
516 Remove the line or hairpin at the start of the line. For
517 piano voice indicators, it makes no sense to have them at
518 the start of the line.
520 I'm not sure what the official rules for glissandi are, but
521 usually the 2nd note of the glissando is "exact", so when playing
522 from the start of the line, there is no need to glide.
524 From a typographical p.o.v. this makes sense, since the amount of
525 space left of a note at the start of a line is very small.
530 if (me->get_bound (LEFT)->break_status_dir ())
532 Interval_t<Moment> moments = me->spanned_time ();
533 moments [LEFT].grace_part_ = 0;
534 if (moments.length () == Moment (0, 0))
538 return SCM_UNSPECIFIED;
542 Spanner::get_cached_pure_property (SCM sym, int start, int end)
544 // The pure property cache is indexed by (name start . end), where name is
545 // a symbol, and start and end are numbers referring to the starting and
546 // ending column ranks of the current line.
547 if (scm_is_false (scm_hash_table_p (pure_property_cache_)))
548 return SCM_UNDEFINED;
550 SCM key = scm_cons (sym, scm_cons (scm_from_int (start), scm_from_int (end)));
551 return scm_hash_ref (pure_property_cache_, key, SCM_UNDEFINED);
555 Spanner::cache_pure_property (SCM sym, int start, int end, SCM val)
557 if (scm_is_false (scm_hash_table_p (pure_property_cache_)))
558 pure_property_cache_ = scm_c_make_hash_table (17);
560 SCM key = scm_cons (sym, scm_cons (scm_from_int (start), scm_from_int (end)));
561 scm_hash_set_x (pure_property_cache_, key, val);
564 ADD_INTERFACE (Spanner,
565 "Some objects are horizontally spanned between objects. For"
566 " example, slurs, beams, ties, etc. These grobs form a subtype"
567 " called @code{Spanner}. All spanners have two span points"
568 " (these must be @code{Item} objects), one on the left and one"
569 " on the right. The left bound is also the X@tie{}reference"
570 " point of the spanner.",
573 "normalized-endpoints "
575 "minimum-length-after-break "