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