For all these cases, we need to repaint the referencing element/frame
when referenced content changes --- but we actually care about the
styles in the referenced content too, since they affect rendering.
There are several schemes in use:
1) <use> installs itself as a mutation observer on the referenced
subtree. This works fine as far as I can tell so I'll leave that
alone.
2) For fliters, clip-paths and masks, the referencing frame gets a
property attached to it that acts as a mutation observer on the
referenced content subtree. There are bugs because the style of frames
for the referenced subtree can change and the referencing frame
doesn't notice and doesn't get repainted.
3) For paint servers, the referencing frame acts as an
nsISVGValueObserver observing the referenced frame.
3a) For gradients, style changes, frame changes and relevant attribute
changes on the stop and gradient frames send notifications through the
value-observer framework and things seem to work OK. When one gradient
references another, it installs itself as an nsISVGValueObserver of
the other and that works.
3b) For patterns, the pattern element installs itself as a mutation
observer on its own subtree. Style and attribute changes to the
pattern frame send notifications through the value-observer framework
OK, and content subtree changes are noticed by the pattern element
which forwards notifications through the value-observer framework, but
as in case 2, style changes to children of the pattern are not
necessarily detected.
4) We don't implement tref references yet.
5) textPath makes itself a mutation observer of the referenced path. I
don't *think* style changes can influence paths so this is probably
OK.
Clip-paths, masks and patterns have the additional problem that if
their subtree content references a resource, we basically fail to
propagate changes from that resource through the clip-path, mask or
pattern to users of that clip-path, mask or pattern --- we invalidate
rendering for the referencing content, but we don't propagate
notifications.
On trunk there is another issue: we don't detect changes in which
element is *the* element for a given ID. This can change when elements
with the given ID are added to or removed from the DOM or when IDs are
changed. I have a fix for this in my SVG branch but it doesn't cover
all the ID-reference usage yet.
We also have to worry about circular references, which can cause
problems both when we paint and when we invalidate (infinite
recursion). It's pretty easy to produce stack overflows on trunk ---
we generally check for cycles with a single kind of reference edge in
them, but it's easy to create examples that crash. Patterns that
reference each other, a pattern that references a mask that references
the pattern, etc.
I want to fix the bugs here and simplify the code, plus prepare for
future expansion where any frame can use an SVG paint server, by
unifying as much of this as possible. Here's my plan:
a) for every frame that references another frame, we have a frame
property attached to the referencing frame. This property is
persistent and contains the object that tracks ID changes; it
maintains a reference to the referenced content element.
b) at paint time, we resolve the referenced frame and add the property
as an observer of the referenced frame.
c) style changes, frame tree changes, attribute changes and change
notifications in SVG frame subtrees search for the nearest clipPath,
filter, mask, pattern, or gradient frame, and notify all observers of
that frame that the referenced rendering has changed. When we do that,
we should remove the observers! They'll be re-added next time they
paint. This avoids infinite recursion and speeds things up too because
we send less notifications. We could optimize these notifications
using a frame state bit to indicate whether an SVG frame has a
clipPath, filter, mask, pattern, or gradient ancestor with observers.
d) to prevent infinite recursion when painting, we should probably use
a flag in each reference property to indicate whether it's already
active for the current paint stack. If it is, we should refuse to
traverse it again.
e) we can get rid of mutation observers for clipPath, filter, mask and
pattern, and the use of nsSVGValueObserver here.
Any thoughts? I wonder if I've missed any major issues.
Rob