]> git.donarmstrong.com Git - lilypond.git/blob - lily/vaticana-ligature-engraver.cc
Fix ending the dynamic extent in Text_interface::interpret_markup
[lilypond.git] / lily / vaticana-ligature-engraver.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 2003--2015 Juergen Reuter <reuter@ipd.uka.de>
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 "gregorian-ligature-engraver.hh"
21
22 #include "font-interface.hh"
23 #include "gregorian-ligature.hh"
24 #include "international.hh"
25 #include "output-def.hh"
26 #include "paper-column.hh"
27 #include "separation-item.hh"
28 #include "spanner.hh"
29 #include "staff-symbol-referencer.hh"
30 #include "stream-event.hh"
31 #include "vaticana-ligature.hh"
32 #include "warn.hh"
33 #include "dot-column.hh"
34 #include "rhythmic-head.hh"
35 #include "pitch.hh"
36 #include "translator.icc"
37
38 /*
39  * This class implements the notation specific aspects of Vaticana
40  * style ligatures for Gregorian chant notation.
41  */
42
43 /*
44  * TODO: Maybe move handling of dots/mora to
45  * Gregorian_ligature_engraver?  It's probably common for all types of
46  * Gregorian chant notation that have dotted notes.
47  *
48  * FIXME: The horizontal alignment of the mora column is bad (too far
49  * to the left), if the last dotted note is not the last primitive in
50  * the ligature.  Fortunately, in practice this bug should have no
51  * negative impact, since dotted notes appear within a ligature
52  * usually always at the end of the ligature, such that the bug never
53  * should apply for valid ligatures.
54  *
55  * TODO: Graduale Triplex, tempus per annum, hebdomada septima,
56  * alleluia (page 280) shows a counter-example for collecting dots
57  * always in a single column behind the ligature.  Maybe only the last
58  * two dots in a ligature should be collected and all other dots put
59  * behind or on top of the head?
60  */
61 class Vaticana_ligature_engraver : public Gregorian_ligature_engraver
62 {
63
64 private:
65   static bool
66   need_extra_horizontal_space (int prev_prefix_set, int prefix_set,
67                                int context_info, int delta_pitch);
68   bool is_stacked_head (int prefix_set,
69                         int context_info);
70   Real align_heads (vector<Grob_info> const &primitives,
71                     Real flexa_width,
72                     Real thickness);
73   void check_for_prefix_loss (Item *primitive);
74   void check_for_ambiguous_dot_pitch (Grob_info primitive);
75   void add_mora_column (Paper_column *column);
76   vector<Grob_info> augmented_primitives_;
77
78 public:
79   TRANSLATOR_DECLARATIONS (Vaticana_ligature_engraver);
80   TRANSLATOR_INHERIT (Gregorian_ligature_engraver);
81 protected:
82   virtual Spanner *create_ligature_spanner ();
83   virtual void transform_heads (Spanner *ligature,
84                                 vector<Grob_info> const &primitives);
85 };
86
87 Vaticana_ligature_engraver::Vaticana_ligature_engraver ()
88 {
89   brew_ligature_primitive_proc
90     = Vaticana_ligature::brew_ligature_primitive_proc;
91   augmented_primitives_.clear ();
92 }
93
94 Spanner *
95 Vaticana_ligature_engraver::create_ligature_spanner ()
96 {
97   return make_spanner ("VaticanaLigature", SCM_EOL);
98 }
99
100 bool
101 Vaticana_ligature_engraver::is_stacked_head (int prefix_set,
102                                              int context_info)
103 {
104   bool is_stacked;
105
106   // upper head of pes is stacked upon lower head of pes ...
107   is_stacked = context_info & PES_UPPER;
108
109   // ... unless this note starts a flexa
110   if (context_info & FLEXA_LEFT)
111     is_stacked = false;
112
113   // ... or another pes
114   if (context_info & PES_LOWER)
115     is_stacked = false;
116
117   // ... or the previous note is a semivocalis or inclinatum
118   if (context_info & AFTER_DEMINUTUM)
119     is_stacked = false;
120
121   // auctum head is never stacked upon preceding note
122   if (prefix_set & AUCTUM)
123     is_stacked = false;
124
125   // virga is never stacked upon preceding note
126   if (prefix_set & VIRGA)
127     is_stacked = false;
128
129   // oriscus is never stacked upon preceding note
130   if (prefix_set & ORISCUS)
131     is_stacked = false;
132
133   if ((prefix_set & DEMINUTUM)
134       && ! (prefix_set & INCLINATUM)
135       && (context_info & FLEXA_RIGHT))
136     is_stacked = true; // semivocalis head of deminutus form
137
138   return is_stacked;
139 }
140
141 /*
142  * When aligning the heads, sometimes extra space is needed, e.g. to
143  * avoid clashing with the appendix of an adjacent notehead or with an
144  * adjacent notehead itself if it has the same pitch.  Extra space is
145  * added at most once between to heads.
146  */
147 bool
148 Vaticana_ligature_engraver::need_extra_horizontal_space (int prev_prefix_set, int prefix_set,
149                                                          int context_info, int delta_pitch)
150 {
151   if (prev_prefix_set & VIRGA)
152     /*
153      * After a virga, make an additional small space such that the
154      * appendix on the right side of the head does not touch the
155      * following head.
156      */
157     return true;
158
159   if ((prefix_set & INCLINATUM)
160       && ! (prev_prefix_set & INCLINATUM))
161     /*
162      * Always start a series of inclinatum heads with an extra space.
163      */
164     return true;
165
166   if ((context_info & FLEXA_LEFT) && ! (context_info & PES_UPPER))
167     /*
168      * Before a flexa (but not within a torculus), make an
169      * additional small space such that the appendix on the left side
170      * of the flexa does not touch the this head.
171      */
172     return true;
173
174   if (delta_pitch == 0)
175     /*
176      * If there are two adjacent noteheads with the same pitch, add
177      * additional small space between them, such that they do not
178      * touch each other.
179      */
180     return true;
181
182   return false;
183 }
184
185 Real
186 Vaticana_ligature_engraver::align_heads (vector<Grob_info> const &primitives,
187                                          Real flexa_width,
188                                          Real thickness)
189 {
190   if (!primitives.size ())
191     {
192       programming_error ("Vaticana_ligature:"
193                          " empty ligature [ignored]");
194       return 0.0;
195     }
196
197   /*
198    * The paper column where we put the whole ligature into.
199    */
200   Paper_column *column
201     = dynamic_cast<Item *> (primitives[0].grob ())->get_column ();
202
203   Real join_thickness
204     = thickness * column->layout ()->get_dimension (ly_symbol2scm ("line-thickness"));
205
206   /*
207    * Amount of extra space two put between some particular
208    * configurations of adjacent heads.
209    *
210    * TODO: make this a property of primtive grobs.
211    */
212   Real extra_space = 4.0 * join_thickness;
213
214   /*
215    * Keep track of the total width of the ligature.
216    */
217   Real ligature_width = 0.0;
218
219   Item *prev_primitive = 0;
220   int prev_prefix_set = 0;
221   for (vsize i = 0; i < primitives.size (); i++)
222     {
223       Item *primitive = dynamic_cast<Item *> (primitives[i].grob ());
224       int prefix_set
225         = scm_to_int (primitive->get_property ("prefix-set"));
226       int context_info
227         = scm_to_int (primitive->get_property ("context-info"));
228
229       /*
230        * Get glyph_name, delta_pitch and context_info for this head.
231        */
232
233       SCM glyph_name_scm = primitive->get_property ("glyph-name");
234       if (scm_is_null (glyph_name_scm))
235         {
236           primitive->programming_error ("Vaticana_ligature:"
237                                         " undefined glyph-name ->"
238                                         " ignoring grob");
239           continue;
240         }
241       string glyph_name = ly_scm2string (glyph_name_scm);
242
243       int delta_pitch = 0;
244       if (prev_primitive) /* urgh, need prev_primitive only here */
245         {
246           SCM delta_pitch_scm = prev_primitive->get_property ("delta-position");
247           if (!scm_is_null (delta_pitch_scm))
248             delta_pitch = scm_to_int (delta_pitch_scm);
249           else
250             {
251               primitive->programming_error ("Vaticana_ligature:"
252                                             " delta-position undefined ->"
253                                             " ignoring grob");
254               continue;
255             }
256         }
257
258       /*
259        * Now determine width and x-offset of head.
260        */
261
262       Real head_width;
263       Real x_offset;
264
265       if (context_info & STACKED_HEAD)
266         {
267           /*
268            * This head is stacked upon the previous one; hence, it
269            * does not contribute to the total width of the ligature,
270            * and its width is assumed to be 0.0.  Moreover, it is
271            * shifted to the left by its width such that the right side
272            * of this and the other head are horizontally aligned.
273            */
274           head_width = 0.0;
275           x_offset = join_thickness
276                      - Font_interface::get_default_font (primitive)->
277                      find_by_name ("noteheads.s" + glyph_name).extent (X_AXIS).length ();
278         }
279       else if (glyph_name == "flexa" || glyph_name == "")
280         {
281           /*
282            * This head represents either half of a flexa shape.
283            * Hence, it is assigned half the width of this shape.
284            */
285           head_width = 0.5 * flexa_width;
286           x_offset = 0.0;
287         }
288       else
289         {
290           /*
291            * This is a regular head, placed right to the previous one.
292            * Retrieve its width from corresponding font.
293            */
294           head_width
295             = Font_interface::get_default_font (primitive)->
296               find_by_name ("noteheads.s" + glyph_name).extent (X_AXIS).length ();
297           x_offset = 0.0;
298         }
299
300       /*
301        * Save the head's final x-offset.
302        */
303       primitive->set_property ("x-offset",
304                                scm_from_double (x_offset));
305
306       /*
307        * If the head is the 2nd head of a pes or flexa (but not a
308        * flexa shape), mark this head to be joined with the left-side
309        * neighbour head (i.e. the previous head) by a vertical beam.
310        */
311       if ((context_info & PES_UPPER)
312           || ((context_info & FLEXA_RIGHT)
313               && ! (context_info & PES_LOWER)))
314         {
315           if (!prev_primitive)
316             {
317               primitive->programming_error ("Vaticana ligature: add-join:"
318                                             " missing previous primitive");
319             }
320           else
321             {
322               prev_primitive->set_property ("add-join",
323                                             ly_bool2scm (true));
324
325               /*
326                * Create a small overlap of adjacent heads so that the join
327                * can be drawn perfectly between them.
328                */
329               ligature_width -= join_thickness;
330             }
331         }
332       else if (glyph_name == "")
333         {
334           /*
335            * This is the 2nd (virtual) head of flexa shape.  Join it
336            * tightly with 1st head, i.e. do *not* add additional
337            * space, such that next head will not be off from the flexa
338            * shape.
339            */
340         }
341
342       if (need_extra_horizontal_space (prev_prefix_set, prefix_set,
343                                        context_info, delta_pitch))
344         ligature_width += extra_space;
345
346       /*
347        * Horizontally line-up this head to form a ligature.
348        */
349       move_related_items_to_column (primitive, column, ligature_width);
350       ligature_width += head_width;
351
352       prev_primitive = primitive;
353       prev_prefix_set = prefix_set;
354     }
355
356   /*
357    * Add extra horizontal padding space after ligature, such that
358    * neighbouring ligatures do not touch each other.
359    */
360   ligature_width += extra_space;
361
362   return ligature_width;
363 }
364
365 /*
366  * Depending on the typographical features of a particular ligature
367  * style, some prefixes may be ignored.  In particular, if a curved
368  * flexa shape is produced, any prefixes to either of the two
369  * contributing heads that would select a head other than punctum, is
370  * by definition ignored.
371  *
372  * This function prints a warning, if the given primitive is prefixed
373  * such that a head other than punctum would be chosen, if this
374  * primitive were engraved as a stand-alone head.
375  */
376 void
377 Vaticana_ligature_engraver::check_for_prefix_loss (Item *primitive)
378 {
379   int prefix_set
380     = scm_to_int (primitive->get_property ("prefix-set"));
381   if (prefix_set & ~PES_OR_FLEXA)
382     {
383       string prefs = Gregorian_ligature::prefixes_to_str (primitive);
384       primitive->warning (_f ("ignored prefix(es) `%s' of this head"
385                               " according to restrictions of the selected"
386                               " ligature style",
387                               prefs.c_str ()));
388     }
389 }
390
391 void
392 Vaticana_ligature_engraver::add_mora_column (Paper_column *column)
393 {
394   if (augmented_primitives_.size () == 0) // no dot for column
395     return;
396   if (!column) // empty ligature???
397     {
398       augmented_primitives_[0].grob ()->
399       programming_error ("no paper column to add dot");
400       return;
401     }
402   Item *dotcol = make_item ("DotColumn", SCM_EOL);
403   dotcol->set_parent (column, X_AXIS);
404   for (vsize i = 0; i < augmented_primitives_.size (); i++)
405     {
406       Item *primitive
407         = dynamic_cast<Item *> (augmented_primitives_[i].grob ());
408       Item *dot = make_item ("Dots", primitive->self_scm ());
409       dot->set_property ("dot-count", scm_from_int (1));
410       dot->set_parent (primitive, Y_AXIS);
411       primitive->set_object ("dot", dot->self_scm ());
412       Dot_column::add_head (dotcol, primitive);
413
414       // FIXME: why isn't the dot picked up by Paper_column_engraver?
415       Separation_item::add_item (column, dot);
416     }
417 }
418
419 /*
420  * This function prints a warning, if the given primitive has the same
421  * pitch as at least one of the primitives already stored in the
422  * augmented_primitives_ array.
423  *
424  * The rationale of this check is, that, if there are two dotted
425  * primitives with the same pitch, then collecting all dots in a dot
426  * column behind the ligature leads to a notational ambiguity of to
427  * which head the corresponding dot refers.
428  *
429  * Such a case should be treated as a badly specified ligature.  The
430  * user should split the ligature to make the notation of dots
431  * unambiguous.
432  */
433 void
434 Vaticana_ligature_engraver::check_for_ambiguous_dot_pitch (Grob_info primitive)
435 {
436   // TODO: Fix performance, which is currently O (n^2) (since this
437   // method is called O (n) times and takes O (n) steps in the for
438   // loop), but could be O (n) (by replacing the for loop by e.g. a
439   // bitmask based O (1) test); where n=<number of primitives in the
440   // ligature> (which is typically small (n<10), though).
441   Stream_event *new_cause = primitive.event_cause ();
442   int new_pitch = unsmob<Pitch> (new_cause->get_property ("pitch"))->steps ();
443   for (vsize i = 0; i < augmented_primitives_.size (); i++)
444     {
445       Stream_event *cause = augmented_primitives_[i].event_cause ();
446       int pitch = unsmob<Pitch> (cause->get_property ("pitch"))->steps ();
447       if (pitch == new_pitch)
448         {
449           primitive.grob ()->
450           warning (_ ("Ambiguous use of dots in ligature: there are"
451                       " multiple dotted notes with the same pitch."
452                       "  The ligature should be split."));
453           return; // supress multiple identical warnings
454         }
455     }
456 }
457
458 void
459 Vaticana_ligature_engraver::transform_heads (Spanner *ligature,
460                                              vector<Grob_info> const &primitives)
461 {
462   Real flexa_width = robust_scm2double (ligature->get_property ("flexa-width"), 2);
463
464   Real thickness = robust_scm2double (ligature->get_property ("thickness"), 1);
465
466   Item *prev_primitive = 0;
467   int prev_prefix_set = 0;
468   int prev_context_info = 0;
469   int prev_delta_pitch = 0;
470   string prev_glyph_name = "";
471   augmented_primitives_.clear ();
472   for (vsize i = 0; i < primitives.size (); i++)
473     {
474       Item *primitive = dynamic_cast<Item *> (primitives[i].grob ());
475
476       int delta_pitch;
477       SCM delta_pitch_scm = primitive->get_property ("delta-position");
478       if (!scm_is_null (delta_pitch_scm))
479         delta_pitch = scm_to_int (delta_pitch_scm);
480       else
481         {
482           primitive->programming_error ("Vaticana_ligature:"
483                                         " delta-position undefined ->"
484                                         " ignoring grob");
485           continue;
486         }
487
488       /* retrieve & complete prefix_set and context_info */
489       int prefix_set
490         = scm_to_int (primitive->get_property ("prefix-set"));
491       int context_info
492         = scm_to_int (primitive->get_property ("context-info"));
493
494       if (Rhythmic_head::dot_count (primitive) > 0)
495         // remove dots from primitive and add remember primitive for
496         // creating a dot column
497         {
498           Rhythmic_head::get_dots (primitive)->set_property ("dot-count",
499                                                              scm_from_int (0));
500           // TODO: Maybe completely remove grob "Dots" (dots->suicide
501           // () ?) rather than setting property "dot-count" to 0.
502
503           check_for_ambiguous_dot_pitch (primitives[i]);
504           augmented_primitives_.push_back (primitives[i]);
505         }
506       else if (augmented_primitives_.size () > 0)
507         {
508           primitive->warning (_ ("This ligature has a dotted head followed by"
509                                  " a non-dotted head.  The ligature should be"
510                                  " split after the last dotted head before"
511                                  " this head."));
512         }
513
514       if (is_stacked_head (prefix_set, context_info))
515         {
516           context_info |= STACKED_HEAD;
517           primitive->set_property ("context-info",
518                                    scm_from_int (context_info));
519         }
520
521       /*
522        * Now determine which head to typeset (this is context sensitive
523        * information, since it depends on neighbouring heads; therefore,
524        * this decision must be made here in the engraver rather than in
525        * the backend).
526        */
527       string glyph_name;
528       if (prefix_set & VIRGA)
529         {
530           glyph_name = "vaticana.punctum";
531           primitive->set_property ("add-stem", ly_bool2scm (true));
532         }
533       else if (prefix_set & QUILISMA)
534         glyph_name = "vaticana.quilisma";
535       else if (prefix_set & ORISCUS)
536         glyph_name = "solesmes.oriscus";
537       else if (prefix_set & STROPHA)
538         if (prefix_set & AUCTUM)
539           glyph_name = "solesmes.stropha.aucta";
540         else glyph_name = "solesmes.stropha";
541       else if (prefix_set & INCLINATUM)
542         if (prefix_set & AUCTUM)
543           glyph_name = "solesmes.incl.auctum";
544         else if (prefix_set & DEMINUTUM)
545           glyph_name = "solesmes.incl.parvum";
546         else
547           glyph_name = "vaticana.inclinatum";
548       else if (prefix_set & DEMINUTUM)
549         {
550           if (i == 0)
551             {
552               // initio debilis
553               glyph_name = "vaticana.reverse.plica";
554             }
555           else if (prev_delta_pitch > 0)
556             {
557               // epiphonus
558               if (! (prev_context_info & FLEXA_RIGHT))
559                 {
560                   /* correct head of previous primitive */
561                   if (prev_delta_pitch > 1)
562                     prev_glyph_name = "vaticana.epiphonus";
563                   else
564                     prev_glyph_name = "vaticana.vepiphonus";
565                 }
566               if (prev_delta_pitch > 1)
567                 glyph_name = "vaticana.plica";
568               else
569                 glyph_name = "vaticana.vplica";
570             }
571           else if (prev_delta_pitch < 0)
572             {
573               // cephalicus
574               if (! (prev_context_info & FLEXA_RIGHT))
575                 /* correct head of previous primitive */
576                 {
577                   if (i > 1)
578                     {
579                       /* cephalicus head with fixed size cauda */
580                       prev_glyph_name = "vaticana.inner.cephalicus";
581                     }
582                   else
583                     {
584                       /* cephalicus head without cauda */
585                       prev_glyph_name = "vaticana.cephalicus";
586                     }
587
588                   /*
589                    * Flexa has no variable size cauda if its left head is
590                    * stacked on the right head.  This is true for
591                    * cephalicus.  Hence, remove the cauda.
592                    *
593                    * Urgh: for the current implementation, this rule only
594                    * applies for cephalicus; but it is a fundamental rule.
595                    * Therefore, the following line of code should be
596                    * placed somewhere else.
597                    */
598                   prev_primitive->set_property ("add-cauda",
599                                                 ly_bool2scm (false));
600                 }
601               if (prev_delta_pitch < - 1)
602                 glyph_name = "vaticana.reverse.plica";
603               else
604                 glyph_name = "vaticana.reverse.vplica";
605             }
606           else // (prev_delta_pitch == 0)
607             {
608               primitive->programming_error ("Vaticana_ligature:"
609                                             " deminutum head must have different"
610                                             " pitch -> ignoring grob");
611             }
612         }
613       else if (prefix_set & (CAVUM | LINEA))
614         if ((prefix_set & CAVUM) && (prefix_set & LINEA))
615           glyph_name = "vaticana.linea.punctum.cavum";
616         else if (prefix_set & CAVUM)
617           glyph_name = "vaticana.punctum.cavum";
618         else
619           glyph_name = "vaticana.linea.punctum";
620       else if (prefix_set & AUCTUM)
621         if (prefix_set & ASCENDENS)
622           glyph_name = "solesmes.auct.asc";
623         else
624           glyph_name = "solesmes.auct.desc";
625       else if ((context_info & STACKED_HEAD)
626                && (context_info & PES_UPPER))
627         if (prev_delta_pitch > 1)
628           glyph_name = "vaticana.upes";
629         else
630           glyph_name = "vaticana.vupes";
631       else
632         glyph_name = "vaticana.punctum";
633
634       /*
635        * This head needs a cauda, if it starts a flexa, is not the upper
636        * head of a pes, and if it is a punctum.
637        */
638       if ((context_info & FLEXA_LEFT) && ! (context_info & PES_UPPER))
639         if (glyph_name == "vaticana.punctum")
640           primitive->set_property ("add-cauda", ly_bool2scm (true));
641
642       /*
643        * Execptional rule for porrectus:
644        *
645        * If the current head is preceded by a \flexa and succeded by a
646        * \pes (e.g. "a \flexa g \pes a"), then join the current head and
647        * the previous head into a single curved flexa shape.
648        */
649       if ((context_info & FLEXA_RIGHT) && (context_info & PES_LOWER))
650         {
651           check_for_prefix_loss (prev_primitive);
652           prev_glyph_name = "flexa";
653           prev_primitive->set_property ("flexa-height",
654                                         scm_from_int (prev_delta_pitch));
655           prev_primitive->set_property ("flexa-width",
656                                         scm_from_double (flexa_width));
657           bool add_cauda = !(prev_prefix_set && PES_OR_FLEXA);
658           prev_primitive->set_property ("add-cauda",
659                                         ly_bool2scm (add_cauda));
660           check_for_prefix_loss (primitive);
661           glyph_name = "";
662           primitive->set_property ("flexa-width",
663                                    scm_from_double (flexa_width));
664         }
665
666       /*
667        * Exceptional rule for pes:
668        *
669        * If this head is stacked on the previous one due to a \pes, then
670        * set the glyph of the previous head to that for this special
671        * case, thereby avoiding potential vertical collision with the
672        * current head.
673        */
674       if (prefix_set & PES_OR_FLEXA)
675         {
676           if ((context_info & PES_UPPER) && (context_info & STACKED_HEAD))
677             {
678               if (prev_glyph_name == "vaticana.punctum")
679                 {
680                   if (prev_delta_pitch > 1)
681                     prev_glyph_name = "vaticana.lpes";
682                   else
683                     prev_glyph_name = "vaticana.vlpes";
684                 }
685             }
686         }
687
688       if (prev_primitive)
689         prev_primitive->set_property ("glyph-name",
690                                       ly_string2scm (prev_glyph_name));
691
692       /*
693        * In the backend, flexa shapes and joins need to know about line
694        * thickness.  Hence, for simplicity, let's distribute the
695        * ligature grob's value for thickness to each ligature head (even
696        * if not all of them need to know).
697        */
698       primitive->set_property ("thickness", scm_from_double (thickness));
699
700       prev_primitive = primitive;
701       prev_prefix_set = prefix_set;
702       prev_context_info = context_info;
703       prev_delta_pitch = delta_pitch;
704       prev_glyph_name = glyph_name;
705     }
706
707   prev_primitive->set_property ("glyph-name",
708                                 ly_string2scm (prev_glyph_name));
709
710   align_heads (primitives, flexa_width, thickness);
711
712   // append all dots to paper column of ligature's last head
713   add_mora_column (prev_primitive->get_column ());
714
715 #if 0 // experimental code to collapse spacing after ligature
716   /* TODO: set to max (old/new spacing-increment), since other
717      voices/staves also may want to set this property. */
718   Item *first_primitive = dynamic_cast<Item *> (primitives[0].grob ());
719   Paper_column *paper_column = first_primitive->get_column ();
720   paper_column->warning (_f ("Vaticana_ligature_engraver:"
721                              " setting `spacing-increment = %f': ptr =%ul",
722                              ligature_width, paper_column));
723   paper_column->
724   set_property ("forced-spacing", scm_from_double (ligature_width));
725 #endif
726 }
727
728 void
729 Vaticana_ligature_engraver::boot ()
730 {
731   ADD_LISTENER (Vaticana_ligature_engraver, pes_or_flexa);
732   ADD_LISTENER (Vaticana_ligature_engraver, ligature);
733   ADD_ACKNOWLEDGER (Vaticana_ligature_engraver, rest);
734   ADD_ACKNOWLEDGER (Vaticana_ligature_engraver, ligature_head);
735 }
736
737 ADD_TRANSLATOR (Vaticana_ligature_engraver,
738                 /* doc */
739                 "Handle ligatures by glueing special ligature heads"
740                 " together.",
741
742                 /* create */
743                 "VaticanaLigature "
744                 "DotColumn ",
745
746                 /* read */
747                 "",
748
749                 /* write */
750                 ""
751                );