1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/svg/nsSVGEffects.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,771 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +// Main header first: 1.10 +#include "nsSVGEffects.h" 1.11 + 1.12 +// Keep others in (case-insensitive) order: 1.13 +#include "nsCSSFrameConstructor.h" 1.14 +#include "nsISupportsImpl.h" 1.15 +#include "nsSVGClipPathFrame.h" 1.16 +#include "nsSVGPaintServerFrame.h" 1.17 +#include "nsSVGPathGeometryElement.h" 1.18 +#include "nsSVGFilterFrame.h" 1.19 +#include "nsSVGMaskFrame.h" 1.20 +#include "nsIReflowCallback.h" 1.21 +#include "RestyleManager.h" 1.22 + 1.23 +using namespace mozilla; 1.24 +using namespace mozilla::dom; 1.25 + 1.26 +// nsSVGRenderingObserver impl 1.27 +NS_IMPL_ISUPPORTS(nsSVGRenderingObserver, nsIMutationObserver) 1.28 + 1.29 +void 1.30 +nsSVGRenderingObserver::StartListening() 1.31 +{ 1.32 + Element* target = GetTarget(); 1.33 + if (target) { 1.34 + target->AddMutationObserver(this); 1.35 + } 1.36 +} 1.37 + 1.38 +void 1.39 +nsSVGRenderingObserver::StopListening() 1.40 +{ 1.41 + Element* target = GetTarget(); 1.42 + 1.43 + if (target) { 1.44 + target->RemoveMutationObserver(this); 1.45 + if (mInObserverList) { 1.46 + nsSVGEffects::RemoveRenderingObserver(target, this); 1.47 + mInObserverList = false; 1.48 + } 1.49 + } 1.50 + NS_ASSERTION(!mInObserverList, "still in an observer list?"); 1.51 +} 1.52 + 1.53 + 1.54 + 1.55 +/** 1.56 + * Note that in the current setup there are two separate observer lists. 1.57 + * 1.58 + * In nsSVGIDRenderingObserver's ctor, the new object adds itself to the 1.59 + * mutation observer list maintained by the referenced element. In this way the 1.60 + * nsSVGIDRenderingObserver is notified if there are any attribute or content 1.61 + * tree changes to the element or any of its *descendants*. 1.62 + * 1.63 + * In nsSVGIDRenderingObserver::GetReferencedElement() the 1.64 + * nsSVGIDRenderingObserver object also adds itself to an 1.65 + * nsSVGRenderingObserverList object belonging to the referenced 1.66 + * element. 1.67 + * 1.68 + * XXX: it would be nice to have a clear and concise executive summary of the 1.69 + * benefits/necessity of maintaining a second observer list. 1.70 + */ 1.71 + 1.72 +nsSVGIDRenderingObserver::nsSVGIDRenderingObserver(nsIURI *aURI, 1.73 + nsIFrame *aFrame, 1.74 + bool aReferenceImage) 1.75 + : mElement(MOZ_THIS_IN_INITIALIZER_LIST()), mFrame(aFrame), 1.76 + mFramePresShell(aFrame->PresContext()->PresShell()) 1.77 +{ 1.78 + // Start watching the target element 1.79 + mElement.Reset(aFrame->GetContent(), aURI, true, aReferenceImage); 1.80 + StartListening(); 1.81 +} 1.82 + 1.83 +nsSVGIDRenderingObserver::~nsSVGIDRenderingObserver() 1.84 +{ 1.85 + StopListening(); 1.86 +} 1.87 + 1.88 +static nsSVGRenderingObserverList * 1.89 +GetObserverList(Element *aElement) 1.90 +{ 1.91 + return static_cast<nsSVGRenderingObserverList*> 1.92 + (aElement->GetProperty(nsGkAtoms::renderingobserverlist)); 1.93 +} 1.94 + 1.95 +Element* 1.96 +nsSVGRenderingObserver::GetReferencedElement() 1.97 +{ 1.98 + Element* target = GetTarget(); 1.99 +#ifdef DEBUG 1.100 + if (target) { 1.101 + nsSVGRenderingObserverList *observerList = GetObserverList(target); 1.102 + bool inObserverList = observerList && observerList->Contains(this); 1.103 + NS_ASSERTION(inObserverList == mInObserverList, "failed to track whether we're in our referenced element's observer list!"); 1.104 + } else { 1.105 + NS_ASSERTION(!mInObserverList, "In whose observer list are we, then?"); 1.106 + } 1.107 +#endif 1.108 + if (target && !mInObserverList) { 1.109 + nsSVGEffects::AddRenderingObserver(target, this); 1.110 + mInObserverList = true; 1.111 + } 1.112 + return target; 1.113 +} 1.114 + 1.115 +nsIFrame* 1.116 +nsSVGRenderingObserver::GetReferencedFrame() 1.117 +{ 1.118 + Element* referencedElement = GetReferencedElement(); 1.119 + return referencedElement ? referencedElement->GetPrimaryFrame() : nullptr; 1.120 +} 1.121 + 1.122 +nsIFrame* 1.123 +nsSVGRenderingObserver::GetReferencedFrame(nsIAtom* aFrameType, bool* aOK) 1.124 +{ 1.125 + nsIFrame* frame = GetReferencedFrame(); 1.126 + if (frame) { 1.127 + if (frame->GetType() == aFrameType) 1.128 + return frame; 1.129 + if (aOK) { 1.130 + *aOK = false; 1.131 + } 1.132 + } 1.133 + return nullptr; 1.134 +} 1.135 + 1.136 +void 1.137 +nsSVGIDRenderingObserver::DoUpdate() 1.138 +{ 1.139 + if (mFramePresShell->IsDestroying()) { 1.140 + // mFrame is no longer valid. Bail out. 1.141 + mFrame = nullptr; 1.142 + return; 1.143 + } 1.144 + if (mElement.get() && mInObserverList) { 1.145 + nsSVGEffects::RemoveRenderingObserver(mElement.get(), this); 1.146 + mInObserverList = false; 1.147 + } 1.148 + if (mFrame && mFrame->IsFrameOfType(nsIFrame::eSVG)) { 1.149 + // Changes should propagate out to things that might be observing 1.150 + // the referencing frame or its ancestors. 1.151 + nsSVGEffects::InvalidateRenderingObservers(mFrame); 1.152 + } 1.153 +} 1.154 + 1.155 +void 1.156 +nsSVGRenderingObserver::InvalidateViaReferencedElement() 1.157 +{ 1.158 + mInObserverList = false; 1.159 + DoUpdate(); 1.160 +} 1.161 + 1.162 +void 1.163 +nsSVGRenderingObserver::NotifyEvictedFromRenderingObserverList() 1.164 +{ 1.165 + mInObserverList = false; // We've been removed from rendering-obs. list. 1.166 + StopListening(); // Remove ourselves from mutation-obs. list. 1.167 +} 1.168 + 1.169 +void 1.170 +nsSVGRenderingObserver::AttributeChanged(nsIDocument* aDocument, 1.171 + dom::Element* aElement, 1.172 + int32_t aNameSpaceID, 1.173 + nsIAtom* aAttribute, 1.174 + int32_t aModType) 1.175 +{ 1.176 + // An attribute belonging to the element that we are observing *or one of its 1.177 + // descendants* has changed. 1.178 + // 1.179 + // In the case of observing a gradient element, say, we want to know if any 1.180 + // of its 'stop' element children change, but we don't actually want to do 1.181 + // anything for changes to SMIL element children, for example. Maybe it's not 1.182 + // worth having logic to optimize for that, but in most cases it could be a 1.183 + // small check? 1.184 + // 1.185 + // XXXjwatt: do we really want to blindly break the link between our 1.186 + // observers and ourselves for all attribute changes? For non-ID changes 1.187 + // surely that is unnecessary. 1.188 + 1.189 + DoUpdate(); 1.190 +} 1.191 + 1.192 +void 1.193 +nsSVGRenderingObserver::ContentAppended(nsIDocument *aDocument, 1.194 + nsIContent *aContainer, 1.195 + nsIContent *aFirstNewContent, 1.196 + int32_t /* unused */) 1.197 +{ 1.198 + DoUpdate(); 1.199 +} 1.200 + 1.201 +void 1.202 +nsSVGRenderingObserver::ContentInserted(nsIDocument *aDocument, 1.203 + nsIContent *aContainer, 1.204 + nsIContent *aChild, 1.205 + int32_t /* unused */) 1.206 +{ 1.207 + DoUpdate(); 1.208 +} 1.209 + 1.210 +void 1.211 +nsSVGRenderingObserver::ContentRemoved(nsIDocument *aDocument, 1.212 + nsIContent *aContainer, 1.213 + nsIContent *aChild, 1.214 + int32_t aIndexInContainer, 1.215 + nsIContent *aPreviousSibling) 1.216 +{ 1.217 + DoUpdate(); 1.218 +} 1.219 + 1.220 +NS_IMPL_ISUPPORTS(nsSVGFilterProperty, nsISupports) 1.221 + 1.222 +nsSVGFilterProperty::nsSVGFilterProperty(const nsTArray<nsStyleFilter> &aFilters, 1.223 + nsIFrame *aFilteredFrame) : 1.224 + mFilters(aFilters) 1.225 +{ 1.226 + for (uint32_t i = 0; i < mFilters.Length(); i++) { 1.227 + if (mFilters[i].GetType() != NS_STYLE_FILTER_URL) 1.228 + continue; 1.229 + 1.230 + nsSVGFilterReference *reference = 1.231 + new nsSVGFilterReference(mFilters[i].GetURL(), aFilteredFrame); 1.232 + NS_ADDREF(reference); 1.233 + mReferences.AppendElement(reference); 1.234 + } 1.235 +} 1.236 + 1.237 +nsSVGFilterProperty::~nsSVGFilterProperty() 1.238 +{ 1.239 + for (uint32_t i = 0; i < mReferences.Length(); i++) { 1.240 + NS_RELEASE(mReferences[i]); 1.241 + } 1.242 +} 1.243 + 1.244 +bool 1.245 +nsSVGFilterProperty::ReferencesValidResources() 1.246 +{ 1.247 + for (uint32_t i = 0; i < mReferences.Length(); i++) { 1.248 + if (!mReferences[i]->ReferencesValidResource()) 1.249 + return false; 1.250 + } 1.251 + return true; 1.252 +} 1.253 + 1.254 +bool 1.255 +nsSVGFilterProperty::IsInObserverLists() const 1.256 +{ 1.257 + for (uint32_t i = 0; i < mReferences.Length(); i++) { 1.258 + if (!mReferences[i]->IsInObserverList()) 1.259 + return false; 1.260 + } 1.261 + return true; 1.262 +} 1.263 + 1.264 +void 1.265 +nsSVGFilterProperty::Invalidate() 1.266 +{ 1.267 + for (uint32_t i = 0; i < mReferences.Length(); i++) { 1.268 + mReferences[i]->Invalidate(); 1.269 + } 1.270 +} 1.271 + 1.272 +NS_IMPL_ISUPPORTS_INHERITED(nsSVGFilterReference, 1.273 + nsSVGIDRenderingObserver, 1.274 + nsISVGFilterReference); 1.275 + 1.276 +nsSVGFilterFrame * 1.277 +nsSVGFilterReference::GetFilterFrame() 1.278 +{ 1.279 + return static_cast<nsSVGFilterFrame *> 1.280 + (GetReferencedFrame(nsGkAtoms::svgFilterFrame, nullptr)); 1.281 +} 1.282 + 1.283 +static void 1.284 +InvalidateAllContinuations(nsIFrame* aFrame) 1.285 +{ 1.286 + for (nsIFrame* f = aFrame; f; 1.287 + f = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(f)) { 1.288 + f->InvalidateFrame(); 1.289 + } 1.290 +} 1.291 + 1.292 +void 1.293 +nsSVGFilterReference::DoUpdate() 1.294 +{ 1.295 + nsSVGIDRenderingObserver::DoUpdate(); 1.296 + if (!mFrame) 1.297 + return; 1.298 + 1.299 + // Repaint asynchronously in case the filter frame is being torn down 1.300 + nsChangeHint changeHint = 1.301 + nsChangeHint(nsChangeHint_RepaintFrame); 1.302 + 1.303 + // Don't need to request UpdateOverflow if we're being reflowed. 1.304 + if (!(mFrame->GetStateBits() & NS_FRAME_IN_REFLOW)) { 1.305 + NS_UpdateHint(changeHint, nsChangeHint_UpdateOverflow); 1.306 + } 1.307 + mFramePresShell->GetPresContext()->RestyleManager()->PostRestyleEvent( 1.308 + mFrame->GetContent()->AsElement(), nsRestyleHint(0), changeHint); 1.309 +} 1.310 + 1.311 +void 1.312 +nsSVGMarkerProperty::DoUpdate() 1.313 +{ 1.314 + nsSVGIDRenderingObserver::DoUpdate(); 1.315 + if (!mFrame) 1.316 + return; 1.317 + 1.318 + NS_ASSERTION(mFrame->IsFrameOfType(nsIFrame::eSVG), "SVG frame expected"); 1.319 + 1.320 + // Repaint asynchronously in case the marker frame is being torn down 1.321 + nsChangeHint changeHint = 1.322 + nsChangeHint(nsChangeHint_RepaintFrame); 1.323 + 1.324 + // Don't need to request ReflowFrame if we're being reflowed. 1.325 + if (!(mFrame->GetStateBits() & NS_FRAME_IN_REFLOW)) { 1.326 + // XXXjwatt: We need to unify SVG into standard reflow so we can just use 1.327 + // nsChangeHint_NeedReflow | nsChangeHint_NeedDirtyReflow here. 1.328 + nsSVGEffects::InvalidateRenderingObservers(mFrame); 1.329 + // XXXSDL KILL THIS!!! 1.330 + nsSVGUtils::ScheduleReflowSVG(mFrame); 1.331 + } 1.332 + mFramePresShell->GetPresContext()->RestyleManager()->PostRestyleEvent( 1.333 + mFrame->GetContent()->AsElement(), nsRestyleHint(0), changeHint); 1.334 +} 1.335 + 1.336 +bool 1.337 +nsSVGTextPathProperty::TargetIsValid() 1.338 +{ 1.339 + Element* target = GetTarget(); 1.340 + return target && target->IsSVG(nsGkAtoms::path); 1.341 +} 1.342 + 1.343 +void 1.344 +nsSVGTextPathProperty::DoUpdate() 1.345 +{ 1.346 + nsSVGIDRenderingObserver::DoUpdate(); 1.347 + if (!mFrame) 1.348 + return; 1.349 + 1.350 + NS_ASSERTION(mFrame->IsFrameOfType(nsIFrame::eSVG) || mFrame->IsSVGText(), 1.351 + "SVG frame expected"); 1.352 + 1.353 + // Avoid getting into an infinite loop of reflows if the <textPath> is 1.354 + // pointing to one of its ancestors. TargetIsValid returns true iff 1.355 + // the target element is a <path> element, and we would not have this 1.356 + // nsSVGTextPathProperty if this <textPath> were a descendant of the 1.357 + // target <path>. 1.358 + // 1.359 + // Note that we still have to post the restyle event when we 1.360 + // change from being valid to invalid, so that mPositions on the 1.361 + // SVGTextFrame gets updated, skipping the <textPath>, ensuring 1.362 + // that nothing gets painted for that element. 1.363 + bool nowValid = TargetIsValid(); 1.364 + if (!mValid && !nowValid) { 1.365 + // Just return if we were previously invalid, and are still invalid. 1.366 + return; 1.367 + } 1.368 + mValid = nowValid; 1.369 + 1.370 + // Repaint asynchronously in case the path frame is being torn down 1.371 + nsChangeHint changeHint = 1.372 + nsChangeHint(nsChangeHint_RepaintFrame | nsChangeHint_UpdateTextPath); 1.373 + mFramePresShell->GetPresContext()->RestyleManager()->PostRestyleEvent( 1.374 + mFrame->GetContent()->AsElement(), nsRestyleHint(0), changeHint); 1.375 +} 1.376 + 1.377 +void 1.378 +nsSVGPaintingProperty::DoUpdate() 1.379 +{ 1.380 + nsSVGIDRenderingObserver::DoUpdate(); 1.381 + if (!mFrame) 1.382 + return; 1.383 + 1.384 + if (mFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) { 1.385 + nsSVGEffects::InvalidateRenderingObservers(mFrame); 1.386 + mFrame->InvalidateFrameSubtree(); 1.387 + } else { 1.388 + InvalidateAllContinuations(mFrame); 1.389 + } 1.390 +} 1.391 + 1.392 +static nsSVGRenderingObserver * 1.393 +CreateMarkerProperty(nsIURI *aURI, nsIFrame *aFrame, bool aReferenceImage) 1.394 +{ return new nsSVGMarkerProperty(aURI, aFrame, aReferenceImage); } 1.395 + 1.396 +static nsSVGRenderingObserver * 1.397 +CreateTextPathProperty(nsIURI *aURI, nsIFrame *aFrame, bool aReferenceImage) 1.398 +{ return new nsSVGTextPathProperty(aURI, aFrame, aReferenceImage); } 1.399 + 1.400 +static nsSVGRenderingObserver * 1.401 +CreatePaintingProperty(nsIURI *aURI, nsIFrame *aFrame, bool aReferenceImage) 1.402 +{ return new nsSVGPaintingProperty(aURI, aFrame, aReferenceImage); } 1.403 + 1.404 +static nsSVGRenderingObserver * 1.405 +GetEffectProperty(nsIURI *aURI, nsIFrame *aFrame, 1.406 + const FramePropertyDescriptor *aProperty, 1.407 + nsSVGRenderingObserver * (* aCreate)(nsIURI *, nsIFrame *, bool)) 1.408 +{ 1.409 + if (!aURI) 1.410 + return nullptr; 1.411 + 1.412 + FrameProperties props = aFrame->Properties(); 1.413 + nsSVGRenderingObserver *prop = 1.414 + static_cast<nsSVGRenderingObserver*>(props.Get(aProperty)); 1.415 + if (prop) 1.416 + return prop; 1.417 + prop = aCreate(aURI, aFrame, false); 1.418 + if (!prop) 1.419 + return nullptr; 1.420 + NS_ADDREF(prop); 1.421 + props.Set(aProperty, static_cast<nsISupports*>(prop)); 1.422 + return prop; 1.423 +} 1.424 + 1.425 +static nsSVGFilterProperty* 1.426 +GetOrCreateFilterProperty(nsIFrame *aFrame) 1.427 +{ 1.428 + const nsStyleSVGReset* style = aFrame->StyleSVGReset(); 1.429 + if (!style->HasFilters()) 1.430 + return nullptr; 1.431 + 1.432 + FrameProperties props = aFrame->Properties(); 1.433 + nsSVGFilterProperty *prop = 1.434 + static_cast<nsSVGFilterProperty*>(props.Get(nsSVGEffects::FilterProperty())); 1.435 + if (prop) 1.436 + return prop; 1.437 + prop = new nsSVGFilterProperty(style->mFilters, aFrame); 1.438 + if (!prop) 1.439 + return nullptr; 1.440 + NS_ADDREF(prop); 1.441 + props.Set(nsSVGEffects::FilterProperty(), static_cast<nsISupports*>(prop)); 1.442 + return prop; 1.443 +} 1.444 + 1.445 +nsSVGMarkerProperty * 1.446 +nsSVGEffects::GetMarkerProperty(nsIURI *aURI, nsIFrame *aFrame, 1.447 + const FramePropertyDescriptor *aProp) 1.448 +{ 1.449 + NS_ABORT_IF_FALSE(aFrame->GetType() == nsGkAtoms::svgPathGeometryFrame && 1.450 + static_cast<nsSVGPathGeometryElement*>(aFrame->GetContent())->IsMarkable(), 1.451 + "Bad frame"); 1.452 + return static_cast<nsSVGMarkerProperty*>( 1.453 + GetEffectProperty(aURI, aFrame, aProp, CreateMarkerProperty)); 1.454 +} 1.455 + 1.456 +nsSVGTextPathProperty * 1.457 +nsSVGEffects::GetTextPathProperty(nsIURI *aURI, nsIFrame *aFrame, 1.458 + const FramePropertyDescriptor *aProp) 1.459 +{ 1.460 + return static_cast<nsSVGTextPathProperty*>( 1.461 + GetEffectProperty(aURI, aFrame, aProp, CreateTextPathProperty)); 1.462 +} 1.463 + 1.464 +nsSVGPaintingProperty * 1.465 +nsSVGEffects::GetPaintingProperty(nsIURI *aURI, nsIFrame *aFrame, 1.466 + const FramePropertyDescriptor *aProp) 1.467 +{ 1.468 + return static_cast<nsSVGPaintingProperty*>( 1.469 + GetEffectProperty(aURI, aFrame, aProp, CreatePaintingProperty)); 1.470 +} 1.471 + 1.472 +static nsSVGRenderingObserver * 1.473 +GetEffectPropertyForURI(nsIURI *aURI, nsIFrame *aFrame, 1.474 + const FramePropertyDescriptor *aProperty, 1.475 + nsSVGRenderingObserver * (* aCreate)(nsIURI *, nsIFrame *, bool)) 1.476 +{ 1.477 + if (!aURI) 1.478 + return nullptr; 1.479 + 1.480 + FrameProperties props = aFrame->Properties(); 1.481 + nsSVGEffects::URIObserverHashtable *hashtable = 1.482 + static_cast<nsSVGEffects::URIObserverHashtable*>(props.Get(aProperty)); 1.483 + if (!hashtable) { 1.484 + hashtable = new nsSVGEffects::URIObserverHashtable(); 1.485 + props.Set(aProperty, hashtable); 1.486 + } 1.487 + nsSVGRenderingObserver* prop = 1.488 + static_cast<nsSVGRenderingObserver*>(hashtable->GetWeak(aURI)); 1.489 + if (!prop) { 1.490 + bool watchImage = aProperty == nsSVGEffects::BackgroundImageProperty(); 1.491 + prop = aCreate(aURI, aFrame, watchImage); 1.492 + hashtable->Put(aURI, prop); 1.493 + } 1.494 + return prop; 1.495 +} 1.496 + 1.497 +nsSVGPaintingProperty * 1.498 +nsSVGEffects::GetPaintingPropertyForURI(nsIURI *aURI, nsIFrame *aFrame, 1.499 + const FramePropertyDescriptor *aProp) 1.500 +{ 1.501 + return static_cast<nsSVGPaintingProperty*>( 1.502 + GetEffectPropertyForURI(aURI, aFrame, aProp, CreatePaintingProperty)); 1.503 +} 1.504 + 1.505 +nsSVGEffects::EffectProperties 1.506 +nsSVGEffects::GetEffectProperties(nsIFrame *aFrame) 1.507 +{ 1.508 + NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame should be first continuation"); 1.509 + 1.510 + EffectProperties result; 1.511 + const nsStyleSVGReset *style = aFrame->StyleSVGReset(); 1.512 + result.mFilter = GetOrCreateFilterProperty(aFrame); 1.513 + result.mClipPath = 1.514 + GetPaintingProperty(style->mClipPath, aFrame, ClipPathProperty()); 1.515 + result.mMask = 1.516 + GetPaintingProperty(style->mMask, aFrame, MaskProperty()); 1.517 + return result; 1.518 +} 1.519 + 1.520 +nsSVGPaintServerFrame * 1.521 +nsSVGEffects::GetPaintServer(nsIFrame *aTargetFrame, const nsStyleSVGPaint *aPaint, 1.522 + const FramePropertyDescriptor *aType) 1.523 +{ 1.524 + if (aPaint->mType != eStyleSVGPaintType_Server) 1.525 + return nullptr; 1.526 + 1.527 + nsIFrame *frame = aTargetFrame->GetContent()->IsNodeOfType(nsINode::eTEXT) ? 1.528 + aTargetFrame->GetParent() : aTargetFrame; 1.529 + nsSVGPaintingProperty *property = 1.530 + nsSVGEffects::GetPaintingProperty(aPaint->mPaint.mPaintServer, frame, aType); 1.531 + if (!property) 1.532 + return nullptr; 1.533 + nsIFrame *result = property->GetReferencedFrame(); 1.534 + if (!result) 1.535 + return nullptr; 1.536 + 1.537 + nsIAtom *type = result->GetType(); 1.538 + if (type != nsGkAtoms::svgLinearGradientFrame && 1.539 + type != nsGkAtoms::svgRadialGradientFrame && 1.540 + type != nsGkAtoms::svgPatternFrame) 1.541 + return nullptr; 1.542 + 1.543 + return static_cast<nsSVGPaintServerFrame*>(result); 1.544 +} 1.545 + 1.546 +nsSVGClipPathFrame * 1.547 +nsSVGEffects::EffectProperties::GetClipPathFrame(bool *aOK) 1.548 +{ 1.549 + if (!mClipPath) 1.550 + return nullptr; 1.551 + nsSVGClipPathFrame *frame = static_cast<nsSVGClipPathFrame *> 1.552 + (mClipPath->GetReferencedFrame(nsGkAtoms::svgClipPathFrame, aOK)); 1.553 + if (frame && aOK && *aOK) { 1.554 + *aOK = frame->IsValid(); 1.555 + } 1.556 + return frame; 1.557 +} 1.558 + 1.559 +nsSVGMaskFrame * 1.560 +nsSVGEffects::EffectProperties::GetMaskFrame(bool *aOK) 1.561 +{ 1.562 + if (!mMask) 1.563 + return nullptr; 1.564 + return static_cast<nsSVGMaskFrame *> 1.565 + (mMask->GetReferencedFrame(nsGkAtoms::svgMaskFrame, aOK)); 1.566 +} 1.567 + 1.568 +void 1.569 +nsSVGEffects::UpdateEffects(nsIFrame *aFrame) 1.570 +{ 1.571 + NS_ASSERTION(aFrame->GetContent()->IsElement(), 1.572 + "aFrame's content should be an element"); 1.573 + 1.574 + FrameProperties props = aFrame->Properties(); 1.575 + props.Delete(FilterProperty()); 1.576 + props.Delete(MaskProperty()); 1.577 + props.Delete(ClipPathProperty()); 1.578 + props.Delete(MarkerBeginProperty()); 1.579 + props.Delete(MarkerMiddleProperty()); 1.580 + props.Delete(MarkerEndProperty()); 1.581 + props.Delete(FillProperty()); 1.582 + props.Delete(StrokeProperty()); 1.583 + props.Delete(BackgroundImageProperty()); 1.584 + 1.585 + // Ensure that the filter is repainted correctly 1.586 + // We can't do that in DoUpdate as the referenced frame may not be valid 1.587 + GetOrCreateFilterProperty(aFrame); 1.588 + 1.589 + if (aFrame->GetType() == nsGkAtoms::svgPathGeometryFrame && 1.590 + static_cast<nsSVGPathGeometryElement*>(aFrame->GetContent())->IsMarkable()) { 1.591 + // Set marker properties here to avoid reference loops 1.592 + const nsStyleSVG *style = aFrame->StyleSVG(); 1.593 + GetEffectProperty(style->mMarkerStart, aFrame, MarkerBeginProperty(), 1.594 + CreateMarkerProperty); 1.595 + GetEffectProperty(style->mMarkerMid, aFrame, MarkerMiddleProperty(), 1.596 + CreateMarkerProperty); 1.597 + GetEffectProperty(style->mMarkerEnd, aFrame, MarkerEndProperty(), 1.598 + CreateMarkerProperty); 1.599 + } 1.600 +} 1.601 + 1.602 +nsSVGFilterProperty * 1.603 +nsSVGEffects::GetFilterProperty(nsIFrame *aFrame) 1.604 +{ 1.605 + NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame should be first continuation"); 1.606 + 1.607 + if (!aFrame->StyleSVGReset()->HasFilters()) 1.608 + return nullptr; 1.609 + 1.610 + return static_cast<nsSVGFilterProperty *> 1.611 + (aFrame->Properties().Get(FilterProperty())); 1.612 +} 1.613 + 1.614 +static PLDHashOperator 1.615 +GatherEnumerator(nsPtrHashKey<nsSVGRenderingObserver>* aEntry, void* aArg) 1.616 +{ 1.617 + nsTArray<nsSVGRenderingObserver*>* array = 1.618 + static_cast<nsTArray<nsSVGRenderingObserver*>*>(aArg); 1.619 + array->AppendElement(aEntry->GetKey()); 1.620 + 1.621 + return PL_DHASH_REMOVE; 1.622 +} 1.623 + 1.624 +static PLDHashOperator 1.625 +GatherEnumeratorForReflow(nsPtrHashKey<nsSVGRenderingObserver>* aEntry, void* aArg) 1.626 +{ 1.627 + if (!aEntry->GetKey()->ObservesReflow()) { 1.628 + return PL_DHASH_NEXT; 1.629 + } 1.630 + 1.631 + nsTArray<nsSVGRenderingObserver*>* array = 1.632 + static_cast<nsTArray<nsSVGRenderingObserver*>*>(aArg); 1.633 + array->AppendElement(aEntry->GetKey()); 1.634 + 1.635 + return PL_DHASH_REMOVE; 1.636 +} 1.637 + 1.638 +void 1.639 +nsSVGRenderingObserverList::InvalidateAll() 1.640 +{ 1.641 + if (mObservers.Count() == 0) 1.642 + return; 1.643 + 1.644 + nsAutoTArray<nsSVGRenderingObserver*,10> observers; 1.645 + 1.646 + // The PL_DHASH_REMOVE in GatherEnumerator drops all our observers here: 1.647 + mObservers.EnumerateEntries(GatherEnumerator, &observers); 1.648 + 1.649 + for (uint32_t i = 0; i < observers.Length(); ++i) { 1.650 + observers[i]->InvalidateViaReferencedElement(); 1.651 + } 1.652 +} 1.653 + 1.654 +void 1.655 +nsSVGRenderingObserverList::InvalidateAllForReflow() 1.656 +{ 1.657 + if (mObservers.Count() == 0) 1.658 + return; 1.659 + 1.660 + nsAutoTArray<nsSVGRenderingObserver*,10> observers; 1.661 + 1.662 + // The PL_DHASH_REMOVE in GatherEnumerator drops all our observers here: 1.663 + mObservers.EnumerateEntries(GatherEnumeratorForReflow, &observers); 1.664 + 1.665 + for (uint32_t i = 0; i < observers.Length(); ++i) { 1.666 + observers[i]->InvalidateViaReferencedElement(); 1.667 + } 1.668 +} 1.669 + 1.670 +void 1.671 +nsSVGRenderingObserverList::RemoveAll() 1.672 +{ 1.673 + nsAutoTArray<nsSVGRenderingObserver*,10> observers; 1.674 + 1.675 + // The PL_DHASH_REMOVE in GatherEnumerator drops all our observers here: 1.676 + mObservers.EnumerateEntries(GatherEnumerator, &observers); 1.677 + 1.678 + // Our list is now cleared. We need to notify the observers we've removed, 1.679 + // so they can update their state & remove themselves as mutation-observers. 1.680 + for (uint32_t i = 0; i < observers.Length(); ++i) { 1.681 + observers[i]->NotifyEvictedFromRenderingObserverList(); 1.682 + } 1.683 +} 1.684 + 1.685 +void 1.686 +nsSVGEffects::AddRenderingObserver(Element *aElement, nsSVGRenderingObserver *aObserver) 1.687 +{ 1.688 + nsSVGRenderingObserverList *observerList = GetObserverList(aElement); 1.689 + if (!observerList) { 1.690 + observerList = new nsSVGRenderingObserverList(); 1.691 + if (!observerList) 1.692 + return; 1.693 + aElement->SetProperty(nsGkAtoms::renderingobserverlist, observerList, 1.694 + nsINode::DeleteProperty<nsSVGRenderingObserverList>); 1.695 + } 1.696 + aElement->SetHasRenderingObservers(true); 1.697 + observerList->Add(aObserver); 1.698 +} 1.699 + 1.700 +void 1.701 +nsSVGEffects::RemoveRenderingObserver(Element *aElement, nsSVGRenderingObserver *aObserver) 1.702 +{ 1.703 + nsSVGRenderingObserverList *observerList = GetObserverList(aElement); 1.704 + if (observerList) { 1.705 + NS_ASSERTION(observerList->Contains(aObserver), 1.706 + "removing observer from an element we're not observing?"); 1.707 + observerList->Remove(aObserver); 1.708 + if (observerList->IsEmpty()) { 1.709 + aElement->SetHasRenderingObservers(false); 1.710 + } 1.711 + } 1.712 +} 1.713 + 1.714 +void 1.715 +nsSVGEffects::RemoveAllRenderingObservers(Element *aElement) 1.716 +{ 1.717 + nsSVGRenderingObserverList *observerList = GetObserverList(aElement); 1.718 + if (observerList) { 1.719 + observerList->RemoveAll(); 1.720 + aElement->SetHasRenderingObservers(false); 1.721 + } 1.722 +} 1.723 + 1.724 +void 1.725 +nsSVGEffects::InvalidateRenderingObservers(nsIFrame *aFrame) 1.726 +{ 1.727 + NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame must be first continuation"); 1.728 + 1.729 + if (!aFrame->GetContent()->IsElement()) 1.730 + return; 1.731 + 1.732 + nsSVGRenderingObserverList *observerList = 1.733 + GetObserverList(aFrame->GetContent()->AsElement()); 1.734 + if (observerList) { 1.735 + observerList->InvalidateAll(); 1.736 + return; 1.737 + } 1.738 + 1.739 + // Check ancestor SVG containers. The root frame cannot be of type 1.740 + // eSVGContainer so we don't have to check f for null here. 1.741 + for (nsIFrame *f = aFrame->GetParent(); 1.742 + f->IsFrameOfType(nsIFrame::eSVGContainer); f = f->GetParent()) { 1.743 + if (f->GetContent()->IsElement()) { 1.744 + observerList = GetObserverList(f->GetContent()->AsElement()); 1.745 + if (observerList) { 1.746 + observerList->InvalidateAll(); 1.747 + return; 1.748 + } 1.749 + } 1.750 + } 1.751 +} 1.752 + 1.753 +void 1.754 +nsSVGEffects::InvalidateDirectRenderingObservers(Element *aElement, uint32_t aFlags /* = 0 */) 1.755 +{ 1.756 + if (aElement->HasRenderingObservers()) { 1.757 + nsSVGRenderingObserverList *observerList = GetObserverList(aElement); 1.758 + if (observerList) { 1.759 + if (aFlags & INVALIDATE_REFLOW) { 1.760 + observerList->InvalidateAllForReflow(); 1.761 + } else { 1.762 + observerList->InvalidateAll(); 1.763 + } 1.764 + } 1.765 + } 1.766 +} 1.767 + 1.768 +void 1.769 +nsSVGEffects::InvalidateDirectRenderingObservers(nsIFrame *aFrame, uint32_t aFlags /* = 0 */) 1.770 +{ 1.771 + if (aFrame->GetContent() && aFrame->GetContent()->IsElement()) { 1.772 + InvalidateDirectRenderingObservers(aFrame->GetContent()->AsElement(), aFlags); 1.773 + } 1.774 +}