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"
42 #include "ly-smobs.icc"
47 return new Grob (*this);
50 Grob::Grob (SCM basicprops)
53 /* FIXME: default should be no callback. */
56 interfaces_ = SCM_EOL;
57 immutable_property_alist_ = basicprops;
58 mutable_property_alist_ = SCM_EOL;
59 object_alist_ = SCM_EOL;
61 /* We do smobify_self () as the first step. Since the object lives
62 on the heap, none of its SCM variables are protected from
63 GC. After smobify_self (), they are. */
66 SCM meta = get_property ("meta");
67 if (scm_is_pair (meta))
69 interfaces_ = scm_cdr (scm_assq (ly_symbol2scm ("interfaces"), meta));
71 SCM object_cbs = scm_assq (ly_symbol2scm ("object-callbacks"), meta);
72 if (scm_is_pair (object_cbs))
74 for (SCM s = scm_cdr (object_cbs); scm_is_pair (s); s = scm_cdr (s))
75 set_object (scm_caar (s), scm_cdar (s));
79 if (get_property_data ("X-extent") == SCM_EOL)
80 set_property ("X-extent", Grob::stencil_width_proc);
81 if (get_property_data ("Y-extent") == SCM_EOL)
82 set_property ("Y-extent",
83 ly_make_unpure_pure_container (Grob::stencil_height_proc,
84 Grob::pure_stencil_height_proc));
85 if (get_property_data ("vertical-skylines") == SCM_EOL)
86 set_property ("vertical-skylines",
87 ly_make_unpure_pure_container (Grob::simple_vertical_skylines_from_extents_proc,
88 Grob::pure_simple_vertical_skylines_from_extents_proc));
89 if (get_property_data ("horizontal-skylines") == SCM_EOL)
90 set_property ("horizontal-skylines",
91 ly_make_unpure_pure_container (Grob::simple_horizontal_skylines_from_extents_proc,
92 Grob::pure_simple_horizontal_skylines_from_extents_proc));
95 Grob::Grob (Grob const &s)
97 original_ = (Grob *) & s;
99 immutable_property_alist_ = s.immutable_property_alist_;
100 mutable_property_alist_ = SCM_EOL;
102 for (Axis a = X_AXIS; a < NO_AXES; incr (a))
103 dim_cache_ [a] = s.dim_cache_ [a];
105 interfaces_ = s.interfaces_;
106 object_alist_ = SCM_EOL;
112 mutable_property_alist_ = ly_deep_copy (s.mutable_property_alist_);
119 /****************************************************************
121 ****************************************************************/
124 Grob::get_stencil () const
129 SCM stil = get_property ("stencil");
130 return Stencil::unsmob (stil);
134 Grob::get_print_stencil () const
136 SCM stil = get_property ("stencil");
139 if (Stencil *m = Stencil::unsmob (stil))
142 bool transparent = to_boolean (get_property ("transparent"));
145 retval = Stencil (m->extent_box (), SCM_EOL);
148 SCM expr = m->expr ();
149 expr = scm_list_3 (ly_symbol2scm ("grob-cause"),
152 retval = Stencil (m->extent_box (), expr);
155 SCM rot = get_property ("rotation");
156 if (scm_is_pair (rot))
158 Real angle = scm_to_double (scm_car (rot));
159 Real x = scm_to_double (scm_cadr (rot));
160 Real y = scm_to_double (scm_caddr (rot));
162 retval.rotate_degrees (angle, Offset (x, y));
165 /* color support... see interpret_stencil_expression () for more... */
166 SCM color = get_property ("color");
167 if (scm_is_pair (color))
169 SCM expr = scm_list_3 (ly_symbol2scm ("color"),
173 retval = Stencil (retval.extent_box (), expr);
176 /* process whiteout */
177 /* a grob has to be visible, otherwise the whiteout property has no effect */
178 if (!transparent && to_boolean (get_property ("whiteout")))
180 /* Call the scheme procedure stencil-whiteout in scm/stencils.scm */
181 /* to add a round-filled-box stencil to the stencil list */
183 = *Stencil::unsmob (scm_call_1 (ly_lily_module_constant ("stencil-whiteout"),
184 retval.smobbed_copy ()));
187 SCM id = get_property ("id");
188 if (scm_is_string (id))
190 SCM expr = scm_list_3 (ly_symbol2scm ("id"),
194 retval = Stencil (retval.extent_box (), expr);
202 /****************************************************************
204 ****************************************************************/
206 Grob::do_break_processing ()
211 Grob::discretionary_processing ()
216 Grob::get_system () const
221 /* This version of get_system is more reliable than this->get_system ()
222 before line-breaking has been done, at which point there is only
223 one system in the whole score and we can find it just by following
226 Grob::get_system (Grob *me)
228 Grob *p = me->get_parent (X_AXIS);
229 return p ? get_system (p) : dynamic_cast<System *>(me);
233 Grob::handle_broken_dependencies ()
235 Spanner *sp = dynamic_cast<Spanner *> (this);
236 if (original () && sp)
240 /* THIS, SP is the original spanner. We use a special function
241 because some Spanners have enormously long lists in their
242 properties, and a special function fixes FOO */
244 for (SCM s = object_alist_; scm_is_pair (s); s = scm_cdr (s))
245 sp->substitute_one_mutable_property (scm_caar (s), scm_cdar (s));
247 System *system = get_system ();
251 && common_refpoint (system, X_AXIS)
252 && common_refpoint (system, Y_AXIS))
253 substitute_object_links (system->self_scm (), object_alist_);
254 else if (dynamic_cast<System *> (this))
255 substitute_object_links (SCM_UNDEFINED, object_alist_);
257 /* THIS element is `invalid'; it has been removed from all
258 dependencies, so let's junk the element itself.
260 Do not do this for System, since that would remove references
261 to the originals of score-grobs, which get then GC'd (a bad
266 /* Note that we still want references to this element to be
267 rearranged, and not silently thrown away, so we keep pointers like
268 {broken_into_{drul, array}, original}
276 for (int a = X_AXIS; a < NO_AXES; a++)
277 dim_cache_[a].clear ();
279 mutable_property_alist_ = SCM_EOL;
280 object_alist_ = SCM_EOL;
281 immutable_property_alist_ = SCM_EOL;
282 interfaces_ = SCM_EOL;
286 Grob::handle_prebroken_dependencies ()
288 /* Don't do this in the derived method, since we want to keep access to
289 object_alist_ centralized. */
292 Item *it = dynamic_cast<Item *> (this);
293 substitute_object_links (scm_from_int (it->break_status_dir ()),
294 original ()->object_alist_);
299 Grob::find_broken_piece (System *) const
304 /****************************************************************
306 ****************************************************************/
309 Grob::translate_axis (Real y, Axis a)
311 if (isinf (y) || isnan (y))
313 programming_error ("Infinity or NaN encountered");
317 if (!dim_cache_[a].offset_)
318 dim_cache_[a].offset_ = new Real (y);
320 *dim_cache_[a].offset_ += y;
323 /* Find the offset relative to D. If D equals THIS, then it is 0.
324 Otherwise, it recursively defd as
326 OFFSET_ + PARENT_L_->relative_coordinate (D) */
328 Grob::relative_coordinate (Grob const *refp, Axis a) const
330 /* eaa - hmmm, should we do a programming_error() here? */
331 if ((this == NULL) || (refp == this))
334 /* We catch PARENT_L_ == nil case with this, but we crash if we did
335 not ask for the absolute coordinate (ie. REFP == nil.) */
336 Real off = get_offset (a);
337 if (refp == dim_cache_[a].parent_)
340 off += dim_cache_[a].parent_->relative_coordinate (refp, a);
346 Grob::pure_relative_y_coordinate (Grob const *refp, int start, int end)
353 if (dim_cache_[Y_AXIS].offset_)
355 if (to_boolean (get_property ("pure-Y-offset-in-progress")))
356 programming_error ("cyclic chain in pure-Y-offset callbacks");
358 off = *dim_cache_[Y_AXIS].offset_;
362 SCM proc = get_property_data ("Y-offset");
364 dim_cache_[Y_AXIS].offset_ = new Real (0.0);
365 set_property ("pure-Y-offset-in-progress", SCM_BOOL_T);
366 off = robust_scm2double (call_pure_function (proc,
367 scm_list_1 (self_scm ()),
370 del_property ("pure-Y-offset-in-progress");
371 delete dim_cache_[Y_AXIS].offset_;
372 dim_cache_[Y_AXIS].offset_ = 0;
375 /* we simulate positioning-done if we are the child of a VerticalAlignment,
376 but only if we don't have a cached offset. If we do have a cached offset,
377 it probably means that the Alignment was fixed and it has already been
380 if (Grob *p = get_parent (Y_AXIS))
383 if (Align_interface::has_interface (p) && !dim_cache_[Y_AXIS].offset_)
384 trans = Align_interface::get_pure_child_y_translation (p, this, start, end);
386 return off + trans + p->pure_relative_y_coordinate (refp, start, end);
391 /* Invoke callbacks to get offset relative to parent. */
393 Grob::get_offset (Axis a) const
395 if (dim_cache_[a].offset_)
396 return *dim_cache_[a].offset_;
398 Grob *me = (Grob *) this;
400 SCM sym = axis_offset_symbol (a);
401 me->dim_cache_[a].offset_ = new Real (0.0);
404 UGH: can't fold next 2 statements together. Apparently GCC thinks
405 dim_cache_[a].offset_ is unaliased.
407 Real off = robust_scm2double (internal_get_property (sym), 0.0);
408 if (me->dim_cache_[a].offset_)
410 *me->dim_cache_[a].offset_ += off;
411 me->del_property (sym);
412 return *me->dim_cache_[a].offset_;
419 Grob::maybe_pure_coordinate (Grob const *refp, Axis a, bool pure, int start, int end)
421 if (pure && a != Y_AXIS)
422 programming_error ("tried to get pure X-offset");
423 return (pure && a == Y_AXIS) ? pure_relative_y_coordinate (refp, start, end)
424 : relative_coordinate (refp, a);
427 /****************************************************************
429 ****************************************************************/
432 Grob::flush_extent_cache (Axis axis)
434 if (dim_cache_[axis].extent_)
437 Ugh, this is not accurate; will flush property, causing
438 callback to be called if.
440 del_property ((axis == X_AXIS) ? ly_symbol2scm ("X-extent") : ly_symbol2scm ("Y-extent"));
441 delete dim_cache_[axis].extent_;
442 dim_cache_[axis].extent_ = 0;
443 if (get_parent (axis))
444 get_parent (axis)->flush_extent_cache (axis);
449 Grob::extent (Grob *refp, Axis a) const
451 Real offset = relative_coordinate (refp, a);
453 if (dim_cache_[a].extent_)
455 real_ext = *dim_cache_[a].extent_;
460 Order is significant: ?-extent may trigger suicide.
464 ? ly_symbol2scm ("X-extent")
465 : ly_symbol2scm ("Y-extent");
467 SCM ext = internal_get_property (ext_sym);
468 if (is_number_pair (ext))
469 real_ext.unite (ly_scm2interval (ext));
473 ? ly_symbol2scm ("minimum-X-extent")
474 : ly_symbol2scm ("minimum-Y-extent");
475 SCM min_ext = internal_get_property (min_ext_sym);
476 if (is_number_pair (min_ext))
477 real_ext.unite (ly_scm2interval (min_ext));
479 ((Grob *)this)->dim_cache_[a].extent_ = new Interval (real_ext);
482 // We never want nan, so we avoid shifting infinite values.
484 real_ext.translate(offset);
486 this->warning(_f ("ignored infinite %s-offset",
487 a == X_AXIS ? "X" : "Y"));
493 Grob::pure_height (Grob *refp, int start, int end)
495 SCM iv_scm = get_pure_property ("Y-extent", start, end);
496 Interval iv = robust_scm2interval (iv_scm, Interval ());
497 Real offset = pure_relative_y_coordinate (refp, start, end);
499 SCM min_ext = get_property ("minimum-Y-extent");
501 /* we don't add minimum-Y-extent if the extent is empty. This solves
502 a problem with Hara-kiri spanners. They would request_suicide and
503 return empty extents, but we would force them here to be large. */
504 if (!iv.is_empty () && is_number_pair (min_ext))
505 iv.unite (ly_scm2interval (min_ext));
508 iv.translate (offset);
513 Grob::maybe_pure_extent (Grob *refp, Axis a, bool pure, int start, int end)
515 return (pure && a == Y_AXIS) ? pure_height (refp, start, end) : extent (refp, a);
519 Grob::spanned_rank_interval () const
521 return Interval_t<int> (-1, 0);
525 Grob::pure_is_visible (int /* start */, int /* end */) const
530 /* Sort grobs according to their starting column. */
532 Grob::less (Grob *g1, Grob *g2)
534 return g1->spanned_rank_interval ()[LEFT] < g2->spanned_rank_interval ()[LEFT];
537 /****************************************************************
539 ****************************************************************/
541 /* Find the group-element which has both #this# and #s# */
543 Grob::common_refpoint (Grob const *s, Axis a) const
546 /* Catching the trivial cases is likely costlier than just running
547 through: one can't avoid going to the respective chain ends
548 anyway. We might save the second run through when the chain ends
549 differ, but keeping track of the ends makes the loop more costly.
556 for (c = this; c; ++balance)
557 c = c->dim_cache_[a].parent_;
559 for (d = s; d; --balance)
560 d = d->dim_cache_[a].parent_;
562 /* Cut down ancestry to same size */
564 for (c = this; balance > 0; --balance)
565 c = c->dim_cache_[a].parent_;
567 for (d = s; balance < 0; ++balance)
568 d = d->dim_cache_[a].parent_;
570 /* Now find point where our lineages converge */
573 c = c->dim_cache_[a].parent_;
574 d = d->dim_cache_[a].parent_;
581 Grob::set_parent (Grob *g, Axis a)
583 dim_cache_[a].parent_ = g;
587 Grob::get_parent (Axis a) const
589 return dim_cache_[a].parent_;
593 Grob::fixup_refpoint ()
595 for (int a = X_AXIS; a < NO_AXES; a++)
598 Grob *parent = get_parent (ax);
603 if (parent->get_system () != get_system () && get_system ())
605 Grob *newparent = parent->find_broken_piece (get_system ());
606 set_parent (newparent, ax);
609 if (Item *i = dynamic_cast<Item *> (this))
611 Item *parenti = dynamic_cast<Item *> (parent);
615 Direction my_dir = i->break_status_dir ();
616 if (my_dir != parenti->break_status_dir ())
618 Item *newparent = parenti->find_prebroken_piece (my_dir);
619 set_parent (newparent, ax);
626 /****************************************************************
628 ****************************************************************/
631 get_maybe_root_vertical_alignment (Grob *g, Grob *maybe)
635 if (Align_interface::has_interface (g))
636 return get_maybe_root_vertical_alignment (g->get_parent (Y_AXIS), g);
637 return get_maybe_root_vertical_alignment (g->get_parent (Y_AXIS), maybe);
642 Grob::get_root_vertical_alignment (Grob *g)
644 return get_maybe_root_vertical_alignment (g, 0);
648 Grob::get_vertical_axis_group (Grob *g)
652 if (!g->get_parent (Y_AXIS))
654 if (Axis_group_interface::has_interface (g)
655 && Align_interface::has_interface (g->get_parent (Y_AXIS)))
657 return get_vertical_axis_group (g->get_parent (Y_AXIS));
662 Grob::get_vertical_axis_group_index (Grob *g)
664 Grob *val = get_root_vertical_alignment (g);
667 Grob *vax = get_vertical_axis_group (g);
668 extract_grob_set (val, "elements", elts);
669 for (vsize i = 0; i < elts.size (); i++)
672 g->programming_error ("could not find this grob's vertical axis group in the vertical alignment");
677 Grob::vertical_less (Grob *g1, Grob *g2)
679 return internal_vertical_less (g1, g2, false);
683 Grob::pure_vertical_less (Grob *g1, Grob *g2)
685 return internal_vertical_less (g1, g2, true);
689 Grob::internal_vertical_less (Grob *g1, Grob *g2, bool pure)
691 Grob *vag = get_root_vertical_alignment (g1);
694 g1->programming_error ("grob does not belong to a VerticalAlignment?");
698 Grob *ag1 = get_vertical_axis_group (g1);
699 Grob *ag2 = get_vertical_axis_group (g2);
701 extract_grob_set (vag, "elements", elts);
703 if (ag1 == ag2 && !pure)
705 Grob *common = g1->common_refpoint (g2, Y_AXIS);
706 return g1->relative_coordinate (common, Y_AXIS) > g2->relative_coordinate (common, Y_AXIS);
709 for (vsize i = 0; i < elts.size (); i++)
717 g1->programming_error ("could not place this grob in its axis group");
721 /****************************************************************
723 ****************************************************************/
725 Grob::programming_error (const string &s) const
727 SCM cause = self_scm ();
728 while (Grob *g = Grob::unsmob (cause))
729 cause = g->get_property ("cause");
731 /* ES TODO: cause can't be Music*/
732 if (Music *m = Music::unsmob (cause))
733 m->origin ()->programming_error (s);
734 else if (Stream_event *ev = Stream_event::unsmob (cause))
735 ev->origin ()->programming_error (s);
737 ::programming_error (s);
741 Grob::warning (const string &s) const
743 SCM cause = self_scm ();
744 while (Grob *g = Grob::unsmob (cause))
745 cause = g->get_property ("cause");
747 /* ES TODO: cause can't be Music*/
748 if (Music *m = Music::unsmob (cause))
749 m->origin ()->warning (s);
750 else if (Stream_event *ev = Stream_event::unsmob (cause))
751 ev->origin ()->warning (s);
759 SCM meta = get_property ("meta");
760 SCM nm = scm_assq (ly_symbol2scm ("name"), meta);
761 nm = (scm_is_pair (nm)) ? scm_cdr (nm) : SCM_EOL;
762 return scm_is_symbol (nm) ? ly_symbol2string (nm) : this->class_name ();
766 "A grob represents a piece of music notation.\n"
768 "All grobs have an X and Y@tie{}position on the page. These"
769 " X and Y@tie{}positions are stored in a relative format, thus"
770 " they can easily be combined by stacking them, hanging one"
771 " grob to the side of another, or coupling them into grouping"
774 "Each grob has a reference point (a.k.a.@: parent): The"
775 " position of a grob is stored relative to that reference"
776 " point. For example, the X@tie{}reference point of a staccato"
777 " dot usually is the note head that it applies to. When the"
778 " note head is moved, the staccato dot moves along"
781 "A grob is often associated with a symbol, but some grobs do"
782 " not print any symbols. They take care of grouping objects."
783 " For example, there is a separate grob that stacks staves"
784 " vertically. The @ref{NoteCollision} object is also an"
785 " abstract grob: It only moves around chords, but doesn't print"
788 "Grobs have properties (Scheme variables) that can be read and"
789 " set. Two types of them exist: immutable and mutable."
790 " Immutable variables define the default style and behavior."
791 " They are shared between many objects. They can be changed"
792 " using @code{\\override} and @code{\\revert}. Mutable"
793 " properties are variables that are specific to one grob."
794 " Typically, lists of other objects, or results from"
795 " computations are stored in mutable properties. In"
796 " particular, every call to @code{ly:grob-set-property!}"
797 " (or its C++ equivalent) sets a mutable property.\n"
799 "The properties @code{after-line-breaking} and"
800 " @code{before-line-breaking} are dummies that are not"
801 " user-serviceable.",
808 "after-line-breaking "
810 "axis-group-parent-X "
811 "axis-group-parent-Y "
812 "before-line-breaking "
820 "horizontal-skylines "
826 "pure-Y-offset-in-progress "
828 "skyline-horizontal-padding "
837 /****************************************************************
839 ****************************************************************/
842 grob_stencil_extent (Grob *me, Axis a)
844 Stencil *m = me->get_stencil ();
848 return ly_interval2scm (e);
851 MAKE_SCHEME_CALLBACK (Grob, stencil_height, 1);
853 Grob::stencil_height (SCM smob)
855 Grob *me = Grob::unsmob (smob);
856 return grob_stencil_extent (me, Y_AXIS);
859 MAKE_SCHEME_CALLBACK (Grob, pure_stencil_height, 3);
861 Grob::pure_stencil_height (SCM smob, SCM /* beg */, SCM /* end */)
863 Grob *me = Grob::unsmob (smob);
864 if (Stencil::unsmob (me->get_property_data ("stencil")))
865 return grob_stencil_extent (me, Y_AXIS);
867 return ly_interval2scm (Interval ());
871 MAKE_SCHEME_CALLBACK (Grob, y_parent_positioning, 1);
873 Grob::y_parent_positioning (SCM smob)
875 Grob *me = Grob::unsmob (smob);
876 Grob *par = me->get_parent (Y_AXIS);
878 (void) par->get_property ("positioning-done");
880 return scm_from_double (0.0);
883 MAKE_SCHEME_CALLBACK (Grob, x_parent_positioning, 1);
885 Grob::x_parent_positioning (SCM smob)
887 Grob *me = Grob::unsmob (smob);
889 Grob *par = me->get_parent (X_AXIS);
891 (void) par->get_property ("positioning-done");
893 return scm_from_double (0.0);
896 MAKE_SCHEME_CALLBACK (Grob, stencil_width, 1);
898 Grob::stencil_width (SCM smob)
900 Grob *me = Grob::unsmob (smob);
901 return grob_stencil_extent (me, X_AXIS);
905 common_refpoint_of_list (SCM elist, Grob *common, Axis a)
907 for (; scm_is_pair (elist); elist = scm_cdr (elist))
908 if (Grob *s = Grob::unsmob (scm_car (elist)))
911 common = common->common_refpoint (s, a);
920 common_refpoint_of_array (vector<Grob *> const &arr, Grob *common, Axis a)
922 for (vsize i = 0; i < arr.size (); i++)
924 common = common->common_refpoint (arr[i], a);
932 common_refpoint_of_array (set<Grob *> const &arr, Grob *common, Axis a)
934 set<Grob *>::iterator it;
936 for (it = arr.begin (); it != arr.end (); it++)
938 common = common->common_refpoint (*it, a);
946 robust_relative_extent (Grob *me, Grob *refpoint, Axis a)
948 Interval ext = me->extent (refpoint, a);
950 ext.add_point (me->relative_coordinate (refpoint, a));
955 // Checks whether there is a vertical alignment in the chain of
956 // parents between this and commony.
958 Grob::check_cross_staff (Grob *commony)
960 if (Align_interface::has_interface (commony))
963 for (Grob *g = this; g && g != commony; g = g->get_parent (Y_AXIS))
964 if (Align_interface::has_interface (g))
972 indirect_less (Grob **a, Grob **b)
974 // Use original order as tie breaker. That gives us a stable sort
975 // at the lower price tag of an unstable one, and we want a stable
976 // sort in order to reliably retain the first instance of a grob
978 return *a < *b || (*a == *b && a < b);
983 indirect_eq (Grob **a, Grob **b)
990 direct_less (Grob **a, Grob **b)
995 // uniquify uniquifies on the memory addresses of the Grobs, but then
996 // uses the original order. This makes results independent from the
997 // memory allocation of Grobs.
1000 uniquify (vector <Grob *> & grobs)
1002 vector <Grob **> vec (grobs.size ());
1003 for (vsize i = 0; i < grobs.size (); i++)
1005 vector_sort (vec, indirect_less);
1006 vec.erase (unique (vec.begin (), vec.end (), indirect_eq), vec.end ());
1007 vector_sort (vec, direct_less);
1009 // Since the output is a sorted copy of the input with some elements
1010 // removed, we can fill in the vector in-place if we do it starting
1012 for (vsize i = 0; i < vec.size (); i++)
1014 grobs.erase (grobs.begin () + vec.size (), grobs.end ());