]> git.donarmstrong.com Git - lilypond.git/blob - lily/grob.cc
Don't assign 'safe' values to self_scm_ outside of smobify_self
[lilypond.git] / lily / grob.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1997--2014 Han-Wen Nienhuys <hanwen@xs4all.nl>
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 "grob.hh"
21
22 #include <cstring>
23 #include <set>
24
25 #include "align-interface.hh"
26 #include "axis-group-interface.hh"
27 #include "input.hh"
28 #include "international.hh"
29 #include "item.hh"
30 #include "main.hh"
31 #include "misc.hh"
32 #include "music.hh"
33 #include "output-def.hh"
34 #include "pointer-group-interface.hh"
35 #include "program-option.hh"
36 #include "stencil.hh"
37 #include "stream-event.hh"
38 #include "system.hh"
39 #include "unpure-pure-container.hh"
40 #include "warn.hh"
41
42 #include "ly-smobs.icc"
43
44 Grob *
45 Grob::clone () const
46 {
47   return new Grob (*this);
48 }
49
50 Grob::Grob (SCM basicprops)
51 {
52
53   /* FIXME: default should be no callback.  */
54   layout_ = 0;
55   original_ = 0;
56   interfaces_ = SCM_EOL;
57   immutable_property_alist_ = basicprops;
58   mutable_property_alist_ = SCM_EOL;
59   object_alist_ = SCM_EOL;
60
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.  */
64   smobify_self ();
65
66   SCM meta = get_property ("meta");
67   if (scm_is_pair (meta))
68     {
69       interfaces_ = scm_cdr (scm_assq (ly_symbol2scm ("interfaces"), meta));
70
71       SCM object_cbs = scm_assq (ly_symbol2scm ("object-callbacks"), meta);
72       if (scm_is_pair (object_cbs))
73         {
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));
76         }
77     }
78
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));
93 }
94
95 Grob::Grob (Grob const &s)
96 {
97   original_ = (Grob *) & s;
98
99   immutable_property_alist_ = s.immutable_property_alist_;
100   mutable_property_alist_ = SCM_EOL;
101
102   for (Axis a = X_AXIS; a < NO_AXES; incr (a))
103       dim_cache_ [a] = s.dim_cache_ [a];
104
105   interfaces_ = s.interfaces_;
106   object_alist_ = SCM_EOL;
107
108   layout_ = 0;
109
110   smobify_self ();
111
112   mutable_property_alist_ = ly_deep_copy (s.mutable_property_alist_);
113
114 }
115
116 Grob::~Grob ()
117 {
118 }
119 /****************************************************************
120   STENCILS
121 ****************************************************************/
122
123 Stencil *
124 Grob::get_stencil () const
125 {
126   if (!is_live ())
127     return 0;
128
129   SCM stil = get_property ("stencil");
130   return Stencil::unsmob (stil);
131 }
132
133 Stencil
134 Grob::get_print_stencil () const
135 {
136   SCM stil = get_property ("stencil");
137
138   Stencil retval;
139   if (Stencil *m = Stencil::unsmob (stil))
140     {
141       retval = *m;
142       bool transparent = to_boolean (get_property ("transparent"));
143
144       if (transparent)
145         retval = Stencil (m->extent_box (), SCM_EOL);
146       else
147         {
148           SCM expr = m->expr ();
149           expr = scm_list_3 (ly_symbol2scm ("grob-cause"),
150                              self_scm (), expr);
151
152           retval = Stencil (m->extent_box (), expr);
153         }
154
155       SCM rot = get_property ("rotation");
156       if (scm_is_pair (rot))
157         {
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));
161
162           retval.rotate_degrees (angle, Offset (x, y));
163         }
164
165       /* color support... see interpret_stencil_expression () for more... */
166       SCM color = get_property ("color");
167       if (scm_is_pair (color))
168         {
169           SCM expr = scm_list_3 (ly_symbol2scm ("color"),
170                                  color,
171                                  retval.expr ());
172
173           retval = Stencil (retval.extent_box (), expr);
174         }
175
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")))
179         {
180           /* Call the scheme procedure stencil-whiteout in scm/stencils.scm */
181           /* to add a round-filled-box stencil to the stencil list */
182           retval
183             = *Stencil::unsmob (scm_call_1 (ly_lily_module_constant ("stencil-whiteout"),
184                                            retval.smobbed_copy ()));
185         }
186
187       SCM id = get_property ("id");
188       if (scm_is_string (id))
189         {
190           SCM expr = scm_list_3 (ly_symbol2scm ("id"),
191                                  id,
192                                  retval.expr ());
193
194           retval = Stencil (retval.extent_box (), expr);
195         }
196
197     }
198
199   return retval;
200 }
201
202 /****************************************************************
203   VIRTUAL STUBS
204 ****************************************************************/
205 void
206 Grob::do_break_processing ()
207 {
208 }
209
210 void
211 Grob::discretionary_processing ()
212 {
213 }
214
215 System *
216 Grob::get_system () const
217 {
218   return 0;
219 }
220
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
224    parent pointers. */
225 System *
226 Grob::get_system (Grob *me)
227 {
228   Grob *p = me->get_parent (X_AXIS);
229   return p ? get_system (p) : dynamic_cast<System *>(me);
230 }
231
232 void
233 Grob::handle_broken_dependencies ()
234 {
235   Spanner *sp = dynamic_cast<Spanner *> (this);
236   if (original () && sp)
237     return;
238
239   if (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  */
243     {
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));
246     }
247   System *system = get_system ();
248
249   if (is_live ()
250       && 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_);
256   else
257     /* THIS element is `invalid'; it has been removed from all
258        dependencies, so let's junk the element itself.
259
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
262        thing).  */
263     suicide ();
264 }
265
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}
269 */
270 void
271 Grob::suicide ()
272 {
273   if (!is_live ())
274     return;
275
276   for (int a = X_AXIS; a < NO_AXES; a++)
277     dim_cache_[a].clear ();
278
279   mutable_property_alist_ = SCM_EOL;
280   object_alist_ = SCM_EOL;
281   immutable_property_alist_ = SCM_EOL;
282   interfaces_ = SCM_EOL;
283 }
284
285 void
286 Grob::handle_prebroken_dependencies ()
287 {
288   /* Don't do this in the derived method, since we want to keep access to
289      object_alist_ centralized.  */
290   if (original ())
291     {
292       Item *it = dynamic_cast<Item *> (this);
293       substitute_object_links (scm_from_int (it->break_status_dir ()),
294                                original ()->object_alist_);
295     }
296 }
297
298 Grob *
299 Grob::find_broken_piece (System *) const
300 {
301   return 0;
302 }
303
304 /****************************************************************
305    OFFSETS
306 ****************************************************************/
307
308 void
309 Grob::translate_axis (Real y, Axis a)
310 {
311   if (isinf (y) || isnan (y))
312     {
313       programming_error ("Infinity or NaN encountered");
314       return;
315     }
316
317   if (!dim_cache_[a].offset_)
318     dim_cache_[a].offset_ = new Real (y);
319   else
320     *dim_cache_[a].offset_ += y;
321 }
322
323 /* Find the offset relative to D.  If D equals THIS, then it is 0.
324    Otherwise, it recursively defd as
325
326    OFFSET_ + PARENT_L_->relative_coordinate (D) */
327 Real
328 Grob::relative_coordinate (Grob const *refp, Axis a) const
329 {
330   /* eaa - hmmm, should we do a programming_error() here? */
331   if ((this == NULL) || (refp == this))
332     return 0.0;
333
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_)
338     return off;
339
340   off += dim_cache_[a].parent_->relative_coordinate (refp, a);
341
342   return off;
343 }
344
345 Real
346 Grob::pure_relative_y_coordinate (Grob const *refp, int start, int end)
347 {
348   if (refp == this)
349     return 0.0;
350
351   Real off = 0;
352
353   if (dim_cache_[Y_AXIS].offset_)
354     {
355       if (to_boolean (get_property ("pure-Y-offset-in-progress")))
356         programming_error ("cyclic chain in pure-Y-offset callbacks");
357
358       off = *dim_cache_[Y_AXIS].offset_;
359     }
360   else
361     {
362       SCM proc = get_property_data ("Y-offset");
363
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 ()),
368                                                    start, end),
369                                0.0);
370       del_property ("pure-Y-offset-in-progress");
371       delete dim_cache_[Y_AXIS].offset_;
372       dim_cache_[Y_AXIS].offset_ = 0;
373     }
374
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
378      calculated.
379   */
380   if (Grob *p = get_parent (Y_AXIS))
381     {
382       Real trans = 0;
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);
385
386       return off + trans + p->pure_relative_y_coordinate (refp, start, end);
387     }
388   return off;
389 }
390
391 /* Invoke callbacks to get offset relative to parent.  */
392 Real
393 Grob::get_offset (Axis a) const
394 {
395   if (dim_cache_[a].offset_)
396     return *dim_cache_[a].offset_;
397
398   Grob *me = (Grob *) this;
399
400   SCM sym = axis_offset_symbol (a);
401   me->dim_cache_[a].offset_ = new Real (0.0);
402
403   /*
404     UGH: can't fold next 2 statements together. Apparently GCC thinks
405     dim_cache_[a].offset_ is unaliased.
406   */
407   Real off = robust_scm2double (internal_get_property (sym), 0.0);
408   if (me->dim_cache_[a].offset_)
409     {
410       *me->dim_cache_[a].offset_ += off;
411       me->del_property (sym);
412       return *me->dim_cache_[a].offset_;
413     }
414   else
415     return 0.0;
416 }
417
418 Real
419 Grob::maybe_pure_coordinate (Grob const *refp, Axis a, bool pure, int start, int end)
420 {
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);
425 }
426
427 /****************************************************************
428   extents
429 ****************************************************************/
430
431 void
432 Grob::flush_extent_cache (Axis axis)
433 {
434   if (dim_cache_[axis].extent_)
435     {
436       /*
437         Ugh, this is not accurate; will flush property, causing
438         callback to be called if.
439        */
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);
445     }
446 }
447
448 Interval
449 Grob::extent (Grob *refp, Axis a) const
450 {
451   Real offset = relative_coordinate (refp, a);
452   Interval real_ext;
453   if (dim_cache_[a].extent_)
454     {
455       real_ext = *dim_cache_[a].extent_;
456     }
457   else
458     {
459       /*
460         Order is significant: ?-extent may trigger suicide.
461        */
462       SCM ext_sym
463         = (a == X_AXIS)
464           ? ly_symbol2scm ("X-extent")
465           : ly_symbol2scm ("Y-extent");
466
467       SCM ext = internal_get_property (ext_sym);
468       if (is_number_pair (ext))
469         real_ext.unite (ly_scm2interval (ext));
470
471       SCM min_ext_sym
472         = (a == X_AXIS)
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));
478
479       ((Grob *)this)->dim_cache_[a].extent_ = new Interval (real_ext);
480     }
481
482   // We never want nan, so we avoid shifting infinite values.
483     if(!isinf (offset))
484       real_ext.translate(offset);
485     else
486       this->warning(_f ("ignored infinite %s-offset",
487                         a == X_AXIS ? "X" : "Y"));
488
489   return real_ext;
490 }
491
492 Interval
493 Grob::pure_height (Grob *refp, int start, int end)
494 {
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);
498
499   SCM min_ext = get_property ("minimum-Y-extent");
500
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));
506
507   if (!iv.is_empty ())
508     iv.translate (offset);
509   return iv;
510 }
511
512 Interval
513 Grob::maybe_pure_extent (Grob *refp, Axis a, bool pure, int start, int end)
514 {
515   return (pure && a == Y_AXIS) ? pure_height (refp, start, end) : extent (refp, a);
516 }
517
518 Interval_t<int>
519 Grob::spanned_rank_interval () const
520 {
521   return Interval_t<int> (-1, 0);
522 }
523
524 bool
525 Grob::pure_is_visible (int /* start */, int /* end */) const
526 {
527   return true;
528 }
529
530 /* Sort grobs according to their starting column. */
531 bool
532 Grob::less (Grob *g1, Grob *g2)
533 {
534   return g1->spanned_rank_interval ()[LEFT] < g2->spanned_rank_interval ()[LEFT];
535 }
536
537 /****************************************************************
538   REFPOINTS
539 ****************************************************************/
540
541 /* Find the group-element which has both #this# and #s#  */
542 Grob *
543 Grob::common_refpoint (Grob const *s, Axis a) const
544 {
545
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.
550   */
551
552   int balance = 0;
553   Grob const *c;
554   Grob const *d;
555
556   for (c = this; c; ++balance)
557     c = c->dim_cache_[a].parent_;
558
559   for (d = s; d; --balance)
560     d = d->dim_cache_[a].parent_;
561
562   /* Cut down ancestry to same size */
563
564   for (c = this; balance > 0; --balance)
565     c = c->dim_cache_[a].parent_;
566
567   for (d = s; balance < 0; ++balance)
568     d = d->dim_cache_[a].parent_;
569
570   /* Now find point where our lineages converge */
571   while (c != d)
572     {
573       c = c->dim_cache_[a].parent_;
574       d = d->dim_cache_[a].parent_;
575     }
576
577   return (Grob *) c;
578 }
579
580 void
581 Grob::set_parent (Grob *g, Axis a)
582 {
583   dim_cache_[a].parent_ = g;
584 }
585
586 Grob *
587 Grob::get_parent (Axis a) const
588 {
589   return dim_cache_[a].parent_;
590 }
591
592 void
593 Grob::fixup_refpoint ()
594 {
595   for (int a = X_AXIS; a < NO_AXES; a++)
596     {
597       Axis ax = (Axis)a;
598       Grob *parent = get_parent (ax);
599
600       if (!parent)
601         continue;
602
603       if (parent->get_system () != get_system () && get_system ())
604         {
605           Grob *newparent = parent->find_broken_piece (get_system ());
606           set_parent (newparent, ax);
607         }
608
609       if (Item *i = dynamic_cast<Item *> (this))
610         {
611           Item *parenti = dynamic_cast<Item *> (parent);
612
613           if (parenti && i)
614             {
615               Direction my_dir = i->break_status_dir ();
616               if (my_dir != parenti->break_status_dir ())
617                 {
618                   Item *newparent = parenti->find_prebroken_piece (my_dir);
619                   set_parent (newparent, ax);
620                 }
621             }
622         }
623     }
624 }
625
626 /****************************************************************
627   VERTICAL ORDERING
628 ****************************************************************/
629
630 Grob *
631 get_maybe_root_vertical_alignment (Grob *g, Grob *maybe)
632 {
633   if (!g)
634     return 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);
638
639 }
640
641 Grob *
642 Grob::get_root_vertical_alignment (Grob *g)
643 {
644   return get_maybe_root_vertical_alignment (g, 0);
645 }
646
647 Grob *
648 Grob::get_vertical_axis_group (Grob *g)
649 {
650   if (!g)
651     return 0;
652   if (!g->get_parent (Y_AXIS))
653     return 0;
654   if (Axis_group_interface::has_interface (g)
655       && Align_interface::has_interface (g->get_parent (Y_AXIS)))
656     return g;
657   return get_vertical_axis_group (g->get_parent (Y_AXIS));
658
659 }
660
661 int
662 Grob::get_vertical_axis_group_index (Grob *g)
663 {
664   Grob *val = get_root_vertical_alignment (g);
665   if (!val)
666     return -1;
667   Grob *vax = get_vertical_axis_group (g);
668   extract_grob_set (val, "elements", elts);
669   for (vsize i = 0; i < elts.size (); i++)
670     if (elts[i] == vax)
671       return (int) i;
672   g->programming_error ("could not find this grob's vertical axis group in the vertical alignment");
673   return -1;
674 }
675
676 bool
677 Grob::vertical_less (Grob *g1, Grob *g2)
678 {
679   return internal_vertical_less (g1, g2, false);
680 }
681
682 bool
683 Grob::pure_vertical_less (Grob *g1, Grob *g2)
684 {
685   return internal_vertical_less (g1, g2, true);
686 }
687
688 bool
689 Grob::internal_vertical_less (Grob *g1, Grob *g2, bool pure)
690 {
691   Grob *vag = get_root_vertical_alignment (g1);
692   if (!vag)
693     {
694       g1->programming_error ("grob does not belong to a VerticalAlignment?");
695       return false;
696     }
697
698   Grob *ag1 = get_vertical_axis_group (g1);
699   Grob *ag2 = get_vertical_axis_group (g2);
700
701   extract_grob_set (vag, "elements", elts);
702
703   if (ag1 == ag2 && !pure)
704     {
705       Grob *common = g1->common_refpoint (g2, Y_AXIS);
706       return g1->relative_coordinate (common, Y_AXIS) > g2->relative_coordinate (common, Y_AXIS);
707     }
708
709   for (vsize i = 0; i < elts.size (); i++)
710     {
711       if (elts[i] == ag1)
712         return true;
713       if (elts[i] == ag2)
714         return false;
715     }
716
717   g1->programming_error ("could not place this grob in its axis group");
718   return false;
719 }
720
721 /****************************************************************
722   MESSAGES
723 ****************************************************************/
724 void
725 Grob::programming_error (const string &s) const
726 {
727   SCM cause = self_scm ();
728   while (Grob *g = Grob::unsmob (cause))
729     cause = g->get_property ("cause");
730
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);
736   else
737     ::programming_error (s);
738 }
739
740 void
741 Grob::warning (const string &s) const
742 {
743   SCM cause = self_scm ();
744   while (Grob *g = Grob::unsmob (cause))
745     cause = g->get_property ("cause");
746
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);
752   else
753     ::warning (s);
754 }
755
756 string
757 Grob::name () const
758 {
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 ();
763 }
764
765 ADD_INTERFACE (Grob,
766                "A grob represents a piece of music notation.\n"
767                "\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"
772                " objects.\n"
773                "\n"
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"
779                " automatically.\n"
780                "\n"
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"
786                " anything.\n"
787                "\n"
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"
798                "\n"
799                "The properties @code{after-line-breaking} and"
800                " @code{before-line-breaking} are dummies that are not"
801                " user-serviceable.",
802
803                /* properties */
804                "X-extent "
805                "X-offset "
806                "Y-extent "
807                "Y-offset "
808                "after-line-breaking "
809                "avoid-slur "
810                "axis-group-parent-X "
811                "axis-group-parent-Y "
812                "before-line-breaking "
813                "cause "
814                "color "
815                "cross-staff "
816                "id "
817                "extra-offset "
818                "footnote-music "
819                "forced-spacing "
820                "horizontal-skylines "
821                "interfaces "
822                "layer "
823                "meta "
824                "minimum-X-extent "
825                "minimum-Y-extent "
826                "pure-Y-offset-in-progress "
827                "rotation "
828                "skyline-horizontal-padding "
829                "springs-and-rods "
830                "staff-symbol "
831                "stencil "
832                "transparent "
833                "vertical-skylines "
834                "whiteout "
835               );
836
837 /****************************************************************
838   CALLBACKS
839 ****************************************************************/
840
841 static SCM
842 grob_stencil_extent (Grob *me, Axis a)
843 {
844   Stencil *m = me->get_stencil ();
845   Interval e;
846   if (m)
847     e = m->extent (a);
848   return ly_interval2scm (e);
849 }
850
851 MAKE_SCHEME_CALLBACK (Grob, stencil_height, 1);
852 SCM
853 Grob::stencil_height (SCM smob)
854 {
855   Grob *me = Grob::unsmob (smob);
856   return grob_stencil_extent (me, Y_AXIS);
857 }
858
859 MAKE_SCHEME_CALLBACK (Grob, pure_stencil_height, 3);
860 SCM
861 Grob::pure_stencil_height (SCM smob, SCM /* beg */, SCM /* end */)
862 {
863   Grob *me = Grob::unsmob (smob);
864   if (Stencil::unsmob (me->get_property_data ("stencil")))
865     return grob_stencil_extent (me, Y_AXIS);
866
867   return ly_interval2scm (Interval ());
868
869 }
870
871 MAKE_SCHEME_CALLBACK (Grob, y_parent_positioning, 1);
872 SCM
873 Grob::y_parent_positioning (SCM smob)
874 {
875   Grob *me = Grob::unsmob (smob);
876   Grob *par = me->get_parent (Y_AXIS);
877   if (par)
878     (void) par->get_property ("positioning-done");
879
880   return scm_from_double (0.0);
881 }
882
883 MAKE_SCHEME_CALLBACK (Grob, x_parent_positioning, 1);
884 SCM
885 Grob::x_parent_positioning (SCM smob)
886 {
887   Grob *me = Grob::unsmob (smob);
888
889   Grob *par = me->get_parent (X_AXIS);
890   if (par)
891     (void) par->get_property ("positioning-done");
892
893   return scm_from_double (0.0);
894 }
895
896 MAKE_SCHEME_CALLBACK (Grob, stencil_width, 1);
897 SCM
898 Grob::stencil_width (SCM smob)
899 {
900   Grob *me = Grob::unsmob (smob);
901   return grob_stencil_extent (me, X_AXIS);
902 }
903
904 Grob *
905 common_refpoint_of_list (SCM elist, Grob *common, Axis a)
906 {
907   for (; scm_is_pair (elist); elist = scm_cdr (elist))
908     if (Grob *s = Grob::unsmob (scm_car (elist)))
909       {
910         if (common)
911           common = common->common_refpoint (s, a);
912         else
913           common = s;
914       }
915
916   return common;
917 }
918
919 Grob *
920 common_refpoint_of_array (vector<Grob *> const &arr, Grob *common, Axis a)
921 {
922   for (vsize i = 0; i < arr.size (); i++)
923     if (common)
924       common = common->common_refpoint (arr[i], a);
925     else
926       common = arr[i];
927
928   return common;
929 }
930
931 Grob *
932 common_refpoint_of_array (set<Grob *> const &arr, Grob *common, Axis a)
933 {
934   set<Grob *>::iterator it;
935
936   for (it = arr.begin (); it != arr.end (); it++)
937     if (common)
938       common = common->common_refpoint (*it, a);
939     else
940       common = *it;
941
942   return common;
943 }
944
945 Interval
946 robust_relative_extent (Grob *me, Grob *refpoint, Axis a)
947 {
948   Interval ext = me->extent (refpoint, a);
949   if (ext.is_empty ())
950     ext.add_point (me->relative_coordinate (refpoint, a));
951
952   return ext;
953 }
954
955 // Checks whether there is a vertical alignment in the chain of
956 // parents between this and commony.
957 bool
958 Grob::check_cross_staff (Grob *commony)
959 {
960   if (Align_interface::has_interface (commony))
961     return true;
962
963   for (Grob *g = this; g && g != commony; g = g->get_parent (Y_AXIS))
964     if (Align_interface::has_interface (g))
965       return true;
966
967   return false;
968 }
969
970 static
971 bool
972 indirect_less (Grob **a, Grob **b)
973 {
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
977   // pointer.
978   return *a < *b || (*a == *b && a < b);
979 }
980
981 static
982 bool
983 indirect_eq (Grob **a, Grob **b)
984 {
985   return *a == *b;
986 }
987
988 static
989 bool
990 direct_less (Grob **a, Grob **b)
991 {
992   return a < b;
993 }
994
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.
998
999 void
1000 uniquify (vector <Grob *> & grobs)
1001 {
1002   vector <Grob **> vec (grobs.size ());
1003   for (vsize i = 0; i < grobs.size (); i++)
1004     vec[i] = &grobs[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);
1008
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
1011   // from the front.
1012   for (vsize i = 0; i < vec.size (); i++)
1013     grobs[i] = *vec[i];
1014   grobs.erase (grobs.begin () + vec.size (), grobs.end ());
1015   return;
1016 }