2 system.cc -- implement System
4 source file of the GNU LilyPond music typesetter
6 (c) 1996--2007 Han-Wen Nienhuys <hanwen@xs4all.nl>
11 #include "align-interface.hh"
12 #include "all-font-metrics.hh"
13 #include "axis-group-interface.hh"
14 #include "grob-array.hh"
15 #include "international.hh"
18 #include "output-def.hh"
19 #include "paper-column.hh"
20 #include "paper-score.hh"
21 #include "paper-system.hh"
22 #include "pointer-group-interface.hh"
23 #include "skyline-pair.hh"
24 #include "staff-symbol-referencer.hh"
27 System::System (System
const &src
)
36 System::System (SCM s
)
45 System::init_elements ()
47 SCM scm_arr
= Grob_array::make_array ();
48 all_elements_
= unsmob_grob_array (scm_arr
);
49 all_elements_
->set_ordered (false);
50 set_object ("all-elements", scm_arr
);
54 System::clone () const
56 return new System (*this);
60 System::element_count () const
62 return all_elements_
->size ();
66 System::spanner_count () const
69 for (vsize i
= all_elements_
->size (); i
--;)
70 if (dynamic_cast<Spanner
*> (all_elements_
->grob (i
)))
76 System::typeset_grob (Grob
*elem
)
79 programming_error ("adding element twice");
82 elem
->layout_
= pscore_
->layout ();
83 all_elements_
->add (elem
);
89 System::derived_mark () const
91 if (!all_elements_
->empty ())
93 Grob
**ptr
= &all_elements_
->array_reference ()[0];
94 Grob
**end
= ptr
+ all_elements_
->size ();
97 scm_gc_mark ((*ptr
)->self_scm ());
103 scm_gc_mark (pscore_
->self_scm ());
105 Spanner::derived_mark ();
109 fixup_refpoints (vector
<Grob
*> const &grobs
)
111 for (vsize i
= grobs
.size (); i
--;)
112 grobs
[i
]->fixup_refpoint ();
116 System::do_break_substitution_and_fixup_refpoints ()
118 for (vsize i
= 0; i
< all_elements_
->size (); i
++)
120 Grob
*g
= all_elements_
->grob (i
);
121 if (g
->internal_has_interface (ly_symbol2scm ("only-prebreak-interface")))
124 Kill no longer needed grobs.
126 Item
*it
= dynamic_cast<Item
*> (g
);
127 if (it
&& Item::is_non_musical (it
))
129 it
->find_prebroken_piece (LEFT
)->suicide ();
130 it
->find_prebroken_piece (RIGHT
)->suicide ();
134 else if (g
->is_live ())
135 g
->do_break_processing ();
139 fixups must be done in broken line_of_scores, because new elements
140 are put over there. */
142 for (vsize i
= 0; i
< broken_intos_
.size (); i
++)
144 Grob
*se
= broken_intos_
[i
];
146 extract_grob_set (se
, "all-elements", all_elts
);
147 for (vsize j
= 0; j
< all_elts
.size (); j
++)
149 Grob
*g
= all_elts
[j
];
150 g
->fixup_refpoint ();
153 count
+= all_elts
.size ();
157 needed for doing items.
159 fixup_refpoints (all_elements_
->array ());
161 for (vsize i
= 0; i
< all_elements_
->size (); i
++)
162 all_elements_
->grob (i
)->handle_broken_dependencies ();
164 handle_broken_dependencies ();
166 /* Because the this->get_property (all-elements) contains items in 3
167 versions, handle_broken_dependencies () will leave duplicated
168 items in all-elements. Strictly speaking this is harmless, but
169 it leads to duplicated symbols in the output. uniq makes sure
170 that no duplicates are in the list. */
171 for (vsize i
= 0; i
< broken_intos_
.size (); i
++)
173 System
*child
= dynamic_cast<System
*> (broken_intos_
[i
]);
174 child
->all_elements_
->remove_duplicates ();
177 if (be_verbose_global
)
178 message (_f ("Element count %d.", count
+ element_count ()));
182 System::get_broken_system_grobs ()
185 for (vsize i
= 0; i
< broken_intos_
.size (); i
++)
186 ret
= scm_cons (broken_intos_
[i
]->self_scm (), ret
);
187 return scm_reverse (ret
);
191 System::get_paper_systems ()
193 SCM lines
= scm_c_make_vector (broken_intos_
.size (), SCM_EOL
);
194 for (vsize i
= 0; i
< broken_intos_
.size (); i
++)
196 if (be_verbose_global
)
197 progress_indication ("[");
199 System
*system
= dynamic_cast<System
*> (broken_intos_
[i
]);
201 scm_vector_set_x (lines
, scm_from_int (i
),
202 system
->get_paper_system ());
204 if (be_verbose_global
)
205 progress_indication (to_string (i
) + "]");
211 System::break_into_pieces (vector
<Column_x_positions
> const &breaking
)
213 for (vsize i
= 0; i
< breaking
.size (); i
++)
215 System
*system
= dynamic_cast<System
*> (clone ());
216 system
->rank_
= broken_intos_
.size ();
218 vector
<Grob
*> c (breaking
[i
].cols_
);
219 pscore_
->typeset_system (system
);
221 int st
= Paper_column::get_rank (c
[0]);
222 int end
= Paper_column::get_rank (c
.back ());
223 Interval
iv (pure_height (this, st
, end
));
224 system
->set_property ("pure-Y-extent", ly_interval2scm (iv
));
226 system
->set_bound (LEFT
, c
[0]);
227 system
->set_bound (RIGHT
, c
.back ());
228 SCM system_labels
= SCM_EOL
;
229 for (vsize j
= 0; j
< c
.size (); j
++)
231 c
[j
]->translate_axis (breaking
[i
].config_
[j
], X_AXIS
);
232 dynamic_cast<Paper_column
*> (c
[j
])->system_
= system
;
233 /* collect the column labels */
234 SCM col_labels
= c
[j
]->get_property ("labels");
235 if (scm_is_pair (col_labels
))
236 system_labels
= scm_append (scm_list_2 (col_labels
, system_labels
));
238 system
->set_property ("labels", system_labels
);
240 set_loose_columns (system
, &breaking
[i
]);
241 broken_intos_
.push_back (system
);
246 System::add_column (Paper_column
*p
)
249 Grob_array
*ga
= unsmob_grob_array (me
->get_object ("columns"));
252 SCM scm_ga
= Grob_array::make_array ();
253 me
->set_object ("columns", scm_ga
);
254 ga
= unsmob_grob_array (scm_ga
);
257 p
->rank_
= ga
->size ();
260 Axis_group_interface::add_element (this, p
);
264 System::pre_processing ()
266 for (vsize i
= 0; i
< all_elements_
->size (); i
++)
267 all_elements_
->grob (i
)->discretionary_processing ();
269 if (be_verbose_global
)
270 message (_f ("Grob count %d", element_count ()));
273 order is significant: broken grobs are added to the end of the
274 array, and should be processed before the original is potentially
277 for (vsize i
= all_elements_
->size (); i
--;)
278 all_elements_
->grob (i
)->handle_prebroken_dependencies ();
280 fixup_refpoints (all_elements_
->array ());
282 for (vsize i
= 0; i
< all_elements_
->size (); i
++)
284 Grob
*g
= all_elements_
->grob (i
);
285 (void) g
->get_property ("before-line-breaking");
288 for (vsize i
= 0; i
< all_elements_
->size (); i
++)
290 Grob
*e
= all_elements_
->grob (i
);
291 (void) e
->get_property ("springs-and-rods");
296 System::post_processing ()
298 for (vsize i
= 0; i
< all_elements_
->size (); i
++)
300 Grob
*g
= all_elements_
->grob (i
);
302 (void) g
->get_property ("after-line-breaking");
305 Interval
iv (extent (this, Y_AXIS
));
307 programming_error ("system with empty extent");
309 translate_axis (-iv
[MAX
], Y_AXIS
);
311 /* Generate all stencils to trigger font loads.
312 This might seem inefficient, but Stencils are cached per grob
315 vector
<Grob
*> all_elts_sorted (all_elements_
->array ());
316 vector_sort (all_elts_sorted
, std::less
<Grob
*> ());
317 uniq (all_elts_sorted
);
318 this->get_stencil ();
319 for (vsize i
= all_elts_sorted
.size (); i
--;)
321 Grob
*g
= all_elts_sorted
[i
];
333 operator< (Layer_entry
const &a
,
334 Layer_entry
const &b
)
336 return a
.layer_
< b
.layer_
;
341 System::get_paper_system ()
348 vector
<Layer_entry
> entries
;
349 for (vsize j
= 0; j
< all_elements_
->size (); j
++)
352 e
.grob_
= all_elements_
->grob (j
);
353 e
.layer_
= robust_scm2int (e
.grob_
->get_property ("layer"), 1);
355 entries
.push_back (e
);
358 vector_sort (entries
, std::less
<Layer_entry
> ());
359 for (vsize j
= 0; j
< entries
.size (); j
++)
361 Grob
*g
= entries
[j
].grob_
;
362 Stencil st
= g
->get_print_stencil ();
364 if (st
.expr () == SCM_EOL
)
368 for (int a
= X_AXIS
; a
< NO_AXES
; a
++)
369 o
[Axis (a
)] = g
->relative_coordinate (this, Axis (a
));
371 Offset extra
= robust_scm2offset (g
->get_property ("extra-offset"),
373 * Staff_symbol_referencer::staff_space (g
);
375 /* Must copy the stencil, for we cannot change the stencil
378 st
.translate (o
+ extra
);
380 *tail
= scm_cons (st
.expr (), SCM_EOL
);
381 tail
= SCM_CDRLOC (*tail
);
384 if (Stencil
*me
= get_stencil ())
385 exprs
= scm_cons (me
->expr (), exprs
);
387 Interval
x (extent (this, X_AXIS
));
388 Interval
y (extent (this, Y_AXIS
));
389 Stencil
sys_stencil (Box (x
, y
),
390 scm_cons (ly_symbol2scm ("combine-stencil"),
394 Skyline_pair
*skylines
= Skyline_pair::unsmob (get_property ("vertical-skylines"));
398 = Lookup::points_to_line_stencil (0.1, (*skylines
)[UP
].to_points (X_AXIS
));
400 = Lookup::points_to_line_stencil (0.1, (*skylines
)[DOWN
].to_points (X_AXIS
));
401 sys_stencil
.add_stencil (up
.in_color (255, 0, 0));
402 sys_stencil
.add_stencil (down
.in_color (0, 255, 0));
406 Grob
*left_bound
= this->get_bound (LEFT
);
407 SCM prop_init
= left_bound
->get_property ("line-break-system-details");
408 Prob
*pl
= make_paper_system (prop_init
);
409 paper_system_set_stencil (pl
, sys_stencil
);
411 /* information that the page breaker might need */
412 Grob
*right_bound
= this->get_bound (RIGHT
);
413 pl
->set_property ("vertical-skylines", this->get_property ("vertical-skylines"));
414 pl
->set_property ("page-break-permission", right_bound
->get_property ("page-break-permission"));
415 pl
->set_property ("page-turn-permission", right_bound
->get_property ("page-turn-permission"));
416 pl
->set_property ("page-break-penalty", right_bound
->get_property ("page-break-penalty"));
417 pl
->set_property ("page-turn-penalty", right_bound
->get_property ("page-turn-penalty"));
419 Interval staff_refpoints
;
420 extract_grob_set (this, "spaceable-staves", staves
);
421 for (vsize i
= 0; i
< staves
.size (); i
++)
422 staff_refpoints
.add_point (staves
[i
]->relative_coordinate (this, Y_AXIS
));
424 pl
->set_property ("staff-refpoint-extent", ly_interval2scm (staff_refpoints
));
425 pl
->set_property ("system-grob", this->self_scm ());
427 return pl
->unprotect ();
431 System::broken_col_range (Item
const *left
, Item
const *right
) const
435 left
= left
->get_column ();
436 right
= right
->get_column ();
439 extract_grob_set (this, "columns", cols
);
441 vsize i
= Paper_column::get_rank (left
);
442 int end_rank
= Paper_column::get_rank (right
);
443 if (i
< cols
.size ())
446 while (i
< cols
.size ()
447 && Paper_column::get_rank (cols
[i
]) < end_rank
)
449 Paper_column
*c
= dynamic_cast<Paper_column
*> (cols
[i
]);
450 if (Paper_column::is_breakable (c
) && !c
->system_
)
459 /** Return all columns, but filter out any unused columns , since they might
460 disrupt the spacing problem. */
462 System::used_columns () const
464 extract_grob_set (this, "columns", ro_columns
);
466 int last_breakable
= ro_columns
.size ();
468 while (last_breakable
--)
470 if (Paper_column::is_breakable (ro_columns
[last_breakable
]))
474 vector
<Grob
*> columns
;
475 for (int i
= 0; i
<= last_breakable
; i
++)
477 if (Paper_column::is_used (ro_columns
[i
]))
478 columns
.push_back (ro_columns
[i
]);
485 System::column (vsize which
) const
487 extract_grob_set (this, "columns", columns
);
488 if (which
>= columns
.size ())
491 return dynamic_cast<Paper_column
*> (columns
[which
]);
495 System::paper_score () const
501 System::get_rank () const
507 get_root_system (Grob
*me
)
509 Grob
*system_grob
= me
;
511 while (system_grob
->get_parent (Y_AXIS
))
512 system_grob
= system_grob
->get_parent (Y_AXIS
);
514 return dynamic_cast<System
*> (system_grob
);
517 ADD_INTERFACE (System
,
518 "This is the top-level object: Each object in a score"
519 " ultimately has a @code{System} object as its X and"
529 "skyline-horizontal-padding "