2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1997--2014 Han-Wen Nienhuys <hanwen@xs4all.nl>
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.
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.
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/>.
25 #include "align-interface.hh"
26 #include "axis-group-interface.hh"
28 #include "international.hh"
33 #include "output-def.hh"
34 #include "pointer-group-interface.hh"
35 #include "program-option.hh"
37 #include "stream-event.hh"
39 #include "unpure-pure-container.hh"
46 return new Grob (*this);
49 Grob::Grob (SCM basicprops)
52 /* FIXME: default should be no callback. */
55 interfaces_ = SCM_EOL;
56 immutable_property_alist_ = basicprops;
57 mutable_property_alist_ = SCM_EOL;
58 object_alist_ = SCM_EOL;
60 /* We do smobify_self () as the first step. Since the object lives
61 on the heap, none of its SCM variables are protected from
62 GC. After smobify_self (), they are. */
65 SCM meta = get_property ("meta");
66 if (scm_is_pair (meta))
68 interfaces_ = scm_cdr (scm_assq (ly_symbol2scm ("interfaces"), meta));
70 SCM object_cbs = scm_assq (ly_symbol2scm ("object-callbacks"), meta);
71 if (scm_is_pair (object_cbs))
73 for (SCM s = scm_cdr (object_cbs); scm_is_pair (s); s = scm_cdr (s))
74 set_object (scm_caar (s), scm_cdar (s));
78 if (get_property_data ("X-extent") == SCM_EOL)
79 set_property ("X-extent", Grob::stencil_width_proc);
80 if (get_property_data ("Y-extent") == SCM_EOL)
81 set_property ("Y-extent",
82 Unpure_pure_container::make_smob (Grob::stencil_height_proc,
83 Grob::pure_stencil_height_proc));
84 if (get_property_data ("vertical-skylines") == SCM_EOL)
85 set_property ("vertical-skylines",
86 Unpure_pure_container::make_smob (Grob::simple_vertical_skylines_from_extents_proc,
87 Grob::pure_simple_vertical_skylines_from_extents_proc));
88 if (get_property_data ("horizontal-skylines") == SCM_EOL)
89 set_property ("horizontal-skylines",
90 Unpure_pure_container::make_smob (Grob::simple_horizontal_skylines_from_extents_proc,
91 Grob::pure_simple_horizontal_skylines_from_extents_proc));
94 Grob::Grob (Grob const &s)
96 original_ = (Grob *) & s;
98 immutable_property_alist_ = s.immutable_property_alist_;
99 mutable_property_alist_ = SCM_EOL;
101 for (Axis a = X_AXIS; a < NO_AXES; incr (a))
102 dim_cache_ [a] = s.dim_cache_ [a];
104 interfaces_ = s.interfaces_;
105 object_alist_ = SCM_EOL;
111 mutable_property_alist_ = ly_deep_copy (s.mutable_property_alist_);
118 /****************************************************************
120 ****************************************************************/
123 Grob::get_stencil () const
128 SCM stil = get_property ("stencil");
129 return Stencil::unsmob (stil);
133 Grob::get_print_stencil () const
135 SCM stil = get_property ("stencil");
138 if (Stencil *m = Stencil::unsmob (stil))
141 bool transparent = to_boolean (get_property ("transparent"));
144 retval = Stencil (m->extent_box (), SCM_EOL);
147 SCM expr = m->expr ();
148 expr = scm_list_3 (ly_symbol2scm ("grob-cause"),
151 retval = Stencil (m->extent_box (), expr);
154 SCM rot = get_property ("rotation");
155 if (scm_is_pair (rot))
157 Real angle = scm_to_double (scm_car (rot));
158 Real x = scm_to_double (scm_cadr (rot));
159 Real y = scm_to_double (scm_caddr (rot));
161 retval.rotate_degrees (angle, Offset (x, y));
164 /* color support... see interpret_stencil_expression () for more... */
165 SCM color = get_property ("color");
166 if (scm_is_pair (color))
168 SCM expr = scm_list_3 (ly_symbol2scm ("color"),
172 retval = Stencil (retval.extent_box (), expr);
175 /* process whiteout */
176 /* a grob has to be visible, otherwise the whiteout property has no effect */
177 if (!transparent && to_boolean (get_property ("whiteout")))
179 /* Call the scheme procedure stencil-whiteout in scm/stencils.scm */
180 /* to add a round-filled-box stencil to the stencil list */
182 = *Stencil::unsmob (scm_call_1 (ly_lily_module_constant ("stencil-whiteout"),
183 retval.smobbed_copy ()));
186 SCM id = get_property ("id");
187 if (scm_is_string (id))
189 SCM expr = scm_list_3 (ly_symbol2scm ("id"),
193 retval = Stencil (retval.extent_box (), expr);
201 /****************************************************************
203 ****************************************************************/
205 Grob::do_break_processing ()
210 Grob::discretionary_processing ()
215 Grob::get_system () const
220 /* This version of get_system is more reliable than this->get_system ()
221 before line-breaking has been done, at which point there is only
222 one system in the whole score and we can find it just by following
225 Grob::get_system (Grob *me)
227 Grob *p = me->get_parent (X_AXIS);
228 return p ? get_system (p) : dynamic_cast<System *>(me);
232 Grob::handle_broken_dependencies ()
234 Spanner *sp = dynamic_cast<Spanner *> (this);
235 if (original () && sp)
239 /* THIS, SP is the original spanner. We use a special function
240 because some Spanners have enormously long lists in their
241 properties, and a special function fixes FOO */
243 for (SCM s = object_alist_; scm_is_pair (s); s = scm_cdr (s))
244 sp->substitute_one_mutable_property (scm_caar (s), scm_cdar (s));
246 System *system = get_system ();
250 && common_refpoint (system, X_AXIS)
251 && common_refpoint (system, Y_AXIS))
252 substitute_object_links (system->self_scm (), object_alist_);
253 else if (dynamic_cast<System *> (this))
254 substitute_object_links (SCM_UNDEFINED, object_alist_);
256 /* THIS element is `invalid'; it has been removed from all
257 dependencies, so let's junk the element itself.
259 Do not do this for System, since that would remove references
260 to the originals of score-grobs, which get then GC'd (a bad
265 /* Note that we still want references to this element to be
266 rearranged, and not silently thrown away, so we keep pointers like
267 {broken_into_{drul, array}, original}
275 for (int a = X_AXIS; a < NO_AXES; a++)
276 dim_cache_[a].clear ();
278 mutable_property_alist_ = SCM_EOL;
279 object_alist_ = SCM_EOL;
280 immutable_property_alist_ = SCM_EOL;
281 interfaces_ = SCM_EOL;
285 Grob::handle_prebroken_dependencies ()
287 /* Don't do this in the derived method, since we want to keep access to
288 object_alist_ centralized. */
291 Item *it = dynamic_cast<Item *> (this);
292 substitute_object_links (scm_from_int (it->break_status_dir ()),
293 original ()->object_alist_);
298 Grob::find_broken_piece (System *) const
303 /****************************************************************
305 ****************************************************************/
308 Grob::translate_axis (Real y, Axis a)
310 if (isinf (y) || isnan (y))
312 programming_error ("Infinity or NaN encountered");
316 if (!dim_cache_[a].offset_)
317 dim_cache_[a].offset_ = new Real (y);
319 *dim_cache_[a].offset_ += y;
322 /* Find the offset relative to D. If D equals THIS, then it is 0.
323 Otherwise, it recursively defd as
325 OFFSET_ + PARENT_L_->relative_coordinate (D) */
327 Grob::relative_coordinate (Grob const *refp, Axis a) const
329 /* eaa - hmmm, should we do a programming_error() here? */
330 if ((this == NULL) || (refp == this))
333 /* We catch PARENT_L_ == nil case with this, but we crash if we did
334 not ask for the absolute coordinate (ie. REFP == nil.) */
335 Real off = get_offset (a);
336 if (refp == dim_cache_[a].parent_)
339 off += dim_cache_[a].parent_->relative_coordinate (refp, a);
345 Grob::pure_relative_y_coordinate (Grob const *refp, int start, int end)
352 if (dim_cache_[Y_AXIS].offset_)
354 if (to_boolean (get_property ("pure-Y-offset-in-progress")))
355 programming_error ("cyclic chain in pure-Y-offset callbacks");
357 off = *dim_cache_[Y_AXIS].offset_;
361 SCM proc = get_property_data ("Y-offset");
363 dim_cache_[Y_AXIS].offset_ = new Real (0.0);
364 set_property ("pure-Y-offset-in-progress", SCM_BOOL_T);
365 off = robust_scm2double (call_pure_function (proc,
366 scm_list_1 (self_scm ()),
369 del_property ("pure-Y-offset-in-progress");
370 delete dim_cache_[Y_AXIS].offset_;
371 dim_cache_[Y_AXIS].offset_ = 0;
374 /* we simulate positioning-done if we are the child of a VerticalAlignment,
375 but only if we don't have a cached offset. If we do have a cached offset,
376 it probably means that the Alignment was fixed and it has already been
379 if (Grob *p = get_parent (Y_AXIS))
382 if (Align_interface::has_interface (p) && !dim_cache_[Y_AXIS].offset_)
383 trans = Align_interface::get_pure_child_y_translation (p, this, start, end);
385 return off + trans + p->pure_relative_y_coordinate (refp, start, end);
390 /* Invoke callbacks to get offset relative to parent. */
392 Grob::get_offset (Axis a) const
394 if (dim_cache_[a].offset_)
395 return *dim_cache_[a].offset_;
397 Grob *me = (Grob *) this;
399 SCM sym = axis_offset_symbol (a);
400 me->dim_cache_[a].offset_ = new Real (0.0);
403 UGH: can't fold next 2 statements together. Apparently GCC thinks
404 dim_cache_[a].offset_ is unaliased.
406 Real off = robust_scm2double (get_property (sym), 0.0);
407 if (me->dim_cache_[a].offset_)
409 *me->dim_cache_[a].offset_ += off;
410 me->del_property (sym);
411 return *me->dim_cache_[a].offset_;
418 Grob::maybe_pure_coordinate (Grob const *refp, Axis a, bool pure, int start, int end)
420 if (pure && a != Y_AXIS)
421 programming_error ("tried to get pure X-offset");
422 return (pure && a == Y_AXIS) ? pure_relative_y_coordinate (refp, start, end)
423 : relative_coordinate (refp, a);
426 /****************************************************************
428 ****************************************************************/
431 Grob::flush_extent_cache (Axis axis)
433 if (dim_cache_[axis].extent_)
436 Ugh, this is not accurate; will flush property, causing
437 callback to be called if.
439 del_property ((axis == X_AXIS) ? ly_symbol2scm ("X-extent") : ly_symbol2scm ("Y-extent"));
440 delete dim_cache_[axis].extent_;
441 dim_cache_[axis].extent_ = 0;
442 if (get_parent (axis))
443 get_parent (axis)->flush_extent_cache (axis);
448 Grob::extent (Grob *refp, Axis a) const
450 Real offset = relative_coordinate (refp, a);
452 if (dim_cache_[a].extent_)
454 real_ext = *dim_cache_[a].extent_;
459 Order is significant: ?-extent may trigger suicide.
461 SCM ext = (a == X_AXIS)
462 ? get_property ("X-extent")
463 : get_property ("Y-extent");
464 if (is_number_pair (ext))
465 real_ext.unite (ly_scm2interval (ext));
467 SCM min_ext = (a == X_AXIS)
468 ? get_property ("minimum-X-extent")
469 : get_property ("minimum-Y-extent");
470 if (is_number_pair (min_ext))
471 real_ext.unite (ly_scm2interval (min_ext));
473 ((Grob *)this)->dim_cache_[a].extent_ = new Interval (real_ext);
476 // We never want nan, so we avoid shifting infinite values.
478 real_ext.translate(offset);
480 this->warning(_f ("ignored infinite %s-offset",
481 a == X_AXIS ? "X" : "Y"));
487 Grob::pure_height (Grob *refp, int start, int end)
489 SCM iv_scm = get_pure_property ("Y-extent", start, end);
490 Interval iv = robust_scm2interval (iv_scm, Interval ());
491 Real offset = pure_relative_y_coordinate (refp, start, end);
493 SCM min_ext = get_property ("minimum-Y-extent");
495 /* we don't add minimum-Y-extent if the extent is empty. This solves
496 a problem with Hara-kiri spanners. They would request_suicide and
497 return empty extents, but we would force them here to be large. */
498 if (!iv.is_empty () && is_number_pair (min_ext))
499 iv.unite (ly_scm2interval (min_ext));
502 iv.translate (offset);
507 Grob::maybe_pure_extent (Grob *refp, Axis a, bool pure, int start, int end)
509 return (pure && a == Y_AXIS) ? pure_height (refp, start, end) : extent (refp, a);
513 Grob::spanned_rank_interval () const
515 return Interval_t<int> (-1, 0);
519 Grob::pure_is_visible (int /* start */, int /* end */) const
524 /* Sort grobs according to their starting column. */
526 Grob::less (Grob *g1, Grob *g2)
528 return g1->spanned_rank_interval ()[LEFT] < g2->spanned_rank_interval ()[LEFT];
531 /****************************************************************
533 ****************************************************************/
535 /* Find the group-element which has both #this# and #s# */
537 Grob::common_refpoint (Grob const *s, Axis a) const
540 /* Catching the trivial cases is likely costlier than just running
541 through: one can't avoid going to the respective chain ends
542 anyway. We might save the second run through when the chain ends
543 differ, but keeping track of the ends makes the loop more costly.
550 for (c = this; c; ++balance)
551 c = c->dim_cache_[a].parent_;
553 for (d = s; d; --balance)
554 d = d->dim_cache_[a].parent_;
556 /* Cut down ancestry to same size */
558 for (c = this; balance > 0; --balance)
559 c = c->dim_cache_[a].parent_;
561 for (d = s; balance < 0; ++balance)
562 d = d->dim_cache_[a].parent_;
564 /* Now find point where our lineages converge */
567 c = c->dim_cache_[a].parent_;
568 d = d->dim_cache_[a].parent_;
575 Grob::set_parent (Grob *g, Axis a)
577 dim_cache_[a].parent_ = g;
581 Grob::get_parent (Axis a) const
583 return dim_cache_[a].parent_;
587 Grob::fixup_refpoint ()
589 for (int a = X_AXIS; a < NO_AXES; a++)
592 Grob *parent = get_parent (ax);
597 if (parent->get_system () != get_system () && get_system ())
599 Grob *newparent = parent->find_broken_piece (get_system ());
600 set_parent (newparent, ax);
603 if (Item *i = dynamic_cast<Item *> (this))
605 Item *parenti = dynamic_cast<Item *> (parent);
609 Direction my_dir = i->break_status_dir ();
610 if (my_dir != parenti->break_status_dir ())
612 Item *newparent = parenti->find_prebroken_piece (my_dir);
613 set_parent (newparent, ax);
620 /****************************************************************
622 ****************************************************************/
625 get_maybe_root_vertical_alignment (Grob *g, Grob *maybe)
629 if (Align_interface::has_interface (g))
630 return get_maybe_root_vertical_alignment (g->get_parent (Y_AXIS), g);
631 return get_maybe_root_vertical_alignment (g->get_parent (Y_AXIS), maybe);
636 Grob::get_root_vertical_alignment (Grob *g)
638 return get_maybe_root_vertical_alignment (g, 0);
642 Grob::get_vertical_axis_group (Grob *g)
646 if (!g->get_parent (Y_AXIS))
648 if (Axis_group_interface::has_interface (g)
649 && Align_interface::has_interface (g->get_parent (Y_AXIS)))
651 return get_vertical_axis_group (g->get_parent (Y_AXIS));
656 Grob::get_vertical_axis_group_index (Grob *g)
658 Grob *val = get_root_vertical_alignment (g);
661 Grob *vax = get_vertical_axis_group (g);
662 extract_grob_set (val, "elements", elts);
663 for (vsize i = 0; i < elts.size (); i++)
666 g->programming_error ("could not find this grob's vertical axis group in the vertical alignment");
671 Grob::vertical_less (Grob *g1, Grob *g2)
673 return internal_vertical_less (g1, g2, false);
677 Grob::pure_vertical_less (Grob *g1, Grob *g2)
679 return internal_vertical_less (g1, g2, true);
683 Grob::internal_vertical_less (Grob *g1, Grob *g2, bool pure)
685 Grob *vag = get_root_vertical_alignment (g1);
688 g1->programming_error ("grob does not belong to a VerticalAlignment?");
692 Grob *ag1 = get_vertical_axis_group (g1);
693 Grob *ag2 = get_vertical_axis_group (g2);
695 extract_grob_set (vag, "elements", elts);
697 if (ag1 == ag2 && !pure)
699 Grob *common = g1->common_refpoint (g2, Y_AXIS);
700 return g1->relative_coordinate (common, Y_AXIS) > g2->relative_coordinate (common, Y_AXIS);
703 for (vsize i = 0; i < elts.size (); i++)
711 g1->programming_error ("could not place this grob in its axis group");
715 /****************************************************************
717 ****************************************************************/
719 Grob::programming_error (const string &s) const
721 SCM cause = self_scm ();
722 while (Grob *g = Grob::unsmob (cause))
723 cause = g->get_property ("cause");
725 /* ES TODO: cause can't be Music*/
726 if (Music *m = Music::unsmob (cause))
727 m->origin ()->programming_error (s);
728 else if (Stream_event *ev = Stream_event::unsmob (cause))
729 ev->origin ()->programming_error (s);
731 ::programming_error (s);
735 Grob::warning (const string &s) const
737 SCM cause = self_scm ();
738 while (Grob *g = Grob::unsmob (cause))
739 cause = g->get_property ("cause");
741 /* ES TODO: cause can't be Music*/
742 if (Music *m = Music::unsmob (cause))
743 m->origin ()->warning (s);
744 else if (Stream_event *ev = Stream_event::unsmob (cause))
745 ev->origin ()->warning (s);
753 SCM meta = get_property ("meta");
754 SCM nm = scm_assq (ly_symbol2scm ("name"), meta);
755 nm = (scm_is_pair (nm)) ? scm_cdr (nm) : SCM_EOL;
756 return scm_is_symbol (nm) ? ly_symbol2string (nm) : this->class_name ();
760 "A grob represents a piece of music notation.\n"
762 "All grobs have an X and Y@tie{}position on the page. These"
763 " X and Y@tie{}positions are stored in a relative format, thus"
764 " they can easily be combined by stacking them, hanging one"
765 " grob to the side of another, or coupling them into grouping"
768 "Each grob has a reference point (a.k.a.@: parent): The"
769 " position of a grob is stored relative to that reference"
770 " point. For example, the X@tie{}reference point of a staccato"
771 " dot usually is the note head that it applies to. When the"
772 " note head is moved, the staccato dot moves along"
775 "A grob is often associated with a symbol, but some grobs do"
776 " not print any symbols. They take care of grouping objects."
777 " For example, there is a separate grob that stacks staves"
778 " vertically. The @ref{NoteCollision} object is also an"
779 " abstract grob: It only moves around chords, but doesn't print"
782 "Grobs have properties (Scheme variables) that can be read and"
783 " set. Two types of them exist: immutable and mutable."
784 " Immutable variables define the default style and behavior."
785 " They are shared between many objects. They can be changed"
786 " using @code{\\override} and @code{\\revert}. Mutable"
787 " properties are variables that are specific to one grob."
788 " Typically, lists of other objects, or results from"
789 " computations are stored in mutable properties. In"
790 " particular, every call to @code{ly:grob-set-property!}"
791 " (or its C++ equivalent) sets a mutable property.\n"
793 "The properties @code{after-line-breaking} and"
794 " @code{before-line-breaking} are dummies that are not"
795 " user-serviceable.",
802 "after-line-breaking "
804 "axis-group-parent-X "
805 "axis-group-parent-Y "
806 "before-line-breaking "
814 "horizontal-skylines "
820 "pure-Y-offset-in-progress "
822 "skyline-horizontal-padding "
831 /****************************************************************
833 ****************************************************************/
836 grob_stencil_extent (Grob *me, Axis a)
838 Stencil *m = me->get_stencil ();
842 return ly_interval2scm (e);
845 MAKE_SCHEME_CALLBACK (Grob, stencil_height, 1);
847 Grob::stencil_height (SCM smob)
849 Grob *me = Grob::unsmob (smob);
850 return grob_stencil_extent (me, Y_AXIS);
853 MAKE_SCHEME_CALLBACK (Grob, pure_stencil_height, 3);
855 Grob::pure_stencil_height (SCM smob, SCM /* beg */, SCM /* end */)
857 Grob *me = Grob::unsmob (smob);
858 if (Stencil::unsmob (me->get_property_data ("stencil")))
859 return grob_stencil_extent (me, Y_AXIS);
861 return ly_interval2scm (Interval ());
865 MAKE_SCHEME_CALLBACK (Grob, y_parent_positioning, 1);
867 Grob::y_parent_positioning (SCM smob)
869 Grob *me = Grob::unsmob (smob);
870 Grob *par = me->get_parent (Y_AXIS);
872 (void) par->get_property ("positioning-done");
874 return scm_from_double (0.0);
877 MAKE_SCHEME_CALLBACK (Grob, x_parent_positioning, 1);
879 Grob::x_parent_positioning (SCM smob)
881 Grob *me = Grob::unsmob (smob);
883 Grob *par = me->get_parent (X_AXIS);
885 (void) par->get_property ("positioning-done");
887 return scm_from_double (0.0);
890 MAKE_SCHEME_CALLBACK (Grob, stencil_width, 1);
892 Grob::stencil_width (SCM smob)
894 Grob *me = Grob::unsmob (smob);
895 return grob_stencil_extent (me, X_AXIS);
899 common_refpoint_of_list (SCM elist, Grob *common, Axis a)
901 for (; scm_is_pair (elist); elist = scm_cdr (elist))
902 if (Grob *s = Grob::unsmob (scm_car (elist)))
905 common = common->common_refpoint (s, a);
914 common_refpoint_of_array (vector<Grob *> const &arr, Grob *common, Axis a)
916 for (vsize i = 0; i < arr.size (); i++)
918 common = common->common_refpoint (arr[i], a);
926 common_refpoint_of_array (set<Grob *> const &arr, Grob *common, Axis a)
928 set<Grob *>::iterator it;
930 for (it = arr.begin (); it != arr.end (); it++)
932 common = common->common_refpoint (*it, a);
940 robust_relative_extent (Grob *me, Grob *refpoint, Axis a)
942 Interval ext = me->extent (refpoint, a);
944 ext.add_point (me->relative_coordinate (refpoint, a));
949 // Checks whether there is a vertical alignment in the chain of
950 // parents between this and commony.
952 Grob::check_cross_staff (Grob *commony)
954 if (Align_interface::has_interface (commony))
957 for (Grob *g = this; g && g != commony; g = g->get_parent (Y_AXIS))
958 if (Align_interface::has_interface (g))
966 indirect_less (Grob **a, Grob **b)
968 // Use original order as tie breaker. That gives us a stable sort
969 // at the lower price tag of an unstable one, and we want a stable
970 // sort in order to reliably retain the first instance of a grob
972 return *a < *b || (*a == *b && a < b);
977 indirect_eq (Grob **a, Grob **b)
984 direct_less (Grob **a, Grob **b)
989 // uniquify uniquifies on the memory addresses of the Grobs, but then
990 // uses the original order. This makes results independent from the
991 // memory allocation of Grobs.
994 uniquify (vector <Grob *> & grobs)
996 vector <Grob **> vec (grobs.size ());
997 for (vsize i = 0; i < grobs.size (); i++)
999 vector_sort (vec, indirect_less);
1000 vec.erase (unique (vec.begin (), vec.end (), indirect_eq), vec.end ());
1001 vector_sort (vec, direct_less);
1003 // Since the output is a sorted copy of the input with some elements
1004 // removed, we can fill in the vector in-place if we do it starting
1006 for (vsize i = 0; i < vec.size (); i++)
1008 grobs.erase (grobs.begin () + vec.size (), grobs.end ());