]> git.donarmstrong.com Git - lilypond.git/blob - lily/vaticana-ligature-engraver.cc
Merge branch 'master' of ssh+git://hanwen@git.sv.gnu.org/srv/git/lilypond
[lilypond.git] / lily / vaticana-ligature-engraver.cc
1 /*
2   vaticana-ligature-engraver.cc -- implement Vaticana_ligature_engraver
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 2003--2007 Juergen Reuter <reuter@ipd.uka.de>
7 */
8
9 #include "gregorian-ligature-engraver.hh"
10
11 #include "font-interface.hh"
12 #include "gregorian-ligature.hh"
13 #include "international.hh"
14 #include "output-def.hh"
15 #include "paper-column.hh"
16 #include "spanner.hh"
17 #include "staff-symbol-referencer.hh"
18 #include "stream-event.hh"
19 #include "vaticana-ligature.hh"
20 #include "warn.hh"
21 #include "dot-column.hh"
22 #include "rhythmic-head.hh"
23 #include "pitch.hh"
24 #include "translator.icc"
25
26 /*
27  * This class implements the notation specific aspects of Vaticana
28  * style ligatures for Gregorian chant notation.
29  */
30
31 /*
32  * TODO: Maybe move handling of dots/mora to
33  * Gregorian_ligature_engraver?  It's probably common for all types of
34  * Gregorian chant notation that have dotted notes.
35  *
36  * FIXME: The horizontal alignment of the mora column is bad (too far
37  * to the left), if the last dotted note is not the last primitive in
38  * the ligature.  Fortunately, in practice this bug should have no
39  * negative impact, since dotted notes appear within a ligature
40  * usually always at the end of the ligature, such that the bug never
41  * should apply for valid ligatures.
42  *
43  * TODO: Graduale Triplex, tempus per annum, hebdomada septima,
44  * alleluia (page 280) shows a counter-example for collecting dots
45  * always in a single column behind the ligature.  Maybe only the last
46  * two dots in a ligature should be collected and all other dots put
47  * behind or on top of the head?
48  */
49 class Vaticana_ligature_engraver : public Gregorian_ligature_engraver
50 {
51
52 private:
53   static bool
54   need_extra_horizontal_space (int prev_prefix_set, int prefix_set,
55                                int context_info, int delta_pitch);
56   bool is_stacked_head (int prefix_set,
57                         int context_info);
58   Real align_heads (vector<Grob_info> primitives,
59                     Real flexa_width,
60                     Real thickness);
61   void check_for_prefix_loss (Item *primitive);
62   void check_for_ambiguous_dot_pitch (Grob_info primitive);
63   void add_mora_column (Paper_column *column);
64   vector<Grob_info> augmented_primitives_;
65
66 public:
67   TRANSLATOR_DECLARATIONS (Vaticana_ligature_engraver);
68
69 protected:
70   virtual Spanner *create_ligature_spanner ();
71   virtual void transform_heads (Spanner *ligature,
72                                 vector<Grob_info> primitives);
73   DECLARE_TRANSLATOR_LISTENER (pes_or_flexa);
74   DECLARE_TRANSLATOR_LISTENER (ligature);
75 };
76
77 IMPLEMENT_TRANSLATOR_LISTENER (Vaticana_ligature_engraver, pes_or_flexa);
78 void
79 Vaticana_ligature_engraver::listen_pes_or_flexa (Stream_event *ev)
80 {
81   Gregorian_ligature_engraver::listen_pes_or_flexa (ev);
82 }
83
84 IMPLEMENT_TRANSLATOR_LISTENER (Vaticana_ligature_engraver, ligature);
85 void
86 Vaticana_ligature_engraver::listen_ligature (Stream_event *ev)
87 {
88   Ligature_engraver::listen_ligature (ev);
89 }
90
91 Vaticana_ligature_engraver::Vaticana_ligature_engraver ()
92 {
93   brew_ligature_primitive_proc = 
94     Vaticana_ligature::brew_ligature_primitive_proc;
95   augmented_primitives_.clear ();
96 }
97
98 Spanner *
99 Vaticana_ligature_engraver::create_ligature_spanner ()
100 {
101   return make_spanner ("VaticanaLigature", SCM_EOL);
102 }
103
104 bool
105 Vaticana_ligature_engraver::is_stacked_head (int prefix_set,
106                                              int context_info)
107 {
108   bool is_stacked_b;
109
110   // upper head of pes is stacked upon lower head of pes ...
111   is_stacked_b = context_info & PES_UPPER;
112
113   // ... unless this note starts a flexa
114   if (context_info & FLEXA_LEFT)
115     is_stacked_b = false;
116
117   // ... or another pes
118   if (context_info & PES_LOWER)
119     is_stacked_b = false;
120
121   // ... or the previous note is a semivocalis or inclinatum
122   if (context_info & AFTER_DEMINUTUM)
123     is_stacked_b = false;
124
125   // auctum head is never stacked upon preceding note
126   if (prefix_set & AUCTUM)
127     is_stacked_b = false;
128
129   // virga is never stacked upon preceding note
130   if (prefix_set & VIRGA)
131     is_stacked_b = false;
132
133   // oriscus is never stacked upon preceding note
134   if (prefix_set & ORISCUS)
135     is_stacked_b = false;
136
137   if ((prefix_set & DEMINUTUM)
138       && ! (prefix_set & INCLINATUM)
139       && (context_info & FLEXA_RIGHT))
140     is_stacked_b = true; // semivocalis head of deminutus form
141
142   return is_stacked_b;
143 }
144
145 /*
146  * When aligning the heads, sometimes extra space is needed, e.g. to
147  * avoid clashing with the appendix of an adjacent notehead or with an
148  * adjacent notehead itself if it has the same pitch.  Extra space is
149  * added at most once between to heads.
150  */
151 bool
152 Vaticana_ligature_engraver::need_extra_horizontal_space (int prev_prefix_set, int prefix_set,
153                                                          int context_info, int delta_pitch)
154 {
155   if (prev_prefix_set & VIRGA)
156     /*
157      * After a virga, make a an additional small space such that the
158      * appendix on the right side of the head does not touch the
159      * following head.
160      */
161     return true;
162
163   if ((prefix_set & INCLINATUM)
164       && ! (prev_prefix_set & INCLINATUM))
165     /*
166      * Always start a series of inclinatum heads with an extra space.
167      */
168     return true;
169
170   if ((context_info & FLEXA_LEFT) && ! (context_info & PES_UPPER))
171     /*
172      * Before a flexa (but not within a torculus), make a an
173      * additional small space such that the appendix on the left side
174      * of the flexa does not touch the this head.
175      */
176     return true;
177
178   if (delta_pitch == 0)
179     /*
180      * If there are two adjacent noteheads with the same pitch, add
181      * additional small space between them, such that they do not
182      * touch each other.
183      */
184     return true;
185
186   return false;
187 }
188
189 Real
190 Vaticana_ligature_engraver::align_heads (vector<Grob_info> primitives,
191                                          Real flexa_width,
192                                          Real thickness)
193 {
194   if (!primitives.size ())
195     {
196       programming_error ("Vaticana_ligature: "
197                          "empty ligature [ignored]");
198       return 0.0;
199     }
200
201   /*
202    * The paper column where we put the whole ligature into.
203    */
204   Paper_column *column
205     = dynamic_cast<Item *> (primitives[0].grob ())->get_column ();
206
207   Real join_thickness
208     = thickness * column->layout ()->get_dimension (ly_symbol2scm ("line-thickness"));
209
210   /*
211    * Amount of extra space two put between some particular
212    * configurations of adjacent heads.
213    *
214    * TODO: make this a property of primtive grobs.
215    */
216   Real extra_space = 4.0 * join_thickness;
217
218   /*
219    * Keep track of the total width of the ligature.
220    */
221   Real ligature_width = 0.0;
222
223   Item *prev_primitive = 0;
224   int prev_prefix_set = 0;
225   for (vsize i = 0; i < primitives.size (); i++)
226     {
227       Item *primitive = dynamic_cast<Item *> (primitives[i].grob ());
228       int prefix_set
229         = scm_to_int (primitive->get_property ("prefix-set"));
230       int context_info
231         = scm_to_int (primitive->get_property ("context-info"));
232
233       /*
234        * Get glyph_name, delta_pitch and context_info for this head.
235        */
236
237       SCM glyph_name_scm = primitive->get_property ("glyph-name");
238       if (glyph_name_scm == SCM_EOL)
239         {
240           primitive->programming_error ("Vaticana_ligature:"
241                                         "undefined glyph-name -> "
242                                         "ignoring grob");
243           continue;
244         }
245       string glyph_name = ly_scm2string (glyph_name_scm);
246
247       int delta_pitch = 0;
248       if (prev_primitive) /* urgh, need prev_primitive only here */
249         {
250           SCM delta_pitch_scm = prev_primitive->get_property ("delta-position");
251           if (delta_pitch_scm != SCM_EOL)
252             delta_pitch = scm_to_int (delta_pitch_scm);
253           else
254             {
255               primitive->programming_error ("Vaticana_ligature:"
256                                             "delta-position undefined -> "
257                                             "ignoring grob");
258               continue;
259             }
260         }
261
262       /*
263        * Now determine width and x-offset of head.
264        */
265
266       Real head_width;
267       Real x_offset;
268
269       if (context_info & STACKED_HEAD)
270         {
271           /*
272            * This head is stacked upon the previous one; hence, it
273            * does not contribute to the total width of the ligature,
274            * and its width is assumed to be 0.0.  Moreover, it is
275            * shifted to the left by its width such that the right side
276            * of this and the other head are horizontally aligned.
277            */
278           head_width = 0.0;
279           x_offset = join_thickness
280             - Font_interface::get_default_font (primitive)->
281             find_by_name ("noteheads.s" + glyph_name).extent (X_AXIS).length ();
282         }
283       else if (glyph_name == "flexa" || glyph_name == "")
284         {
285           /*
286            * This head represents either half of a flexa shape.
287            * Hence, it is assigned half the width of this shape.
288            */
289           head_width = 0.5 * flexa_width;
290           x_offset = 0.0;
291         }
292       else
293         {
294           /*
295            * This is a regular head, placed right to the previous one.
296            * Retrieve its width from corresponding font.
297            */
298           head_width
299             = Font_interface::get_default_font (primitive)->
300             find_by_name ("noteheads.s" + glyph_name).extent (X_AXIS).length ();
301           x_offset = 0.0;
302         }
303
304       /*
305        * Save the head's final x-offset.
306        */
307       primitive->set_property ("x-offset",
308                                scm_from_double (x_offset));
309
310       /*
311        * If the head is the 2nd head of a pes or flexa (but not a
312        * flexa shape), mark this head to be joined with the left-side
313        * neighbour head (i.e. the previous head) by a vertical beam.
314        */
315       if ((context_info & PES_UPPER)
316           || ((context_info & FLEXA_RIGHT)
317               && ! (context_info & PES_LOWER)))
318         {
319           if (!prev_primitive)
320             {
321               primitive->programming_error ("vaticana ligature: add-join: "
322                                             "missing previous primitive");
323             }
324           else
325             {
326               prev_primitive->set_property ("add-join",
327                                             ly_bool2scm (true));
328
329               /*
330                * Create a small overlap of adjacent heads so that the join
331                * can be drawn perfectly between them.
332                */
333               ligature_width -= join_thickness;
334             }
335         }
336       else if (glyph_name == "")
337         {
338           /*
339            * This is the 2nd (virtual) head of flexa shape.  Join it
340            * tightly with 1st head, i.e. do *not* add additional
341            * space, such that next head will not be off from the flexa
342            * shape.
343            */
344         }
345
346       if (need_extra_horizontal_space (prev_prefix_set, prefix_set,
347                                        context_info, delta_pitch))
348         ligature_width += extra_space;
349
350       /*
351        * Horizontally line-up this head to form a ligature.
352        */
353       move_related_items_to_column (primitive, column, ligature_width);
354       ligature_width += head_width;
355
356       prev_primitive = primitive;
357       prev_prefix_set = prefix_set;
358     }
359
360   /*
361    * Add extra horizontal padding space after ligature, such that
362    * neighbouring ligatures do not touch each other.
363    */
364   ligature_width += extra_space;
365
366   return ligature_width;
367 }
368
369 /*
370  * Depending on the typographical features of a particular ligature
371  * style, some prefixes may be ignored.  In particular, if a curved
372  * flexa shape is produced, any prefixes to either of the two
373  * contributing heads that would select a head other than punctum, is
374  * by definition ignored.
375  *
376  * This function prints a warning, if the given primitive is prefixed
377  * such that a head other than punctum would be chosen, if this
378  * primitive were engraved as a stand-alone head.
379  */
380 void
381 Vaticana_ligature_engraver::check_for_prefix_loss (Item *primitive)
382 {
383   int prefix_set
384     = scm_to_int (primitive->get_property ("prefix-set"));
385   if (prefix_set & ~PES_OR_FLEXA)
386     {
387       string prefs = Gregorian_ligature::prefixes_to_str (primitive);
388       primitive->warning (_f ("ignored prefix (es) `%s' of this head according "
389                               "to restrictions of the selected ligature style",
390                               prefs.c_str ()));
391     }
392 }
393
394 void
395 Vaticana_ligature_engraver::add_mora_column (Paper_column *column)
396 {
397   if (augmented_primitives_.size () == 0) // no dot for column
398     return;
399   if (!column) // empty ligature???
400     {
401       augmented_primitives_[0].grob ()->
402         programming_error ("no paper column to add dot");
403       return;
404     }
405   Item *dotcol = make_item ("DotColumn", SCM_EOL);
406   dotcol->set_parent (column, X_AXIS);
407   for (vsize i = 0; i < augmented_primitives_.size (); i++)
408     {
409       Item *primitive =
410         dynamic_cast<Item *> (augmented_primitives_[i].grob ());
411       Item *dot = make_item ("Dots", primitive->self_scm ());
412       dot->set_property ("dot-count", scm_from_int (1));
413       dot->set_parent (primitive, Y_AXIS);
414       primitive->set_object ("dot", dot->self_scm ());
415       Dot_column::add_head (dotcol, primitive);
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> 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 (delta_pitch_scm != SCM_EOL)
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         if (i == 0)
550           {
551             // initio debilis
552             glyph_name = "vaticana.reverse.plica";
553           }
554         else if (prev_delta_pitch > 0)
555           {
556             // epiphonus
557             if (! (prev_context_info & FLEXA_RIGHT))
558               /* correct head of previous primitive */
559               if (prev_delta_pitch > 1)
560                 prev_glyph_name = "vaticana.epiphonus";
561               else
562                 prev_glyph_name = "vaticana.vepiphonus";
563             if (prev_delta_pitch > 1)
564               glyph_name = "vaticana.plica";
565             else
566               glyph_name = "vaticana.vplica";
567           }
568         else if (prev_delta_pitch < 0)
569           {
570             // cephalicus
571             if (! (prev_context_info & FLEXA_RIGHT))
572               /* correct head of previous primitive */
573               {
574                 if (i > 1)
575                   {
576                     /* cephalicus head with fixed size cauda */
577                     prev_glyph_name = "vaticana.inner.cephalicus";
578                   }
579                 else
580                   {
581                     /* cephalicus head without cauda */
582                     prev_glyph_name = "vaticana.cephalicus";
583                   }
584
585                 /*
586                  * Flexa has no variable size cauda if its left head is
587                  * stacked on the right head.  This is true for
588                  * cephalicus.  Hence, remove the cauda.
589                  *
590                  * Urgh: for the current implementation, this rule only
591                  * applies for cephalicus; but it is a fundamental rule.
592                  * Therefore, the following line of code should be
593                  * placed somewhere else.
594                  */
595                 prev_primitive->set_property ("add-cauda",
596                                               ly_bool2scm (false));
597               }
598             if (prev_delta_pitch < - 1)
599               glyph_name = "vaticana.reverse.plica";
600             else
601               glyph_name = "vaticana.reverse.vplica";
602           }
603         else // (prev_delta_pitch == 0)
604           {
605             primitive->programming_error ("Vaticana_ligature:"
606                                           "deminutum head must have different "
607                                           "pitch -> ignoring grob");
608           }
609       else if (prefix_set & (CAVUM | LINEA))
610         if ((prefix_set & CAVUM) && (prefix_set & LINEA))
611           glyph_name = "vaticana.linea.punctum.cavum";
612         else if (prefix_set & CAVUM)
613           glyph_name = "vaticana.punctum.cavum";
614         else
615           glyph_name = "vaticana.linea.punctum";
616       else if (prefix_set & AUCTUM)
617         if (prefix_set & ASCENDENS)
618           glyph_name = "solesmes.auct.asc";
619         else
620           glyph_name = "solesmes.auct.desc";
621       else if ((context_info & STACKED_HEAD)
622                && (context_info & PES_UPPER))
623         if (prev_delta_pitch > 1)
624           glyph_name = "vaticana.upes";
625         else
626           glyph_name = "vaticana.vupes";
627       else
628         glyph_name = "vaticana.punctum";
629
630       /*
631        * This head needs a cauda, if it starts a flexa, is not the upper
632        * head of a pes, and if it is a punctum.
633        */
634       if ((context_info & FLEXA_LEFT) && ! (context_info & PES_UPPER))
635         if (glyph_name == "vaticana.punctum")
636           primitive->set_property ("add-cauda", ly_bool2scm (true));
637
638       /*
639        * Execptional rule for porrectus:
640        *
641        * If the current head is preceded by a \flexa and succeded by a
642        * \pes (e.g. "a \flexa g \pes a"), then join the current head and
643        * the previous head into a single curved flexa shape.
644        */
645       if ((context_info & FLEXA_RIGHT) && (context_info & PES_LOWER))
646         {
647           check_for_prefix_loss (prev_primitive);
648           prev_glyph_name = "flexa";
649           prev_primitive->set_property ("flexa-height",
650                                         scm_from_int (prev_delta_pitch));
651           prev_primitive->set_property ("flexa-width",
652                                         scm_from_double (flexa_width));
653           bool add_cauda = !(prev_prefix_set && PES_OR_FLEXA);
654           prev_primitive->set_property ("add-cauda",
655                                         ly_bool2scm (add_cauda));
656           check_for_prefix_loss (primitive);
657           glyph_name = "";
658           primitive->set_property ("flexa-width",
659                                    scm_from_double (flexa_width));
660         }
661
662       /*
663        * Exceptional rule for pes:
664        *
665        * If this head is stacked on the previous one due to a \pes, then
666        * set the glyph of the previous head to that for this special
667        * case, thereby avoiding potential vertical collision with the
668        * current head.
669        */
670       if (prefix_set & PES_OR_FLEXA)
671         {
672           if ((context_info & PES_UPPER) && (context_info & STACKED_HEAD))
673             {
674               if (prev_glyph_name == "vaticana.punctum")
675                 if (prev_delta_pitch > 1)
676                   prev_glyph_name = "vaticana.lpes";
677                 else
678                   prev_glyph_name = "vaticana.vlpes";
679             }
680         }
681
682       if (prev_primitive)
683         prev_primitive->set_property ("glyph-name",
684                                       ly_string2scm (prev_glyph_name));
685
686       /*
687        * In the backend, flexa shapes and joins need to know about line
688        * thickness.  Hence, for simplicity, let's distribute the
689        * ligature grob's value for thickness to each ligature head (even
690        * if not all of them need to know).
691        */
692       primitive->set_property ("thickness", scm_from_double (thickness));
693
694       prev_primitive = primitive;
695       prev_prefix_set = prefix_set;
696       prev_context_info = context_info;
697       prev_delta_pitch = delta_pitch;
698       prev_glyph_name = glyph_name;
699     }
700
701   prev_primitive->set_property ("glyph-name",
702                                 ly_string2scm (prev_glyph_name));
703
704   align_heads (primitives, flexa_width, thickness);
705
706   // append all dots to paper column of ligature's last head
707   add_mora_column (prev_primitive->get_column ());
708
709 #if 0 // experimental code to collapse spacing after ligature
710   /* TODO: set to max (old/new spacing-increment), since other
711      voices/staves also may want to set this property. */
712   Item *first_primitive = dynamic_cast<Item *> (primitives[0].grob ());
713   Paper_column *paper_column = first_primitive->get_column ();
714   paper_column->warning (_f ("Vaticana_ligature_engraver: "
715                              "setting `spacing-increment = %f': ptr =%ul",
716                              ligature_width, paper_column));
717   paper_column->
718     set_property ("forced-spacing", scm_from_double (ligature_width));
719 #endif
720 }
721
722 ADD_ACKNOWLEDGER (Vaticana_ligature_engraver, rest);
723 ADD_ACKNOWLEDGER (Vaticana_ligature_engraver, note_head);
724 ADD_TRANSLATOR (Vaticana_ligature_engraver,
725                 /* doc */ "Handles ligatures by glueing special ligature heads together.",
726                 /* create */ "VaticanaLigature DotColumn",
727                 /* read */ "",
728                 /* write */ "");