layout/svg/nsSVGEffects.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     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;
    33 /*
    34  * This interface allows us to be notified when a piece of SVG content is
    35  * re-rendered.
    36  *
    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.
    43  */
    44 class nsSVGRenderingObserver : public nsStubMutationObserver {
    45 public:
    46   typedef mozilla::dom::Element Element;
    47   nsSVGRenderingObserver()
    48     : mInObserverList(false)
    49     {}
    50   virtual ~nsSVGRenderingObserver()
    51     {}
    53   // nsISupports
    54   NS_DECL_ISUPPORTS
    56   // nsIMutationObserver
    57   NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
    58   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
    59   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
    60   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
    62   void InvalidateViaReferencedElement();
    64   // When a nsSVGRenderingObserver list gets forcibly cleared, it uses this
    65   // callback to notify every observer that's cleared from it, so they can
    66   // react.
    67   void NotifyEvictedFromRenderingObserverList();
    69   bool IsInObserverList() const { return mInObserverList; }
    71   nsIFrame* GetReferencedFrame();
    72   /**
    73    * @param aOK this is only for the convenience of callers. We set *aOK to false
    74    * if the frame is the wrong type
    75    */
    76   nsIFrame* GetReferencedFrame(nsIAtom* aFrameType, bool* aOK);
    78   Element* GetReferencedElement();
    80   virtual bool ObservesReflow() { return true; }
    82 protected:
    83   // Non-virtual protected methods
    84   void StartListening();
    85   void StopListening();
    87   // Virtual protected methods
    88   virtual void DoUpdate() = 0; // called when the referenced resource changes.
    90   // This is an internally-used version of GetReferencedElement that doesn't
    91   // forcibly add us as an observer. (whereas GetReferencedElement does)
    92   virtual Element* GetTarget() = 0;
    94   // Whether we're in our referenced element's observer list at this time.
    95   bool mInObserverList;
    96 };
    99 /*
   100  * SVG elements reference supporting resources by element ID. We need to
   101  * track when those resources change and when the DOM changes in ways
   102  * that affect which element is referenced by a given ID (e.g., when
   103  * element IDs change). The code here is responsible for that.
   104  * 
   105  * When a frame references a supporting resource, we create a property
   106  * object derived from nsSVGIDRenderingObserver to manage the relationship. The
   107  * property object is attached to the referencing frame.
   108  */
   109 class nsSVGIDRenderingObserver : public nsSVGRenderingObserver {
   110 public:
   111   typedef mozilla::dom::Element Element;
   112   nsSVGIDRenderingObserver(nsIURI* aURI, nsIFrame *aFrame,
   113                          bool aReferenceImage);
   114   virtual ~nsSVGIDRenderingObserver();
   116 protected:
   117   Element* GetTarget() MOZ_OVERRIDE { return mElement.get(); }
   119   // This is called when the referenced resource changes.
   120   virtual void DoUpdate() MOZ_OVERRIDE;
   122   class SourceReference : public nsReferencedElement {
   123   public:
   124     SourceReference(nsSVGIDRenderingObserver* aContainer) : mContainer(aContainer) {}
   125   protected:
   126     virtual void ElementChanged(Element* aFrom, Element* aTo) MOZ_OVERRIDE {
   127       mContainer->StopListening();
   128       nsReferencedElement::ElementChanged(aFrom, aTo);
   129       mContainer->StartListening();
   130       mContainer->DoUpdate();
   131     }
   132     /**
   133      * Override IsPersistent because we want to keep tracking the element
   134      * for the ID even when it changes.
   135      */
   136     virtual bool IsPersistent() MOZ_OVERRIDE { return true; }
   137   private:
   138     nsSVGIDRenderingObserver* mContainer;
   139   };
   141   SourceReference mElement;
   142   // The frame that this property is attached to
   143   nsIFrame *mFrame;
   144   // When a presshell is torn down, we don't delete the properties for
   145   // each frame until after the frames are destroyed. So here we remember
   146   // the presshell for the frames we care about and, before we use the frame,
   147   // we test the presshell to see if it's destroying itself. If it is,
   148   // then the frame pointer is not valid and we know the frame has gone away.
   149   nsIPresShell *mFramePresShell;
   150 };
   152 /**
   153  * In a filter chain, there can be multiple SVG reference filters.
   154  * e.g. filter: url(#svg-filter-1) blur(10px) url(#svg-filter-2);
   155  *
   156  * This class keeps track of one SVG reference filter in a filter chain.
   157  * e.g. url(#svg-filter-1)
   158  *
   159  * It fires invalidations when the SVG filter element's id changes or when
   160  * the SVG filter element's content changes.
   161  *
   162  * The nsSVGFilterProperty class manages a list of nsSVGFilterReferences.
   163  */
   164 class nsSVGFilterReference :
   165   public nsSVGIDRenderingObserver, public nsISVGFilterReference {
   166 public:
   167   nsSVGFilterReference(nsIURI *aURI, nsIFrame *aFilteredFrame)
   168     : nsSVGIDRenderingObserver(aURI, aFilteredFrame, false) {}
   170   bool ReferencesValidResource() { return GetFilterFrame(); }
   172   /**
   173    * @return the filter frame, or null if there is no filter frame
   174    */
   175   nsSVGFilterFrame *GetFilterFrame();
   177   // nsISupports
   178   NS_DECL_ISUPPORTS
   180   // nsISVGFilterReference
   181   virtual void Invalidate() MOZ_OVERRIDE { DoUpdate(); };
   183 private:
   184   // nsSVGIDRenderingObserver
   185   virtual void DoUpdate() MOZ_OVERRIDE;
   186 };
   188 /**
   189  * This class manages a list of nsSVGFilterReferences, which represent SVG
   190  * reference filters in a filter chain.
   191  * e.g. filter: url(#svg-filter-1) blur(10px) url(#svg-filter-2);
   192  *
   193  * In the above example, the nsSVGFilterProperty will manage two
   194  * nsSVGFilterReferences, one for each SVG reference filter. CSS filters like
   195  * "blur(10px)" don't reference filter elements, so they don't need an
   196  * nsSVGFilterReference. The style system invalidates changes to CSS filters.
   197  */
   198 class nsSVGFilterProperty : public nsISupports {
   199 public:
   200   nsSVGFilterProperty(const nsTArray<nsStyleFilter> &aFilters,
   201                       nsIFrame *aFilteredFrame);
   202   virtual ~nsSVGFilterProperty();
   204   const nsTArray<nsStyleFilter>& GetFilters() { return mFilters; }
   205   bool ReferencesValidResources();
   206   bool IsInObserverLists() const;
   207   void Invalidate();
   209   // nsISupports
   210   NS_DECL_ISUPPORTS
   212 private:
   213   nsTArray<nsSVGFilterReference*> mReferences;
   214   nsTArray<nsStyleFilter> mFilters;
   215 };
   217 class nsSVGMarkerProperty : public nsSVGIDRenderingObserver {
   218 public:
   219   nsSVGMarkerProperty(nsIURI *aURI, nsIFrame *aFrame, bool aReferenceImage)
   220     : nsSVGIDRenderingObserver(aURI, aFrame, aReferenceImage) {}
   222 protected:
   223   virtual void DoUpdate() MOZ_OVERRIDE;
   224 };
   226 class nsSVGTextPathProperty : public nsSVGIDRenderingObserver {
   227 public:
   228   nsSVGTextPathProperty(nsIURI *aURI, nsIFrame *aFrame, bool aReferenceImage)
   229     : nsSVGIDRenderingObserver(aURI, aFrame, aReferenceImage)
   230     , mValid(true) {}
   232   virtual bool ObservesReflow() MOZ_OVERRIDE { return false; }
   234 protected:
   235   virtual void DoUpdate() MOZ_OVERRIDE;
   237 private:
   238   /**
   239    * Returns true if the target of the textPath is the frame of a 'path' element.
   240    */
   241   bool TargetIsValid();
   243   bool mValid;
   244 };
   246 class nsSVGPaintingProperty : public nsSVGIDRenderingObserver {
   247 public:
   248   nsSVGPaintingProperty(nsIURI *aURI, nsIFrame *aFrame, bool aReferenceImage)
   249     : nsSVGIDRenderingObserver(aURI, aFrame, aReferenceImage) {}
   251 protected:
   252   virtual void DoUpdate() MOZ_OVERRIDE;
   253 };
   255 /**
   256  * A manager for one-shot nsSVGRenderingObserver tracking.
   257  * nsSVGRenderingObservers can be added or removed. They are not strongly
   258  * referenced so an observer must be removed before it dies.
   259  * When InvalidateAll is called, all outstanding references get
   260  * InvalidateViaReferencedElement()
   261  * called on them and the list is cleared. The intent is that
   262  * the observer will force repainting of whatever part of the document
   263  * is needed, and then at paint time the observer will do a clean lookup
   264  * of the referenced element and [re-]add itself to the element's observer list.
   265  * 
   266  * InvalidateAll must be called before this object is destroyed, i.e.
   267  * before the referenced frame is destroyed. This should normally happen
   268  * via nsSVGContainerFrame::RemoveFrame, since only frames in the frame
   269  * tree should be referenced.
   270  */
   271 class nsSVGRenderingObserverList {
   272 public:
   273   nsSVGRenderingObserverList()
   274     : mObservers(5)
   275   {
   276     MOZ_COUNT_CTOR(nsSVGRenderingObserverList);
   277   }
   279   ~nsSVGRenderingObserverList() {
   280     InvalidateAll();
   281     MOZ_COUNT_DTOR(nsSVGRenderingObserverList);
   282   }
   284   void Add(nsSVGRenderingObserver* aObserver)
   285   { mObservers.PutEntry(aObserver); }
   286   void Remove(nsSVGRenderingObserver* aObserver)
   287   { mObservers.RemoveEntry(aObserver); }
   288 #ifdef DEBUG
   289   bool Contains(nsSVGRenderingObserver* aObserver)
   290   { return (mObservers.GetEntry(aObserver) != nullptr); }
   291 #endif
   292   bool IsEmpty()
   293   { return mObservers.Count() == 0; }
   295   /**
   296    * Drop all our observers, and notify them that we have changed and dropped
   297    * our reference to them.
   298    */
   299   void InvalidateAll();
   301   /**
   302    * Drop all observers that observe reflow, and notify them that we have changed and dropped
   303    * our reference to them.
   304    */
   305   void InvalidateAllForReflow();
   307   /**
   308    * Drop all our observers, and notify them that we have dropped our reference
   309    * to them.
   310    */
   311   void RemoveAll();
   313 private:
   314   nsTHashtable<nsPtrHashKey<nsSVGRenderingObserver> > mObservers;
   315 };
   317 class nsSVGEffects {
   318 public:
   319   typedef mozilla::dom::Element Element;
   320   typedef mozilla::FramePropertyDescriptor FramePropertyDescriptor;
   321   typedef nsInterfaceHashtable<nsURIHashKey, nsIMutationObserver>
   322     URIObserverHashtable;
   324   static void DestroySupports(void* aPropertyValue)
   325   {
   326     (static_cast<nsISupports*>(aPropertyValue))->Release();
   327   }
   329   static void DestroyHashtable(void* aPropertyValue)
   330   {
   331     delete static_cast<URIObserverHashtable*> (aPropertyValue);
   332   }
   334   NS_DECLARE_FRAME_PROPERTY(FilterProperty, DestroySupports)
   335   NS_DECLARE_FRAME_PROPERTY(MaskProperty, DestroySupports)
   336   NS_DECLARE_FRAME_PROPERTY(ClipPathProperty, DestroySupports)
   337   NS_DECLARE_FRAME_PROPERTY(MarkerBeginProperty, DestroySupports)
   338   NS_DECLARE_FRAME_PROPERTY(MarkerMiddleProperty, DestroySupports)
   339   NS_DECLARE_FRAME_PROPERTY(MarkerEndProperty, DestroySupports)
   340   NS_DECLARE_FRAME_PROPERTY(FillProperty, DestroySupports)
   341   NS_DECLARE_FRAME_PROPERTY(StrokeProperty, DestroySupports)
   342   NS_DECLARE_FRAME_PROPERTY(HrefProperty, DestroySupports)
   343   NS_DECLARE_FRAME_PROPERTY(BackgroundImageProperty, DestroyHashtable)
   345   /**
   346    * Get the paint server for a aTargetFrame.
   347    */
   348   static nsSVGPaintServerFrame *GetPaintServer(nsIFrame *aTargetFrame,
   349                                                const nsStyleSVGPaint *aPaint,
   350                                                const FramePropertyDescriptor *aProperty);
   352   struct EffectProperties {
   353     nsSVGFilterProperty*   mFilter;
   354     nsSVGPaintingProperty* mMask;
   355     nsSVGPaintingProperty* mClipPath;
   357     /**
   358      * @return the clip-path frame, or null if there is no clip-path frame
   359      * @param aOK if a clip-path was specified and the designated element
   360      * exists but is an element of the wrong type, *aOK is set to false.
   361      * Otherwise *aOK is untouched.
   362      */
   363     nsSVGClipPathFrame *GetClipPathFrame(bool *aOK);
   364     /**
   365      * @return the mask frame, or null if there is no mask frame
   366      * @param aOK if a mask was specified and the designated element
   367      * exists but is an element of the wrong type, *aOK is set to false.
   368      * Otherwise *aOK is untouched.
   369      */
   370     nsSVGMaskFrame *GetMaskFrame(bool *aOK);
   372     bool HasValidFilter() {
   373       return mFilter && mFilter->ReferencesValidResources();
   374     }
   376     bool HasNoFilterOrHasValidFilter() {
   377       return !mFilter || mFilter->ReferencesValidResources();
   378     }
   379   };
   381   /**
   382    * @param aFrame should be the first continuation
   383    */
   384   static EffectProperties GetEffectProperties(nsIFrame *aFrame);
   386   /**
   387    * Called when changes to an element (e.g. CSS property changes) cause its
   388    * frame to start/stop referencing (or reference different) SVG resource
   389    * elements. (_Not_ called for changes to referenced resource elements.)
   390    *
   391    * This function handles such changes by discarding _all_ the frame's SVG
   392    * effects frame properties (causing those properties to stop watching their
   393    * target element). It also synchronously (re)creates the filter and marker
   394    * frame properties (XXX why not the other properties?), which makes it
   395    * useful for initializing those properties during first reflow.
   396    *
   397    * XXX rename to something more meaningful like RefreshResourceReferences?
   398    */
   399   static void UpdateEffects(nsIFrame *aFrame);
   401   /**
   402    * @param aFrame should be the first continuation
   403    */
   404   static nsSVGFilterProperty *GetFilterProperty(nsIFrame *aFrame);
   406   /**
   407    * @param aFrame must be a first-continuation.
   408    */
   409   static void AddRenderingObserver(Element *aElement, nsSVGRenderingObserver *aObserver);
   410   /**
   411    * @param aFrame must be a first-continuation.
   412    */
   413   static void RemoveRenderingObserver(Element *aElement, nsSVGRenderingObserver *aObserver);
   415   /**
   416    * Removes all rendering observers from aElement.
   417    */
   418   static void RemoveAllRenderingObservers(Element *aElement);
   420   /**
   421    * This can be called on any frame. We invalidate the observers of aFrame's
   422    * element, if any, or else walk up to the nearest observable SVG parent
   423    * frame with observers and invalidate them instead.
   424    *
   425    * Note that this method is very different to e.g.
   426    * nsNodeUtils::AttributeChanged which walks up the content node tree all the
   427    * way to the root node (not stopping if it encounters a non-container SVG
   428    * node) invalidating all mutation observers (not just
   429    * nsSVGRenderingObservers) on all nodes along the way (not just the first
   430    * node it finds with observers). In other words, by doing all the
   431    * things in parentheses in the preceding sentence, this method uses
   432    * knowledge about our implementation and what can be affected by SVG effects
   433    * to make invalidation relatively lightweight when an SVG effect changes.
   434    */
   435   static void InvalidateRenderingObservers(nsIFrame *aFrame);
   437   enum {
   438     INVALIDATE_REFLOW = 1
   439   };
   441   /**
   442    * This can be called on any element or frame. Only direct observers of this
   443    * (frame's) element, if any, are invalidated.
   444    */
   445   static void InvalidateDirectRenderingObservers(Element *aElement, uint32_t aFlags = 0);
   446   static void InvalidateDirectRenderingObservers(nsIFrame *aFrame, uint32_t aFlags = 0);
   448   /**
   449    * Get an nsSVGMarkerProperty for the frame, creating a fresh one if necessary
   450    */
   451   static nsSVGMarkerProperty *
   452   GetMarkerProperty(nsIURI *aURI, nsIFrame *aFrame,
   453                     const FramePropertyDescriptor *aProperty);
   454   /**
   455    * Get an nsSVGTextPathProperty for the frame, creating a fresh one if necessary
   456    */
   457   static nsSVGTextPathProperty *
   458   GetTextPathProperty(nsIURI *aURI, nsIFrame *aFrame,
   459                       const FramePropertyDescriptor *aProperty);
   460   /**
   461    * Get an nsSVGPaintingProperty for the frame, creating a fresh one if necessary
   462    */
   463   static nsSVGPaintingProperty *
   464   GetPaintingProperty(nsIURI *aURI, nsIFrame *aFrame,
   465                       const FramePropertyDescriptor *aProperty);
   466   /**
   467    * Get an nsSVGPaintingProperty for the frame for that URI, creating a fresh
   468    * one if necessary
   469    */
   470   static nsSVGPaintingProperty *
   471   GetPaintingPropertyForURI(nsIURI *aURI, nsIFrame *aFrame,
   472                             const FramePropertyDescriptor *aProp);
   473 };
   475 #endif /*NSSVGEFFECTS_H_*/

mercurial