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