]> git.donarmstrong.com Git - lilypond.git/blob - lily/engraver-group-engraver.cc
* lily/include/translator.icc (ADD_ACKNOWLEDGER): new macro.
[lilypond.git] / lily / engraver-group-engraver.cc
1 /*
2   engraver-group-engraver.cc -- implement Engraver_group_engraver
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1997--2005 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8
9 #include "engraver-group-engraver.hh"
10
11 #include "warn.hh"
12 #include "paper-score.hh"
13 #include "grob.hh"
14 #include "context.hh"
15 #include "translator-dispatch-list.hh"
16
17 void
18 Engraver_group_engraver::announce_grob (Grob_info info)
19 {
20   announce_infos_.push (info);
21
22   Engraver_group_engraver * dad_eng =
23     context_->get_parent_context ()
24     ? dynamic_cast<Engraver_group_engraver*> (context_->get_parent_context ()->implementation ())
25     : 0;
26   if (dad_eng)
27     dad_eng->announce_grob (info);
28 }
29
30 SCM find_acknowledge_engravers (SCM gravlist, SCM meta);
31 SCM find_accept_engravers (SCM gravlist, SCM music_descr);
32
33 void
34 Engraver_group_engraver::acknowledge_grobs ()
35 {
36   if (!announce_infos_.size ())
37     return;
38
39   SCM name_sym = ly_symbol2scm ("name");
40   SCM meta_sym = ly_symbol2scm ("meta");
41
42   for (int j = 0; j < announce_infos_.size (); j++)
43     {
44       Grob_info info = announce_infos_[j];
45
46       SCM meta = info.grob ()->internal_get_property (meta_sym);
47       SCM nm = scm_assoc (name_sym, meta);
48       if (scm_is_pair (nm))
49         nm = scm_cdr (nm);
50       else
51         {
52           /*
53             it's tempting to put an assert for
54             immutable_property_alist_ == '(), but in fact, some
55             engravers (clef-engraver) add some more information to the
56             immutable_property_alist_ (after it has been '()-ed).
57
58             We ignore the grob anyway. He who has no name, shall not
59             be helped.  */
60
61           continue;
62         }
63
64       SCM acklist = scm_hashq_ref (acknowledge_hash_table_, nm, SCM_UNDEFINED);
65       Engraver_dispatch_list *dispatch
66         = Engraver_dispatch_list::unsmob (acklist);
67
68       if (acklist == SCM_BOOL_F)
69         {
70           SCM ifaces
71             = scm_cdr (scm_assoc (ly_symbol2scm ("interfaces"), meta));
72           acklist = Engraver_dispatch_list::create (get_simple_trans_list (),
73                                                       ifaces);
74
75           dispatch
76             = Engraver_dispatch_list::unsmob (acklist);
77
78           if (dispatch)
79             scm_hashq_set_x (acknowledge_hash_table_, nm, acklist);
80         }
81
82
83       if (dispatch)
84         {
85           dispatch->apply (info);
86         }
87       else
88         {
89           if (acklist == SCM_BOOL_F)
90             {
91               acklist = find_acknowledge_engravers (get_simple_trans_list (),
92                                                     meta);
93               scm_hashq_set_x (acknowledge_hash_table_, nm, acklist);
94             }
95
96           for (SCM p = acklist; scm_is_pair (p); p = scm_cdr (p))
97             {
98               Translator *t = unsmob_translator (scm_car (p));
99               Engraver *eng = dynamic_cast<Engraver *> (t);
100               if (eng && eng != info.origin_translator ())
101                 eng->acknowledge_grob (info);
102             }
103         }
104     }
105 }
106 /*
107   Ugh. This is slightly expensive. We could/should cache the value of
108   the group count?
109 */
110 int
111 Engraver_group_engraver::pending_grob_count () const
112 {
113   int count = announce_infos_.size ();
114   for (SCM s = context_->children_contexts ();
115        scm_is_pair (s); s = scm_cdr (s))
116     {
117       Context *c = unsmob_context (scm_car (s));
118       Engraver_group_engraver *group
119         = dynamic_cast<Engraver_group_engraver *> (c->implementation ());
120
121       if (group)
122         count += group->pending_grob_count ();
123     }
124   return count;
125 }
126
127 void
128 Engraver_group_engraver::do_announces ()
129 {
130   do
131     {
132       for (SCM s = context ()->children_contexts ();
133            scm_is_pair (s); s = scm_cdr (s))
134         {
135           Context *c = unsmob_context (scm_car (s));
136           Engraver_group_engraver *group
137             = dynamic_cast<Engraver_group_engraver *> (c->implementation ());
138           if (group)
139             group->do_announces ();
140         }
141
142       while (1)
143         {
144           precomputed_translator_foreach (PROCESS_ACKNOWLEDGED);
145           if (announce_infos_.size () == 0)
146             break;
147
148           acknowledge_grobs ();
149           announce_infos_.clear ();
150         }
151     }
152   while (pending_grob_count () > 0);
153 }
154
155
156 Engraver_group_engraver::Engraver_group_engraver ()
157 {
158   acknowledge_hash_table_ = SCM_EOL;
159   acknowledge_hash_table_ = scm_c_make_hash_table (61);
160 }
161
162 #include "translator.icc"
163
164 ADD_TRANSLATOR_GROUP (Engraver_group_engraver,
165                       /* descr */ "A group of engravers taken together",
166                       /* creats*/ "",
167                       /* accepts */ "",
168                       /* acks  */ "",
169                       /* reads */ "",
170                       /* write */ "");
171
172
173 bool
174 engraver_valid (Translator *tr, SCM ifaces)
175 {
176   SCM ack_ifs = scm_assoc (ly_symbol2scm ("interfaces-acked"),
177                            tr->translator_description ());
178   ack_ifs = scm_cdr (ack_ifs);
179   for (SCM s = ifaces; scm_is_pair (s); s = scm_cdr (s))
180     if (scm_c_memq (scm_car (s), ack_ifs) != SCM_BOOL_F)
181       return true;
182   return false;
183 }
184
185 SCM
186 find_acknowledge_engravers (SCM gravlist, SCM ifaces)
187 {
188   SCM l = SCM_EOL;
189   for (SCM s = gravlist; scm_is_pair (s); s = scm_cdr (s))
190     {
191       Translator *tr = unsmob_translator (scm_car (s));
192       if (engraver_valid (tr, ifaces))
193         l = scm_cons (tr->self_scm (), l);
194     }
195   l = scm_reverse_x (l, SCM_EOL);
196
197   return l;
198 }
199
200 void
201 Engraver_group_engraver::derived_mark () const
202 {
203   scm_gc_mark (acknowledge_hash_table_);
204 }