2 system.cc -- implement System
4 source file of the GNU LilyPond music typesetter
6 (c) 1996--2006 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"
17 #include "output-def.hh"
18 #include "paper-column.hh"
19 #include "paper-score.hh"
20 #include "paper-system.hh"
21 #include "pointer-group-interface.hh"
22 #include "spacing-interface.hh"
23 #include "staff-symbol-referencer.hh"
24 #include "tweak-registration.hh"
27 System::System (System
const &src
, int count
)
28 : Spanner (src
, count
)
36 System::System (SCM s
, Object_key
const *key
)
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 (int index
) const
56 return new System (*this, index
);
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::get_paper_systems ()
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 ()));
180 SCM lines
= scm_c_make_vector (broken_intos_
.size (), SCM_EOL
);
181 for (vsize i
= 0; i
< broken_intos_
.size (); i
++)
183 if (be_verbose_global
)
184 progress_indication ("[");
186 System
*system
= dynamic_cast<System
*> (broken_intos_
[i
]);
188 system
->post_processing ();
189 scm_vector_set_x (lines
, scm_from_int (i
),
190 system
->get_paper_system ());
192 if (be_verbose_global
)
193 progress_indication (to_string (i
) + "]");
199 System::break_into_pieces (vector
<Column_x_positions
> const &breaking
)
201 for (vsize i
= 0; i
< breaking
.size (); i
++)
203 System
*system
= dynamic_cast<System
*> (clone (broken_intos_
.size ()));
204 system
->rank_
= broken_intos_
.size ();
206 vector
<Grob
*> c (breaking
[i
].cols_
);
207 pscore_
->typeset_system (system
);
209 int st
= Paper_column::get_rank (c
[0]);
210 int end
= Paper_column::get_rank (c
.back ());
211 Interval
iv (pure_height (this, st
, end
));
212 system
->set_property ("pure-Y-extent", ly_interval2scm (iv
));
214 system
->set_bound (LEFT
, c
[0]);
215 system
->set_bound (RIGHT
, c
.back ());
216 for (vsize j
= 0; j
< c
.size (); j
++)
218 c
[j
]->translate_axis (breaking
[i
].config_
[j
], X_AXIS
);
219 dynamic_cast<Paper_column
*> (c
[j
])->system_
= system
;
222 set_loose_columns (system
, &breaking
[i
]);
223 broken_intos_
.push_back (system
);
228 System::add_column (Paper_column
*p
)
231 Grob_array
*ga
= unsmob_grob_array (me
->get_object ("columns"));
234 SCM scm_ga
= Grob_array::make_array ();
235 me
->set_object ("columns", scm_ga
);
236 ga
= unsmob_grob_array (scm_ga
);
241 ? Paper_column::get_rank (ga
->array ().back ()) + 1
245 Axis_group_interface::add_element (this, p
);
249 apply_tweaks (Grob
*g
, bool broken
)
251 if (bool (g
->original ()) == broken
)
253 SCM tweaks
= global_registry_
->get_tweaks (g
);
254 for (SCM s
= tweaks
; scm_is_pair (s
); s
= scm_cdr (s
))
256 SCM proc
= scm_caar (s
);
257 SCM rest
= scm_cdar (s
);
258 scm_apply_1 (proc
, g
->self_scm (), rest
);
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
++)
283 apply_tweaks (all_elements_
->grob (i
), false);
285 for (vsize i
= 0; i
< all_elements_
->size (); i
++)
287 Grob
*g
= all_elements_
->grob (i
);
288 (void) g
->get_property ("before-line-breaking");
291 for (vsize i
= 0; i
< all_elements_
->size (); i
++)
293 Grob
*e
= all_elements_
->grob (i
);
294 (void) e
->get_property ("springs-and-rods");
299 System::post_processing ()
301 for (vsize i
= 0; i
< all_elements_
->size (); i
++)
303 Grob
*g
= all_elements_
->grob (i
);
305 apply_tweaks (g
, true);
306 (void) g
->get_property ("after-line-breaking");
309 Interval
iv (extent (this, Y_AXIS
));
311 programming_error ("system with empty extent");
313 translate_axis (-iv
[MAX
], Y_AXIS
);
315 /* Generate all stencils to trigger font loads.
316 This might seem inefficient, but Stencils are cached per grob
319 vector
<Grob
*> all_elts_sorted (all_elements_
->array ());
320 vector_sort (all_elts_sorted
, std::less
<Grob
*> ());
321 uniq (all_elts_sorted
);
322 this->get_stencil ();
323 for (vsize i
= all_elts_sorted
.size (); i
--;)
325 Grob
*g
= all_elts_sorted
[i
];
337 operator< (Layer_entry
const &a
,
338 Layer_entry
const &b
)
340 return a
.layer_
< b
.layer_
;
345 System::get_paper_system ()
350 vector
<Layer_entry
> entries
;
351 for (vsize j
= 0; j
< all_elements_
->size (); j
++)
354 e
.grob_
= all_elements_
->grob (j
);
355 e
.layer_
= robust_scm2int (e
.grob_
->get_property ("layer"), 1);
357 entries
.push_back (e
);
360 vector_sort (entries
, std::less
<Layer_entry
> ());
361 for (vsize j
= 0; j
< entries
.size (); j
++)
363 Grob
*g
= entries
[j
].grob_
;
364 Stencil st
= g
->get_print_stencil ();
366 if (st
.expr() == SCM_EOL
)
370 for (int a
= X_AXIS
; a
< NO_AXES
; a
++)
371 o
[Axis (a
)] = g
->relative_coordinate (this, Axis (a
));
373 Offset extra
= robust_scm2offset (g
->get_property ("extra-offset"),
375 * Staff_symbol_referencer::staff_space (g
);
377 /* Must copy the stencil, for we cannot change the stencil
380 st
.translate (o
+ extra
);
382 *tail
= scm_cons (st
.expr (), SCM_EOL
);
383 tail
= SCM_CDRLOC (*tail
);
386 if (Stencil
*me
= get_stencil ())
387 exprs
= scm_cons (me
->expr (), exprs
);
389 Interval
x (extent (this, X_AXIS
));
390 Interval
y (extent (this, Y_AXIS
));
391 Stencil
sys_stencil (Box (x
, y
),
392 scm_cons (ly_symbol2scm ("combine-stencil"),
395 Grob
*left_bound
= this->get_bound (LEFT
);
396 SCM prop_init
= left_bound
->get_property ("line-break-system-details");
397 Prob
*pl
= make_paper_system (prop_init
);
398 paper_system_set_stencil (pl
, sys_stencil
);
400 /* information that the page breaker might need */
401 Grob
*right_bound
= this->get_bound (RIGHT
);
402 pl
->set_property ("page-break-permission", right_bound
->get_property ("page-break-permission"));
403 pl
->set_property ("page-turn-permission", right_bound
->get_property ("page-turn-permission"));
404 pl
->set_property ("page-break-penalty", right_bound
->get_property ("page-break-penalty"));
405 pl
->set_property ("page-turn-penalty", right_bound
->get_property ("page-turn-penalty"));
407 if (!scm_is_pair (pl
->get_property ("refpoint-Y-extent")))
409 Interval staff_refpoints
;
410 staff_refpoints
.set_empty ();
411 extract_grob_set (this, "spaceable-staves", staves
);
412 for (vsize i
= 0; i
< staves
.size (); i
++)
415 staff_refpoints
.add_point (g
->relative_coordinate (this, Y_AXIS
));
417 pl
->set_property ("refpoint-Y-extent", ly_interval2scm (staff_refpoints
));
420 pl
->set_property ("system-grob", this->self_scm ());
422 return pl
->unprotect ();
426 System::broken_col_range (Item
const *left
, Item
const *right
) const
430 left
= left
->get_column ();
431 right
= right
->get_column ();
433 extract_grob_set (this, "columns", cols
);
435 while (i
< cols
.size ()
439 if (i
< cols
.size ())
442 while (i
< cols
.size ()
445 Paper_column
*c
= dynamic_cast<Paper_column
*> (cols
[i
]);
446 if (Paper_column::is_breakable (c
) && !c
->system_
)
454 /** Return all columns, but filter out any unused columns , since they might
455 disrupt the spacing problem. */
457 System::columns () const
459 extract_grob_set (this, "columns", ro_columns
);
461 int last_breakable
= ro_columns
.size ();
463 while (last_breakable
--)
465 if (Paper_column::is_breakable (ro_columns
[last_breakable
]))
469 vector
<Grob
*> columns
;
470 for (int i
= 0; i
<= last_breakable
; i
++)
472 if (Paper_column::is_used (ro_columns
[i
]))
473 columns
.push_back (ro_columns
[i
]);
480 System::paper_score () const
486 System::get_rank () const
492 get_root_system (Grob
*me
)
494 Grob
*system_grob
= me
;
496 while (system_grob
->get_parent (Y_AXIS
))
497 system_grob
= system_grob
->get_parent (Y_AXIS
);
499 return dynamic_cast<System
*> (system_grob
);
504 ADD_INTERFACE (System
, "system-interface",
505 "This is the toplevel object: each object in a score "
506 "ultimately has a System object as its X and Y parent. ",