]> git.donarmstrong.com Git - lilypond.git/blob - lily/spanner.cc
Doc: Included/compile.itexi - CG 4.2 - Updated notes on reqs for compiling
[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 using std::vector;
30
31 Grob *
32 Spanner::clone () const
33 {
34   return new Spanner (*this);
35 }
36
37 void
38 Spanner::do_break_processing ()
39 {
40   //break_into_pieces
41   Item *left = spanned_drul_[LEFT];
42   Item *right = spanned_drul_[RIGHT];
43
44   if (!left || !right)
45     return;
46
47   if (get_system () || is_broken ())
48     return;
49
50   if (left == right)
51     {
52       /*
53         If we have a spanner spanning one column, we must break it
54         anyway because it might provide a parent for another item.  */
55       for (LEFT_and_RIGHT (d))
56         {
57           Item *bound = left->find_prebroken_piece (d);
58           if (!bound)
59             programming_error ("no broken bound");
60           else if (bound->get_system ())
61             {
62               Spanner *span = dynamic_cast<Spanner *> (clone ());
63               span->set_bound (LEFT, bound);
64               span->set_bound (RIGHT, bound);
65
66               assert (span->get_system ());
67               span->get_system ()->typeset_grob (span);
68               broken_intos_.push_back (span);
69             }
70         }
71     }
72   else
73     {
74       System *root = get_root_system (this);
75       vector<Item *> break_points = root->broken_col_range (left, right);
76
77       break_points.insert (break_points.begin () + 0, left);
78       break_points.push_back (right);
79
80       Slice parent_rank_slice;
81       parent_rank_slice.set_full ();
82
83       /*
84         Check if our parent in X-direction spans equally wide
85         or wider than we do.
86       */
87       for (int a = X_AXIS; a < NO_AXES; a++)
88         {
89           if (Spanner *parent = dynamic_cast<Spanner *> (get_parent ((Axis)a)))
90             parent_rank_slice.intersect (parent->spanned_rank_interval ());
91         }
92
93       for (vsize i = 1; i < break_points.size (); i++)
94         {
95           Drul_array<Item *> bounds;
96           bounds[LEFT] = break_points[i - 1];
97           bounds[RIGHT] = break_points[i];
98           for (LEFT_and_RIGHT (d))
99             {
100               if (!bounds[d]->get_system ())
101                 bounds[d] = bounds[d]->find_prebroken_piece (- d);
102             }
103
104           if (!bounds[LEFT] || ! bounds[RIGHT])
105             {
106               programming_error ("bounds of this piece aren't breakable.");
107               continue;
108             }
109
110           bool ok = parent_rank_slice.contains (bounds[LEFT]->get_column ()->get_rank ());
111           ok = ok && parent_rank_slice.contains (bounds[RIGHT]->get_column ()->get_rank ());
112
113           if (!ok)
114             {
115               programming_error (to_string ("Spanner `%s' is not fully contained in parent spanner."
116                                             "  Ignoring orphaned part",
117                                             name ().c_str ()));
118               continue;
119             }
120
121           Spanner *span = dynamic_cast<Spanner *> (clone ());
122           span->set_bound (LEFT, bounds[LEFT]);
123           span->set_bound (RIGHT, bounds[RIGHT]);
124
125           if (!bounds[LEFT]->get_system ()
126               || !bounds[RIGHT]->get_system ()
127               || bounds[LEFT]->get_system () != bounds[RIGHT]->get_system ())
128             {
129               programming_error ("bounds of spanner are invalid");
130               span->suicide ();
131             }
132           else
133             {
134               bounds[LEFT]->get_system ()->typeset_grob (span);
135               broken_intos_.push_back (span);
136             }
137         }
138     }
139   vector_sort (broken_intos_, Spanner::less);
140   for (vsize i = broken_intos_.size (); i--;)
141     broken_intos_[i]->break_index_ = i;
142 }
143
144 vsize
145 Spanner::get_break_index () const
146 {
147   return break_index_;
148 }
149
150 void
151 Spanner::set_my_columns ()
152 {
153   for (LEFT_and_RIGHT (d))
154     {
155       if (!spanned_drul_[d]->get_system ())
156         set_bound (d, spanned_drul_[d]->find_prebroken_piece ((Direction) - d));
157     }
158 }
159
160 Interval_t<int>
161 Spanner::spanned_rank_interval () const
162 {
163   Interval_t<int> iv (0, 0);
164
165   if (spanned_drul_[LEFT] && spanned_drul_[LEFT]->get_column ())
166     iv[LEFT] = spanned_drul_[LEFT]->get_column ()->get_rank ();
167   if (spanned_drul_[RIGHT] && spanned_drul_[RIGHT]->get_column ())
168     iv[RIGHT] = spanned_drul_[RIGHT]->get_column ()->get_rank ();
169   return iv;
170 }
171
172 Interval_t<Moment>
173 Spanner::spanned_time () const
174 {
175   return spanned_time_interval (spanned_drul_[LEFT],
176                                 spanned_drul_[RIGHT]);
177 }
178
179 Item *
180 Spanner::get_bound (Direction d) const
181 {
182   return spanned_drul_[d];
183 }
184
185 /*
186   Set the items that this spanner spans. If D == LEFT, we also set the
187   X-axis parent of THIS to S.
188
189   For example, when a slur crosses a line break, it's broken into two
190   pieces.  The second piece shouldn't be positioned relative to the
191   original NoteColumn, but rather to the PaperColumn after the break.
192 */
193 void
194 Spanner::set_bound (Direction d, Grob *s)
195 {
196   Item *i = dynamic_cast<Item *> (s);
197   if (!i)
198     {
199       programming_error ("must have Item for spanner bound of " + name ());
200       return;
201     }
202
203   spanned_drul_[d] = i;
204
205   /**
206      We check for System to prevent the column -> line_of_score
207      -> column -> line_of_score -> etc situation */
208   if (d == LEFT && !dynamic_cast<System *> (this))
209     /*
210       If the X-parent is a spanner, it will be split across linebreaks, too,
211       so we shouldn't have to overwrite it with the bound. Also, we need
212       original parent for alignment.
213       This happens e.g. for MultiMeasureRestNumbers and PercentRepeatCounters.
214     */
215     if (!dynamic_cast <Spanner *> (get_parent (X_AXIS)))
216       set_parent (i, X_AXIS);
217
218   /*
219     Signal that this column needs to be kept alive. They need to be
220     kept alive to have meaningful position and linebreaking.
221
222     [maybe we should try keeping all columns alive?, and perhaps
223     inherit position from their (non-)musical brother]
224   */
225   if (dynamic_cast<Paper_column *> (i))
226     Pointer_group_interface::add_grob (i, ly_symbol2scm ("bounded-by-me"), this);
227 }
228
229 Spanner::Spanner (SCM s)
230   : Grob (s)
231 {
232   break_index_ = 0;
233   spanned_drul_.set (0, 0);
234   pure_property_cache_ = SCM_UNDEFINED;
235 }
236
237 Spanner::Spanner (Spanner const &s)
238   : Grob (s)
239 {
240   spanned_drul_.set (0, 0);
241   pure_property_cache_ = SCM_UNDEFINED;
242 }
243
244 /*
245   Certain spanners have pre-computed X values that lie either in
246   X-positions or the X key of the alists returned for left-bound-info
247   and right-bound-info.  These are calculated to give the real length
248   of a spanner (which, because of various padding or overhang properties,
249   can extend pass or arrive short of a given bound).  If possible, we
250   use these to calculate the spanner's length, and otherwise, we use
251   the bound.
252
253   For those writing a new spanner, DO NOT use both X-positions and
254   left-bound-info/right-bound-info.
255 */
256 Real
257 Spanner::spanner_length () const
258 {
259   Interval lr = robust_scm2interval (get_property ("X-positions"),
260                                      Interval (1, -1));
261
262   if (lr.is_empty ())
263     {
264       Drul_array<SCM> bounds (get_property ("left-bound-info"),
265                               get_property ("right-bound-info"));
266
267       for (LEFT_and_RIGHT (d))
268         lr[d] = robust_scm2double (ly_assoc_get (ly_symbol2scm ("X"),
269                                                  bounds[d], SCM_BOOL_F), -d);
270     }
271
272   if (lr.is_empty ())
273     {
274       for (LEFT_and_RIGHT (d))
275         lr[d] = spanned_drul_[d]->relative_coordinate (0, X_AXIS);
276     }
277
278   if (lr.is_empty ())
279     programming_error ("spanner with negative length");
280
281   return lr.length ();
282 }
283
284 System *
285 Spanner::get_system () const
286 {
287   if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
288     return 0;
289   if (spanned_drul_[LEFT]->get_system () != spanned_drul_[RIGHT]->get_system ())
290     return 0;
291   return spanned_drul_[LEFT]->get_system ();
292 }
293
294 Grob *
295 Spanner::find_broken_piece (System *l) const
296 {
297   vsize idx = binary_search (broken_intos_, (Spanner *) l, Spanner::less);
298   if (idx != VPOS)
299     return broken_intos_ [idx];
300   return 0;
301 }
302
303 Spanner *
304 Spanner::broken_neighbor (Direction d) const
305 {
306   if (!original_)
307     return 0;
308
309   vsize k = get_break_index ();
310   Spanner *orig = dynamic_cast<Spanner *> (original_);
311   int j = int (k) + d;
312   if (j < 0 || vsize (j) >= orig->broken_intos_.size ())
313     return 0;
314
315   return orig->broken_intos_[j];
316 }
317
318 int
319 Spanner::compare (Spanner *const &p1, Spanner *const &p2)
320 {
321   return p1->get_system ()->get_rank () - p2->get_system ()->get_rank ();
322 }
323
324 bool
325 Spanner::less (Spanner *const &a, Spanner *const &b)
326 {
327   return a->get_system ()->get_rank () < b->get_system ()->get_rank ();
328 }
329
330 bool
331 Spanner::is_broken () const
332 {
333   return broken_intos_.size ();
334 }
335
336 void
337 Spanner::derived_mark () const
338 {
339   scm_gc_mark (pure_property_cache_);
340
341   for (LEFT_and_RIGHT (d))
342     if (spanned_drul_[d])
343       scm_gc_mark (spanned_drul_[d]->self_scm ());
344   ;
345
346   for (vsize i = broken_intos_.size (); i--;)
347     scm_gc_mark (broken_intos_[i]->self_scm ());
348 }
349
350 /*
351   Set left or right bound to IT.
352
353   Warning: caller should ensure that subsequent calls put in ITems
354   that are left-to-right ordered.
355 */
356 void
357 add_bound_item (Spanner *sp, Grob *it)
358 {
359   if (!sp->get_bound (LEFT))
360     sp->set_bound (LEFT, it);
361   else
362     sp->set_bound (RIGHT, it);
363 }
364
365 MAKE_SCHEME_CALLBACK (Spanner, set_spacing_rods, 1);
366 SCM
367 Spanner::set_spacing_rods (SCM smob)
368 {
369   Grob *me = unsmob<Grob> (smob);
370   SCM num_length = me->get_property ("minimum-length");
371   SCM broken_length = me->get_property ("minimum-length-after-break");
372   if (scm_is_number (num_length)
373      || scm_is_number (broken_length))
374     {
375       Spanner *sp = dynamic_cast<Spanner *> (me);
376       System *root = get_root_system (me);
377       Drul_array<Item *> bounds (sp->get_bound (LEFT),
378                                  sp->get_bound (RIGHT));
379       if (!bounds[LEFT] || !bounds[RIGHT])
380         return SCM_UNSPECIFIED;
381
382       vector<Item *> cols (root->broken_col_range (bounds[LEFT]->get_column (),
383                                                    bounds[RIGHT]->get_column ()));
384
385       if (cols.size ())
386         {
387           Rod r;
388           r.item_drul_[LEFT] = sp->get_bound (LEFT);
389           r.item_drul_[RIGHT] = cols[0]->find_prebroken_piece (LEFT);
390           r.distance_ = robust_scm2double (num_length, 0);
391           r.add_to_cols ();
392
393           r.item_drul_[LEFT] = cols.back ()->find_prebroken_piece (RIGHT);
394           r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
395           if (scm_is_number (broken_length))
396             /*
397               r.distance_ may have been modified by add_to_cols ()
398               above.  For treatment of minimum-distance-after-break
399               consistent with minimum-distance (which will use the
400               changed value), we cannot directly reset r.distance_ to
401               broken_length.
402             */
403             r.distance_ += robust_scm2double (broken_length, 0) -
404               robust_scm2double (num_length, 0);
405           r.add_to_cols ();
406         }
407
408       Rod r;
409       /*
410         As r is a fresh rod, we can set distance_ with no complication.
411       */
412       r.distance_ = robust_scm2double (num_length, 0);
413       r.item_drul_[LEFT] = sp->get_bound (LEFT);
414       r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
415       r.add_to_cols ();
416
417       /*
418         We do not know yet if the spanner is going to have a bound that is
419         broken. To account for this uncertainty, we add the rod twice:
420         once for the central column (see above) and once for the left column
421         (see below). As end_rods_ are never used when rods_ are used and vice
422         versa, this rod will only be accessed once for each spacing
423         configuraiton before line breaking. Then, as a grob never exists in
424         both unbroken and broken forms after line breaking, only one of these
425         two rods will be in the column vector used for spacing in
426         simple-spacer.cc get_line_confugration.
427       */
428       if (Item *left_pbp = sp->get_bound (RIGHT)->find_prebroken_piece (LEFT))
429         {
430           r.item_drul_[RIGHT] = left_pbp;
431           r.add_to_cols ();
432         }
433     }
434
435   return SCM_UNSPECIFIED;
436 }
437
438 MAKE_SCHEME_CALLBACK (Spanner, calc_normalized_endpoints, 1);
439 SCM
440 Spanner::calc_normalized_endpoints (SCM smob)
441 {
442   Spanner *me = unsmob<Spanner> (smob);
443   SCM result = SCM_EOL;
444
445   Spanner *orig = dynamic_cast<Spanner *> (me->original ());
446
447   orig = orig ? orig : me;
448
449   if (orig->is_broken ())
450     {
451       Real total_width = 0.0;
452       vector<Real> span_data;
453
454       if (!orig->is_broken ())
455         span_data.push_back (orig->spanner_length ());
456       else
457         for (vsize i = 0; i < orig->broken_intos_.size (); i++)
458           span_data.push_back (orig->broken_intos_[i]->spanner_length ());
459
460       vector<Interval> unnormalized_endpoints;
461
462       for (vsize i = 0; i < span_data.size (); i++)
463         {
464           unnormalized_endpoints.push_back (Interval (total_width, total_width + span_data[i]));
465           total_width += span_data[i];
466         }
467
468       for (vsize i = 0; i < unnormalized_endpoints.size (); i++)
469         {
470           SCM t = ly_interval2scm (1 / total_width * unnormalized_endpoints[i]);
471           orig->broken_intos_[i]->set_property ("normalized-endpoints", t);
472           if (me->get_break_index () == i)
473             result = t;
474         }
475     }
476   else
477     {
478       result = scm_cons (scm_from_double (0.0), scm_from_double (1.0));
479       orig->set_property ("normalized-endpoints", result);
480     }
481
482   return result;
483 }
484
485 MAKE_SCHEME_CALLBACK (Spanner, bounds_width, 1);
486 SCM
487 Spanner::bounds_width (SCM grob)
488 {
489   Spanner *me = unsmob<Spanner> (grob);
490
491   Grob *common = me->get_bound (LEFT)->common_refpoint (me->get_bound (RIGHT), X_AXIS);
492
493   Interval w (me->get_bound (LEFT)->relative_coordinate (common, X_AXIS),
494               me->get_bound (RIGHT)->relative_coordinate (common, X_AXIS));
495
496   w -= me->relative_coordinate (common, X_AXIS);
497
498   return ly_interval2scm (w);
499 }
500
501 MAKE_SCHEME_CALLBACK (Spanner, kill_zero_spanned_time, 1);
502 SCM
503 Spanner::kill_zero_spanned_time (SCM grob)
504 {
505   Spanner *me = unsmob<Spanner> (grob);
506   /*
507     Remove the line or hairpin at the start of the line.  For
508     piano voice indicators, it makes no sense to have them at
509     the start of the line.
510
511     I'm not sure what the official rules for glissandi are, but
512     usually the 2nd note of the glissando is "exact", so when playing
513     from the start of the line, there is no need to glide.
514
515     From a typographical p.o.v. this makes sense, since the amount of
516     space left of a note at the start of a line is very small.
517
518     --hwn.
519
520   */
521   if (me->get_bound (LEFT)->break_status_dir ())
522     {
523       Interval_t<Moment> moments = me->spanned_time ();
524       moments [LEFT].grace_part_ = 0;
525       if (moments.length () == Moment (0, 0))
526         me->suicide ();
527     }
528
529   return SCM_UNSPECIFIED;
530 }
531
532 SCM
533 Spanner::get_cached_pure_property (SCM sym, int start, int end)
534 {
535   // The pure property cache is indexed by (name start . end), where name is
536   // a symbol, and start and end are numbers referring to the starting and
537   // ending column ranks of the current line.
538   if (scm_is_false (scm_hash_table_p (pure_property_cache_)))
539     return SCM_UNDEFINED;
540
541   SCM key = scm_cons (sym, scm_cons (scm_from_int (start), scm_from_int (end)));
542   return scm_hash_ref (pure_property_cache_, key, SCM_UNDEFINED);
543 }
544
545 void
546 Spanner::cache_pure_property (SCM sym, int start, int end, SCM val)
547 {
548   if (scm_is_false (scm_hash_table_p (pure_property_cache_)))
549     pure_property_cache_ = scm_c_make_hash_table (17);
550
551   SCM key = scm_cons (sym, scm_cons (scm_from_int (start), scm_from_int (end)));
552   scm_hash_set_x (pure_property_cache_, key, val);
553 }
554
555 ADD_INTERFACE (Spanner,
556                "Some objects are horizontally spanned between objects.  For"
557                " example, slurs, beams, ties, etc.  These grobs form a subtype"
558                " called @code{Spanner}.  All spanners have two span points"
559                " (these must be @code{Item} objects), one on the left and one"
560                " on the right.  The left bound is also the X@tie{}reference"
561                " point of the spanner.",
562
563                /* properties */
564                "normalized-endpoints "
565                "minimum-length "
566                "minimum-length-after-break "
567                "spanner-broken "
568                "spanner-id "
569                "to-barline "
570               );