mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-01 00:32:11 +00:00
b1fa3e3b36
nsISupports.h includes nsISupportsBase.h, so it should be equivalent. In the next patch, I'm changing things so that nsISupports is defined in nsISupports.h instead of nsISupportsBase.h, and deleting the latter, so this change will be needed anyways. I'm guessing people were using IWYU or something like that. Differential Revision: https://phabricator.services.mozilla.com/D159169
421 lines
16 KiB
C++
421 lines
16 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#ifndef LAYOUT_SVG_SVGOBSERVERUTILS_H_
|
|
#define LAYOUT_SVG_SVGOBSERVERUTILS_H_
|
|
|
|
#include "mozilla/Attributes.h"
|
|
#include "mozilla/dom/IDTracker.h"
|
|
#include "FrameProperties.h"
|
|
#include "nsID.h"
|
|
#include "nsIFrame.h" // only for LayoutFrameType
|
|
#include "nsIMutationObserver.h"
|
|
#include "nsISupports.h"
|
|
#include "nsISupportsImpl.h"
|
|
#include "nsIReferrerInfo.h"
|
|
#include "nsStringFwd.h"
|
|
#include "nsStubMutationObserver.h"
|
|
#include "nsStyleStruct.h"
|
|
#include "nsCycleCollectionParticipant.h"
|
|
|
|
class nsAtom;
|
|
class nsIFrame;
|
|
class nsIURI;
|
|
|
|
namespace mozilla {
|
|
class SVGClipPathFrame;
|
|
class SVGFilterFrame;
|
|
class SVGMarkerFrame;
|
|
class SVGMaskFrame;
|
|
class SVGPaintServerFrame;
|
|
|
|
namespace dom {
|
|
class CanvasRenderingContext2D;
|
|
class Element;
|
|
class SVGGeometryElement;
|
|
} // namespace dom
|
|
} // namespace mozilla
|
|
|
|
namespace mozilla {
|
|
|
|
/*
|
|
* This class contains URL and referrer information (referrer and referrer
|
|
* policy).
|
|
* We use it to pass to svg system instead of nsIURI. The object brings referrer
|
|
* and referrer policy so we can send correct Referer headers.
|
|
*/
|
|
class URLAndReferrerInfo {
|
|
public:
|
|
URLAndReferrerInfo(nsIURI* aURI, nsIReferrerInfo* aReferrerInfo)
|
|
: mURI(aURI), mReferrerInfo(aReferrerInfo) {
|
|
MOZ_ASSERT(aURI);
|
|
}
|
|
|
|
URLAndReferrerInfo(nsIURI* aURI, const URLExtraData& aExtraData)
|
|
: mURI(aURI), mReferrerInfo(aExtraData.ReferrerInfo()) {
|
|
MOZ_ASSERT(aURI);
|
|
}
|
|
|
|
NS_INLINE_DECL_REFCOUNTING(URLAndReferrerInfo)
|
|
|
|
nsIURI* GetURI() const { return mURI; }
|
|
nsIReferrerInfo* GetReferrerInfo() const { return mReferrerInfo; }
|
|
|
|
bool operator==(const URLAndReferrerInfo& aRHS) const;
|
|
|
|
private:
|
|
~URLAndReferrerInfo() = default;
|
|
|
|
nsCOMPtr<nsIURI> mURI;
|
|
nsCOMPtr<nsIReferrerInfo> mReferrerInfo;
|
|
};
|
|
|
|
/**
|
|
* This interface allows us to be notified when a piece of SVG content is
|
|
* re-rendered.
|
|
*
|
|
* Concrete implementations of this base class need to implement
|
|
* GetReferencedElementWithoutObserving to specify the SVG element that
|
|
* they'd like to monitor for rendering changes, and they need to implement
|
|
* OnRenderingChange to specify how we'll react when that content gets
|
|
* re-rendered. They also need to implement a constructor and destructor,
|
|
* which should call StartObserving and StopObserving, respectively.
|
|
*
|
|
* The referenced element is generally looked up and stored during
|
|
* construction. If the referenced element is in an extenal SVG resource
|
|
* document, the lookup code will initiate loading of the external resource and
|
|
* OnRenderingChange will be called once the element in the external resource
|
|
* is available.
|
|
*
|
|
* Although the referenced element may be found and stored during construction,
|
|
* observing for rendering changes does not start until requested.
|
|
*/
|
|
class SVGRenderingObserver : public nsStubMutationObserver {
|
|
protected:
|
|
virtual ~SVGRenderingObserver() = default;
|
|
|
|
public:
|
|
using Element = dom::Element;
|
|
|
|
SVGRenderingObserver() : mInObserverSet(false) {}
|
|
|
|
// nsIMutationObserver
|
|
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
|
|
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
|
|
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
|
|
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
|
|
|
|
/**
|
|
* Called when non-DOM-mutation changes to the observed element should likely
|
|
* cause the rendering of our observer to change. This includes changes to
|
|
* CSS computed values, but also changes to rendering observers that the
|
|
* observed element itself may have (for example, when we're being used to
|
|
* observe an SVG pattern, and an element in that pattern references and
|
|
* observes a gradient that has changed).
|
|
*/
|
|
void OnNonDOMMutationRenderingChange();
|
|
|
|
// When a SVGRenderingObserver list gets forcibly cleared, it uses this
|
|
// callback to notify every observer that's cleared from it, so they can
|
|
// react.
|
|
void NotifyEvictedFromRenderingObserverSet();
|
|
|
|
nsIFrame* GetAndObserveReferencedFrame();
|
|
/**
|
|
* @param aOK this is only for the convenience of callers. We set *aOK to
|
|
* false if the frame is the wrong type
|
|
*/
|
|
nsIFrame* GetAndObserveReferencedFrame(mozilla::LayoutFrameType aFrameType,
|
|
bool* aOK);
|
|
|
|
Element* GetAndObserveReferencedElement();
|
|
|
|
virtual bool ObservesReflow() { return false; }
|
|
|
|
protected:
|
|
void StartObserving();
|
|
void StopObserving();
|
|
|
|
/**
|
|
* Called whenever the rendering of the observed element may have changed.
|
|
*
|
|
* More specifically, this method is called whenever DOM mutation occurs in
|
|
* the observed element's subtree, or whenever
|
|
* SVGObserverUtils::InvalidateRenderingObservers or
|
|
* SVGObserverUtils::InvalidateDirectRenderingObservers is called for the
|
|
* observed element's frame.
|
|
*
|
|
* Subclasses should override this method to handle rendering changes
|
|
* appropriately.
|
|
*/
|
|
virtual void OnRenderingChange() = 0;
|
|
|
|
virtual Element* GetReferencedElementWithoutObserving() = 0;
|
|
|
|
#ifdef DEBUG
|
|
void DebugObserverSet();
|
|
#endif
|
|
|
|
// Whether we're in our observed element's observer set at this time.
|
|
bool mInObserverSet;
|
|
};
|
|
|
|
class SVGObserverUtils {
|
|
public:
|
|
using CanvasRenderingContext2D = dom::CanvasRenderingContext2D;
|
|
using Element = dom::Element;
|
|
using SVGGeometryElement = dom::SVGGeometryElement;
|
|
using HrefToTemplateCallback = const std::function<void(nsAString&)>&;
|
|
|
|
/**
|
|
* Ensures that that if the given frame requires any resources that are in
|
|
* SVG resource documents that the loading of those documents is initiated.
|
|
* This does not make aFrame start to observe any elements that it
|
|
* references.
|
|
*/
|
|
static void InitiateResourceDocLoads(nsIFrame* aFrame);
|
|
|
|
/**
|
|
* Called when changes to an element (e.g. CSS property changes) cause its
|
|
* frame to start/stop referencing (or reference different) SVG resource
|
|
* elements. (_Not_ called for changes to referenced resource elements.)
|
|
*
|
|
* This function handles such changes by discarding _all_ the frame's SVG
|
|
* effects frame properties (causing those properties to stop watching their
|
|
* target element). It also synchronously (re)creates the filter and marker
|
|
* frame properties (XXX why not the other properties?), which makes it
|
|
* useful for initializing those properties during first reflow.
|
|
*
|
|
* XXX rename to something more meaningful like RefreshResourceReferences?
|
|
*/
|
|
static void UpdateEffects(nsIFrame* aFrame);
|
|
|
|
/**
|
|
* @param aFrame must be a first-continuation.
|
|
*/
|
|
static void AddRenderingObserver(Element* aElement,
|
|
SVGRenderingObserver* aObserver);
|
|
/**
|
|
* @param aFrame must be a first-continuation.
|
|
*/
|
|
static void RemoveRenderingObserver(Element* aElement,
|
|
SVGRenderingObserver* aObserver);
|
|
|
|
/**
|
|
* Removes all rendering observers from aElement.
|
|
*/
|
|
static void RemoveAllRenderingObservers(Element* aElement);
|
|
|
|
/**
|
|
* This can be called on any frame. We invalidate the observers of aFrame's
|
|
* element, if any, or else walk up to the nearest observable SVG parent
|
|
* frame with observers and invalidate them instead.
|
|
*
|
|
* Note that this method is very different to e.g.
|
|
* MutationObservers::AttributeChanged which walks up the content node tree
|
|
* all the way to the root node (not stopping if it encounters a non-container
|
|
* SVG node) invalidating all mutation observers (not just
|
|
* SVGRenderingObservers) on all nodes along the way (not just the first
|
|
* node it finds with observers). In other words, by doing all the
|
|
* things in parentheses in the preceding sentence, this method uses
|
|
* knowledge about our implementation and what can be affected by SVG effects
|
|
* to make invalidation relatively lightweight when an SVG effect changes.
|
|
*/
|
|
static void InvalidateRenderingObservers(nsIFrame* aFrame);
|
|
|
|
enum { INVALIDATE_REFLOW = 1 };
|
|
|
|
enum ReferenceState {
|
|
/// Has no references to SVG filters (may still have CSS filter functions!)
|
|
eHasNoRefs,
|
|
eHasRefsAllValid,
|
|
eHasRefsSomeInvalid,
|
|
};
|
|
|
|
/**
|
|
* This can be called on any element or frame. Only direct observers of this
|
|
* (frame's) element, if any, are invalidated.
|
|
*/
|
|
static void InvalidateDirectRenderingObservers(Element* aElement,
|
|
uint32_t aFlags = 0);
|
|
static void InvalidateDirectRenderingObservers(nsIFrame* aFrame,
|
|
uint32_t aFlags = 0);
|
|
|
|
/**
|
|
* Get the paint server for aPaintedFrame.
|
|
*/
|
|
static SVGPaintServerFrame* GetAndObservePaintServer(
|
|
nsIFrame* aPaintedFrame, mozilla::StyleSVGPaint nsStyleSVG::*aPaint);
|
|
|
|
/**
|
|
* Get the start/mid/end-markers for the given frame, and add the frame as
|
|
* an observer to those markers. Returns true if at least one marker type is
|
|
* found, false otherwise.
|
|
*/
|
|
static bool GetAndObserveMarkers(nsIFrame* aMarkedFrame,
|
|
SVGMarkerFrame* (*aFrames)[3]);
|
|
|
|
/**
|
|
* Get the frames of the SVG filters applied to the given frame, and add the
|
|
* frame as an observer to those filter frames.
|
|
*
|
|
* NOTE! A return value of eHasNoRefs does NOT mean that there are no filters
|
|
* to be applied, only that there are no references to SVG filter elements.
|
|
*
|
|
* XXX Callers other than ComputePostEffectsInkOverflowRect and
|
|
* SVGUtils::GetPostFilterInkOverflowRect should not need to initiate
|
|
* observing. If we have a bug that causes invalidation (which would remove
|
|
* observers) between reflow and painting, then we don't really want to
|
|
* re-add abservers during painting. That has the potential to hide logic
|
|
* bugs, or cause later invalidation problems. However, let's not change
|
|
* that behavior just yet due to the regression potential.
|
|
*/
|
|
static ReferenceState GetAndObserveFilters(
|
|
nsIFrame* aFilteredFrame, nsTArray<SVGFilterFrame*>* aFilterFrames);
|
|
|
|
/**
|
|
* If the given frame is already observing SVG filters, this function gets
|
|
* those filters. If the frame is not already observing filters this
|
|
* function assumes that it doesn't have anything to observe.
|
|
*/
|
|
static ReferenceState GetFiltersIfObserving(
|
|
nsIFrame* aFilteredFrame, nsTArray<SVGFilterFrame*>* aFilterFrames);
|
|
|
|
/**
|
|
* Starts observing filters for a <canvas> element's CanvasRenderingContext2D.
|
|
*
|
|
* Returns a RAII object that the caller should make sure is released once
|
|
* the CanvasRenderingContext2D is no longer using them (that is, when the
|
|
* CanvasRenderingContext2D "drawing style state" on which the filters were
|
|
* set is destroyed or has its filter style reset).
|
|
*
|
|
* XXXjwatt: It's a bit unfortunate that both we and
|
|
* CanvasRenderingContext2D::UpdateFilter process the list of StyleFilter
|
|
* objects separately. It would be better to refactor things so that we only
|
|
* do that work once.
|
|
*/
|
|
static already_AddRefed<nsISupports> ObserveFiltersForCanvasContext(
|
|
CanvasRenderingContext2D* aContext, Element* aCanvasElement,
|
|
Span<const StyleFilter> aFilters);
|
|
|
|
/**
|
|
* Called when cycle collecting CanvasRenderingContext2D, and requires the
|
|
* RAII object returned from ObserveFiltersForCanvasContext to be passed in.
|
|
*
|
|
* XXXjwatt: I don't think this is doing anything useful. All we do under
|
|
* this function is clear a raw C-style (i.e. not strong) pointer. That's
|
|
* clearly not helping in breaking any cycles. The fact that we MOZ_CRASH
|
|
* in OnRenderingChange if that pointer is null indicates that this isn't
|
|
* even doing anything useful in terms of preventing further invalidation
|
|
* from any observed filters.
|
|
*/
|
|
static void DetachFromCanvasContext(nsISupports* aAutoObserver);
|
|
|
|
/**
|
|
* Get the frame of the SVG clipPath applied to aClippedFrame, if any, and
|
|
* set up aClippedFrame as a rendering observer of the clipPath's frame, to
|
|
* be invalidated if it changes.
|
|
*
|
|
* Currently we only have support for 'clip-path' with a single item, but the
|
|
* spec. now says 'clip-path' can be set to an arbitrary number of items.
|
|
* Once we support that, aClipPathFrame will need to be an nsTArray as it
|
|
* is for 'filter' and 'mask'. Currently a return value of eHasNoRefs means
|
|
* that there is no clipping at all, but once we support more than one item
|
|
* then - as for filter and mask - we could still have basic shape clipping
|
|
* to apply even if there are no references to SVG clipPath elements.
|
|
*
|
|
* Note that, unlike for filters, a reference to an ID that doesn't exist
|
|
* is not invalid for clip-path or mask. We will return eHasNoRefs in that
|
|
* case.
|
|
*/
|
|
static ReferenceState GetAndObserveClipPath(
|
|
nsIFrame* aClippedFrame, SVGClipPathFrame** aClipPathFrame);
|
|
|
|
/**
|
|
* If masking is applied to aMaskedFrame, gets an array of any SVG masks
|
|
* that are referenced, setting up aMaskFrames as a rendering observer of
|
|
* those masks (if any).
|
|
*
|
|
* NOTE! A return value of eHasNoRefs does NOT mean that there are no masks
|
|
* to be applied, only that there are no references to SVG mask elements.
|
|
*
|
|
* Note that, unlike for filters, a reference to an ID that doesn't exist
|
|
* is not invalid for clip-path or mask. We will return eHasNoRefs in that
|
|
* case.
|
|
*/
|
|
static ReferenceState GetAndObserveMasks(
|
|
nsIFrame* aMaskedFrame, nsTArray<SVGMaskFrame*>* aMaskFrames);
|
|
|
|
/**
|
|
* Get the SVGGeometryElement that is referenced by aTextPathFrame, and make
|
|
* aTextPathFrame start observing rendering changes to that element.
|
|
*/
|
|
static SVGGeometryElement* GetAndObserveTextPathsPath(
|
|
nsIFrame* aTextPathFrame);
|
|
|
|
/**
|
|
* Make aTextPathFrame stop observing rendering changes to the
|
|
* SVGGeometryElement that it references, if any.
|
|
*/
|
|
static void RemoveTextPathObserver(nsIFrame* aTextPathFrame);
|
|
|
|
/**
|
|
* Gets the nsIFrame of a referenced SVG "template" element, if any, and
|
|
* makes aFrame start observing rendering changes to the template element.
|
|
*
|
|
* Template elements: some elements like gradients, pattern or filter can
|
|
* reference another element of the same type using their 'href' attribute,
|
|
* and use that element as a template that provides attributes or content
|
|
* that is missing from the referring element.
|
|
*
|
|
* The frames that this function is called for do not have a common base
|
|
* class, which is why it is necessary to pass in a function that can be
|
|
* used as a callback to lazily get the href value, if necessary.
|
|
*/
|
|
static nsIFrame* GetAndObserveTemplate(nsIFrame* aFrame,
|
|
HrefToTemplateCallback aGetHref);
|
|
|
|
static void RemoveTemplateObserver(nsIFrame* aFrame);
|
|
|
|
/**
|
|
* Gets an arbitrary element and starts observing it. Used to implement
|
|
* '-moz-element'.
|
|
*
|
|
* Note that bug 1496065 has been filed to remove support for referencing
|
|
* arbitrary elements using '-moz-element'.
|
|
*/
|
|
static Element* GetAndObserveBackgroundImage(nsIFrame* aFrame,
|
|
const nsAtom* aHref);
|
|
|
|
/**
|
|
* Gets an arbitrary element and starts observing it. Used to detect
|
|
* invalidation changes for background-clip:text.
|
|
*/
|
|
static Element* GetAndObserveBackgroundClip(nsIFrame* aFrame);
|
|
|
|
/**
|
|
* A helper function to resolve filter URL.
|
|
*/
|
|
static already_AddRefed<URLAndReferrerInfo> GetFilterURI(
|
|
nsIFrame* aFrame, const StyleFilter& aFilter);
|
|
|
|
/**
|
|
* Return a baseURL for resolving a local-ref URL.
|
|
*
|
|
* @param aContent an element which uses a local-ref property. Here are some
|
|
* examples:
|
|
* <rect fill=url(#foo)>
|
|
* <circle clip-path=url(#foo)>
|
|
* <use xlink:href="#foo">
|
|
*/
|
|
static already_AddRefed<nsIURI> GetBaseURLForLocalRef(nsIContent* aContent,
|
|
nsIURI* aDocURI);
|
|
};
|
|
|
|
} // namespace mozilla
|
|
|
|
#endif // LAYOUT_SVG_SVGOBSERVERUTILS_H_
|