Bumping manifests a=b2g-bump
[gecko.git] / layout / svg / nsSVGEffects.h
blob0aaee9654b6cd64d3d8673b2bba0455c5673c545
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef NSSVGEFFECTS_H_
7 #define NSSVGEFFECTS_H_
9 #include "mozilla/Attributes.h"
10 #include "FramePropertyTable.h"
11 #include "mozilla/dom/Element.h"
12 #include "nsHashKeys.h"
13 #include "nsID.h"
14 #include "nsIFrame.h"
15 #include "nsIMutationObserver.h"
16 #include "nsInterfaceHashtable.h"
17 #include "nsISupportsBase.h"
18 #include "nsISupportsImpl.h"
19 #include "nsReferencedElement.h"
20 #include "nsStubMutationObserver.h"
21 #include "nsSVGUtils.h"
22 #include "nsTHashtable.h"
23 #include "nsURIHashKey.h"
25 class nsIAtom;
26 class nsIPresShell;
27 class nsIURI;
28 class nsSVGClipPathFrame;
29 class nsSVGPaintServerFrame;
30 class nsSVGFilterFrame;
31 class nsSVGMaskFrame;
34 * This interface allows us to be notified when a piece of SVG content is
35 * re-rendered.
37 * Concrete implementations of this interface need to implement
38 * "GetTarget()" to specify the piece of SVG content that they'd like to
39 * monitor, and they need to implement "DoUpdate" to specify how we'll react
40 * when that content gets re-rendered. They also need to implement a
41 * constructor and destructor, which should call StartListening and
42 * StopListening, respectively.
44 class nsSVGRenderingObserver : public nsStubMutationObserver {
46 protected:
47 virtual ~nsSVGRenderingObserver()
50 public:
51 typedef mozilla::dom::Element Element;
52 nsSVGRenderingObserver()
53 : mInObserverList(false)
56 // nsISupports
57 NS_DECL_ISUPPORTS
59 // nsIMutationObserver
60 NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
61 NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
62 NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
63 NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
65 void InvalidateViaReferencedElement();
67 // When a nsSVGRenderingObserver list gets forcibly cleared, it uses this
68 // callback to notify every observer that's cleared from it, so they can
69 // react.
70 void NotifyEvictedFromRenderingObserverList();
72 bool IsInObserverList() const { return mInObserverList; }
74 nsIFrame* GetReferencedFrame();
75 /**
76 * @param aOK this is only for the convenience of callers. We set *aOK to false
77 * if the frame is the wrong type
79 nsIFrame* GetReferencedFrame(nsIAtom* aFrameType, bool* aOK);
81 Element* GetReferencedElement();
83 virtual bool ObservesReflow() { return true; }
85 protected:
86 // Non-virtual protected methods
87 void StartListening();
88 void StopListening();
90 // Virtual protected methods
91 virtual void DoUpdate() = 0; // called when the referenced resource changes.
93 // This is an internally-used version of GetReferencedElement that doesn't
94 // forcibly add us as an observer. (whereas GetReferencedElement does)
95 virtual Element* GetTarget() = 0;
97 // Whether we're in our referenced element's observer list at this time.
98 bool mInObserverList;
103 * SVG elements reference supporting resources by element ID. We need to
104 * track when those resources change and when the DOM changes in ways
105 * that affect which element is referenced by a given ID (e.g., when
106 * element IDs change). The code here is responsible for that.
108 * When a frame references a supporting resource, we create a property
109 * object derived from nsSVGIDRenderingObserver to manage the relationship. The
110 * property object is attached to the referencing frame.
112 class nsSVGIDRenderingObserver : public nsSVGRenderingObserver {
113 public:
114 typedef mozilla::dom::Element Element;
115 nsSVGIDRenderingObserver(nsIURI* aURI, nsIFrame *aFrame,
116 bool aReferenceImage);
117 virtual ~nsSVGIDRenderingObserver();
119 protected:
120 Element* GetTarget() MOZ_OVERRIDE { return mElement.get(); }
122 // This is called when the referenced resource changes.
123 virtual void DoUpdate() MOZ_OVERRIDE;
125 class SourceReference : public nsReferencedElement {
126 public:
127 explicit SourceReference(nsSVGIDRenderingObserver* aContainer) : mContainer(aContainer) {}
128 protected:
129 virtual void ElementChanged(Element* aFrom, Element* aTo) MOZ_OVERRIDE {
130 mContainer->StopListening();
131 nsReferencedElement::ElementChanged(aFrom, aTo);
132 mContainer->StartListening();
133 mContainer->DoUpdate();
136 * Override IsPersistent because we want to keep tracking the element
137 * for the ID even when it changes.
139 virtual bool IsPersistent() MOZ_OVERRIDE { return true; }
140 private:
141 nsSVGIDRenderingObserver* mContainer;
144 SourceReference mElement;
145 // The frame that this property is attached to
146 nsIFrame *mFrame;
147 // When a presshell is torn down, we don't delete the properties for
148 // each frame until after the frames are destroyed. So here we remember
149 // the presshell for the frames we care about and, before we use the frame,
150 // we test the presshell to see if it's destroying itself. If it is,
151 // then the frame pointer is not valid and we know the frame has gone away.
152 nsIPresShell *mFramePresShell;
156 * In a filter chain, there can be multiple SVG reference filters.
157 * e.g. filter: url(#svg-filter-1) blur(10px) url(#svg-filter-2);
159 * This class keeps track of one SVG reference filter in a filter chain.
160 * e.g. url(#svg-filter-1)
162 * It fires invalidations when the SVG filter element's id changes or when
163 * the SVG filter element's content changes.
165 * The nsSVGFilterProperty class manages a list of nsSVGFilterReferences.
167 class nsSVGFilterReference MOZ_FINAL :
168 public nsSVGIDRenderingObserver, public nsISVGFilterReference {
169 public:
170 nsSVGFilterReference(nsIURI *aURI, nsIFrame *aFilteredFrame)
171 : nsSVGIDRenderingObserver(aURI, aFilteredFrame, false) {}
173 bool ReferencesValidResource() { return GetFilterFrame(); }
176 * @return the filter frame, or null if there is no filter frame
178 nsSVGFilterFrame *GetFilterFrame();
180 // nsISupports
181 NS_DECL_ISUPPORTS_INHERITED
183 // nsISVGFilterReference
184 virtual void Invalidate() MOZ_OVERRIDE { DoUpdate(); };
186 protected:
187 virtual ~nsSVGFilterReference() {}
189 private:
190 // nsSVGIDRenderingObserver
191 virtual void DoUpdate() MOZ_OVERRIDE;
195 * This class manages a list of nsSVGFilterReferences, which represent SVG
196 * reference filters in a filter chain.
197 * e.g. filter: url(#svg-filter-1) blur(10px) url(#svg-filter-2);
199 * In the above example, the nsSVGFilterProperty will manage two
200 * nsSVGFilterReferences, one for each SVG reference filter. CSS filters like
201 * "blur(10px)" don't reference filter elements, so they don't need an
202 * nsSVGFilterReference. The style system invalidates changes to CSS filters.
204 class nsSVGFilterProperty : public nsISupports {
205 public:
206 nsSVGFilterProperty(const nsTArray<nsStyleFilter> &aFilters,
207 nsIFrame *aFilteredFrame);
209 const nsTArray<nsStyleFilter>& GetFilters() { return mFilters; }
210 bool ReferencesValidResources();
211 bool IsInObserverLists() const;
212 void Invalidate();
214 // nsISupports
215 NS_DECL_ISUPPORTS
217 protected:
218 virtual ~nsSVGFilterProperty();
220 private:
221 nsTArray<nsSVGFilterReference*> mReferences;
222 nsTArray<nsStyleFilter> mFilters;
225 class nsSVGMarkerProperty : public nsSVGIDRenderingObserver {
226 public:
227 nsSVGMarkerProperty(nsIURI *aURI, nsIFrame *aFrame, bool aReferenceImage)
228 : nsSVGIDRenderingObserver(aURI, aFrame, aReferenceImage) {}
230 protected:
231 virtual void DoUpdate() MOZ_OVERRIDE;
234 class nsSVGTextPathProperty : public nsSVGIDRenderingObserver {
235 public:
236 nsSVGTextPathProperty(nsIURI *aURI, nsIFrame *aFrame, bool aReferenceImage)
237 : nsSVGIDRenderingObserver(aURI, aFrame, aReferenceImage)
238 , mValid(true) {}
240 virtual bool ObservesReflow() MOZ_OVERRIDE { return false; }
242 protected:
243 virtual void DoUpdate() MOZ_OVERRIDE;
245 private:
247 * Returns true if the target of the textPath is the frame of a 'path' element.
249 bool TargetIsValid();
251 bool mValid;
254 class nsSVGPaintingProperty : public nsSVGIDRenderingObserver {
255 public:
256 nsSVGPaintingProperty(nsIURI *aURI, nsIFrame *aFrame, bool aReferenceImage)
257 : nsSVGIDRenderingObserver(aURI, aFrame, aReferenceImage) {}
259 protected:
260 virtual void DoUpdate() MOZ_OVERRIDE;
264 * A manager for one-shot nsSVGRenderingObserver tracking.
265 * nsSVGRenderingObservers can be added or removed. They are not strongly
266 * referenced so an observer must be removed before it dies.
267 * When InvalidateAll is called, all outstanding references get
268 * InvalidateViaReferencedElement()
269 * called on them and the list is cleared. The intent is that
270 * the observer will force repainting of whatever part of the document
271 * is needed, and then at paint time the observer will do a clean lookup
272 * of the referenced element and [re-]add itself to the element's observer list.
274 * InvalidateAll must be called before this object is destroyed, i.e.
275 * before the referenced frame is destroyed. This should normally happen
276 * via nsSVGContainerFrame::RemoveFrame, since only frames in the frame
277 * tree should be referenced.
279 class nsSVGRenderingObserverList {
280 public:
281 nsSVGRenderingObserverList()
282 : mObservers(4)
284 MOZ_COUNT_CTOR(nsSVGRenderingObserverList);
287 ~nsSVGRenderingObserverList() {
288 InvalidateAll();
289 MOZ_COUNT_DTOR(nsSVGRenderingObserverList);
292 void Add(nsSVGRenderingObserver* aObserver)
293 { mObservers.PutEntry(aObserver); }
294 void Remove(nsSVGRenderingObserver* aObserver)
295 { mObservers.RemoveEntry(aObserver); }
296 #ifdef DEBUG
297 bool Contains(nsSVGRenderingObserver* aObserver)
298 { return (mObservers.GetEntry(aObserver) != nullptr); }
299 #endif
300 bool IsEmpty()
301 { return mObservers.Count() == 0; }
304 * Drop all our observers, and notify them that we have changed and dropped
305 * our reference to them.
307 void InvalidateAll();
310 * Drop all observers that observe reflow, and notify them that we have changed and dropped
311 * our reference to them.
313 void InvalidateAllForReflow();
316 * Drop all our observers, and notify them that we have dropped our reference
317 * to them.
319 void RemoveAll();
321 private:
322 nsTHashtable<nsPtrHashKey<nsSVGRenderingObserver> > mObservers;
325 class nsSVGEffects {
326 public:
327 typedef mozilla::dom::Element Element;
328 typedef mozilla::FramePropertyDescriptor FramePropertyDescriptor;
329 typedef nsInterfaceHashtable<nsURIHashKey, nsIMutationObserver>
330 URIObserverHashtable;
332 static void DestroySupports(void* aPropertyValue)
334 (static_cast<nsISupports*>(aPropertyValue))->Release();
337 static void DestroyHashtable(void* aPropertyValue)
339 delete static_cast<URIObserverHashtable*> (aPropertyValue);
342 NS_DECLARE_FRAME_PROPERTY(FilterProperty, DestroySupports)
343 NS_DECLARE_FRAME_PROPERTY(MaskProperty, DestroySupports)
344 NS_DECLARE_FRAME_PROPERTY(ClipPathProperty, DestroySupports)
345 NS_DECLARE_FRAME_PROPERTY(MarkerBeginProperty, DestroySupports)
346 NS_DECLARE_FRAME_PROPERTY(MarkerMiddleProperty, DestroySupports)
347 NS_DECLARE_FRAME_PROPERTY(MarkerEndProperty, DestroySupports)
348 NS_DECLARE_FRAME_PROPERTY(FillProperty, DestroySupports)
349 NS_DECLARE_FRAME_PROPERTY(StrokeProperty, DestroySupports)
350 NS_DECLARE_FRAME_PROPERTY(HrefProperty, DestroySupports)
351 NS_DECLARE_FRAME_PROPERTY(BackgroundImageProperty, DestroyHashtable)
354 * Get the paint server for a aTargetFrame.
356 static nsSVGPaintServerFrame *GetPaintServer(nsIFrame *aTargetFrame,
357 const nsStyleSVGPaint *aPaint,
358 const FramePropertyDescriptor *aProperty);
360 struct EffectProperties {
361 nsSVGFilterProperty* mFilter;
362 nsSVGPaintingProperty* mMask;
363 nsSVGPaintingProperty* mClipPath;
366 * @return the clip-path frame, or null if there is no clip-path frame
367 * @param aOK if a clip-path was specified and the designated element
368 * exists but is an element of the wrong type, *aOK is set to false.
369 * Otherwise *aOK is untouched.
371 nsSVGClipPathFrame *GetClipPathFrame(bool *aOK);
373 * @return the mask frame, or null if there is no mask frame
374 * @param aOK if a mask was specified and the designated element
375 * exists but is an element of the wrong type, *aOK is set to false.
376 * Otherwise *aOK is untouched.
378 nsSVGMaskFrame *GetMaskFrame(bool *aOK);
380 bool HasValidFilter() {
381 return mFilter && mFilter->ReferencesValidResources();
384 bool HasNoFilterOrHasValidFilter() {
385 return !mFilter || mFilter->ReferencesValidResources();
390 * @param aFrame should be the first continuation
392 static EffectProperties GetEffectProperties(nsIFrame *aFrame);
395 * Called when changes to an element (e.g. CSS property changes) cause its
396 * frame to start/stop referencing (or reference different) SVG resource
397 * elements. (_Not_ called for changes to referenced resource elements.)
399 * This function handles such changes by discarding _all_ the frame's SVG
400 * effects frame properties (causing those properties to stop watching their
401 * target element). It also synchronously (re)creates the filter and marker
402 * frame properties (XXX why not the other properties?), which makes it
403 * useful for initializing those properties during first reflow.
405 * XXX rename to something more meaningful like RefreshResourceReferences?
407 static void UpdateEffects(nsIFrame *aFrame);
410 * @param aFrame should be the first continuation
412 static nsSVGFilterProperty *GetFilterProperty(nsIFrame *aFrame);
415 * @param aFrame must be a first-continuation.
417 static void AddRenderingObserver(Element *aElement, nsSVGRenderingObserver *aObserver);
419 * @param aFrame must be a first-continuation.
421 static void RemoveRenderingObserver(Element *aElement, nsSVGRenderingObserver *aObserver);
424 * Removes all rendering observers from aElement.
426 static void RemoveAllRenderingObservers(Element *aElement);
429 * This can be called on any frame. We invalidate the observers of aFrame's
430 * element, if any, or else walk up to the nearest observable SVG parent
431 * frame with observers and invalidate them instead.
433 * Note that this method is very different to e.g.
434 * nsNodeUtils::AttributeChanged which walks up the content node tree all the
435 * way to the root node (not stopping if it encounters a non-container SVG
436 * node) invalidating all mutation observers (not just
437 * nsSVGRenderingObservers) on all nodes along the way (not just the first
438 * node it finds with observers). In other words, by doing all the
439 * things in parentheses in the preceding sentence, this method uses
440 * knowledge about our implementation and what can be affected by SVG effects
441 * to make invalidation relatively lightweight when an SVG effect changes.
443 static void InvalidateRenderingObservers(nsIFrame *aFrame);
445 enum {
446 INVALIDATE_REFLOW = 1
450 * This can be called on any element or frame. Only direct observers of this
451 * (frame's) element, if any, are invalidated.
453 static void InvalidateDirectRenderingObservers(Element *aElement, uint32_t aFlags = 0);
454 static void InvalidateDirectRenderingObservers(nsIFrame *aFrame, uint32_t aFlags = 0);
457 * Get an nsSVGMarkerProperty for the frame, creating a fresh one if necessary
459 static nsSVGMarkerProperty *
460 GetMarkerProperty(nsIURI *aURI, nsIFrame *aFrame,
461 const FramePropertyDescriptor *aProperty);
463 * Get an nsSVGTextPathProperty for the frame, creating a fresh one if necessary
465 static nsSVGTextPathProperty *
466 GetTextPathProperty(nsIURI *aURI, nsIFrame *aFrame,
467 const FramePropertyDescriptor *aProperty);
469 * Get an nsSVGPaintingProperty for the frame, creating a fresh one if necessary
471 static nsSVGPaintingProperty *
472 GetPaintingProperty(nsIURI *aURI, nsIFrame *aFrame,
473 const FramePropertyDescriptor *aProperty);
475 * Get an nsSVGPaintingProperty for the frame for that URI, creating a fresh
476 * one if necessary
478 static nsSVGPaintingProperty *
479 GetPaintingPropertyForURI(nsIURI *aURI, nsIFrame *aFrame,
480 const FramePropertyDescriptor *aProp);
483 #endif /*NSSVGEFFECTS_H_*/