-b eps -> -dbackend=eps
[lilypond.git] / lily / vaticana-ligature-engraver.cc
blob5007d553ca8b91bcf68ce50d09bfb1ea9f4e0de3
1 /*
2 vaticana-ligature-engraver.cc -- implement Vaticana_ligature_engraver
4 source file of the GNU LilyPond music typesetter
6 (c) 2003--2007 Juergen Reuter <reuter@ipd.uka.de>
7 */
9 #include "gregorian-ligature-engraver.hh"
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"
27 * This class implements the notation specific aspects of Vaticana
28 * style ligatures for Gregorian chant notation.
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.
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.
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?
49 class Vaticana_ligature_engraver : public Gregorian_ligature_engraver
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_;
66 public:
67 TRANSLATOR_DECLARATIONS (Vaticana_ligature_engraver);
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);
77 IMPLEMENT_TRANSLATOR_LISTENER (Vaticana_ligature_engraver, pes_or_flexa);
78 void
79 Vaticana_ligature_engraver::listen_pes_or_flexa (Stream_event *ev)
81 Gregorian_ligature_engraver::listen_pes_or_flexa (ev);
84 IMPLEMENT_TRANSLATOR_LISTENER (Vaticana_ligature_engraver, ligature);
85 void
86 Vaticana_ligature_engraver::listen_ligature (Stream_event *ev)
88 Ligature_engraver::listen_ligature (ev);
91 Vaticana_ligature_engraver::Vaticana_ligature_engraver ()
93 brew_ligature_primitive_proc =
94 Vaticana_ligature::brew_ligature_primitive_proc;
95 augmented_primitives_.clear ();
98 Spanner *
99 Vaticana_ligature_engraver::create_ligature_spanner ()
101 return make_spanner ("VaticanaLigature", SCM_EOL);
104 bool
105 Vaticana_ligature_engraver::is_stacked_head (int prefix_set,
106 int context_info)
108 bool is_stacked_b;
110 // upper head of pes is stacked upon lower head of pes ...
111 is_stacked_b = context_info & PES_UPPER;
113 // ... unless this note starts a flexa
114 if (context_info & FLEXA_LEFT)
115 is_stacked_b = false;
117 // ... or another pes
118 if (context_info & PES_LOWER)
119 is_stacked_b = false;
121 // ... or the previous note is a semivocalis or inclinatum
122 if (context_info & AFTER_DEMINUTUM)
123 is_stacked_b = false;
125 // auctum head is never stacked upon preceding note
126 if (prefix_set & AUCTUM)
127 is_stacked_b = false;
129 // virga is never stacked upon preceding note
130 if (prefix_set & VIRGA)
131 is_stacked_b = false;
133 // oriscus is never stacked upon preceding note
134 if (prefix_set & ORISCUS)
135 is_stacked_b = false;
137 if ((prefix_set & DEMINUTUM)
138 && ! (prefix_set & INCLINATUM)
139 && (context_info & FLEXA_RIGHT))
140 is_stacked_b = true; // semivocalis head of deminutus form
142 return is_stacked_b;
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.
151 bool
152 Vaticana_ligature_engraver::need_extra_horizontal_space (int prev_prefix_set, int prefix_set,
153 int context_info, int delta_pitch)
155 if (prev_prefix_set & VIRGA)
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.
161 return true;
163 if ((prefix_set & INCLINATUM)
164 && ! (prev_prefix_set & INCLINATUM))
166 * Always start a series of inclinatum heads with an extra space.
168 return true;
170 if ((context_info & FLEXA_LEFT) && ! (context_info & PES_UPPER))
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.
176 return true;
178 if (delta_pitch == 0)
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.
184 return true;
186 return false;
189 Real
190 Vaticana_ligature_engraver::align_heads (vector<Grob_info> primitives,
191 Real flexa_width,
192 Real thickness)
194 if (!primitives.size ())
196 programming_error ("Vaticana_ligature: "
197 "empty ligature [ignored]");
198 return 0.0;
202 * The paper column where we put the whole ligature into.
204 Paper_column *column
205 = dynamic_cast<Item *> (primitives[0].grob ())->get_column ();
207 Real join_thickness
208 = thickness * column->layout ()->get_dimension (ly_symbol2scm ("line-thickness"));
211 * Amount of extra space two put between some particular
212 * configurations of adjacent heads.
214 * TODO: make this a property of primtive grobs.
216 Real extra_space = 4.0 * join_thickness;
219 * Keep track of the total width of the ligature.
221 Real ligature_width = 0.0;
223 Item *prev_primitive = 0;
224 int prev_prefix_set = 0;
225 for (vsize i = 0; i < primitives.size (); i++)
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"));
234 * Get glyph_name, delta_pitch and context_info for this head.
237 SCM glyph_name_scm = primitive->get_property ("glyph-name");
238 if (glyph_name_scm == SCM_EOL)
240 primitive->programming_error ("Vaticana_ligature:"
241 "undefined glyph-name -> "
242 "ignoring grob");
243 continue;
245 string glyph_name = ly_scm2string (glyph_name_scm);
247 int delta_pitch = 0;
248 if (prev_primitive) /* urgh, need prev_primitive only here */
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
255 primitive->programming_error ("Vaticana_ligature:"
256 "delta-position undefined -> "
257 "ignoring grob");
258 continue;
263 * Now determine width and x-offset of head.
266 Real head_width;
267 Real x_offset;
269 if (context_info & STACKED_HEAD)
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.
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 ();
283 else if (glyph_name == "flexa" || glyph_name == "")
286 * This head represents either half of a flexa shape.
287 * Hence, it is assigned half the width of this shape.
289 head_width = 0.5 * flexa_width;
290 x_offset = 0.0;
292 else
295 * This is a regular head, placed right to the previous one.
296 * Retrieve its width from corresponding font.
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;
305 * Save the head's final x-offset.
307 primitive->set_property ("x-offset",
308 scm_from_double (x_offset));
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.
315 if ((context_info & PES_UPPER)
316 || ((context_info & FLEXA_RIGHT)
317 && ! (context_info & PES_LOWER)))
319 if (!prev_primitive)
321 primitive->programming_error ("vaticana ligature: add-join: "
322 "missing previous primitive");
324 else
326 prev_primitive->set_property ("add-join",
327 ly_bool2scm (true));
330 * Create a small overlap of adjacent heads so that the join
331 * can be drawn perfectly between them.
333 ligature_width -= join_thickness;
336 else if (glyph_name == "")
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.
346 if (need_extra_horizontal_space (prev_prefix_set, prefix_set,
347 context_info, delta_pitch))
348 ligature_width += extra_space;
351 * Horizontally line-up this head to form a ligature.
353 move_related_items_to_column (primitive, column, ligature_width);
354 ligature_width += head_width;
356 prev_primitive = primitive;
357 prev_prefix_set = prefix_set;
361 * Add extra horizontal padding space after ligature, such that
362 * neighbouring ligatures do not touch each other.
364 ligature_width += extra_space;
366 return ligature_width;
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.
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.
380 void
381 Vaticana_ligature_engraver::check_for_prefix_loss (Item *primitive)
383 int prefix_set
384 = scm_to_int (primitive->get_property ("prefix-set"));
385 if (prefix_set & ~PES_OR_FLEXA)
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 ()));
394 void
395 Vaticana_ligature_engraver::add_mora_column (Paper_column *column)
397 if (augmented_primitives_.size () == 0) // no dot for column
398 return;
399 if (!column) // empty ligature???
401 augmented_primitives_[0].grob ()->
402 programming_error ("no paper column to add dot");
403 return;
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++)
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);
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.
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.
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.
433 void
434 Vaticana_ligature_engraver::check_for_ambiguous_dot_pitch (Grob_info primitive)
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++)
445 Stream_event *cause = augmented_primitives_[i].event_cause ();
446 int pitch = unsmob_pitch (cause->get_property ("pitch"))->steps ();
447 if (pitch == new_pitch)
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
458 void
459 Vaticana_ligature_engraver::transform_heads (Spanner *ligature,
460 vector<Grob_info> primitives)
462 Real flexa_width = robust_scm2double (ligature->get_property ("flexa-width"), 2);
464 Real thickness = robust_scm2double (ligature->get_property ("thickness"), 1);
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++)
474 Item *primitive = dynamic_cast<Item *> (primitives[i].grob ());
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
482 primitive->programming_error ("Vaticana_ligature:"
483 "delta-position undefined -> "
484 "ignoring grob");
485 continue;
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"));
494 if (Rhythmic_head::dot_count (primitive) > 0)
495 // remove dots from primitive and add remember primitive for
496 // creating a dot column
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.
503 check_for_ambiguous_dot_pitch (primitives[i]);
504 augmented_primitives_.push_back (primitives[i]);
506 else if (augmented_primitives_.size () > 0)
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.");
514 if (is_stacked_head (prefix_set, context_info))
516 context_info |= STACKED_HEAD;
517 primitive->set_property ("context-info",
518 scm_from_int (context_info));
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).
527 string glyph_name;
528 if (prefix_set & VIRGA)
530 glyph_name = "vaticana.punctum";
531 primitive->set_property ("add-stem", ly_bool2scm (true));
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)
551 // initio debilis
552 glyph_name = "vaticana.reverse.plica";
554 else if (prev_delta_pitch > 0)
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";
568 else if (prev_delta_pitch < 0)
570 // cephalicus
571 if (! (prev_context_info & FLEXA_RIGHT))
572 /* correct head of previous primitive */
574 if (i > 1)
576 /* cephalicus head with fixed size cauda */
577 prev_glyph_name = "vaticana.inner.cephalicus";
579 else
581 /* cephalicus head without cauda */
582 prev_glyph_name = "vaticana.cephalicus";
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.
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.
595 prev_primitive->set_property ("add-cauda",
596 ly_bool2scm (false));
598 if (prev_delta_pitch < - 1)
599 glyph_name = "vaticana.reverse.plica";
600 else
601 glyph_name = "vaticana.reverse.vplica";
603 else // (prev_delta_pitch == 0)
605 primitive->programming_error ("Vaticana_ligature:"
606 "deminutum head must have different "
607 "pitch -> ignoring grob");
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";
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.
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));
639 * Execptional rule for porrectus:
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.
645 if ((context_info & FLEXA_RIGHT) && (context_info & PES_LOWER))
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));
663 * Exceptional rule for pes:
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.
670 if (prefix_set & PES_OR_FLEXA)
672 if ((context_info & PES_UPPER) && (context_info & STACKED_HEAD))
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";
682 if (prev_primitive)
683 prev_primitive->set_property ("glyph-name",
684 ly_string2scm (prev_glyph_name));
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).
692 primitive->set_property ("thickness", scm_from_double (thickness));
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;
701 prev_primitive->set_property ("glyph-name",
702 ly_string2scm (prev_glyph_name));
704 align_heads (primitives, flexa_width, thickness);
706 // append all dots to paper column of ligature's last head
707 add_mora_column (prev_primitive->get_column ());
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
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 */ "");