layout/svg/nsSVGEffects.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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 // Main header first:
     7 #include "nsSVGEffects.h"
     9 // Keep others in (case-insensitive) order:
    10 #include "nsCSSFrameConstructor.h"
    11 #include "nsISupportsImpl.h"
    12 #include "nsSVGClipPathFrame.h"
    13 #include "nsSVGPaintServerFrame.h"
    14 #include "nsSVGPathGeometryElement.h"
    15 #include "nsSVGFilterFrame.h"
    16 #include "nsSVGMaskFrame.h"
    17 #include "nsIReflowCallback.h"
    18 #include "RestyleManager.h"
    20 using namespace mozilla;
    21 using namespace mozilla::dom;
    23 // nsSVGRenderingObserver impl
    24 NS_IMPL_ISUPPORTS(nsSVGRenderingObserver, nsIMutationObserver)
    26 void
    27 nsSVGRenderingObserver::StartListening()
    28 {
    29   Element* target = GetTarget();
    30   if (target) {
    31     target->AddMutationObserver(this);
    32   }
    33 }
    35 void
    36 nsSVGRenderingObserver::StopListening()
    37 {
    38   Element* target = GetTarget();
    40   if (target) {
    41     target->RemoveMutationObserver(this);
    42     if (mInObserverList) {
    43       nsSVGEffects::RemoveRenderingObserver(target, this);
    44       mInObserverList = false;
    45     }
    46   }
    47   NS_ASSERTION(!mInObserverList, "still in an observer list?");
    48 }
    52 /**
    53  * Note that in the current setup there are two separate observer lists.
    54  *
    55  * In nsSVGIDRenderingObserver's ctor, the new object adds itself to the
    56  * mutation observer list maintained by the referenced element. In this way the
    57  * nsSVGIDRenderingObserver is notified if there are any attribute or content
    58  * tree changes to the element or any of its *descendants*.
    59  *
    60  * In nsSVGIDRenderingObserver::GetReferencedElement() the
    61  * nsSVGIDRenderingObserver object also adds itself to an
    62  * nsSVGRenderingObserverList object belonging to the referenced
    63  * element.
    64  *
    65  * XXX: it would be nice to have a clear and concise executive summary of the
    66  * benefits/necessity of maintaining a second observer list.
    67  */
    69 nsSVGIDRenderingObserver::nsSVGIDRenderingObserver(nsIURI *aURI,
    70                                                    nsIFrame *aFrame,
    71                                                    bool aReferenceImage)
    72   : mElement(MOZ_THIS_IN_INITIALIZER_LIST()), mFrame(aFrame),
    73     mFramePresShell(aFrame->PresContext()->PresShell())
    74 {
    75   // Start watching the target element
    76   mElement.Reset(aFrame->GetContent(), aURI, true, aReferenceImage);
    77   StartListening();
    78 }
    80 nsSVGIDRenderingObserver::~nsSVGIDRenderingObserver()
    81 {
    82   StopListening();
    83 }
    85 static nsSVGRenderingObserverList *
    86 GetObserverList(Element *aElement)
    87 {
    88   return static_cast<nsSVGRenderingObserverList*>
    89     (aElement->GetProperty(nsGkAtoms::renderingobserverlist));
    90 }
    92 Element*
    93 nsSVGRenderingObserver::GetReferencedElement()
    94 {
    95   Element* target = GetTarget();
    96 #ifdef DEBUG
    97   if (target) {
    98     nsSVGRenderingObserverList *observerList = GetObserverList(target);
    99     bool inObserverList = observerList && observerList->Contains(this);
   100     NS_ASSERTION(inObserverList == mInObserverList, "failed to track whether we're in our referenced element's observer list!");
   101   } else {
   102     NS_ASSERTION(!mInObserverList, "In whose observer list are we, then?");
   103   }
   104 #endif
   105   if (target && !mInObserverList) {
   106     nsSVGEffects::AddRenderingObserver(target, this);
   107     mInObserverList = true;
   108   }
   109   return target;
   110 }
   112 nsIFrame*
   113 nsSVGRenderingObserver::GetReferencedFrame()
   114 {
   115   Element* referencedElement = GetReferencedElement();
   116   return referencedElement ? referencedElement->GetPrimaryFrame() : nullptr;
   117 }
   119 nsIFrame*
   120 nsSVGRenderingObserver::GetReferencedFrame(nsIAtom* aFrameType, bool* aOK)
   121 {
   122   nsIFrame* frame = GetReferencedFrame();
   123   if (frame) {
   124     if (frame->GetType() == aFrameType)
   125       return frame;
   126     if (aOK) {
   127       *aOK = false;
   128     }
   129   }
   130   return nullptr;
   131 }
   133 void
   134 nsSVGIDRenderingObserver::DoUpdate()
   135 {
   136   if (mFramePresShell->IsDestroying()) {
   137     // mFrame is no longer valid. Bail out.
   138     mFrame = nullptr;
   139     return;
   140   }
   141   if (mElement.get() && mInObserverList) {
   142     nsSVGEffects::RemoveRenderingObserver(mElement.get(), this);
   143     mInObserverList = false;
   144   }
   145   if (mFrame && mFrame->IsFrameOfType(nsIFrame::eSVG)) {
   146     // Changes should propagate out to things that might be observing
   147     // the referencing frame or its ancestors.
   148     nsSVGEffects::InvalidateRenderingObservers(mFrame);
   149   }
   150 }
   152 void
   153 nsSVGRenderingObserver::InvalidateViaReferencedElement()
   154 {
   155   mInObserverList = false;
   156   DoUpdate();
   157 }
   159 void
   160 nsSVGRenderingObserver::NotifyEvictedFromRenderingObserverList()
   161 {
   162   mInObserverList = false; // We've been removed from rendering-obs. list.
   163   StopListening();            // Remove ourselves from mutation-obs. list.
   164 }
   166 void
   167 nsSVGRenderingObserver::AttributeChanged(nsIDocument* aDocument,
   168                                          dom::Element* aElement,
   169                                          int32_t aNameSpaceID,
   170                                          nsIAtom* aAttribute,
   171                                          int32_t aModType)
   172 {
   173   // An attribute belonging to the element that we are observing *or one of its
   174   // descendants* has changed.
   175   //
   176   // In the case of observing a gradient element, say, we want to know if any
   177   // of its 'stop' element children change, but we don't actually want to do
   178   // anything for changes to SMIL element children, for example. Maybe it's not
   179   // worth having logic to optimize for that, but in most cases it could be a
   180   // small check?
   181   //
   182   // XXXjwatt: do we really want to blindly break the link between our
   183   // observers and ourselves for all attribute changes? For non-ID changes
   184   // surely that is unnecessary.
   186   DoUpdate();
   187 }
   189 void
   190 nsSVGRenderingObserver::ContentAppended(nsIDocument *aDocument,
   191                                         nsIContent *aContainer,
   192                                         nsIContent *aFirstNewContent,
   193                                         int32_t /* unused */)
   194 {
   195   DoUpdate();
   196 }
   198 void
   199 nsSVGRenderingObserver::ContentInserted(nsIDocument *aDocument,
   200                                         nsIContent *aContainer,
   201                                         nsIContent *aChild,
   202                                         int32_t /* unused */)
   203 {
   204   DoUpdate();
   205 }
   207 void
   208 nsSVGRenderingObserver::ContentRemoved(nsIDocument *aDocument,
   209                                        nsIContent *aContainer,
   210                                        nsIContent *aChild,
   211                                        int32_t aIndexInContainer,
   212                                        nsIContent *aPreviousSibling)
   213 {
   214   DoUpdate();
   215 }
   217 NS_IMPL_ISUPPORTS(nsSVGFilterProperty, nsISupports)
   219 nsSVGFilterProperty::nsSVGFilterProperty(const nsTArray<nsStyleFilter> &aFilters,
   220                                          nsIFrame *aFilteredFrame) :
   221   mFilters(aFilters)
   222 {
   223   for (uint32_t i = 0; i < mFilters.Length(); i++) {
   224     if (mFilters[i].GetType() != NS_STYLE_FILTER_URL)
   225       continue;
   227     nsSVGFilterReference *reference =
   228       new nsSVGFilterReference(mFilters[i].GetURL(), aFilteredFrame);
   229     NS_ADDREF(reference);
   230     mReferences.AppendElement(reference);
   231   }
   232 }
   234 nsSVGFilterProperty::~nsSVGFilterProperty()
   235 {
   236   for (uint32_t i = 0; i < mReferences.Length(); i++) {
   237     NS_RELEASE(mReferences[i]);
   238   }
   239 }
   241 bool
   242 nsSVGFilterProperty::ReferencesValidResources()
   243 {
   244   for (uint32_t i = 0; i < mReferences.Length(); i++) {
   245     if (!mReferences[i]->ReferencesValidResource())
   246       return false;
   247   }
   248   return true;
   249 }
   251 bool
   252 nsSVGFilterProperty::IsInObserverLists() const
   253 {
   254   for (uint32_t i = 0; i < mReferences.Length(); i++) {
   255     if (!mReferences[i]->IsInObserverList())
   256       return false;
   257   }
   258   return true;
   259 }
   261 void
   262 nsSVGFilterProperty::Invalidate()
   263 {
   264   for (uint32_t i = 0; i < mReferences.Length(); i++) {
   265     mReferences[i]->Invalidate();
   266   }
   267 }
   269 NS_IMPL_ISUPPORTS_INHERITED(nsSVGFilterReference,
   270                             nsSVGIDRenderingObserver,
   271                             nsISVGFilterReference);
   273 nsSVGFilterFrame *
   274 nsSVGFilterReference::GetFilterFrame()
   275 {
   276   return static_cast<nsSVGFilterFrame *>
   277     (GetReferencedFrame(nsGkAtoms::svgFilterFrame, nullptr));
   278 }
   280 static void
   281 InvalidateAllContinuations(nsIFrame* aFrame)
   282 {
   283   for (nsIFrame* f = aFrame; f;
   284        f = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(f)) {
   285     f->InvalidateFrame();
   286   }
   287 }
   289 void
   290 nsSVGFilterReference::DoUpdate()
   291 {
   292   nsSVGIDRenderingObserver::DoUpdate();
   293   if (!mFrame)
   294     return;
   296   // Repaint asynchronously in case the filter frame is being torn down
   297   nsChangeHint changeHint =
   298     nsChangeHint(nsChangeHint_RepaintFrame);
   300   // Don't need to request UpdateOverflow if we're being reflowed.
   301   if (!(mFrame->GetStateBits() & NS_FRAME_IN_REFLOW)) {
   302     NS_UpdateHint(changeHint, nsChangeHint_UpdateOverflow);
   303   }
   304   mFramePresShell->GetPresContext()->RestyleManager()->PostRestyleEvent(
   305     mFrame->GetContent()->AsElement(), nsRestyleHint(0), changeHint);
   306 }
   308 void
   309 nsSVGMarkerProperty::DoUpdate()
   310 {
   311   nsSVGIDRenderingObserver::DoUpdate();
   312   if (!mFrame)
   313     return;
   315   NS_ASSERTION(mFrame->IsFrameOfType(nsIFrame::eSVG), "SVG frame expected");
   317   // Repaint asynchronously in case the marker frame is being torn down
   318   nsChangeHint changeHint =
   319     nsChangeHint(nsChangeHint_RepaintFrame);
   321   // Don't need to request ReflowFrame if we're being reflowed.
   322   if (!(mFrame->GetStateBits() & NS_FRAME_IN_REFLOW)) {
   323     // XXXjwatt: We need to unify SVG into standard reflow so we can just use
   324     // nsChangeHint_NeedReflow | nsChangeHint_NeedDirtyReflow here.
   325     nsSVGEffects::InvalidateRenderingObservers(mFrame);
   326     // XXXSDL KILL THIS!!!
   327     nsSVGUtils::ScheduleReflowSVG(mFrame);
   328   }
   329   mFramePresShell->GetPresContext()->RestyleManager()->PostRestyleEvent(
   330     mFrame->GetContent()->AsElement(), nsRestyleHint(0), changeHint);
   331 }
   333 bool
   334 nsSVGTextPathProperty::TargetIsValid()
   335 {
   336   Element* target = GetTarget();
   337   return target && target->IsSVG(nsGkAtoms::path);
   338 }
   340 void
   341 nsSVGTextPathProperty::DoUpdate()
   342 {
   343   nsSVGIDRenderingObserver::DoUpdate();
   344   if (!mFrame)
   345     return;
   347   NS_ASSERTION(mFrame->IsFrameOfType(nsIFrame::eSVG) || mFrame->IsSVGText(),
   348                "SVG frame expected");
   350   // Avoid getting into an infinite loop of reflows if the <textPath> is
   351   // pointing to one of its ancestors.  TargetIsValid returns true iff
   352   // the target element is a <path> element, and we would not have this
   353   // nsSVGTextPathProperty if this <textPath> were a descendant of the
   354   // target <path>.
   355   //
   356   // Note that we still have to post the restyle event when we
   357   // change from being valid to invalid, so that mPositions on the
   358   // SVGTextFrame gets updated, skipping the <textPath>, ensuring
   359   // that nothing gets painted for that element.
   360   bool nowValid = TargetIsValid();
   361   if (!mValid && !nowValid) {
   362     // Just return if we were previously invalid, and are still invalid.
   363     return;
   364   }
   365   mValid = nowValid;
   367   // Repaint asynchronously in case the path frame is being torn down
   368   nsChangeHint changeHint =
   369     nsChangeHint(nsChangeHint_RepaintFrame | nsChangeHint_UpdateTextPath);
   370   mFramePresShell->GetPresContext()->RestyleManager()->PostRestyleEvent(
   371     mFrame->GetContent()->AsElement(), nsRestyleHint(0), changeHint);
   372 }
   374 void
   375 nsSVGPaintingProperty::DoUpdate()
   376 {
   377   nsSVGIDRenderingObserver::DoUpdate();
   378   if (!mFrame)
   379     return;
   381   if (mFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) {
   382     nsSVGEffects::InvalidateRenderingObservers(mFrame);
   383     mFrame->InvalidateFrameSubtree();
   384   } else {
   385     InvalidateAllContinuations(mFrame);
   386   }
   387 }
   389 static nsSVGRenderingObserver *
   390 CreateMarkerProperty(nsIURI *aURI, nsIFrame *aFrame, bool aReferenceImage)
   391 { return new nsSVGMarkerProperty(aURI, aFrame, aReferenceImage); }
   393 static nsSVGRenderingObserver *
   394 CreateTextPathProperty(nsIURI *aURI, nsIFrame *aFrame, bool aReferenceImage)
   395 { return new nsSVGTextPathProperty(aURI, aFrame, aReferenceImage); }
   397 static nsSVGRenderingObserver *
   398 CreatePaintingProperty(nsIURI *aURI, nsIFrame *aFrame, bool aReferenceImage)
   399 { return new nsSVGPaintingProperty(aURI, aFrame, aReferenceImage); }
   401 static nsSVGRenderingObserver *
   402 GetEffectProperty(nsIURI *aURI, nsIFrame *aFrame,
   403                   const FramePropertyDescriptor *aProperty,
   404                   nsSVGRenderingObserver * (* aCreate)(nsIURI *, nsIFrame *, bool))
   405 {
   406   if (!aURI)
   407     return nullptr;
   409   FrameProperties props = aFrame->Properties();
   410   nsSVGRenderingObserver *prop =
   411     static_cast<nsSVGRenderingObserver*>(props.Get(aProperty));
   412   if (prop)
   413     return prop;
   414   prop = aCreate(aURI, aFrame, false);
   415   if (!prop)
   416     return nullptr;
   417   NS_ADDREF(prop);
   418   props.Set(aProperty, static_cast<nsISupports*>(prop));
   419   return prop;
   420 }
   422 static nsSVGFilterProperty*
   423 GetOrCreateFilterProperty(nsIFrame *aFrame)
   424 {
   425   const nsStyleSVGReset* style = aFrame->StyleSVGReset();
   426   if (!style->HasFilters())
   427     return nullptr;
   429   FrameProperties props = aFrame->Properties();
   430   nsSVGFilterProperty *prop =
   431     static_cast<nsSVGFilterProperty*>(props.Get(nsSVGEffects::FilterProperty()));
   432   if (prop)
   433     return prop;
   434   prop = new nsSVGFilterProperty(style->mFilters, aFrame);
   435   if (!prop)
   436     return nullptr;
   437   NS_ADDREF(prop);
   438   props.Set(nsSVGEffects::FilterProperty(), static_cast<nsISupports*>(prop));
   439   return prop;
   440 }
   442 nsSVGMarkerProperty *
   443 nsSVGEffects::GetMarkerProperty(nsIURI *aURI, nsIFrame *aFrame,
   444                                 const FramePropertyDescriptor *aProp)
   445 {
   446   NS_ABORT_IF_FALSE(aFrame->GetType() == nsGkAtoms::svgPathGeometryFrame &&
   447                       static_cast<nsSVGPathGeometryElement*>(aFrame->GetContent())->IsMarkable(),
   448                     "Bad frame");
   449   return static_cast<nsSVGMarkerProperty*>(
   450           GetEffectProperty(aURI, aFrame, aProp, CreateMarkerProperty));
   451 }
   453 nsSVGTextPathProperty *
   454 nsSVGEffects::GetTextPathProperty(nsIURI *aURI, nsIFrame *aFrame,
   455                                   const FramePropertyDescriptor *aProp)
   456 {
   457   return static_cast<nsSVGTextPathProperty*>(
   458           GetEffectProperty(aURI, aFrame, aProp, CreateTextPathProperty));
   459 }
   461 nsSVGPaintingProperty *
   462 nsSVGEffects::GetPaintingProperty(nsIURI *aURI, nsIFrame *aFrame,
   463                                   const FramePropertyDescriptor *aProp)
   464 {
   465   return static_cast<nsSVGPaintingProperty*>(
   466           GetEffectProperty(aURI, aFrame, aProp, CreatePaintingProperty));
   467 }
   469 static nsSVGRenderingObserver *
   470 GetEffectPropertyForURI(nsIURI *aURI, nsIFrame *aFrame,
   471                         const FramePropertyDescriptor *aProperty,
   472                         nsSVGRenderingObserver * (* aCreate)(nsIURI *, nsIFrame *, bool))
   473 {
   474   if (!aURI)
   475     return nullptr;
   477   FrameProperties props = aFrame->Properties();
   478   nsSVGEffects::URIObserverHashtable *hashtable =
   479     static_cast<nsSVGEffects::URIObserverHashtable*>(props.Get(aProperty));
   480   if (!hashtable) {
   481     hashtable = new nsSVGEffects::URIObserverHashtable();
   482     props.Set(aProperty, hashtable);
   483   }
   484   nsSVGRenderingObserver* prop =
   485     static_cast<nsSVGRenderingObserver*>(hashtable->GetWeak(aURI));
   486   if (!prop) {
   487     bool watchImage = aProperty == nsSVGEffects::BackgroundImageProperty();
   488     prop = aCreate(aURI, aFrame, watchImage);
   489     hashtable->Put(aURI, prop);
   490   }
   491   return prop;
   492 }
   494 nsSVGPaintingProperty *
   495 nsSVGEffects::GetPaintingPropertyForURI(nsIURI *aURI, nsIFrame *aFrame,
   496                                         const FramePropertyDescriptor *aProp)
   497 {
   498   return static_cast<nsSVGPaintingProperty*>(
   499           GetEffectPropertyForURI(aURI, aFrame, aProp, CreatePaintingProperty));
   500 }
   502 nsSVGEffects::EffectProperties
   503 nsSVGEffects::GetEffectProperties(nsIFrame *aFrame)
   504 {
   505   NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame should be first continuation");
   507   EffectProperties result;
   508   const nsStyleSVGReset *style = aFrame->StyleSVGReset();
   509   result.mFilter = GetOrCreateFilterProperty(aFrame);
   510   result.mClipPath =
   511     GetPaintingProperty(style->mClipPath, aFrame, ClipPathProperty());
   512   result.mMask =
   513     GetPaintingProperty(style->mMask, aFrame, MaskProperty());
   514   return result;
   515 }
   517 nsSVGPaintServerFrame *
   518 nsSVGEffects::GetPaintServer(nsIFrame *aTargetFrame, const nsStyleSVGPaint *aPaint,
   519                              const FramePropertyDescriptor *aType)
   520 {
   521   if (aPaint->mType != eStyleSVGPaintType_Server)
   522     return nullptr;
   524   nsIFrame *frame = aTargetFrame->GetContent()->IsNodeOfType(nsINode::eTEXT) ?
   525                       aTargetFrame->GetParent() : aTargetFrame;
   526   nsSVGPaintingProperty *property =
   527     nsSVGEffects::GetPaintingProperty(aPaint->mPaint.mPaintServer, frame, aType);
   528   if (!property)
   529     return nullptr;
   530   nsIFrame *result = property->GetReferencedFrame();
   531   if (!result)
   532     return nullptr;
   534   nsIAtom *type = result->GetType();
   535   if (type != nsGkAtoms::svgLinearGradientFrame &&
   536       type != nsGkAtoms::svgRadialGradientFrame &&
   537       type != nsGkAtoms::svgPatternFrame)
   538     return nullptr;
   540   return static_cast<nsSVGPaintServerFrame*>(result);
   541 }
   543 nsSVGClipPathFrame *
   544 nsSVGEffects::EffectProperties::GetClipPathFrame(bool *aOK)
   545 {
   546   if (!mClipPath)
   547     return nullptr;
   548   nsSVGClipPathFrame *frame = static_cast<nsSVGClipPathFrame *>
   549     (mClipPath->GetReferencedFrame(nsGkAtoms::svgClipPathFrame, aOK));
   550   if (frame && aOK && *aOK) {
   551     *aOK = frame->IsValid();
   552   }
   553   return frame;
   554 }
   556 nsSVGMaskFrame *
   557 nsSVGEffects::EffectProperties::GetMaskFrame(bool *aOK)
   558 {
   559   if (!mMask)
   560     return nullptr;
   561   return static_cast<nsSVGMaskFrame *>
   562     (mMask->GetReferencedFrame(nsGkAtoms::svgMaskFrame, aOK));
   563 }
   565 void
   566 nsSVGEffects::UpdateEffects(nsIFrame *aFrame)
   567 {
   568   NS_ASSERTION(aFrame->GetContent()->IsElement(),
   569                "aFrame's content should be an element");
   571   FrameProperties props = aFrame->Properties();
   572   props.Delete(FilterProperty());
   573   props.Delete(MaskProperty());
   574   props.Delete(ClipPathProperty());
   575   props.Delete(MarkerBeginProperty());
   576   props.Delete(MarkerMiddleProperty());
   577   props.Delete(MarkerEndProperty());
   578   props.Delete(FillProperty());
   579   props.Delete(StrokeProperty());
   580   props.Delete(BackgroundImageProperty());
   582   // Ensure that the filter is repainted correctly
   583   // We can't do that in DoUpdate as the referenced frame may not be valid
   584   GetOrCreateFilterProperty(aFrame);
   586   if (aFrame->GetType() == nsGkAtoms::svgPathGeometryFrame &&
   587       static_cast<nsSVGPathGeometryElement*>(aFrame->GetContent())->IsMarkable()) {
   588     // Set marker properties here to avoid reference loops
   589     const nsStyleSVG *style = aFrame->StyleSVG();
   590     GetEffectProperty(style->mMarkerStart, aFrame, MarkerBeginProperty(),
   591                       CreateMarkerProperty);
   592     GetEffectProperty(style->mMarkerMid, aFrame, MarkerMiddleProperty(),
   593                       CreateMarkerProperty);
   594     GetEffectProperty(style->mMarkerEnd, aFrame, MarkerEndProperty(),
   595                       CreateMarkerProperty);
   596   }
   597 }
   599 nsSVGFilterProperty *
   600 nsSVGEffects::GetFilterProperty(nsIFrame *aFrame)
   601 {
   602   NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame should be first continuation");
   604   if (!aFrame->StyleSVGReset()->HasFilters())
   605     return nullptr;
   607   return static_cast<nsSVGFilterProperty *>
   608     (aFrame->Properties().Get(FilterProperty()));
   609 }
   611 static PLDHashOperator
   612 GatherEnumerator(nsPtrHashKey<nsSVGRenderingObserver>* aEntry, void* aArg)
   613 {
   614   nsTArray<nsSVGRenderingObserver*>* array =
   615     static_cast<nsTArray<nsSVGRenderingObserver*>*>(aArg);
   616   array->AppendElement(aEntry->GetKey());
   618   return PL_DHASH_REMOVE;
   619 }
   621 static PLDHashOperator
   622 GatherEnumeratorForReflow(nsPtrHashKey<nsSVGRenderingObserver>* aEntry, void* aArg)
   623 {
   624   if (!aEntry->GetKey()->ObservesReflow()) {
   625     return PL_DHASH_NEXT;
   626   }
   628   nsTArray<nsSVGRenderingObserver*>* array =
   629     static_cast<nsTArray<nsSVGRenderingObserver*>*>(aArg);
   630   array->AppendElement(aEntry->GetKey());
   632   return PL_DHASH_REMOVE;
   633 }
   635 void
   636 nsSVGRenderingObserverList::InvalidateAll()
   637 {
   638   if (mObservers.Count() == 0)
   639     return;
   641   nsAutoTArray<nsSVGRenderingObserver*,10> observers;
   643   // The PL_DHASH_REMOVE in GatherEnumerator drops all our observers here:
   644   mObservers.EnumerateEntries(GatherEnumerator, &observers);
   646   for (uint32_t i = 0; i < observers.Length(); ++i) {
   647     observers[i]->InvalidateViaReferencedElement();
   648   }
   649 }
   651 void
   652 nsSVGRenderingObserverList::InvalidateAllForReflow()
   653 {
   654   if (mObservers.Count() == 0)
   655     return;
   657   nsAutoTArray<nsSVGRenderingObserver*,10> observers;
   659   // The PL_DHASH_REMOVE in GatherEnumerator drops all our observers here:
   660   mObservers.EnumerateEntries(GatherEnumeratorForReflow, &observers);
   662   for (uint32_t i = 0; i < observers.Length(); ++i) {
   663     observers[i]->InvalidateViaReferencedElement();
   664   }
   665 }
   667 void
   668 nsSVGRenderingObserverList::RemoveAll()
   669 {
   670   nsAutoTArray<nsSVGRenderingObserver*,10> observers;
   672   // The PL_DHASH_REMOVE in GatherEnumerator drops all our observers here:
   673   mObservers.EnumerateEntries(GatherEnumerator, &observers);
   675   // Our list is now cleared.  We need to notify the observers we've removed,
   676   // so they can update their state & remove themselves as mutation-observers.
   677   for (uint32_t i = 0; i < observers.Length(); ++i) {
   678     observers[i]->NotifyEvictedFromRenderingObserverList();
   679   }
   680 }
   682 void
   683 nsSVGEffects::AddRenderingObserver(Element *aElement, nsSVGRenderingObserver *aObserver)
   684 {
   685   nsSVGRenderingObserverList *observerList = GetObserverList(aElement);
   686   if (!observerList) {
   687     observerList = new nsSVGRenderingObserverList();
   688     if (!observerList)
   689       return;
   690     aElement->SetProperty(nsGkAtoms::renderingobserverlist, observerList,
   691                           nsINode::DeleteProperty<nsSVGRenderingObserverList>);
   692   }
   693   aElement->SetHasRenderingObservers(true);
   694   observerList->Add(aObserver);
   695 }
   697 void
   698 nsSVGEffects::RemoveRenderingObserver(Element *aElement, nsSVGRenderingObserver *aObserver)
   699 {
   700   nsSVGRenderingObserverList *observerList = GetObserverList(aElement);
   701   if (observerList) {
   702     NS_ASSERTION(observerList->Contains(aObserver),
   703                  "removing observer from an element we're not observing?");
   704     observerList->Remove(aObserver);
   705     if (observerList->IsEmpty()) {
   706       aElement->SetHasRenderingObservers(false);
   707     }
   708   }
   709 }
   711 void
   712 nsSVGEffects::RemoveAllRenderingObservers(Element *aElement)
   713 {
   714   nsSVGRenderingObserverList *observerList = GetObserverList(aElement);
   715   if (observerList) {
   716     observerList->RemoveAll();
   717     aElement->SetHasRenderingObservers(false);
   718   }
   719 }
   721 void
   722 nsSVGEffects::InvalidateRenderingObservers(nsIFrame *aFrame)
   723 {
   724   NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame must be first continuation");
   726   if (!aFrame->GetContent()->IsElement())
   727     return;
   729   nsSVGRenderingObserverList *observerList =
   730     GetObserverList(aFrame->GetContent()->AsElement());
   731   if (observerList) {
   732     observerList->InvalidateAll();
   733     return;
   734   }
   736   // Check ancestor SVG containers. The root frame cannot be of type
   737   // eSVGContainer so we don't have to check f for null here.
   738   for (nsIFrame *f = aFrame->GetParent();
   739        f->IsFrameOfType(nsIFrame::eSVGContainer); f = f->GetParent()) {
   740     if (f->GetContent()->IsElement()) {
   741       observerList = GetObserverList(f->GetContent()->AsElement());
   742       if (observerList) {
   743         observerList->InvalidateAll();
   744         return;
   745       }
   746     }
   747   }
   748 }
   750 void
   751 nsSVGEffects::InvalidateDirectRenderingObservers(Element *aElement, uint32_t aFlags /* = 0 */)
   752 {
   753   if (aElement->HasRenderingObservers()) {
   754     nsSVGRenderingObserverList *observerList = GetObserverList(aElement);
   755     if (observerList) {
   756       if (aFlags & INVALIDATE_REFLOW) {
   757         observerList->InvalidateAllForReflow();
   758       } else {
   759         observerList->InvalidateAll();
   760       }
   761     }
   762   }
   763 }
   765 void
   766 nsSVGEffects::InvalidateDirectRenderingObservers(nsIFrame *aFrame, uint32_t aFlags /* = 0 */)
   767 {
   768   if (aFrame->GetContent() && aFrame->GetContent()->IsElement()) {
   769     InvalidateDirectRenderingObservers(aFrame->GetContent()->AsElement(), aFlags);
   770   }
   771 }

mercurial