]> git.donarmstrong.com Git - lilypond.git/blob - lily/page-layout-problem.cc
7c9967055146637364524d559b0e11095482e739
[lilypond.git] / lily / page-layout-problem.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 2009--2012 Joe Neeman <joeneeman@gmail.com>
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 "page-layout-problem.hh"
21
22 #include "align-interface.hh"
23 #include "axis-group-interface.hh"
24 #include "hara-kiri-group-spanner.hh"
25 #include "international.hh"
26 #include "item.hh"
27 #include "output-def.hh"
28 #include "paper-book.hh"
29 #include "paper-column.hh"
30 #include "paper-score.hh"
31 #include "pointer-group-interface.hh"
32 #include "prob.hh"
33 #include "skyline-pair.hh"
34 #include "system.hh"
35 #include "text-interface.hh"
36
37 /*
38  Returns the number of footntoes associated with a given line.
39 */
40
41 vector<Grob *>
42 Page_layout_problem::get_footnote_grobs (SCM lines)
43 {
44   vector<Grob *> footnotes;
45   for (SCM s = lines; scm_is_pair (s); s = scm_cdr (s))
46     {
47       if (Grob *g = unsmob_grob (scm_car (s)))
48         {
49           System *sys = dynamic_cast<System *> (g);
50           if (!sys)
51             {
52               programming_error ("got a grob for footnotes that wasn't a System");
53               continue;
54             }
55           extract_grob_set (sys, "footnotes-after-line-breaking", footnote_grobs);
56           footnotes.insert (footnotes.end (), footnote_grobs.begin (), footnote_grobs.end ());
57         }
58       else if (Prob *p = unsmob_prob (scm_car (s)))
59         {
60           SCM stencils = p->get_property ("footnotes");
61           if (stencils == SCM_EOL)
62             continue;
63           for (SCM st = stencils; scm_is_pair (st); st = scm_cdr (st))
64             footnotes.push_back (0);
65         }
66     }
67
68   return footnotes;
69 }
70
71 vsize
72 Page_layout_problem::get_footnote_count (SCM lines)
73 {
74   vector<Grob *> notes = get_footnote_grobs (lines);
75   return notes.size ();
76 }
77
78 SCM
79 Page_layout_problem::get_footnotes_from_lines (SCM lines)
80 {
81   if (!scm_is_pair (lines))
82     return SCM_EOL;
83
84   bool footnotes_added;
85   if (Grob *g = unsmob_grob (scm_car (lines)))
86     footnotes_added = !scm_is_null (g->get_property ("footnote-stencil"));
87   else if (Prob *p = unsmob_prob (scm_car (lines)))
88     footnotes_added = !scm_is_null (p->get_property ("footnote-stencil"));
89   else
90     {
91       programming_error ("Systems on a page must be a prob or grob.");
92       return SCM_EOL;
93     }
94   if (!footnotes_added)
95     {
96       programming_error ("Footnotes must be added to lines before they are retrieved.");
97       return SCM_EOL;
98     }
99
100   SCM out = SCM_EOL;
101   for (SCM s = lines; scm_is_pair (s); s = scm_cdr (s))
102     {
103       if (Grob *g = unsmob_grob (scm_car (s)))
104         out = scm_cons (g->get_property ("footnote-stencil"), out);
105       else if (Prob *p = unsmob_prob (scm_car (s)))
106         out = scm_cons (p->get_property ("footnote-stencil"), out);
107       else
108         programming_error ("Systems on a page must be a prob or grob.");
109     }
110
111   return scm_reverse_x (out, SCM_EOL);
112 }
113
114 /*
115    Adds a footnote stencil to each system.  This stencil may
116    itself be comprised of several footnotes.
117
118    This is a long function, but it seems better to keep it intact rather than
119    splitting it into parts.
120 */
121
122 void
123 Page_layout_problem::add_footnotes_to_lines (SCM lines, int counter, Paper_book *pb)
124 {
125   /*
126     first, we have to see how many footnotes are on this page.
127     we need to do this first so that we can line them up
128   */
129
130   Output_def *paper = pb->paper_;
131
132   if (!paper)
133     {
134       programming_error ("Cannot get footnotes because there is no valid paper block.");
135       return;
136     }
137
138   SCM number_footnote_table = pb->top_paper ()->c_variable ("number-footnote-table");
139   if (!scm_is_pair (number_footnote_table))
140     number_footnote_table = SCM_EOL;
141   SCM numbering_function = paper->c_variable ("footnote-numbering-function");
142   SCM layout = paper->self_scm ();
143   SCM props = scm_call_1 (ly_lily_module_constant ("layout-extract-page-properties"),
144                           paper->self_scm ());
145   Real padding = robust_scm2double (paper->c_variable ("footnote-padding"), 0.0);
146   Real number_raise = robust_scm2double (paper->c_variable ("footnote-number-raise"), 0.0);
147
148   vector<Grob *> fn_grobs = get_footnote_grobs (lines);
149   vsize fn_count = fn_grobs.size ();
150
151   // now, make the footnote stencils with the numbering function
152   SCM numbers = SCM_EOL;
153   SCM in_text_numbers = SCM_EOL;
154   /*
155     TODO: This recalculates numbering every time this function is called, including once
156     after the balloon prints are called.  Although it is not a huge computational drain,
157     it'd be more elegant to turn this calculation off when it is no longer needed.
158
159     In a separate commit, it'd be nice to streamline the way that page layout property
160     is handled so that the process of building `config's in page-breaking does result
161     in duplicated work, either by making this process less complicated or (preferably)
162     by passing its results downstream.
163   */
164   vector<SCM> footnote_number_markups; // Holds the numbering markups.
165   vector<Stencil> footnote_number_stencils; // Holds translated versions of the stencilized numbering markups.
166   for (vsize i = 0; i < fn_count; i++)
167     {
168       if (fn_grobs[i])
169         {
170           SCM assertion_function = fn_grobs[i]->get_property ("numbering-assertion-function");
171           if (ly_is_procedure (assertion_function))
172             (void) scm_call_1 (assertion_function, scm_from_int (counter));
173         }
174       SCM markup = scm_call_1 (numbering_function, scm_from_int (counter));
175       Stencil *s = unsmob_stencil (Text_interface::interpret_markup (layout, props, markup));
176       if (!s)
177         {
178           programming_error ("Your numbering function needs to return a stencil.");
179           footnote_number_markups.push_back (SCM_EOL);
180           footnote_number_stencils.push_back (Stencil (Box (Interval (0, 0), Interval (0, 0)), SCM_EOL));
181         }
182       else
183         {
184           footnote_number_markups.push_back (markup);
185           footnote_number_stencils.push_back (*s);
186         }
187       counter++;
188     }
189
190   // find the maximum X_AXIS length
191   Real max_length = -infinity_f;
192   for (vsize i = 0; i < fn_count; i++)
193     max_length = max (max_length, footnote_number_stencils[i].extent (X_AXIS).length ());
194
195   /*
196     translate each stencil such that it attains the correct maximum length and bundle the
197     footnotes into a scheme object.
198   */
199
200   for (vsize i = 0; i < fn_count; i++)
201     {
202       in_text_numbers = scm_cons (footnote_number_markups[i], in_text_numbers);
203       footnote_number_stencils[i].translate_axis ((max_length
204                                                    - footnote_number_stencils[i].extent (X_AXIS).length ()),
205                                                   X_AXIS);
206       numbers = scm_cons (footnote_number_stencils[i].smobbed_copy (), numbers);
207     }
208
209   in_text_numbers = scm_reverse_x (in_text_numbers, SCM_EOL);
210   numbers = scm_reverse_x (numbers, SCM_EOL);
211
212   // build the footnotes
213
214   for (SCM s = lines; scm_is_pair (s); s = scm_cdr (s))
215     {
216       // Take care of musical systems.
217       if (Grob *g = unsmob_grob (scm_car (s)))
218         {
219           System *sys = dynamic_cast<System *> (g);
220           if (!sys)
221             {
222               programming_error ("got a grob for footnotes that wasn't a System");
223               continue;
224             }
225           Stencil mol;
226           Stencil in_note_mol;
227           extract_grob_set (sys, "footnotes-after-line-breaking", footnote_grobs);
228           for (vsize i = 0; i < footnote_grobs.size (); i++)
229             {
230               Grob *footnote = footnote_grobs[i];
231               SCM footnote_markup = footnote->get_property ("footnote-text");
232               if (Spanner *orig = dynamic_cast<Spanner *>(footnote))
233                 if (orig->is_broken ())
234                   footnote_markup = orig->broken_intos_[0]->get_property ("footnote-text");
235
236               SCM props = scm_call_1 (ly_lily_module_constant ("layout-extract-page-properties"),
237                                       paper->self_scm ());
238
239               SCM footnote_stl = Text_interface::interpret_markup (paper->self_scm (),
240                                                                    props, footnote_markup);
241
242               Stencil footnote_stencil = *unsmob_stencil (footnote_stl);
243               bool do_numbering = to_boolean (footnote->get_property ("automatically-numbered"));
244               if (Spanner *orig = dynamic_cast<Spanner *>(footnote))
245                 {
246                   if (orig->is_broken ())
247                     for (vsize i = 0; i < orig->broken_intos_.size (); i++)
248                       do_numbering = do_numbering
249                                      || to_boolean (orig->broken_intos_[i]->get_property ("automatically-numbered"));
250                 }
251               if (do_numbering)
252                 {
253                   SCM annotation_scm = scm_car (in_text_numbers);
254                   footnote->set_property ("text", annotation_scm);
255                   if (Spanner *orig = dynamic_cast<Spanner *>(footnote))
256                     {
257                       orig->set_property ("text", annotation_scm);
258                       if (orig->is_broken ())
259                         for (vsize i = 0; i < orig->broken_intos_.size (); i++)
260                           orig->broken_intos_[i]->set_property ("text", annotation_scm);
261                     }
262
263                   Stencil annotation = *unsmob_stencil (scm_car (numbers));
264                   annotation.translate_axis ((footnote_stencil.extent (Y_AXIS)[UP]
265                                               + number_raise
266                                               - annotation.extent (Y_AXIS)[UP]),
267                                              Y_AXIS);
268                   footnote_stencil.add_at_edge (X_AXIS, LEFT, annotation, 0.0);
269                   numbers = scm_cdr (numbers);
270                   in_text_numbers = scm_cdr (in_text_numbers);
271                 }
272               if (!footnote_stencil.is_empty ())
273                 {
274                   if (to_boolean (footnote->get_property ("footnote")))
275                     mol.add_at_edge (Y_AXIS, DOWN, footnote_stencil, padding);
276                   else
277                     in_note_mol.add_at_edge (Y_AXIS, DOWN, footnote_stencil, padding);
278                 }
279             }
280           sys->set_property ("in-note-stencil", in_note_mol.smobbed_copy ());
281           sys->set_property ("footnote-stencil", mol.smobbed_copy ());
282         }
283       // Take care of top-level markups
284       else if (Prob *p = unsmob_prob (scm_car (s)))
285         {
286           SCM stencils = p->get_property ("footnotes");
287           Stencil mol;
288
289           for (SCM st = stencils; scm_is_pair (st); st = scm_cdr (st))
290             {
291               Stencil footnote_stencil = *unsmob_stencil (scm_caddar (st));
292               bool do_numbering = to_boolean (scm_cadar (st));
293               SCM in_text_stencil = Stencil ().smobbed_copy ();
294               if (do_numbering)
295                 {
296                   Stencil annotation = *unsmob_stencil (scm_car (numbers));
297                   SCM in_text_annotation = scm_car (in_text_numbers);
298                   in_text_stencil = Text_interface::interpret_markup (layout,
299                                                                       props,
300                                                                       in_text_annotation);
301                   if (!unsmob_stencil (in_text_stencil))
302                     in_text_stencil = SCM_EOL;
303                   annotation.translate_axis ((footnote_stencil.extent (Y_AXIS)[UP]
304                                               + number_raise
305                                               - annotation.extent (Y_AXIS)[UP]),
306                                              Y_AXIS);
307                   footnote_stencil.add_at_edge (X_AXIS, LEFT, annotation, 0.0);
308                   numbers = scm_cdr (numbers);
309                   in_text_numbers = scm_cdr (in_text_numbers);
310                 }
311               number_footnote_table = scm_cons (scm_cons (scm_caar (st),
312                                                           in_text_stencil),
313                                                 number_footnote_table);
314               if (!footnote_stencil.is_empty ())
315                 mol.add_at_edge (Y_AXIS, DOWN, footnote_stencil, padding);
316             }
317           p->set_property ("footnote-stencil", mol.smobbed_copy ());
318         }
319     }
320
321   // note that this line of code doesn't do anything if numbering isn't turned on
322   pb->top_paper ()->set_variable (ly_symbol2scm ("number-footnote-table"), number_footnote_table);
323 }
324
325 Stencil
326 Page_layout_problem::get_footnote_separator_stencil (Output_def *paper)
327 {
328   SCM props = scm_call_1 (ly_lily_module_constant ("layout-extract-page-properties"),
329                           paper->self_scm ());
330
331   SCM markup = paper->c_variable ("footnote-separator-markup");
332
333   if (!Text_interface::is_markup (markup))
334     return Stencil ();
335
336   SCM footnote_stencil = Text_interface::interpret_markup (paper->self_scm (),
337                                                            props, markup);
338
339   Stencil *footnote_separator = unsmob_stencil (footnote_stencil);
340
341   return footnote_separator ? *footnote_separator : Stencil ();
342 }
343
344 Stencil
345 Page_layout_problem::add_footnotes_to_footer (SCM footnotes, Stencil foot, Paper_book *pb)
346 {
347
348   bool footnotes_found = false;
349   Real footnote_padding = robust_scm2double (pb->paper_->c_variable ("footnote-padding"), 0.0);
350   Real footnote_footer_padding = robust_scm2double (pb->paper_->c_variable ("footnote-footer-padding"), 0.0);
351
352   footnotes = scm_reverse (footnotes);
353
354   for (SCM s = footnotes; scm_is_pair (s); s = scm_cdr (s))
355     {
356       Stencil *stencil = unsmob_stencil (scm_car (s));
357
358       if (!stencil)
359         continue;
360
361       if (!stencil->is_empty ())
362         {
363           foot.add_at_edge (Y_AXIS, UP, *stencil, (!footnotes_found ? footnote_footer_padding : footnote_padding));
364           footnotes_found = true;
365         }
366     }
367
368   if (footnotes_found)
369     {
370       Stencil separator = get_footnote_separator_stencil (pb->paper_);
371       if (!separator.is_empty ())
372         foot.add_at_edge (Y_AXIS, UP, separator, footnote_padding);
373     }
374
375   return foot;
376 }
377
378 Page_layout_problem::Page_layout_problem (Paper_book *pb, SCM page_scm, SCM systems)
379   : bottom_skyline_ (DOWN)
380 {
381   Prob *page = unsmob_prob (page_scm);
382   bottom_loose_baseline_ = 0;
383   header_height_ = 0;
384   footer_height_ = 0;
385   header_padding_ = 0;
386   footer_padding_ = 0;
387   page_height_ = 100;
388   force_ = 0;
389
390   if (page)
391     {
392       Stencil *head = unsmob_stencil (page->get_property ("head-stencil"));
393       Stencil *foot = unsmob_stencil (page->get_property ("foot-stencil"));
394
395       Stencil foot_stencil = foot ? *foot : Stencil ();
396
397       if (pb && pb->paper_)
398         {
399           SCM footnotes = get_footnotes_from_lines (systems);
400           foot_stencil = add_footnotes_to_footer (footnotes, foot_stencil, pb);
401         }
402       else
403         warning (_ ("A page layout problem has been initiated that cannot accommodate footnotes."));
404
405       header_height_ = head ? head->extent (Y_AXIS).length () : 0;
406       footer_height_ = foot_stencil.extent (Y_AXIS).length ();
407       page_height_ = robust_scm2double (page->get_property ("paper-height"), 100);
408     }
409
410   // Initially, bottom_skyline_ represents the top of the page. Make
411   // it solid, so that the top of the first system will be forced
412   // below the top of the printable area.
413   bottom_skyline_.set_minimum_height (-header_height_);
414
415   SCM system_system_spacing = SCM_EOL;
416   SCM score_system_spacing = SCM_EOL;
417   SCM markup_system_spacing = SCM_EOL;
418   SCM score_markup_spacing = SCM_EOL;
419   SCM markup_markup_spacing = SCM_EOL;
420
421   // top_system_spacing controls the spring from the top of the printable
422   // area to the first staff. It allows the user to control the offset of
423   // the first staff (as opposed to the top of the first system) from the
424   // top of the page. Similarly for last_bottom_spacing.
425   SCM top_system_spacing = SCM_EOL;
426   SCM last_bottom_spacing = SCM_EOL;
427   if (pb && pb->paper_)
428     {
429       Output_def *paper = pb->paper_;
430       system_system_spacing = paper->c_variable ("system-system-spacing");
431       score_system_spacing = paper->c_variable ("score-system-spacing");
432       markup_system_spacing = paper->c_variable ("markup-system-spacing");
433       score_markup_spacing = paper->c_variable ("score-markup-spacing");
434       markup_markup_spacing = paper->c_variable ("markup-markup-spacing");
435       last_bottom_spacing = paper->c_variable ("last-bottom-spacing");
436       top_system_spacing = paper->c_variable ("top-system-spacing");
437       if (scm_is_pair (systems) && unsmob_prob (scm_car (systems)))
438         top_system_spacing = paper->c_variable ("top-markup-spacing");
439
440       // Note: the page height here does _not_ reserve space for headers and
441       // footers. This is because we want to anchor the top-system-spacing
442       // spring at the _top_ of the header.
443       page_height_ -= robust_scm2double (paper->c_variable ("top-margin"), 0)
444                       + robust_scm2double (paper->c_variable ("bottom-margin"), 0);
445
446       read_spacing_spec (top_system_spacing, &header_padding_, ly_symbol2scm ("padding"));
447       read_spacing_spec (last_bottom_spacing, &footer_padding_, ly_symbol2scm ("padding"));
448       in_note_padding_ = robust_scm2double (paper->c_variable ("in-note-padding"), 0.5);
449       in_note_direction_ = robust_scm2dir (paper->c_variable ("in-note-direction"), UP);
450     }
451   bool last_system_was_title = false;
452
453   for (SCM s = systems; scm_is_pair (s); s = scm_cdr (s))
454     {
455       bool first = (s == systems);
456
457       if (Grob *g = unsmob_grob (scm_car (s)))
458         {
459           System *sys = dynamic_cast<System *> (g);
460           if (!sys)
461             {
462               programming_error ("got a grob for vertical spacing that wasn't a System");
463               continue;
464             }
465
466           SCM spec = system_system_spacing;
467           if (first)
468             spec = top_system_spacing;
469           else if (last_system_was_title)
470             spec = markup_system_spacing;
471           else if (0 == Paper_column::get_rank (sys->get_bound (LEFT)))
472             spec = score_system_spacing;
473
474           Spring spring (0, 0);
475           Real padding = 0.0;
476           Real indent = line_dimensions_int (sys->paper_score ()->layout (), sys->get_rank ())[LEFT];
477           alter_spring_from_spacing_spec (spec, &spring);
478           read_spacing_spec (spec, &padding, ly_symbol2scm ("padding"));
479
480           append_system (sys, spring, indent, padding);
481           last_system_was_title = false;
482         }
483       else if (Prob *p = unsmob_prob (scm_car (s)))
484         {
485           SCM spec = first ? top_system_spacing
486                      : (last_system_was_title ? markup_markup_spacing : score_markup_spacing);
487           Spring spring (0, 0);
488           Real padding = 0.0;
489           alter_spring_from_spacing_spec (spec, &spring);
490           read_spacing_spec (spec, &padding, ly_symbol2scm ("padding"));
491
492           append_prob (p, spring, padding);
493           last_system_was_title = true;
494         }
495       else
496         programming_error ("got a system that was neither a Grob nor a Prob");
497     }
498
499   Spring last_spring (0, 0);
500   Real last_padding = 0;
501   alter_spring_from_spacing_spec (last_bottom_spacing, &last_spring);
502   read_spacing_spec (last_bottom_spacing, &last_padding, ly_symbol2scm ("padding"));
503   last_spring.ensure_min_distance (last_padding - bottom_skyline_.max_height () + footer_height_);
504   springs_.push_back (last_spring);
505
506   if (elements_.size ())
507     {
508       Real bottom_padding = 0;
509
510       // TODO: junk bottom-space now that we have last-bottom-spacing?
511       // bottom-space has the flexibility that one can do it per-system.
512       // NOTE: bottom-space is misnamed since it is not stretchable space.
513       if (Prob *p = elements_.back ().prob)
514         bottom_padding = robust_scm2double (p->get_property ("bottom-space"), 0);
515       else if (elements_.back ().staves.size ())
516         {
517           SCM details = get_details (elements_.back ());
518           bottom_padding = robust_scm2double (ly_assoc_get (ly_symbol2scm ("bottom-space"),
519                                                             details,
520                                                             SCM_BOOL_F),
521                                               0.0);
522         }
523       page_height_ -= bottom_padding;
524     }
525 }
526
527 void
528 Page_layout_problem::set_header_height (Real height)
529 {
530   header_height_ = height;
531 }
532
533 void
534 Page_layout_problem::set_footer_height (Real height)
535 {
536   footer_height_ = height;
537 }
538
539 void
540 Page_layout_problem::append_system (System *sys, Spring const &spring, Real indent, Real padding)
541 {
542   Grob *align = sys->get_vertical_alignment ();
543   if (!align)
544     return;
545
546   align->set_property ("positioning-done", SCM_BOOL_T);
547
548   extract_grob_set (align, "elements", all_elts);
549   vector<Grob *> elts = filter_dead_elements (all_elts);
550   vector<Real> minimum_offsets = Align_interface::get_minimum_translations_without_min_dist (align, elts, Y_AXIS);
551   vector<Real> minimum_offsets_with_min_dist = Align_interface::get_minimum_translations (align, elts, Y_AXIS);
552
553   Skyline up_skyline (UP);
554   Skyline down_skyline (DOWN);
555   build_system_skyline (elts, minimum_offsets_with_min_dist, &up_skyline, &down_skyline);
556   up_skyline.shift (indent);
557   down_skyline.shift (indent);
558   Stencil *in_note_stencil = unsmob_stencil (sys->get_property ("in-note-stencil"));
559
560   if (in_note_stencil && in_note_stencil->extent (Y_AXIS).length () > 0)
561     {
562       sys->set_property ("in-note-padding", scm_from_double (in_note_padding_));
563       sys->set_property ("in-note-direction", scm_from_int (in_note_direction_));
564       Skyline *sky = in_note_direction_ == UP ? &up_skyline : &down_skyline;
565       sky->set_minimum_height (sky->max_height ()
566                                + in_note_direction_
567                                * (in_note_padding_
568                                   + in_note_stencil->extent (Y_AXIS).length ()));
569     }
570
571   /*
572     We need to call distance with skyline-horizontal-padding because
573     the system skyline-horizontal-padding is not added during the creation
574     of an individual staff.  So we add the padding for the distance check
575     at the time of adding in the system.
576   */
577   Real minimum_distance = up_skyline.distance (bottom_skyline_,
578                                                robust_scm2double (sys->get_property ("skyline-horizontal-padding"),
579                                                    0))
580                           + padding;
581
582   Spring spring_copy = spring;
583   spring_copy.ensure_min_distance (minimum_distance);
584   springs_.push_back (spring_copy);
585
586   if (elts.size () && !is_spaceable (elts[0]))
587     {
588       // store the minimum distance, considering relative indents,
589       // for a loose line
590       Skyline first_skyline (UP);
591       Skyline_pair *sky = Skyline_pair::unsmob (elts[0]->get_property ("vertical-skylines"));
592       if (sky)
593         first_skyline.merge ((*sky)[UP]);
594       first_skyline.shift (indent);
595       minimum_distance = first_skyline.distance (bottom_skyline_) - bottom_loose_baseline_;
596     }
597   bottom_skyline_ = down_skyline;
598   elements_.push_back (Element (elts, minimum_offsets, minimum_distance, padding));
599
600   // Add the springs for the VerticalAxisGroups in this system.
601
602   // If the user has specified the offsets of the individual staves, fix the
603   // springs at the given distances. Otherwise, use stretchable springs.
604   SCM details = get_details (elements_.back ());
605   SCM manual_dists = ly_assoc_get (ly_symbol2scm ("alignment-distances"), details, SCM_EOL);
606   vsize last_spaceable_staff = 0;
607   bool found_spaceable_staff = false;
608   for (vsize i = 0; i < elts.size (); ++i)
609     {
610       if (is_spaceable (elts[i]))
611         {
612           if (!found_spaceable_staff)
613             {
614               // Ensure space for any loose lines above this system
615               if (i > 0)
616                 springs_.back ().ensure_min_distance (bottom_loose_baseline_
617                                                       - minimum_offsets_with_min_dist[i]
618                                                       + padding);
619               found_spaceable_staff = true;
620               last_spaceable_staff = i;
621               // We don't add a spring for the first staff, since
622               // we are only adding springs _between_ staves here.
623               continue;
624             }
625
626           Spring spring (0.5, 0.0);
627           SCM spec = elts[last_spaceable_staff]->get_property ("staff-staff-spacing");
628           alter_spring_from_spacing_spec (spec, &spring);
629
630           springs_.push_back (spring);
631           Real min_distance = (found_spaceable_staff ? minimum_offsets_with_min_dist[last_spaceable_staff] : 0) - minimum_offsets_with_min_dist[i];
632           springs_.back ().ensure_min_distance (min_distance);
633
634           if (scm_is_pair (manual_dists))
635             {
636               if (scm_is_number (scm_car (manual_dists)))
637                 {
638                   Real dy = scm_to_double (scm_car (manual_dists));
639
640                   springs_.back ().set_distance (dy);
641                   springs_.back ().set_min_distance (dy);
642                   springs_.back ().set_inverse_stretch_strength (0);
643                 }
644               manual_dists = scm_cdr (manual_dists);
645             }
646           last_spaceable_staff = i;
647         }
648     }
649
650   bottom_loose_baseline_ = found_spaceable_staff
651                            ? ( minimum_offsets_with_min_dist[last_spaceable_staff]
652                                - minimum_offsets_with_min_dist.back ())
653                            : 0;
654
655   // Corner case: there was only one staff, and it wasn't spaceable.
656   // Mark it spaceable, because we do not allow non-spaceable staves
657   // to be at the top or bottom of a system.
658   if (!found_spaceable_staff && elts.size ())
659     mark_as_spaceable (elts[0]);
660 }
661
662 void
663 Page_layout_problem::append_prob (Prob *prob, Spring const &spring, Real padding)
664 {
665   Skyline_pair *sky = Skyline_pair::unsmob (prob->get_property ("vertical-skylines"));
666   Real minimum_distance = 0;
667   bool tight_spacing = to_boolean (prob->get_property ("tight-spacing"));
668
669   if (sky)
670     {
671       minimum_distance = (*sky)[UP].distance (bottom_skyline_);
672       bottom_skyline_ = (*sky)[DOWN];
673     }
674   else if (Stencil *sten = unsmob_stencil (prob->get_property ("stencil")))
675     {
676       Interval iv = sten->extent (Y_AXIS);
677       minimum_distance = iv[UP] - bottom_skyline_.max_height ();
678
679       bottom_skyline_.clear ();
680       bottom_skyline_.set_minimum_height (iv[DOWN]);
681     }
682
683   Spring spring_copy = spring;
684   if (tight_spacing)
685     {
686       spring_copy.set_min_distance (minimum_distance);
687       spring_copy.set_inverse_stretch_strength (0.0);
688       spring_copy.set_distance (0.0);
689     }
690   else
691     spring_copy.ensure_min_distance (minimum_distance + padding);
692
693   springs_.push_back (spring_copy);
694   elements_.push_back (Element (prob, padding));
695 }
696
697 /**
698    For ragged-last pages, we usually want to stretch the page so that it
699    is not much more compressed than the previous page.  Here, if ragged is
700    true and you pass a value of fixed_force that !isinf, then I will try
701    to space this page using the given force.  If it does not fit, I will
702    resort to just filling the page (non-raggedly).
703 */
704 void
705 Page_layout_problem::solve_rod_spring_problem (bool ragged, Real fixed_force)
706 {
707   Simple_spacer spacer;
708
709   for (vsize i = 0; i < springs_.size (); ++i)
710     spacer.add_spring (springs_[i]);
711
712   if (ragged && !isinf (fixed_force))
713     {
714       // We need to tell the spacer it isn't ragged.  Otherwise, it will
715       // refuse to stretch.
716       spacer.solve (page_height_, false);
717
718       if (spacer.configuration_length (fixed_force) <= page_height_)
719         spacer.set_force (fixed_force);
720     }
721   else
722     spacer.solve (page_height_, ragged);
723
724   solution_ = spacer.spring_positions ();
725   force_ = spacer.force ();
726
727   if (!spacer.fits ())
728     {
729       Real overflow = spacer.configuration_length (spacer.force ())
730                       - page_height_;
731       if (ragged && overflow < 1e-6)
732         warning (_ ("cannot fit music on page: ragged-spacing was requested, but page was compressed"));
733       else
734         {
735           warning (_f ("cannot fit music on page: overflow is %f",
736                        overflow));
737           warning (_ ("compressing music to fit"));
738           vsize space_count = solution_.size ();
739           Real spacing_increment = overflow / (space_count - 2);
740           for (vsize i = 2; i < space_count; i++)
741             solution_[i] -= (i - 1) * spacing_increment;
742         }
743     }
744 }
745
746 Real
747 Page_layout_problem::force () const
748 {
749   return force_;
750 }
751
752 // The solution_ vector stores the position of every live VerticalAxisGroup
753 // and every title. From that information,
754 // 1) within each system, stretch the staves so they land at the right position
755 // 2) find the offset of each system (relative to the printable area of the page).
756 // TODO: this function is getting too long, maybe split it up?
757 SCM
758 Page_layout_problem::find_system_offsets ()
759 {
760   SCM system_offsets = SCM_EOL;
761   SCM *tail = &system_offsets;
762
763   // spring_idx 0 is the top of the page. Interesting values start from 1.
764   vsize spring_idx = 1;
765   vector<Grob *> loose_lines;
766   vector<Real> loose_line_min_distances;
767   Grob *last_spaceable_line = 0;
768   Real last_spaceable_line_translation = 0;
769   Interval last_title_extent;
770   for (vsize i = 0; i < elements_.size (); ++i)
771     {
772       if (elements_[i].prob)
773         {
774           *tail = scm_cons (scm_from_double (solution_[spring_idx]), SCM_EOL);
775           tail = SCM_CDRLOC (*tail);
776           Interval prob_extent = unsmob_stencil (elements_[i].prob->get_property ("stencil"))->extent (Y_AXIS);
777
778           // Lay out any non-spaceable lines between this line and
779           // the last one.
780           if (loose_lines.size ())
781             {
782               Interval loose_extent = loose_lines.back ()->extent (loose_lines.back (), Y_AXIS);
783               Real min_distance = (-loose_extent[DOWN] + prob_extent[UP]
784                                    + elements_[i].padding);
785
786               loose_line_min_distances.push_back (min_distance);
787               loose_lines.push_back (0);
788
789               distribute_loose_lines (loose_lines, loose_line_min_distances,
790                                       last_spaceable_line_translation, -solution_[spring_idx]);
791               loose_lines.clear ();
792               loose_line_min_distances.clear ();
793             }
794
795           last_spaceable_line = 0;
796           last_spaceable_line_translation = -solution_[spring_idx];
797           last_title_extent = prob_extent;
798           spring_idx++;
799         }
800       else
801         {
802           // Getting this signs right here is a little tricky. The configuration
803           // we return has zero at the top of the page and positive numbers further
804           // down, as does the solution_ vector.  Within a staff, however, positive
805           // numbers are up.
806           // TODO: perhaps change the way the page 'configuration variable works so
807           // that it is consistent with the usual up/down sign conventions in
808           // Lilypond. Then this would be less confusing.
809
810           // These two positions are relative to the page (with positive numbers being
811           // down).
812           Real first_staff_position = solution_[spring_idx];
813           Real first_staff_min_translation = elements_[i].min_offsets.size () ? elements_[i].min_offsets[0] : 0;
814           Real system_position = first_staff_position + first_staff_min_translation;
815
816           // Position the staves within this system.
817           vector<Real> const &min_offsets = elements_[i].min_offsets;
818           bool found_spaceable_staff = false;
819           for (vsize staff_idx = 0; staff_idx < elements_[i].staves.size (); ++staff_idx)
820             {
821               Grob *staff = elements_[i].staves[staff_idx];
822               staff->set_property ("system-Y-offset", scm_from_double (-system_position));
823
824               if (is_spaceable (staff))
825                 {
826                   // this is relative to the system: negative numbers are down.
827                   staff->translate_axis (system_position - solution_[spring_idx], Y_AXIS);
828
829                   // Lay out any non-spaceable lines between this line and
830                   // the last one.
831                   if (loose_lines.size ())
832                     {
833                       if (staff_idx)
834                         loose_line_min_distances.push_back (min_offsets[staff_idx - 1] - min_offsets[staff_idx]);
835                       else
836                         {
837                           // A null line to break any staff-affinity from the previous system
838                           loose_line_min_distances.push_back (0.0);
839                           loose_lines.push_back (0);
840                           loose_line_min_distances.push_back (elements_[i].padding - min_offsets[0]);
841                         }
842                       loose_lines.push_back (staff);
843
844                       distribute_loose_lines (loose_lines, loose_line_min_distances,
845                                               last_spaceable_line_translation, -solution_[spring_idx]);
846                       loose_lines.clear ();
847                       loose_line_min_distances.clear ();
848                     }
849                   last_spaceable_line = staff;
850                   last_spaceable_line_translation = -solution_[spring_idx];
851                   found_spaceable_staff = true;
852                   spring_idx++;
853                 }
854               else // ! is_spaceable
855                 {
856                   if (loose_lines.empty ())
857                     loose_lines.push_back (last_spaceable_line);
858
859                   if (staff_idx)
860                     // NOTE: the way we do distances between loose lines (and other lines too, actually)
861                     // is not the most accurate way possible: we only insert rods between adjacent
862                     // lines.  To be more accurate, we could insert rods between non-adjacent lines
863                     // using a scheme similar to the one in set_column_rods.
864                     loose_line_min_distances.push_back (min_offsets[staff_idx - 1] - min_offsets[staff_idx]);
865                   else
866                     {
867                       // this is the first line in a system
868                       Real min_dist = 0;
869                       if (loose_lines.back ())
870                         {
871                           // distance to the final line in the preceding system,
872                           // including 'system-system-spacing 'padding
873                           min_dist = elements_[i].min_distance + elements_[i].padding;
874                           // A null line to break any staff-affinity for the previous system
875                           loose_line_min_distances.push_back (0.0);
876                           loose_lines.push_back (0);
877                         }
878                       else if (!last_title_extent.is_empty ())
879                         // distance to the preceding title,
880                         //  including 'markup-system-wg 'padding
881                         min_dist = (staff->extent (staff, Y_AXIS)[UP] - last_title_extent[DOWN]
882                                     + elements_[i].padding);
883                       else // distance to the top margin
884                         min_dist = header_padding_ + header_height_ + staff->extent (staff, Y_AXIS)[UP];
885
886                       loose_line_min_distances.push_back (min_dist);
887                     }
888                   loose_lines.push_back (staff);
889                 }
890             }
891
892           // Corner case: even if a system has no live staves, it still takes up
893           // one spring (a system with one live staff also takes up one spring),
894           // which we need to increment past.
895           if (!found_spaceable_staff)
896             spring_idx++;
897
898           *tail = scm_cons (scm_from_double (system_position), SCM_EOL);
899           tail = SCM_CDRLOC (*tail);
900         }
901     }
902
903   if (loose_lines.size ())
904     {
905       Grob *last = loose_lines.back ();
906       Interval last_ext = last->extent (last, Y_AXIS);
907       loose_line_min_distances.push_back (-last_ext[DOWN] + footer_height_ + footer_padding_);
908       loose_lines.push_back (0);
909
910       distribute_loose_lines (loose_lines, loose_line_min_distances,
911                               last_spaceable_line_translation, -page_height_);
912
913     }
914
915   assert (spring_idx == solution_.size () - 1);
916   return system_offsets;
917 }
918
919 // Given two lines that are already spaced (the first and last
920 // elements of loose_lines), distribute some unspaced lines between
921 // them.
922 // first_translation and last_translation are relative to the page.
923 void
924 Page_layout_problem::distribute_loose_lines (vector<Grob *> const &loose_lines,
925                                              vector<Real> const &min_distances,
926                                              Real first_translation, Real last_translation)
927 {
928   Simple_spacer spacer;
929   for (vsize i = 0; i + 1 < loose_lines.size (); ++i)
930     {
931       SCM spec = get_spacing_spec (loose_lines[i], loose_lines[i + 1], false, 0, INT_MAX);
932       Spring spring (1.0, 0.0);
933       alter_spring_from_spacing_spec (spec, &spring);
934       spring.ensure_min_distance (min_distances[i]);
935       spacer.add_spring (spring);
936     }
937
938   // Remember: offsets are decreasing, since we're going from UP to DOWN!
939   spacer.solve (first_translation - last_translation, false);
940
941   vector<Real> solution = spacer.spring_positions ();
942   for (vsize i = 1; i + 1 < solution.size (); ++i)
943     if (loose_lines[i])
944       {
945         Real system_offset = scm_to_double (loose_lines[i]->get_property ("system-Y-offset"));
946         loose_lines[i]->translate_axis (first_translation - solution[i] - system_offset, Y_AXIS);
947       }
948 }
949
950 SCM
951 Page_layout_problem::fixed_force_solution (Real force)
952 {
953   solve_rod_spring_problem (true, force);
954   return find_system_offsets ();
955 }
956
957 SCM
958 Page_layout_problem::solution (bool ragged)
959 {
960   solve_rod_spring_problem (ragged, -infinity_f);
961   return find_system_offsets ();
962 }
963
964 // Build upper and lower skylines for a system. We don't yet know the positions
965 // of the staves within the system, so we make the skyline as conservative as
966 // possible. That is, for the upper skyline, we pretend that all of the staves
967 // in the system are packed together close to the top system; for the lower
968 // skyline, we pretend that all of the staves are packed together close to
969 // the bottom system.
970 //
971 // The upper skyline is relative to the top staff; the lower skyline is relative to
972 // the bottom staff.
973 void
974 Page_layout_problem::build_system_skyline (vector<Grob *> const &staves,
975                                            vector<Real> const &minimum_translations,
976                                            Skyline *up,
977                                            Skyline *down)
978 {
979   if (minimum_translations.empty ())
980     return;
981
982   assert (staves.size () == minimum_translations.size ());
983   Real first_translation = minimum_translations[0];
984   Real last_spaceable_dy = 0;
985   Real first_spaceable_dy = 0;
986   bool found_spaceable_staff = false;
987
988   for (vsize i = 0; i < staves.size (); ++i)
989     {
990       Real dy = minimum_translations[i] - first_translation;
991       Grob *g = staves[i];
992       Skyline_pair *sky = Skyline_pair::unsmob (g->get_property ("vertical-skylines"));
993       if (sky)
994         {
995           up->raise (-dy);
996           up->merge ((*sky)[UP]);
997           up->raise (dy);
998
999           down->raise (-dy);
1000           down->merge ((*sky)[DOWN]);
1001           down->raise (dy);
1002         }
1003       if (is_spaceable (staves[i]))
1004         {
1005           if (!found_spaceable_staff)
1006             {
1007               found_spaceable_staff = true;
1008               first_spaceable_dy = dy;
1009             }
1010           last_spaceable_dy = dy;
1011         }
1012     }
1013
1014   // Leave the up skyline at a position relative
1015   // to the top spaceable staff.
1016   up->raise (-first_spaceable_dy);
1017
1018   // Leave the down skyline at a position
1019   // relative to the bottom spaceable staff.
1020   down->raise (-last_spaceable_dy);
1021 }
1022
1023 Interval
1024 Page_layout_problem::prob_extent (Prob *p)
1025 {
1026   Stencil *sten = unsmob_stencil (p->get_property ("stencil"));
1027   return sten ? sten->extent (Y_AXIS) : Interval (0, 0);
1028 }
1029
1030 Interval
1031 Page_layout_problem::first_staff_extent (Element const &e)
1032 {
1033   if (e.prob)
1034     return prob_extent (e.prob);
1035   else if (e.staves.size ())
1036     return e.staves[0]->extent (e.staves[0], Y_AXIS);
1037
1038   return Interval (0, 0);
1039 }
1040
1041 Interval
1042 Page_layout_problem::last_staff_extent (Element const &e)
1043 {
1044   if (e.prob)
1045     return prob_extent (e.prob);
1046   else if (e.staves.size ())
1047     return e.staves.back ()->extent (e.staves.back (), Y_AXIS);
1048
1049   return Interval (0, 0);
1050 }
1051
1052 SCM
1053 Page_layout_problem::get_details (Element const &elt)
1054 {
1055   if (elt.staves.empty ())
1056     return SCM_EOL;
1057
1058   return get_details (elt.staves.back ()->get_system ());
1059 }
1060
1061 SCM
1062 Page_layout_problem::get_details (Grob *g)
1063 {
1064   Grob *left_bound = dynamic_cast<Spanner *> (g)->get_bound (LEFT);
1065   return left_bound->get_property ("line-break-system-details");
1066 }
1067
1068 bool
1069 Page_layout_problem::is_spaceable (Grob *g)
1070 {
1071   return !scm_is_number (g->get_property ("staff-affinity"));
1072 }
1073
1074 void
1075 Page_layout_problem::mark_as_spaceable (Grob *g)
1076 {
1077   g->set_property ("staff-affinity", SCM_BOOL_F);
1078 }
1079
1080 bool
1081 Page_layout_problem::read_spacing_spec (SCM spec, Real *dest, SCM sym)
1082 {
1083   SCM pair = scm_sloppy_assq (sym, spec);
1084   if (scm_is_pair (pair) && scm_is_number (scm_cdr (pair)))
1085     {
1086       *dest = scm_to_double (scm_cdr (pair));
1087       return true;
1088     }
1089   return false;
1090 }
1091
1092 // If there is a forced, fixed spacing between BEFORE and AFTER, return it.
1093 // Otherwise, return -infinity_f.
1094 // If after is spaceable, it is the (spaceable_index + 1)th spaceable grob in
1095 // its alignment.
1096 Real
1097 Page_layout_problem::get_fixed_spacing (Grob *before, Grob *after, int spaceable_index, bool pure, int start, int end)
1098 {
1099   Spanner *after_sp = dynamic_cast<Spanner *> (after);
1100   SCM cache_symbol = (is_spaceable (before) && is_spaceable (after))
1101                      ? ly_symbol2scm ("spaceable-fixed-spacing")
1102                      : ly_symbol2scm ("loose-fixed-spacing");
1103   if (pure)
1104     {
1105       // The result of this function doesn't depend on "end," so we can reduce the
1106       // size of the cache by ignoring it.
1107       SCM cached = after_sp->get_cached_pure_property (cache_symbol, start, 0);
1108       if (scm_is_number (cached))
1109         return robust_scm2double (cached, 0.0);
1110     }
1111
1112   Real ret = -infinity_f;
1113
1114   // If we're pure, then paper-columns have not had their systems set,
1115   // and so elts[i]->get_system () is unreliable.
1116   System *sys = pure ? Grob::get_system (before) : before->get_system ();
1117   Grob *left_bound = sys ? sys->get_maybe_pure_bound (LEFT, pure, start, end) : 0;
1118
1119   if (is_spaceable (before) && is_spaceable (after) && left_bound)
1120     {
1121       SCM details = left_bound->get_property ("line-break-system-details");
1122       SCM manual_dists = ly_assoc_get (ly_symbol2scm ("alignment-distances"), details, SCM_EOL);
1123       if (scm_is_pair (manual_dists))
1124         {
1125           SCM forced = robust_list_ref (spaceable_index - 1, manual_dists);
1126           if (scm_is_number (forced))
1127             ret = max (ret, scm_to_double (forced));
1128         }
1129     }
1130
1131   // Cache the result.  As above, we ignore "end."
1132   if (pure)
1133     after_sp->cache_pure_property (cache_symbol, start, 0, scm_from_double (ret));
1134
1135   return ret;
1136 }
1137
1138 static SCM
1139 add_stretchability (SCM alist, Real stretch)
1140 {
1141   if (!scm_is_pair (scm_sloppy_assq (ly_symbol2scm ("stretchability"), alist)))
1142     return scm_acons (ly_symbol2scm ("stretchability"), scm_from_double (stretch), alist);
1143
1144   return alist;
1145 }
1146
1147 // We want to put a large stretch between a non-spaceable line and its
1148 // non-affinity staff. We want to put an even larger stretch between
1149 // a non-spaceable line and the top/bottom of the page. That way,
1150 // a spacing-affinity UP line at the bottom of the page will still be
1151 // placed close to its staff.
1152 const double LARGE_STRETCH = 10e5;
1153 const double HUGE_STRETCH = 10e7;
1154
1155 // Returns the spacing spec connecting BEFORE to AFTER.
1156 SCM
1157 Page_layout_problem::get_spacing_spec (Grob *before, Grob *after, bool pure, int start, int end)
1158 {
1159   // If there are no spacing wishes, return a very flexible spring.
1160   // This will occur, for example, if there are lyrics at the bottom of
1161   // the page, in which case we don't want the spring from the lyrics to
1162   // the bottom of the page to have much effect.
1163   if (!before || !after)
1164     return add_stretchability (SCM_EOL, HUGE_STRETCH);
1165
1166   if (is_spaceable (before))
1167     {
1168       if (is_spaceable (after))
1169         return before->get_maybe_pure_property ("staff-staff-spacing", pure, start, end);
1170       else
1171         {
1172           Direction affinity = to_dir (after->get_maybe_pure_property ("staff-affinity", pure, start, end));
1173           return (affinity == DOWN)
1174                  ? add_stretchability (after->get_maybe_pure_property ("nonstaff-unrelatedstaff-spacing", pure, start, end),
1175                                        LARGE_STRETCH)
1176                  : after->get_maybe_pure_property ("nonstaff-relatedstaff-spacing", pure, start, end);
1177         }
1178     }
1179   else
1180     {
1181       if (is_spaceable (after))
1182         {
1183           Direction affinity = to_dir (before->get_maybe_pure_property ("staff-affinity", pure, start, end));
1184           return (affinity == UP)
1185                  ? add_stretchability (before->get_maybe_pure_property ("nonstaff-unrelatedstaff-spacing", pure, start, end),
1186                                        LARGE_STRETCH)
1187                  : before->get_maybe_pure_property ("nonstaff-relatedstaff-spacing", pure, start, end);
1188         }
1189       else
1190         {
1191           Direction before_affinity = to_dir (before->get_maybe_pure_property ("staff-affinity", pure, start, end));
1192           Direction after_affinity = to_dir (after->get_maybe_pure_property ("staff-affinity", pure, start, end));
1193           static bool warned = false;
1194           if (after_affinity > before_affinity
1195               && !warned && !pure)
1196             {
1197               warning (_ ("staff-affinities should only decrease"));
1198               warned = true;
1199             }
1200           if (before_affinity != UP)
1201             return before->get_maybe_pure_property ("nonstaff-nonstaff-spacing", pure, start, end);
1202           else if (after_affinity != DOWN)
1203             return before->get_maybe_pure_property ("nonstaff-nonstaff-spacing", pure, start, end);
1204           return add_stretchability (before->get_maybe_pure_property ("nonstaff-unrelatedstaff-spacing", pure, start, end),
1205                                      LARGE_STRETCH);
1206         }
1207     }
1208
1209   assert (0);
1210   return SCM_BOOL_F;
1211 }
1212
1213 void
1214 Page_layout_problem::alter_spring_from_spacing_spec (SCM spec, Spring *spring)
1215 {
1216   Real space;
1217   Real stretch;
1218   Real min_dist;
1219   if (read_spacing_spec (spec, &space, ly_symbol2scm ("basic-distance")))
1220     spring->set_distance (space);
1221   if (read_spacing_spec (spec, &min_dist, ly_symbol2scm ("minimum-distance")))
1222     spring->set_min_distance (min_dist);
1223   spring->set_default_strength ();
1224
1225   if (read_spacing_spec (spec, &stretch, ly_symbol2scm ("stretchability")))
1226     spring->set_inverse_stretch_strength (stretch);
1227 }
1228
1229 vector<Grob *>
1230 Page_layout_problem::filter_dead_elements (vector<Grob *> const &input)
1231 {
1232   vector<Grob *> output;
1233   for (vsize i = 0; i < input.size (); ++i)
1234     {
1235       if (Hara_kiri_group_spanner::has_interface (input[i]))
1236         Hara_kiri_group_spanner::consider_suicide (input[i]);
1237
1238       if (input[i]->is_live ())
1239         output.push_back (input[i]);
1240     }
1241
1242   return output;
1243 }