no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / layout / svg / SVGObserverUtils.h
blob04ee6f3acf4abc9d1d9ccf129aa14bbc155c3e36
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef LAYOUT_SVG_SVGOBSERVERUTILS_H_
8 #define LAYOUT_SVG_SVGOBSERVERUTILS_H_
10 #include "mozilla/Attributes.h"
11 #include "mozilla/SVGIntegrationUtils.h"
12 #include "mozilla/dom/IDTracker.h"
13 #include "FrameProperties.h"
14 #include "nsID.h"
15 #include "nsIFrame.h" // only for LayoutFrameType
16 #include "nsIMutationObserver.h"
17 #include "nsISupports.h"
18 #include "nsISupportsImpl.h"
19 #include "nsIReferrerInfo.h"
20 #include "nsStringFwd.h"
21 #include "nsStubMutationObserver.h"
22 #include "nsStyleStruct.h"
24 class nsAtom;
25 class nsCycleCollectionTraversalCallback;
26 class nsIFrame;
27 class nsIURI;
29 namespace mozilla {
30 class SVGClipPathFrame;
31 class SVGFilterFrame;
32 class SVGMarkerFrame;
33 class SVGMaskFrame;
34 class SVGPaintServerFrame;
36 namespace dom {
37 class CanvasRenderingContext2D;
38 class Element;
39 class SVGGeometryElement;
40 class SVGMPathElement;
41 } // namespace dom
42 } // namespace mozilla
44 namespace mozilla {
47 * This class contains URL and referrer information (referrer and referrer
48 * policy).
49 * We use it to pass to svg system instead of nsIURI. The object brings referrer
50 * and referrer policy so we can send correct Referer headers.
52 class URLAndReferrerInfo {
53 public:
54 URLAndReferrerInfo(nsIURI* aURI, nsIReferrerInfo* aReferrerInfo)
55 : mURI(aURI), mReferrerInfo(aReferrerInfo) {
56 MOZ_ASSERT(aURI);
59 URLAndReferrerInfo(nsIURI* aURI, const URLExtraData& aExtraData)
60 : mURI(aURI), mReferrerInfo(aExtraData.ReferrerInfo()) {
61 MOZ_ASSERT(aURI);
64 NS_INLINE_DECL_REFCOUNTING(URLAndReferrerInfo)
66 nsIURI* GetURI() const { return mURI; }
67 nsIReferrerInfo* GetReferrerInfo() const { return mReferrerInfo; }
69 bool operator==(const URLAndReferrerInfo& aRHS) const;
71 private:
72 ~URLAndReferrerInfo() = default;
74 nsCOMPtr<nsIURI> mURI;
75 nsCOMPtr<nsIReferrerInfo> mReferrerInfo;
78 /**
79 * This interface allows us to be notified when a piece of SVG content is
80 * re-rendered.
82 * Concrete implementations of this base class need to implement
83 * GetReferencedElementWithoutObserving to specify the SVG element that
84 * they'd like to monitor for rendering changes, and they need to implement
85 * OnRenderingChange to specify how we'll react when that content gets
86 * re-rendered. They also need to implement a constructor and destructor,
87 * which should call StartObserving and StopObserving, respectively.
89 * The referenced element is generally looked up and stored during
90 * construction. If the referenced element is in an extenal SVG resource
91 * document, the lookup code will initiate loading of the external resource and
92 * OnRenderingChange will be called once the element in the external resource
93 * is available.
95 * Although the referenced element may be found and stored during construction,
96 * observing for rendering changes does not start until requested.
98 class SVGRenderingObserver : public nsStubMutationObserver {
99 protected:
100 virtual ~SVGRenderingObserver() = default;
102 public:
103 using Element = dom::Element;
105 SVGRenderingObserver(uint32_t aCallbacks = kAttributeChanged |
106 kContentAppended |
107 kContentInserted |
108 kContentRemoved) {
109 SetEnabledCallbacks(aCallbacks);
112 // nsIMutationObserver
113 NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
114 NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
115 NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
116 NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
119 * Called when non-DOM-mutation changes to the observed element should likely
120 * cause the rendering of our observer to change. This includes changes to
121 * CSS computed values, but also changes to rendering observers that the
122 * observed element itself may have (for example, when we're being used to
123 * observe an SVG pattern, and an element in that pattern references and
124 * observes a gradient that has changed).
126 void OnNonDOMMutationRenderingChange();
128 // When a SVGRenderingObserver list gets forcibly cleared, it uses this
129 // callback to notify every observer that's cleared from it, so they can
130 // react.
131 void NotifyEvictedFromRenderingObserverSet();
133 nsIFrame* GetAndObserveReferencedFrame();
135 * @param aOK this is only for the convenience of callers. We set *aOK to
136 * false if the frame is the wrong type
138 nsIFrame* GetAndObserveReferencedFrame(mozilla::LayoutFrameType aFrameType,
139 bool* aOK);
141 Element* GetAndObserveReferencedElement();
143 virtual bool ObservesReflow() { return false; }
145 protected:
146 void StartObserving();
147 void StopObserving();
150 * Called whenever the rendering of the observed element may have changed.
152 * More specifically, this method is called whenever DOM mutation occurs in
153 * the observed element's subtree, or whenever
154 * SVGObserverUtils::InvalidateRenderingObservers or
155 * SVGObserverUtils::InvalidateDirectRenderingObservers is called for the
156 * observed element's frame.
158 * Subclasses should override this method to handle rendering changes
159 * appropriately.
161 virtual void OnRenderingChange() = 0;
163 virtual Element* GetReferencedElementWithoutObserving() = 0;
165 #ifdef DEBUG
166 void DebugObserverSet();
167 #endif
169 // Whether we're in our observed element's observer set at this time.
170 bool mInObserverSet = false;
173 class SVGObserverUtils {
174 public:
175 using CanvasRenderingContext2D = dom::CanvasRenderingContext2D;
176 using Element = dom::Element;
177 using SVGGeometryElement = dom::SVGGeometryElement;
178 using HrefToTemplateCallback = const std::function<void(nsAString&)>&;
181 * Ensures that that if the given frame requires any resources that are in
182 * SVG resource documents that the loading of those documents is initiated.
183 * This does not make aFrame start to observe any elements that it
184 * references.
186 static void InitiateResourceDocLoads(nsIFrame* aFrame);
189 * Called when changes to an element (e.g. CSS property changes) cause its
190 * frame to start/stop referencing (or reference different) SVG resource
191 * elements. (_Not_ called for changes to referenced resource elements.)
193 * This function handles such changes by discarding _all_ the frame's SVG
194 * effects frame properties (causing those properties to stop watching their
195 * target element). It also synchronously (re)creates the filter and marker
196 * frame properties (XXX why not the other properties?), which makes it
197 * useful for initializing those properties during first reflow.
199 * XXX rename to something more meaningful like RefreshResourceReferences?
201 static void UpdateEffects(nsIFrame* aFrame);
204 * @param aFrame must be a first-continuation.
206 static void AddRenderingObserver(Element* aElement,
207 SVGRenderingObserver* aObserver);
209 * @param aFrame must be a first-continuation.
211 static void RemoveRenderingObserver(Element* aElement,
212 SVGRenderingObserver* aObserver);
215 * Removes all rendering observers from aElement.
217 static void RemoveAllRenderingObservers(Element* aElement);
220 * This can be called on any frame. We invalidate the observers of aFrame's
221 * element, if any, or else walk up to the nearest observable SVG parent
222 * frame with observers and invalidate them instead.
224 * Note that this method is very different to e.g.
225 * MutationObservers::AttributeChanged which walks up the content node tree
226 * all the way to the root node (not stopping if it encounters a non-container
227 * SVG node) invalidating all mutation observers (not just
228 * SVGRenderingObservers) on all nodes along the way (not just the first
229 * node it finds with observers). In other words, by doing all the
230 * things in parentheses in the preceding sentence, this method uses
231 * knowledge about our implementation and what can be affected by SVG effects
232 * to make invalidation relatively lightweight when an SVG effect changes.
234 static void InvalidateRenderingObservers(nsIFrame* aFrame);
236 enum { INVALIDATE_REFLOW = 1 };
238 enum ReferenceState {
239 /// Has no references to SVG filters (may still have CSS filter functions!)
240 eHasNoRefs,
241 eHasRefsAllValid,
242 eHasRefsSomeInvalid,
246 * This can be called on any element or frame. Only direct observers of this
247 * (frame's) element, if any, are invalidated.
249 static void InvalidateDirectRenderingObservers(Element* aElement,
250 uint32_t aFlags = 0);
251 static void InvalidateDirectRenderingObservers(nsIFrame* aFrame,
252 uint32_t aFlags = 0);
255 * Get the paint server for aPaintedFrame.
257 static SVGPaintServerFrame* GetAndObservePaintServer(
258 nsIFrame* aPaintedFrame, mozilla::StyleSVGPaint nsStyleSVG::*aPaint);
261 * Get the start/mid/end-markers for the given frame, and add the frame as
262 * an observer to those markers. Returns true if at least one marker type is
263 * found, false otherwise.
265 static bool GetAndObserveMarkers(nsIFrame* aMarkedFrame,
266 SVGMarkerFrame* (*aFrames)[3]);
269 * Get the frames of the SVG filters applied to the given frame, and add the
270 * frame as an observer to those filter frames.
272 * NOTE! A return value of eHasNoRefs does NOT mean that there are no filters
273 * to be applied, only that there are no references to SVG filter elements.
275 * @param aIsBackdrop whether we're observing a backdrop-filter or a filter.
277 * XXX Callers other than ComputePostEffectsInkOverflowRect and
278 * SVGUtils::GetPostFilterInkOverflowRect should not need to initiate
279 * observing. If we have a bug that causes invalidation (which would remove
280 * observers) between reflow and painting, then we don't really want to
281 * re-add abservers during painting. That has the potential to hide logic
282 * bugs, or cause later invalidation problems. However, let's not change
283 * that behavior just yet due to the regression potential.
285 static ReferenceState GetAndObserveFilters(
286 nsIFrame* aFilteredFrame, nsTArray<SVGFilterFrame*>* aFilterFrames,
287 StyleFilterType aStyleFilterType = StyleFilterType::Filter);
290 * NOTE! canvas doesn't have backdrop-filters so there's no StyleFilterType
291 * parameter.
293 static ReferenceState GetAndObserveFilters(
294 nsISupports* aObserverList, nsTArray<SVGFilterFrame*>* aFilterFrames);
297 * If the given frame is already observing SVG filters, this function gets
298 * those filters. If the frame is not already observing filters this
299 * function assumes that it doesn't have anything to observe.
301 static ReferenceState GetFiltersIfObserving(
302 nsIFrame* aFilteredFrame, nsTArray<SVGFilterFrame*>* aFilterFrames);
305 * Starts observing filters for a <canvas> element's CanvasRenderingContext2D.
307 * Returns a RAII object that the caller should make sure is released once
308 * the CanvasRenderingContext2D is no longer using them (that is, when the
309 * CanvasRenderingContext2D "drawing style state" on which the filters were
310 * set is destroyed or has its filter style reset).
312 * XXXjwatt: It's a bit unfortunate that both we and
313 * CanvasRenderingContext2D::UpdateFilter process the list of StyleFilter
314 * objects separately. It would be better to refactor things so that we only
315 * do that work once.
317 static already_AddRefed<nsISupports> ObserveFiltersForCanvasContext(
318 CanvasRenderingContext2D* aContext, Element* aCanvasElement,
319 Span<const StyleFilter> aFilters);
322 * Called when cycle collecting CanvasRenderingContext2D, and requires the
323 * RAII object returned from ObserveFiltersForCanvasContext to be passed in.
325 * XXXjwatt: I don't think this is doing anything useful. All we do under
326 * this function is clear a raw C-style (i.e. not strong) pointer. That's
327 * clearly not helping in breaking any cycles. The fact that we MOZ_CRASH
328 * in OnRenderingChange if that pointer is null indicates that this isn't
329 * even doing anything useful in terms of preventing further invalidation
330 * from any observed filters.
332 static void DetachFromCanvasContext(nsISupports* aAutoObserver);
335 * Get the frame of the SVG clipPath applied to aClippedFrame, if any, and
336 * set up aClippedFrame as a rendering observer of the clipPath's frame, to
337 * be invalidated if it changes.
339 * Currently we only have support for 'clip-path' with a single item, but the
340 * spec. now says 'clip-path' can be set to an arbitrary number of items.
341 * Once we support that, aClipPathFrame will need to be an nsTArray as it
342 * is for 'filter' and 'mask'. Currently a return value of eHasNoRefs means
343 * that there is no clipping at all, but once we support more than one item
344 * then - as for filter and mask - we could still have basic shape clipping
345 * to apply even if there are no references to SVG clipPath elements.
347 * Note that, unlike for filters, a reference to an ID that doesn't exist
348 * is not invalid for clip-path or mask. We will return eHasNoRefs in that
349 * case.
351 static ReferenceState GetAndObserveClipPath(
352 nsIFrame* aClippedFrame, SVGClipPathFrame** aClipPathFrame);
355 * Get the element of the SVG Shape element, if any, and set up |aFrame| as a
356 * rendering observer of the geometry frame, to post a restyle if it changes.
358 * We use this function to resolve offset-path:url() and build the equivalent
359 * path from this shape element, and generate the transformation from for CSS
360 * Motion.
362 static SVGGeometryElement* GetAndObserveGeometry(nsIFrame* aFrame);
365 * If masking is applied to aMaskedFrame, gets an array of any SVG masks
366 * that are referenced, setting up aMaskFrames as a rendering observer of
367 * those masks (if any).
369 * NOTE! A return value of eHasNoRefs does NOT mean that there are no masks
370 * to be applied, only that there are no references to SVG mask elements.
372 * Note that, unlike for filters, a reference to an ID that doesn't exist
373 * is not invalid for clip-path or mask. We will return eHasNoRefs in that
374 * case.
376 static ReferenceState GetAndObserveMasks(
377 nsIFrame* aMaskedFrame, nsTArray<SVGMaskFrame*>* aMaskFrames);
380 * Get the SVGGeometryElement that is referenced by aTextPathFrame, and make
381 * aTextPathFrame start observing rendering changes to that element.
383 static SVGGeometryElement* GetAndObserveTextPathsPath(
384 nsIFrame* aTextPathFrame);
387 * Make aTextPathFrame stop observing rendering changes to the
388 * SVGGeometryElement that it references, if any.
390 static void RemoveTextPathObserver(nsIFrame* aTextPathFrame);
393 * Get the SVGGeometryElement that is referenced by aSVGMPathElement, and
394 * make aSVGMPathElement start observing rendering changes to that element.
396 static SVGGeometryElement* GetAndObserveMPathsPath(
397 dom::SVGMPathElement* aSVGMPathElement);
399 static void TraverseMPathObserver(dom::SVGMPathElement* aSVGMPathElement,
400 nsCycleCollectionTraversalCallback* aCB);
403 * Gets the nsIFrame of a referenced SVG "template" element, if any, and
404 * makes aFrame start observing rendering changes to the template element.
406 * Template elements: some elements like gradients, pattern or filter can
407 * reference another element of the same type using their 'href' attribute,
408 * and use that element as a template that provides attributes or content
409 * that is missing from the referring element.
411 * The frames that this function is called for do not have a common base
412 * class, which is why it is necessary to pass in a function that can be
413 * used as a callback to lazily get the href value, if necessary.
415 static nsIFrame* GetAndObserveTemplate(nsIFrame* aFrame,
416 HrefToTemplateCallback aGetHref);
418 static void RemoveTemplateObserver(nsIFrame* aFrame);
421 * Gets an arbitrary element and starts observing it. Used to implement
422 * '-moz-element'.
424 * Note that bug 1496065 has been filed to remove support for referencing
425 * arbitrary elements using '-moz-element'.
427 static Element* GetAndObserveBackgroundImage(nsIFrame* aFrame,
428 const nsAtom* aHref);
431 * Gets an arbitrary element and starts observing it. Used to detect
432 * invalidation changes for background-clip:text.
434 static Element* GetAndObserveBackgroundClip(nsIFrame* aFrame);
437 } // namespace mozilla
439 #endif // LAYOUT_SVG_SVGOBSERVERUTILS_H_