On Wed, Sep 26, 2012 at 4:15 AM, m...@mikesolomon.org <m...@mikesolomon.org>wrote:
> Hey all, > > As was the case in a few of my previous projects, before I start something > new I make architecture changes that facilitate my work. Working on 2801, > I've realized that any multi-pass algorithm for the spacing of grobs is > difficult because results of callback calculations are always cached. So > triggering callbacks a second time is, in the current architecture, > impractical and requires a fair bit of kludgery. > Are you proposing not to cache callbacks at all? That sounds like a real performance killer to me; we would probably end up re-typesetting each beam hundreds of times. By the way, the problem is not only in the caching of callbacks; there are also many other places with side effects (calls to set_property, translate_axis, suicide, etc). To start this process, I'd like to expand the role of the > side-position-interface significantly. All grobs would use this interface > for their X and Y offsets and they would have two different grob arrays for > X and Y side-position-elements. This would allow me to eliminate two > things: > > 1) parents. Grobs are X/Y aligned to parents, but these parents could be > elements in the side-position-elements array. Functions like get_parent, > which could be kept around for legacy reasons, could return the first > element of these arrays for a given axis and raise a warning if there are > multiple elements. > If you get rid of unique parents, what would X-offset mean? Would it be relative to the System? The first element of side-position-elements array? 2) outside-staff-priority. Saying a grob has outside staff priority is the > same thing as saying that a grob has as its Y side support elements all > inside-staff grobs plus all grobs with lower outside staff priority. A > callback creating the side-position-elements arrays could do the sorting > that takes place in Axis_group_interface::skyline_spacing. > I think you'll have trouble making this fully callbacky/functional. For example, we lay out the outside-staff grobs in a very particular order (the left-to-right layout thing), which we don't know ahead of time. That is, until we get _all_ of the outside-staff grobs together, we don't know which grobs have to depend on which other grobs. That means it isn't really possible for each grob to determine its own position; there needs to be one grob that lays them out simultaneously. The same issue will come up, I think in laying out Accidentals and VerticalAxisGroups. At some point, I had grand plans to formalize this problem by having two distinct kinds of properties: one that is user-overridable using callbacks, and one that is internal and gets set by other grobs as a side-effect. Everything would have explicit dependencies so that caches could be invalidated. I even started to write a proof-of-concept in scala, but I never finished it... > The benefits of this are twofold: > > 1) All work on a multi-pass algorithm could be done with respect to > side-positioning, making it simpler to find bugs and modify code. > Not all positioning is side-positioning. 2) A call to translate_axis in avoid_outside_staff_collisions would be > eliminated, and translate_axis is bad: it goes against the callback model > at the core of LilyPond layout. > Agreed, but this is just one instance of translate_axis, which is just one example of a side-effect in lilypond. Is your eventual goal to remove them all? The disadvantage is that this results in the construction of many more > skylines (one for each call to > Side_position_interface::skyline_side_position). How this will impact > performance is uncertain, but it'd probably require more optimization in > skyline.cc and/or caching of skylines. > I would suggest that you completely ignore performance in favor of a clean design. Performance can come later. Cheers, Joe
_______________________________________________ lilypond-devel mailing list lilypond-devel@gnu.org https://lists.gnu.org/mailman/listinfo/lilypond-devel