]> git.donarmstrong.com Git - lilypond.git/blob - lily/spanner.cc
1b6798086a3244558555a7cd1fa98059e15e834d
[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 void
228 Spanner::pre_init ()
229 {
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;
236 }
237
238 Spanner::Spanner (SCM s)
239   : Grob (s)
240 {
241   break_index_ = 0;
242 }
243
244 Spanner::Spanner (Spanner const &s)
245   : Grob (s)
246 {
247   break_index_ = 0;
248 }
249
250 /*
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
257   the bound.
258
259   For those writing a new spanner, DO NOT use both X-positions and
260   left-bound-info/right-bound-info.
261 */
262 Real
263 Spanner::spanner_length () const
264 {
265   Interval lr = robust_scm2interval (get_property ("X-positions"),
266                                      Interval (1, -1));
267
268   if (lr.is_empty ())
269     {
270       Drul_array<SCM> bounds (get_property ("left-bound-info"),
271                               get_property ("right-bound-info"));
272
273       for (LEFT_and_RIGHT (d))
274         lr[d] = robust_scm2double (ly_assoc_get (ly_symbol2scm ("X"),
275                                                  bounds[d], SCM_BOOL_F), -d);
276     }
277
278   if (lr.is_empty ())
279     {
280       for (LEFT_and_RIGHT (d))
281         lr[d] = spanned_drul_[d]->relative_coordinate (0, X_AXIS);
282     }
283
284   if (lr.is_empty ())
285     programming_error ("spanner with negative length");
286
287   return lr.length ();
288 }
289
290 System *
291 Spanner::get_system () const
292 {
293   if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
294     return 0;
295   if (spanned_drul_[LEFT]->get_system () != spanned_drul_[RIGHT]->get_system ())
296     return 0;
297   return spanned_drul_[LEFT]->get_system ();
298 }
299
300 Grob *
301 Spanner::find_broken_piece (System *l) const
302 {
303   vsize idx = binary_search (broken_intos_, (Spanner *) l, Spanner::less);
304   if (idx != VPOS)
305     return broken_intos_ [idx];
306   return 0;
307 }
308
309 Spanner *
310 Spanner::broken_neighbor (Direction d) const
311 {
312   if (!original_)
313     return 0;
314
315   vsize k = get_break_index ();
316   Spanner *orig = dynamic_cast<Spanner *> (original_);
317   int j = int (k) + d;
318   if (j < 0 || vsize (j) >= orig->broken_intos_.size ())
319     return 0;
320
321   return orig->broken_intos_[j];
322 }
323
324 int
325 Spanner::compare (Spanner *const &p1, Spanner *const &p2)
326 {
327   return p1->get_system ()->get_rank () - p2->get_system ()->get_rank ();
328 }
329
330 bool
331 Spanner::less (Spanner *const &a, Spanner *const &b)
332 {
333   return a->get_system ()->get_rank () < b->get_system ()->get_rank ();
334 }
335
336 bool
337 Spanner::is_broken () const
338 {
339   return broken_intos_.size ();
340 }
341
342 void
343 Spanner::derived_mark () const
344 {
345   scm_gc_mark (pure_property_cache_);
346
347   for (LEFT_and_RIGHT (d))
348     if (spanned_drul_[d])
349       scm_gc_mark (spanned_drul_[d]->self_scm ());
350   ;
351
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 ());
357 }
358
359 /*
360   Set left or right bound to IT.
361
362   Warning: caller should ensure that subsequent calls put in ITems
363   that are left-to-right ordered.
364 */
365 void
366 add_bound_item (Spanner *sp, Grob *it)
367 {
368   if (!sp->get_bound (LEFT))
369     sp->set_bound (LEFT, it);
370   else
371     sp->set_bound (RIGHT, it);
372 }
373
374 MAKE_SCHEME_CALLBACK (Spanner, set_spacing_rods, 1);
375 SCM
376 Spanner::set_spacing_rods (SCM smob)
377 {
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))
383     {
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;
390
391       vector<Item *> cols (root->broken_col_range (bounds[LEFT]->get_column (),
392                                                    bounds[RIGHT]->get_column ()));
393
394       if (cols.size ())
395         {
396           Rod r;
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);
400           r.add_to_cols ();
401
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))
405             /*
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
410               broken_length.
411             */
412             r.distance_ += robust_scm2double (broken_length, 0) -
413               robust_scm2double (num_length, 0);
414           r.add_to_cols ();
415         }
416
417       Rod r;
418       /*
419         As r is a fresh rod, we can set distance_ with no complication.
420       */
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);
424       r.add_to_cols ();
425
426       /*
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.
436       */
437       if (Item *left_pbp = sp->get_bound (RIGHT)->find_prebroken_piece (LEFT))
438         {
439           r.item_drul_[RIGHT] = left_pbp;
440           r.add_to_cols ();
441         }
442     }
443
444   return SCM_UNSPECIFIED;
445 }
446
447 MAKE_SCHEME_CALLBACK (Spanner, calc_normalized_endpoints, 1);
448 SCM
449 Spanner::calc_normalized_endpoints (SCM smob)
450 {
451   Spanner *me = unsmob<Spanner> (smob);
452   SCM result = SCM_EOL;
453
454   Spanner *orig = dynamic_cast<Spanner *> (me->original ());
455
456   orig = orig ? orig : me;
457
458   if (orig->is_broken ())
459     {
460       Real total_width = 0.0;
461       vector<Real> span_data;
462
463       if (!orig->is_broken ())
464         span_data.push_back (orig->spanner_length ());
465       else
466         for (vsize i = 0; i < orig->broken_intos_.size (); i++)
467           span_data.push_back (orig->broken_intos_[i]->spanner_length ());
468
469       vector<Interval> unnormalized_endpoints;
470
471       for (vsize i = 0; i < span_data.size (); i++)
472         {
473           unnormalized_endpoints.push_back (Interval (total_width, total_width + span_data[i]));
474           total_width += span_data[i];
475         }
476
477       for (vsize i = 0; i < unnormalized_endpoints.size (); i++)
478         {
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)
482             result = t;
483         }
484     }
485   else
486     {
487       result = scm_cons (scm_from_double (0.0), scm_from_double (1.0));
488       orig->set_property ("normalized-endpoints", result);
489     }
490
491   return result;
492 }
493
494 MAKE_SCHEME_CALLBACK (Spanner, bounds_width, 1);
495 SCM
496 Spanner::bounds_width (SCM grob)
497 {
498   Spanner *me = unsmob<Spanner> (grob);
499
500   Grob *common = me->get_bound (LEFT)->common_refpoint (me->get_bound (RIGHT), X_AXIS);
501
502   Interval w (me->get_bound (LEFT)->relative_coordinate (common, X_AXIS),
503               me->get_bound (RIGHT)->relative_coordinate (common, X_AXIS));
504
505   w -= me->relative_coordinate (common, X_AXIS);
506
507   return ly_interval2scm (w);
508 }
509
510 MAKE_SCHEME_CALLBACK (Spanner, kill_zero_spanned_time, 1);
511 SCM
512 Spanner::kill_zero_spanned_time (SCM grob)
513 {
514   Spanner *me = unsmob<Spanner> (grob);
515   /*
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.
519
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.
523
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.
526
527     --hwn.
528
529   */
530   if (me->get_bound (LEFT)->break_status_dir ())
531     {
532       Interval_t<Moment> moments = me->spanned_time ();
533       moments [LEFT].grace_part_ = 0;
534       if (moments.length () == Moment (0, 0))
535         me->suicide ();
536     }
537
538   return SCM_UNSPECIFIED;
539 }
540
541 SCM
542 Spanner::get_cached_pure_property (SCM sym, int start, int end)
543 {
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;
549
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);
552 }
553
554 void
555 Spanner::cache_pure_property (SCM sym, int start, int end, SCM val)
556 {
557   if (scm_is_false (scm_hash_table_p (pure_property_cache_)))
558     pure_property_cache_ = scm_c_make_hash_table (17);
559
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);
562 }
563
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.",
571
572                /* properties */
573                "normalized-endpoints "
574                "minimum-length "
575                "minimum-length-after-break "
576                "spanner-broken "
577                "spanner-id "
578                "to-barline "
579               );