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);
227 Preinit_Spanner::Preinit_Spanner ()
229 spanned_drul_.set (0, 0);
230 pure_property_cache_ = SCM_UNDEFINED;
233 Spanner::Spanner (SCM s)
239 Spanner::Spanner (Spanner const &s)
246 Certain spanners have pre-computed X values that lie either in
247 X-positions or the X key of the alists returned for left-bound-info
248 and right-bound-info. These are calculated to give the real length
249 of a spanner (which, because of various padding or overhang properties,
250 can extend pass or arrive short of a given bound). If possible, we
251 use these to calculate the spanner's length, and otherwise, we use
254 For those writing a new spanner, DO NOT use both X-positions and
255 left-bound-info/right-bound-info.
258 Spanner::spanner_length () const
260 Interval lr = robust_scm2interval (get_property ("X-positions"),
265 Drul_array<SCM> bounds (get_property ("left-bound-info"),
266 get_property ("right-bound-info"));
268 for (LEFT_and_RIGHT (d))
269 lr[d] = robust_scm2double (ly_assoc_get (ly_symbol2scm ("X"),
270 bounds[d], SCM_BOOL_F), -d);
275 for (LEFT_and_RIGHT (d))
276 lr[d] = spanned_drul_[d]->relative_coordinate (0, X_AXIS);
280 programming_error ("spanner with negative length");
286 Spanner::get_system () const
288 if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
290 if (spanned_drul_[LEFT]->get_system () != spanned_drul_[RIGHT]->get_system ())
292 return spanned_drul_[LEFT]->get_system ();
296 Spanner::find_broken_piece (System *l) const
298 vsize idx = binary_search (broken_intos_, (Spanner *) l, Spanner::less);
300 return broken_intos_ [idx];
305 Spanner::broken_neighbor (Direction d) const
310 vsize k = get_break_index ();
311 Spanner *orig = dynamic_cast<Spanner *> (original_);
313 if (j < 0 || vsize (j) >= orig->broken_intos_.size ())
316 return orig->broken_intos_[j];
320 Spanner::compare (Spanner *const &p1, Spanner *const &p2)
322 return p1->get_system ()->get_rank () - p2->get_system ()->get_rank ();
326 Spanner::less (Spanner *const &a, Spanner *const &b)
328 return a->get_system ()->get_rank () < b->get_system ()->get_rank ();
332 Spanner::is_broken () const
334 return broken_intos_.size ();
338 Spanner::derived_mark () const
340 scm_gc_mark (pure_property_cache_);
342 for (LEFT_and_RIGHT (d))
343 if (spanned_drul_[d])
344 scm_gc_mark (spanned_drul_[d]->self_scm ());
347 // If break_index_ is -1, broken_intos_ might not yet have run its
348 // constructor and any access might break things.
349 if (break_index_ != (vsize)-1)
350 for (vsize i = broken_intos_.size (); i--;)
351 scm_gc_mark (broken_intos_[i]->self_scm ());
355 Set left or right bound to IT.
357 Warning: caller should ensure that subsequent calls put in ITems
358 that are left-to-right ordered.
361 add_bound_item (Spanner *sp, Grob *it)
363 if (!sp->get_bound (LEFT))
364 sp->set_bound (LEFT, it);
366 sp->set_bound (RIGHT, it);
369 MAKE_SCHEME_CALLBACK (Spanner, set_spacing_rods, 1);
371 Spanner::set_spacing_rods (SCM smob)
373 Grob *me = unsmob<Grob> (smob);
374 SCM num_length = me->get_property ("minimum-length");
375 SCM broken_length = me->get_property ("minimum-length-after-break");
376 if (scm_is_number (num_length)
377 || scm_is_number (broken_length))
379 Spanner *sp = dynamic_cast<Spanner *> (me);
380 System *root = get_root_system (me);
381 Drul_array<Item *> bounds (sp->get_bound (LEFT),
382 sp->get_bound (RIGHT));
383 if (!bounds[LEFT] || !bounds[RIGHT])
384 return SCM_UNSPECIFIED;
386 vector<Item *> cols (root->broken_col_range (bounds[LEFT]->get_column (),
387 bounds[RIGHT]->get_column ()));
392 r.item_drul_[LEFT] = sp->get_bound (LEFT);
393 r.item_drul_[RIGHT] = cols[0]->find_prebroken_piece (LEFT);
394 r.distance_ = robust_scm2double (num_length, 0);
397 r.item_drul_[LEFT] = cols.back ()->find_prebroken_piece (RIGHT);
398 r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
399 if (scm_is_number (broken_length))
401 r.distance_ may have been modified by add_to_cols ()
402 above. For treatment of minimum-distance-after-break
403 consistent with minimum-distance (which will use the
404 changed value), we cannot directly reset r.distance_ to
407 r.distance_ += robust_scm2double (broken_length, 0) -
408 robust_scm2double (num_length, 0);
414 As r is a fresh rod, we can set distance_ with no complication.
416 r.distance_ = robust_scm2double (num_length, 0);
417 r.item_drul_[LEFT] = sp->get_bound (LEFT);
418 r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
422 We do not know yet if the spanner is going to have a bound that is
423 broken. To account for this uncertainty, we add the rod twice:
424 once for the central column (see above) and once for the left column
425 (see below). As end_rods_ are never used when rods_ are used and vice
426 versa, this rod will only be accessed once for each spacing
427 configuraiton before line breaking. Then, as a grob never exists in
428 both unbroken and broken forms after line breaking, only one of these
429 two rods will be in the column vector used for spacing in
430 simple-spacer.cc get_line_confugration.
432 if (Item *left_pbp = sp->get_bound (RIGHT)->find_prebroken_piece (LEFT))
434 r.item_drul_[RIGHT] = left_pbp;
439 return SCM_UNSPECIFIED;
442 MAKE_SCHEME_CALLBACK (Spanner, calc_normalized_endpoints, 1);
444 Spanner::calc_normalized_endpoints (SCM smob)
446 Spanner *me = unsmob<Spanner> (smob);
447 SCM result = SCM_EOL;
449 Spanner *orig = dynamic_cast<Spanner *> (me->original ());
451 orig = orig ? orig : me;
453 if (orig->is_broken ())
455 Real total_width = 0.0;
456 vector<Real> span_data;
458 for (vsize i = 0; i < orig->broken_intos_.size (); i++)
459 span_data.push_back (orig->broken_intos_[i]->spanner_length ());
461 vector<Interval> unnormalized_endpoints;
463 for (vsize i = 0; i < span_data.size (); i++)
465 unnormalized_endpoints.push_back (Interval (total_width, total_width + span_data[i]));
466 total_width += span_data[i];
469 for (vsize i = 0; i < unnormalized_endpoints.size (); i++)
471 SCM t = ly_interval2scm (1 / total_width * unnormalized_endpoints[i]);
472 orig->broken_intos_[i]->set_property ("normalized-endpoints", t);
473 if (me->get_break_index () == i)
479 result = scm_cons (scm_from_double (0.0), scm_from_double (1.0));
480 orig->set_property ("normalized-endpoints", result);
486 MAKE_SCHEME_CALLBACK (Spanner, bounds_width, 1);
488 Spanner::bounds_width (SCM grob)
490 Spanner *me = unsmob<Spanner> (grob);
492 Grob *common = me->get_bound (LEFT)->common_refpoint (me->get_bound (RIGHT), X_AXIS);
494 Interval w (me->get_bound (LEFT)->relative_coordinate (common, X_AXIS),
495 me->get_bound (RIGHT)->relative_coordinate (common, X_AXIS));
497 w -= me->relative_coordinate (common, X_AXIS);
499 return ly_interval2scm (w);
502 MAKE_SCHEME_CALLBACK (Spanner, kill_zero_spanned_time, 1);
504 Spanner::kill_zero_spanned_time (SCM grob)
506 Spanner *me = unsmob<Spanner> (grob);
508 Remove the line or hairpin at the start of the line. For
509 piano voice indicators, it makes no sense to have them at
510 the start of the line.
512 I'm not sure what the official rules for glissandi are, but
513 usually the 2nd note of the glissando is "exact", so when playing
514 from the start of the line, there is no need to glide.
516 From a typographical p.o.v. this makes sense, since the amount of
517 space left of a note at the start of a line is very small.
522 if (me->get_bound (LEFT)->break_status_dir ())
524 Interval_t<Moment> moments = me->spanned_time ();
525 moments [LEFT].grace_part_ = 0;
526 if (moments.length () == Moment (0, 0))
530 return SCM_UNSPECIFIED;
534 Spanner::get_cached_pure_property (SCM sym, int start, int end)
536 // The pure property cache is indexed by (name start . end), where name is
537 // a symbol, and start and end are numbers referring to the starting and
538 // ending column ranks of the current line.
539 if (scm_is_false (scm_hash_table_p (pure_property_cache_)))
540 return SCM_UNDEFINED;
542 SCM key = scm_cons (sym, scm_cons (scm_from_int (start), scm_from_int (end)));
543 return scm_hash_ref (pure_property_cache_, key, SCM_UNDEFINED);
547 Spanner::cache_pure_property (SCM sym, int start, int end, SCM val)
549 if (scm_is_false (scm_hash_table_p (pure_property_cache_)))
550 pure_property_cache_ = scm_c_make_hash_table (17);
552 SCM key = scm_cons (sym, scm_cons (scm_from_int (start), scm_from_int (end)));
553 scm_hash_set_x (pure_property_cache_, key, val);
556 ADD_INTERFACE (Spanner,
557 "Some objects are horizontally spanned between objects. For"
558 " example, slurs, beams, ties, etc. These grobs form a subtype"
559 " called @code{Spanner}. All spanners have two span points"
560 " (these must be @code{Item} objects), one on the left and one"
561 " on the right. The left bound is also the X@tie{}reference"
562 " point of the spanner.",
565 "normalized-endpoints "
567 "minimum-length-after-break "