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