]> git.donarmstrong.com Git - lilypond.git/blob - lily/spanner.cc
Issue 5024: Rework the Preinit framework into something simpler
[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 Preinit_Spanner::Preinit_Spanner ()
228 {
229   spanned_drul_.set (0, 0);
230   pure_property_cache_ = SCM_UNDEFINED;
231 }
232
233 Spanner::Spanner (SCM s)
234   : Grob (s)
235 {
236   break_index_ = 0;
237 }
238
239 Spanner::Spanner (Spanner const &s)
240   : Grob (s)
241 {
242   break_index_ = 0;
243 }
244
245 /*
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
252   the bound.
253
254   For those writing a new spanner, DO NOT use both X-positions and
255   left-bound-info/right-bound-info.
256 */
257 Real
258 Spanner::spanner_length () const
259 {
260   Interval lr = robust_scm2interval (get_property ("X-positions"),
261                                      Interval (1, -1));
262
263   if (lr.is_empty ())
264     {
265       Drul_array<SCM> bounds (get_property ("left-bound-info"),
266                               get_property ("right-bound-info"));
267
268       for (LEFT_and_RIGHT (d))
269         lr[d] = robust_scm2double (ly_assoc_get (ly_symbol2scm ("X"),
270                                                  bounds[d], SCM_BOOL_F), -d);
271     }
272
273   if (lr.is_empty ())
274     {
275       for (LEFT_and_RIGHT (d))
276         lr[d] = spanned_drul_[d]->relative_coordinate (0, X_AXIS);
277     }
278
279   if (lr.is_empty ())
280     programming_error ("spanner with negative length");
281
282   return lr.length ();
283 }
284
285 System *
286 Spanner::get_system () const
287 {
288   if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
289     return 0;
290   if (spanned_drul_[LEFT]->get_system () != spanned_drul_[RIGHT]->get_system ())
291     return 0;
292   return spanned_drul_[LEFT]->get_system ();
293 }
294
295 Grob *
296 Spanner::find_broken_piece (System *l) const
297 {
298   vsize idx = binary_search (broken_intos_, (Spanner *) l, Spanner::less);
299   if (idx != VPOS)
300     return broken_intos_ [idx];
301   return 0;
302 }
303
304 Spanner *
305 Spanner::broken_neighbor (Direction d) const
306 {
307   if (!original_)
308     return 0;
309
310   vsize k = get_break_index ();
311   Spanner *orig = dynamic_cast<Spanner *> (original_);
312   int j = int (k) + d;
313   if (j < 0 || vsize (j) >= orig->broken_intos_.size ())
314     return 0;
315
316   return orig->broken_intos_[j];
317 }
318
319 int
320 Spanner::compare (Spanner *const &p1, Spanner *const &p2)
321 {
322   return p1->get_system ()->get_rank () - p2->get_system ()->get_rank ();
323 }
324
325 bool
326 Spanner::less (Spanner *const &a, Spanner *const &b)
327 {
328   return a->get_system ()->get_rank () < b->get_system ()->get_rank ();
329 }
330
331 bool
332 Spanner::is_broken () const
333 {
334   return broken_intos_.size ();
335 }
336
337 void
338 Spanner::derived_mark () const
339 {
340   scm_gc_mark (pure_property_cache_);
341
342   for (LEFT_and_RIGHT (d))
343     if (spanned_drul_[d])
344       scm_gc_mark (spanned_drul_[d]->self_scm ());
345   ;
346
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 ());
352 }
353
354 /*
355   Set left or right bound to IT.
356
357   Warning: caller should ensure that subsequent calls put in ITems
358   that are left-to-right ordered.
359 */
360 void
361 add_bound_item (Spanner *sp, Grob *it)
362 {
363   if (!sp->get_bound (LEFT))
364     sp->set_bound (LEFT, it);
365   else
366     sp->set_bound (RIGHT, it);
367 }
368
369 MAKE_SCHEME_CALLBACK (Spanner, set_spacing_rods, 1);
370 SCM
371 Spanner::set_spacing_rods (SCM smob)
372 {
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))
378     {
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;
385
386       vector<Item *> cols (root->broken_col_range (bounds[LEFT]->get_column (),
387                                                    bounds[RIGHT]->get_column ()));
388
389       if (cols.size ())
390         {
391           Rod r;
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);
395           r.add_to_cols ();
396
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))
400             /*
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
405               broken_length.
406             */
407             r.distance_ += robust_scm2double (broken_length, 0) -
408               robust_scm2double (num_length, 0);
409           r.add_to_cols ();
410         }
411
412       Rod r;
413       /*
414         As r is a fresh rod, we can set distance_ with no complication.
415       */
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);
419       r.add_to_cols ();
420
421       /*
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.
431       */
432       if (Item *left_pbp = sp->get_bound (RIGHT)->find_prebroken_piece (LEFT))
433         {
434           r.item_drul_[RIGHT] = left_pbp;
435           r.add_to_cols ();
436         }
437     }
438
439   return SCM_UNSPECIFIED;
440 }
441
442 MAKE_SCHEME_CALLBACK (Spanner, calc_normalized_endpoints, 1);
443 SCM
444 Spanner::calc_normalized_endpoints (SCM smob)
445 {
446   Spanner *me = unsmob<Spanner> (smob);
447   SCM result = SCM_EOL;
448
449   Spanner *orig = dynamic_cast<Spanner *> (me->original ());
450
451   orig = orig ? orig : me;
452
453   if (orig->is_broken ())
454     {
455       Real total_width = 0.0;
456       vector<Real> span_data;
457
458       if (!orig->is_broken ())
459         span_data.push_back (orig->spanner_length ());
460       else
461         for (vsize i = 0; i < orig->broken_intos_.size (); i++)
462           span_data.push_back (orig->broken_intos_[i]->spanner_length ());
463
464       vector<Interval> unnormalized_endpoints;
465
466       for (vsize i = 0; i < span_data.size (); i++)
467         {
468           unnormalized_endpoints.push_back (Interval (total_width, total_width + span_data[i]));
469           total_width += span_data[i];
470         }
471
472       for (vsize i = 0; i < unnormalized_endpoints.size (); i++)
473         {
474           SCM t = ly_interval2scm (1 / total_width * unnormalized_endpoints[i]);
475           orig->broken_intos_[i]->set_property ("normalized-endpoints", t);
476           if (me->get_break_index () == i)
477             result = t;
478         }
479     }
480   else
481     {
482       result = scm_cons (scm_from_double (0.0), scm_from_double (1.0));
483       orig->set_property ("normalized-endpoints", result);
484     }
485
486   return result;
487 }
488
489 MAKE_SCHEME_CALLBACK (Spanner, bounds_width, 1);
490 SCM
491 Spanner::bounds_width (SCM grob)
492 {
493   Spanner *me = unsmob<Spanner> (grob);
494
495   Grob *common = me->get_bound (LEFT)->common_refpoint (me->get_bound (RIGHT), X_AXIS);
496
497   Interval w (me->get_bound (LEFT)->relative_coordinate (common, X_AXIS),
498               me->get_bound (RIGHT)->relative_coordinate (common, X_AXIS));
499
500   w -= me->relative_coordinate (common, X_AXIS);
501
502   return ly_interval2scm (w);
503 }
504
505 MAKE_SCHEME_CALLBACK (Spanner, kill_zero_spanned_time, 1);
506 SCM
507 Spanner::kill_zero_spanned_time (SCM grob)
508 {
509   Spanner *me = unsmob<Spanner> (grob);
510   /*
511     Remove the line or hairpin at the start of the line.  For
512     piano voice indicators, it makes no sense to have them at
513     the start of the line.
514
515     I'm not sure what the official rules for glissandi are, but
516     usually the 2nd note of the glissando is "exact", so when playing
517     from the start of the line, there is no need to glide.
518
519     From a typographical p.o.v. this makes sense, since the amount of
520     space left of a note at the start of a line is very small.
521
522     --hwn.
523
524   */
525   if (me->get_bound (LEFT)->break_status_dir ())
526     {
527       Interval_t<Moment> moments = me->spanned_time ();
528       moments [LEFT].grace_part_ = 0;
529       if (moments.length () == Moment (0, 0))
530         me->suicide ();
531     }
532
533   return SCM_UNSPECIFIED;
534 }
535
536 SCM
537 Spanner::get_cached_pure_property (SCM sym, int start, int end)
538 {
539   // The pure property cache is indexed by (name start . end), where name is
540   // a symbol, and start and end are numbers referring to the starting and
541   // ending column ranks of the current line.
542   if (scm_is_false (scm_hash_table_p (pure_property_cache_)))
543     return SCM_UNDEFINED;
544
545   SCM key = scm_cons (sym, scm_cons (scm_from_int (start), scm_from_int (end)));
546   return scm_hash_ref (pure_property_cache_, key, SCM_UNDEFINED);
547 }
548
549 void
550 Spanner::cache_pure_property (SCM sym, int start, int end, SCM val)
551 {
552   if (scm_is_false (scm_hash_table_p (pure_property_cache_)))
553     pure_property_cache_ = scm_c_make_hash_table (17);
554
555   SCM key = scm_cons (sym, scm_cons (scm_from_int (start), scm_from_int (end)));
556   scm_hash_set_x (pure_property_cache_, key, val);
557 }
558
559 ADD_INTERFACE (Spanner,
560                "Some objects are horizontally spanned between objects.  For"
561                " example, slurs, beams, ties, etc.  These grobs form a subtype"
562                " called @code{Spanner}.  All spanners have two span points"
563                " (these must be @code{Item} objects), one on the left and one"
564                " on the right.  The left bound is also the X@tie{}reference"
565                " point of the spanner.",
566
567                /* properties */
568                "normalized-endpoints "
569                "minimum-length "
570                "minimum-length-after-break "
571                "spanner-broken "
572                "spanner-id "
573                "to-barline "
574               );