]> git.donarmstrong.com Git - lilypond.git/blob - lily/spanner.cc
Keep a staff alive with multiple layers
[lilypond.git] / lily / spanner.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1996--2015 Han-Wen Nienhuys <hanwen@xs4all.nl>
5
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.
10
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.
15
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/>.
18 */
19
20 #include "libc-extension.hh"
21 #include "moment.hh"
22 #include "paper-column.hh"
23 #include "paper-score.hh"
24 #include "pointer-group-interface.hh"
25 #include "stencil.hh"
26 #include "system.hh"
27 #include "warn.hh"
28
29 Grob *
30 Spanner::clone () const
31 {
32   return new Spanner (*this);
33 }
34
35 void
36 Spanner::do_break_processing ()
37 {
38   //break_into_pieces
39   Item *left = spanned_drul_[LEFT];
40   Item *right = spanned_drul_[RIGHT];
41
42   if (!left || !right)
43     return;
44
45   if (get_system () || is_broken ())
46     return;
47
48   if (left == right)
49     {
50       /*
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))
54         {
55           Item *bound = left->find_prebroken_piece (d);
56           if (!bound)
57             programming_error ("no broken bound");
58           else if (bound->get_system ())
59             {
60               Spanner *span = dynamic_cast<Spanner *> (clone ());
61               span->set_bound (LEFT, bound);
62               span->set_bound (RIGHT, bound);
63
64               assert (span->get_system ());
65               span->get_system ()->typeset_grob (span);
66               broken_intos_.push_back (span);
67             }
68         }
69     }
70   else
71     {
72       System *root = get_root_system (this);
73       vector<Item *> break_points = root->broken_col_range (left, right);
74
75       break_points.insert (break_points.begin () + 0, left);
76       break_points.push_back (right);
77
78       Slice parent_rank_slice;
79       parent_rank_slice.set_full ();
80
81       /*
82         Check if our parent in X-direction spans equally wide
83         or wider than we do.
84       */
85       for (int a = X_AXIS; a < NO_AXES; a++)
86         {
87           if (Spanner *parent = dynamic_cast<Spanner *> (get_parent ((Axis)a)))
88             parent_rank_slice.intersect (parent->spanned_rank_interval ());
89         }
90
91       for (vsize i = 1; i < break_points.size (); i++)
92         {
93           Drul_array<Item *> bounds;
94           bounds[LEFT] = break_points[i - 1];
95           bounds[RIGHT] = break_points[i];
96           for (LEFT_and_RIGHT (d))
97             {
98               if (!bounds[d]->get_system ())
99                 bounds[d] = bounds[d]->find_prebroken_piece (- d);
100             }
101
102           if (!bounds[LEFT] || ! bounds[RIGHT])
103             {
104               programming_error ("bounds of this piece aren't breakable.");
105               continue;
106             }
107
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 ());
110
111           if (!ok)
112             {
113               programming_error (to_string ("Spanner `%s' is not fully contained in parent spanner."
114                                             "  Ignoring orphaned part",
115                                             name ().c_str ()));
116               continue;
117             }
118
119           Spanner *span = dynamic_cast<Spanner *> (clone ());
120           span->set_bound (LEFT, bounds[LEFT]);
121           span->set_bound (RIGHT, bounds[RIGHT]);
122
123           if (!bounds[LEFT]->get_system ()
124               || !bounds[RIGHT]->get_system ()
125               || bounds[LEFT]->get_system () != bounds[RIGHT]->get_system ())
126             {
127               programming_error ("bounds of spanner are invalid");
128               span->suicide ();
129             }
130           else
131             {
132               bounds[LEFT]->get_system ()->typeset_grob (span);
133               broken_intos_.push_back (span);
134             }
135         }
136     }
137   vector_sort (broken_intos_, Spanner::less);
138   for (vsize i = broken_intos_.size (); i--;)
139     broken_intos_[i]->break_index_ = i;
140 }
141
142 vsize
143 Spanner::get_break_index () const
144 {
145   return break_index_;
146 }
147
148 void
149 Spanner::set_my_columns ()
150 {
151   for (LEFT_and_RIGHT (d))
152     {
153       if (!spanned_drul_[d]->get_system ())
154         set_bound (d, spanned_drul_[d]->find_prebroken_piece ((Direction) - d));
155     }
156 }
157
158 Interval_t<int>
159 Spanner::spanned_rank_interval () const
160 {
161   Interval_t<int> iv (0, 0);
162
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 ();
167   return iv;
168 }
169
170 Interval_t<Moment>
171 Spanner::spanned_time () const
172 {
173   return spanned_time_interval (spanned_drul_[LEFT],
174                                 spanned_drul_[RIGHT]);
175 }
176
177 Item *
178 Spanner::get_bound (Direction d) const
179 {
180   return spanned_drul_[d];
181 }
182
183 /*
184   Set the items that this spanner spans. If D == LEFT, we also set the
185   X-axis parent of THIS to S.
186
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.
190 */
191 void
192 Spanner::set_bound (Direction d, Grob *s)
193 {
194   Item *i = dynamic_cast<Item *> (s);
195   if (!i)
196     {
197       programming_error ("must have Item for spanner bound of " + name ());
198       return;
199     }
200
201   spanned_drul_[d] = i;
202
203   /**
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))
207     /*
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.
212     */
213     if (!dynamic_cast <Spanner *> (get_parent (X_AXIS)))
214       set_parent (i, X_AXIS);
215
216   /*
217     Signal that this column needs to be kept alive. They need to be
218     kept alive to have meaningful position and linebreaking.
219
220     [maybe we should try keeping all columns alive?, and perhaps
221     inherit position from their (non-)musical brother]
222   */
223   if (dynamic_cast<Paper_column *> (i))
224     Pointer_group_interface::add_grob (i, ly_symbol2scm ("bounded-by-me"), this);
225 }
226
227 Spanner::Spanner (SCM s)
228   : Grob (s)
229 {
230   break_index_ = 0;
231   spanned_drul_.set (0, 0);
232   pure_property_cache_ = SCM_UNDEFINED;
233 }
234
235 Spanner::Spanner (Spanner const &s)
236   : Grob (s)
237 {
238   spanned_drul_.set (0, 0);
239   pure_property_cache_ = SCM_UNDEFINED;
240 }
241
242 /*
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
249   the bound.
250
251   For those writing a new spanner, DO NOT use both X-positions and
252   left-bound-info/right-bound-info.
253 */
254 Real
255 Spanner::spanner_length () const
256 {
257   Interval lr = robust_scm2interval (get_property ("X-positions"),
258                                      Interval (1, -1));
259
260   if (lr.is_empty ())
261     {
262       Drul_array<SCM> bounds (get_property ("left-bound-info"),
263                               get_property ("right-bound-info"));
264
265       for (LEFT_and_RIGHT (d))
266         lr[d] = robust_scm2double (ly_assoc_get (ly_symbol2scm ("X"),
267                                                  bounds[d], SCM_BOOL_F), -d);
268     }
269
270   if (lr.is_empty ())
271     {
272       for (LEFT_and_RIGHT (d))
273         lr[d] = spanned_drul_[d]->relative_coordinate (0, X_AXIS);
274     }
275
276   if (lr.is_empty ())
277     programming_error ("spanner with negative length");
278
279   return lr.length ();
280 }
281
282 System *
283 Spanner::get_system () const
284 {
285   if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
286     return 0;
287   if (spanned_drul_[LEFT]->get_system () != spanned_drul_[RIGHT]->get_system ())
288     return 0;
289   return spanned_drul_[LEFT]->get_system ();
290 }
291
292 Grob *
293 Spanner::find_broken_piece (System *l) const
294 {
295   vsize idx = binary_search (broken_intos_, (Spanner *) l, Spanner::less);
296   if (idx != VPOS)
297     return broken_intos_ [idx];
298   return 0;
299 }
300
301 Spanner *
302 Spanner::broken_neighbor (Direction d) const
303 {
304   if (!original_)
305     return 0;
306
307   vsize k = get_break_index ();
308   Spanner *orig = dynamic_cast<Spanner *> (original_);
309   int j = int (k) + d;
310   if (j < 0 || vsize (j) >= orig->broken_intos_.size ())
311     return 0;
312
313   return orig->broken_intos_[j];
314 }
315
316 int
317 Spanner::compare (Spanner *const &p1, Spanner *const &p2)
318 {
319   return p1->get_system ()->get_rank () - p2->get_system ()->get_rank ();
320 }
321
322 bool
323 Spanner::less (Spanner *const &a, Spanner *const &b)
324 {
325   return a->get_system ()->get_rank () < b->get_system ()->get_rank ();
326 }
327
328 bool
329 Spanner::is_broken () const
330 {
331   return broken_intos_.size ();
332 }
333
334 void
335 Spanner::derived_mark () const
336 {
337   scm_gc_mark (pure_property_cache_);
338
339   for (LEFT_and_RIGHT (d))
340     if (spanned_drul_[d])
341       scm_gc_mark (spanned_drul_[d]->self_scm ());
342   ;
343
344   for (vsize i = broken_intos_.size (); i--;)
345     scm_gc_mark (broken_intos_[i]->self_scm ());
346 }
347
348 /*
349   Set left or right bound to IT.
350
351   Warning: caller should ensure that subsequent calls put in ITems
352   that are left-to-right ordered.
353 */
354 void
355 add_bound_item (Spanner *sp, Grob *it)
356 {
357   if (!sp->get_bound (LEFT))
358     sp->set_bound (LEFT, it);
359   else
360     sp->set_bound (RIGHT, it);
361 }
362
363 MAKE_SCHEME_CALLBACK (Spanner, set_spacing_rods, 1);
364 SCM
365 Spanner::set_spacing_rods (SCM smob)
366 {
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))
372     {
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;
379
380       vector<Item *> cols (root->broken_col_range (bounds[LEFT]->get_column (),
381                                                    bounds[RIGHT]->get_column ()));
382
383       if (cols.size ())
384         {
385           Rod r;
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);
389           r.add_to_cols ();
390
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))
394             /*
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
399               broken_length.
400             */
401             r.distance_ += robust_scm2double (broken_length, 0) -
402               robust_scm2double (num_length, 0);
403           r.add_to_cols ();
404         }
405
406       Rod r;
407       /*
408         As r is a fresh rod, we can set distance_ with no complication.
409       */
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);
413       r.add_to_cols ();
414
415       /*
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.
425       */
426       if (Item *left_pbp = sp->get_bound (RIGHT)->find_prebroken_piece (LEFT))
427         {
428           r.item_drul_[RIGHT] = left_pbp;
429           r.add_to_cols ();
430         }
431     }
432
433   return SCM_UNSPECIFIED;
434 }
435
436 MAKE_SCHEME_CALLBACK (Spanner, calc_normalized_endpoints, 1);
437 SCM
438 Spanner::calc_normalized_endpoints (SCM smob)
439 {
440   Spanner *me = unsmob<Spanner> (smob);
441   SCM result = SCM_EOL;
442
443   Spanner *orig = dynamic_cast<Spanner *> (me->original ());
444
445   orig = orig ? orig : me;
446
447   if (orig->is_broken ())
448     {
449       Real total_width = 0.0;
450       vector<Real> span_data;
451
452       if (!orig->is_broken ())
453         span_data.push_back (orig->spanner_length ());
454       else
455         for (vsize i = 0; i < orig->broken_intos_.size (); i++)
456           span_data.push_back (orig->broken_intos_[i]->spanner_length ());
457
458       vector<Interval> unnormalized_endpoints;
459
460       for (vsize i = 0; i < span_data.size (); i++)
461         {
462           unnormalized_endpoints.push_back (Interval (total_width, total_width + span_data[i]));
463           total_width += span_data[i];
464         }
465
466       for (vsize i = 0; i < unnormalized_endpoints.size (); i++)
467         {
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)
471             result = t;
472         }
473     }
474   else
475     {
476       result = scm_cons (scm_from_double (0.0), scm_from_double (1.0));
477       orig->set_property ("normalized-endpoints", result);
478     }
479
480   return result;
481 }
482
483 MAKE_SCHEME_CALLBACK (Spanner, bounds_width, 1);
484 SCM
485 Spanner::bounds_width (SCM grob)
486 {
487   Spanner *me = unsmob<Spanner> (grob);
488
489   Grob *common = me->get_bound (LEFT)->common_refpoint (me->get_bound (RIGHT), X_AXIS);
490
491   Interval w (me->get_bound (LEFT)->relative_coordinate (common, X_AXIS),
492               me->get_bound (RIGHT)->relative_coordinate (common, X_AXIS));
493
494   w -= me->relative_coordinate (common, X_AXIS);
495
496   return ly_interval2scm (w);
497 }
498
499 MAKE_SCHEME_CALLBACK (Spanner, kill_zero_spanned_time, 1);
500 SCM
501 Spanner::kill_zero_spanned_time (SCM grob)
502 {
503   Spanner *me = unsmob<Spanner> (grob);
504   /*
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.
508
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.
512
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.
515
516     --hwn.
517
518   */
519   if (me->get_bound (LEFT)->break_status_dir ())
520     {
521       Interval_t<Moment> moments = me->spanned_time ();
522       moments [LEFT].grace_part_ = 0;
523       if (moments.length () == Moment (0, 0))
524         me->suicide ();
525     }
526
527   return SCM_UNSPECIFIED;
528 }
529
530 SCM
531 Spanner::get_cached_pure_property (SCM sym, int start, int end)
532 {
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;
538
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);
541 }
542
543 void
544 Spanner::cache_pure_property (SCM sym, int start, int end, SCM val)
545 {
546   if (scm_is_false (scm_hash_table_p (pure_property_cache_)))
547     pure_property_cache_ = scm_c_make_hash_table (17);
548
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);
551 }
552
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.",
560
561                /* properties */
562                "normalized-endpoints "
563                "minimum-length "
564                "minimum-length-after-break "
565                "spanner-broken "
566                "spanner-id "
567                "to-barline "
568               );