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 *> (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 = unsmob<Grob> (smob);
368 SCM num_length = me->get_property ("minimum-length");
369 SCM broken_length = me->get_property ("minimum-length-after-break");
370 if (scm_is_number (num_length)
371 || scm_is_number (broken_length))
373 Spanner *sp = dynamic_cast<Spanner *> (me);
374 System *root = get_root_system (me);
375 Drul_array<Item *> bounds (sp->get_bound (LEFT),
376 sp->get_bound (RIGHT));
377 if (!bounds[LEFT] || !bounds[RIGHT])
378 return SCM_UNSPECIFIED;
380 vector<Item *> cols (root->broken_col_range (bounds[LEFT]->get_column (),
381 bounds[RIGHT]->get_column ()));
386 r.item_drul_[LEFT] = sp->get_bound (LEFT);
387 r.item_drul_[RIGHT] = cols[0]->find_prebroken_piece (LEFT);
388 r.distance_ = robust_scm2double (num_length, 0);
391 r.item_drul_[LEFT] = cols.back ()->find_prebroken_piece (RIGHT);
392 r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
393 if (scm_is_number (broken_length))
395 r.distance_ may have been modified by add_to_cols ()
396 above. For treatment of minimum-distance-after-break
397 consistent with minimum-distance (which will use the
398 changed value), we cannot directly reset r.distance_ to
401 r.distance_ += robust_scm2double (broken_length, 0) -
402 robust_scm2double (num_length, 0);
408 As r is a fresh rod, we can set distance_ with no complication.
410 r.distance_ = robust_scm2double (num_length, 0);
411 r.item_drul_[LEFT] = sp->get_bound (LEFT);
412 r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
416 We do not know yet if the spanner is going to have a bound that is
417 broken. To account for this uncertainty, we add the rod twice:
418 once for the central column (see above) and once for the left column
419 (see below). As end_rods_ are never used when rods_ are used and vice
420 versa, this rod will only be accessed once for each spacing
421 configuraiton before line breaking. Then, as a grob never exists in
422 both unbroken and broken forms after line breaking, only one of these
423 two rods will be in the column vector used for spacing in
424 simple-spacer.cc get_line_confugration.
426 if (Item *left_pbp = sp->get_bound (RIGHT)->find_prebroken_piece (LEFT))
428 r.item_drul_[RIGHT] = left_pbp;
433 return SCM_UNSPECIFIED;
436 MAKE_SCHEME_CALLBACK (Spanner, calc_normalized_endpoints, 1);
438 Spanner::calc_normalized_endpoints (SCM smob)
440 Spanner *me = unsmob<Spanner> (smob);
441 SCM result = SCM_EOL;
443 Spanner *orig = dynamic_cast<Spanner *> (me->original ());
445 orig = orig ? orig : me;
447 if (orig->is_broken ())
449 Real total_width = 0.0;
450 vector<Real> span_data;
452 if (!orig->is_broken ())
453 span_data.push_back (orig->spanner_length ());
455 for (vsize i = 0; i < orig->broken_intos_.size (); i++)
456 span_data.push_back (orig->broken_intos_[i]->spanner_length ());
458 vector<Interval> unnormalized_endpoints;
460 for (vsize i = 0; i < span_data.size (); i++)
462 unnormalized_endpoints.push_back (Interval (total_width, total_width + span_data[i]));
463 total_width += span_data[i];
466 for (vsize i = 0; i < unnormalized_endpoints.size (); i++)
468 SCM t = ly_interval2scm (1 / total_width * unnormalized_endpoints[i]);
469 orig->broken_intos_[i]->set_property ("normalized-endpoints", t);
470 if (me->get_break_index () == i)
476 result = scm_cons (scm_from_double (0.0), scm_from_double (1.0));
477 orig->set_property ("normalized-endpoints", result);
483 MAKE_SCHEME_CALLBACK (Spanner, bounds_width, 1);
485 Spanner::bounds_width (SCM grob)
487 Spanner *me = unsmob<Spanner> (grob);
489 Grob *common = me->get_bound (LEFT)->common_refpoint (me->get_bound (RIGHT), X_AXIS);
491 Interval w (me->get_bound (LEFT)->relative_coordinate (common, X_AXIS),
492 me->get_bound (RIGHT)->relative_coordinate (common, X_AXIS));
494 w -= me->relative_coordinate (common, X_AXIS);
496 return ly_interval2scm (w);
499 MAKE_SCHEME_CALLBACK (Spanner, kill_zero_spanned_time, 1);
501 Spanner::kill_zero_spanned_time (SCM grob)
503 Spanner *me = unsmob<Spanner> (grob);
505 Remove the line or hairpin at the start of the line. For
506 piano voice indicators, it makes no sense to have them at
507 the start of the line.
509 I'm not sure what the official rules for glissandi are, but
510 usually the 2nd note of the glissando is "exact", so when playing
511 from the start of the line, there is no need to glide.
513 From a typographical p.o.v. this makes sense, since the amount of
514 space left of a note at the start of a line is very small.
519 if (me->get_bound (LEFT)->break_status_dir ())
521 Interval_t<Moment> moments = me->spanned_time ();
522 moments [LEFT].grace_part_ = 0;
523 if (moments.length () == Moment (0, 0))
527 return SCM_UNSPECIFIED;
531 Spanner::get_cached_pure_property (SCM sym, int start, int end)
533 // The pure property cache is indexed by (name start . end), where name is
534 // a symbol, and start and end are numbers referring to the starting and
535 // ending column ranks of the current line.
536 if (scm_is_false (scm_hash_table_p (pure_property_cache_)))
537 return SCM_UNDEFINED;
539 SCM key = scm_cons (sym, scm_cons (scm_from_int (start), scm_from_int (end)));
540 return scm_hash_ref (pure_property_cache_, key, SCM_UNDEFINED);
544 Spanner::cache_pure_property (SCM sym, int start, int end, SCM val)
546 if (scm_is_false (scm_hash_table_p (pure_property_cache_)))
547 pure_property_cache_ = scm_c_make_hash_table (17);
549 SCM key = scm_cons (sym, scm_cons (scm_from_int (start), scm_from_int (end)));
550 scm_hash_set_x (pure_property_cache_, key, val);
553 ADD_INTERFACE (Spanner,
554 "Some objects are horizontally spanned between objects. For"
555 " example, slurs, beams, ties, etc. These grobs form a subtype"
556 " called @code{Spanner}. All spanners have two span points"
557 " (these must be @code{Item} objects), one on the left and one"
558 " on the right. The left bound is also the X@tie{}reference"
559 " point of the spanner.",
562 "normalized-endpoints "
564 "minimum-length-after-break "