1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is the Mozilla SVG project.
16 : *
17 : * The Initial Developer of the Original Code is IBM Corporation.
18 : * Portions created by the Initial Developer are Copyright (C) 2005
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * rocallahan@mozilla.com
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #include "nsSVGEffects.h"
39 : #include "nsISupportsImpl.h"
40 : #include "nsSVGOuterSVGFrame.h"
41 : #include "nsSVGFilterFrame.h"
42 : #include "nsSVGClipPathFrame.h"
43 : #include "nsSVGMaskFrame.h"
44 : #include "nsSVGTextPathFrame.h"
45 : #include "nsCSSFrameConstructor.h"
46 : #include "nsFrameManager.h"
47 :
48 : using namespace mozilla;
49 : using namespace mozilla::dom;
50 :
51 : // nsSVGRenderingObserver impl
52 0 : NS_IMPL_ISUPPORTS1(nsSVGRenderingObserver, nsIMutationObserver)
53 :
54 : void
55 0 : nsSVGRenderingObserver::StartListening()
56 : {
57 0 : Element* target = GetTarget();
58 0 : if (target) {
59 0 : target->AddMutationObserver(this);
60 : }
61 0 : }
62 :
63 : void
64 0 : nsSVGRenderingObserver::StopListening()
65 : {
66 0 : Element* target = GetTarget();
67 :
68 0 : if (target) {
69 0 : target->RemoveMutationObserver(this);
70 0 : if (mInObserverList) {
71 0 : nsSVGEffects::RemoveRenderingObserver(target, this);
72 0 : mInObserverList = false;
73 : }
74 : }
75 0 : NS_ASSERTION(!mInObserverList, "still in an observer list?");
76 0 : }
77 :
78 :
79 :
80 : /**
81 : * Note that in the current setup there are two separate observer lists.
82 : *
83 : * In nsSVGIDRenderingObserver's ctor, the new object adds itself to the
84 : * mutation observer list maintained by the referenced element. In this way the
85 : * nsSVGIDRenderingObserver is notified if there are any attribute or content
86 : * tree changes to the element or any of its *descendants*.
87 : *
88 : * In nsSVGIDRenderingObserver::GetReferencedElement() the
89 : * nsSVGIDRenderingObserver object also adds itself to an
90 : * nsSVGRenderingObserverList object belonging to the referenced
91 : * element.
92 : *
93 : * XXX: it would be nice to have a clear and concise executive summary of the
94 : * benefits/necessity of maintaining a second observer list.
95 : */
96 :
97 : #ifdef _MSC_VER
98 : // Disable "warning C4355: 'this' : used in base member initializer list".
99 : // We can ignore that warning because we know that mElement's constructor
100 : // doesn't dereference the pointer passed to it.
101 : #pragma warning(push)
102 : #pragma warning(disable:4355)
103 : #endif
104 0 : nsSVGIDRenderingObserver::nsSVGIDRenderingObserver(nsIURI *aURI,
105 : nsIFrame *aFrame,
106 : bool aReferenceImage)
107 : : mElement(this), mFrame(aFrame),
108 0 : mFramePresShell(aFrame->PresContext()->PresShell())
109 : #ifdef _MSC_VER
110 : #pragma warning(pop)
111 : #endif
112 : {
113 : // Start watching the target element
114 0 : mElement.Reset(aFrame->GetContent(), aURI, true, aReferenceImage);
115 0 : StartListening();
116 0 : }
117 :
118 0 : nsSVGIDRenderingObserver::~nsSVGIDRenderingObserver()
119 : {
120 0 : StopListening();
121 0 : }
122 :
123 : static nsSVGRenderingObserverList *
124 0 : GetObserverList(Element *aElement)
125 : {
126 : return static_cast<nsSVGRenderingObserverList*>
127 0 : (aElement->GetProperty(nsGkAtoms::renderingobserverlist));
128 : }
129 :
130 : Element*
131 0 : nsSVGRenderingObserver::GetReferencedElement()
132 : {
133 0 : Element* target = GetTarget();
134 : #ifdef DEBUG
135 0 : if (target) {
136 0 : nsSVGRenderingObserverList *observerList = GetObserverList(target);
137 0 : bool inObserverList = observerList && observerList->Contains(this);
138 0 : NS_ASSERTION(inObserverList == mInObserverList, "failed to track whether we're in our referenced element's observer list!");
139 : } else {
140 0 : NS_ASSERTION(!mInObserverList, "In whose observer list are we, then?");
141 : }
142 : #endif
143 0 : if (target && !mInObserverList) {
144 0 : nsSVGEffects::AddRenderingObserver(target, this);
145 0 : mInObserverList = true;
146 : }
147 0 : return target;
148 : }
149 :
150 : nsIFrame*
151 0 : nsSVGRenderingObserver::GetReferencedFrame()
152 : {
153 0 : Element* referencedElement = GetReferencedElement();
154 0 : return referencedElement ? referencedElement->GetPrimaryFrame() : nsnull;
155 : }
156 :
157 : nsIFrame*
158 0 : nsSVGRenderingObserver::GetReferencedFrame(nsIAtom* aFrameType, bool* aOK)
159 : {
160 0 : nsIFrame* frame = GetReferencedFrame();
161 0 : if (frame) {
162 0 : if (frame->GetType() == aFrameType)
163 0 : return frame;
164 0 : if (aOK) {
165 0 : *aOK = false;
166 : }
167 : }
168 0 : return nsnull;
169 : }
170 :
171 : void
172 0 : nsSVGIDRenderingObserver::DoUpdate()
173 : {
174 0 : if (mFramePresShell->IsDestroying()) {
175 : // mFrame is no longer valid. Bail out.
176 0 : mFrame = nsnull;
177 0 : return;
178 : }
179 0 : if (mElement.get() && mInObserverList) {
180 0 : nsSVGEffects::RemoveRenderingObserver(mElement.get(), this);
181 0 : mInObserverList = false;
182 : }
183 0 : if (mFrame && mFrame->IsFrameOfType(nsIFrame::eSVG)) {
184 : // Changes should propagate out to things that might be observing
185 : // the referencing frame or its ancestors.
186 0 : nsSVGEffects::InvalidateRenderingObservers(mFrame);
187 : }
188 : }
189 :
190 : void
191 0 : nsSVGRenderingObserver::InvalidateViaReferencedElement()
192 : {
193 0 : mInObserverList = false;
194 0 : DoUpdate();
195 0 : }
196 :
197 : void
198 0 : nsSVGRenderingObserver::NotifyEvictedFromRenderingObserverList()
199 : {
200 0 : mInObserverList = false; // We've been removed from rendering-obs. list.
201 0 : StopListening(); // Remove ourselves from mutation-obs. list.
202 0 : }
203 :
204 : void
205 0 : nsSVGRenderingObserver::AttributeChanged(nsIDocument* aDocument,
206 : dom::Element* aElement,
207 : PRInt32 aNameSpaceID,
208 : nsIAtom* aAttribute,
209 : PRInt32 aModType)
210 : {
211 : // An attribute belonging to the element that we are observing *or one of its
212 : // descendants* has changed.
213 : //
214 : // In the case of observing a gradient element, say, we want to know if any
215 : // of its 'stop' element children change, but we don't actually want to do
216 : // anything for changes to SMIL element children, for example. Maybe it's not
217 : // worth having logic to optimize for that, but in most cases it could be a
218 : // small check?
219 : //
220 : // XXXjwatt: do we really want to blindly break the link between our
221 : // observers and ourselves for all attribute changes? For non-ID changes
222 : // surely that is unnecessary.
223 :
224 0 : DoUpdate();
225 0 : }
226 :
227 : void
228 0 : nsSVGRenderingObserver::ContentAppended(nsIDocument *aDocument,
229 : nsIContent *aContainer,
230 : nsIContent *aFirstNewContent,
231 : PRInt32 /* unused */)
232 : {
233 0 : DoUpdate();
234 0 : }
235 :
236 : void
237 0 : nsSVGRenderingObserver::ContentInserted(nsIDocument *aDocument,
238 : nsIContent *aContainer,
239 : nsIContent *aChild,
240 : PRInt32 /* unused */)
241 : {
242 0 : DoUpdate();
243 0 : }
244 :
245 : void
246 0 : nsSVGRenderingObserver::ContentRemoved(nsIDocument *aDocument,
247 : nsIContent *aContainer,
248 : nsIContent *aChild,
249 : PRInt32 aIndexInContainer,
250 : nsIContent *aPreviousSibling)
251 : {
252 0 : DoUpdate();
253 0 : }
254 :
255 0 : NS_IMPL_ISUPPORTS_INHERITED1(nsSVGFilterProperty,
256 : nsSVGIDRenderingObserver,
257 : nsISVGFilterProperty)
258 :
259 : nsSVGFilterFrame *
260 0 : nsSVGFilterProperty::GetFilterFrame()
261 : {
262 : return static_cast<nsSVGFilterFrame *>
263 0 : (GetReferencedFrame(nsGkAtoms::svgFilterFrame, nsnull));
264 : }
265 :
266 : static void
267 0 : InvalidateAllContinuations(nsIFrame* aFrame)
268 : {
269 0 : for (nsIFrame* f = aFrame; f; f = f->GetNextContinuation()) {
270 0 : f->InvalidateOverflowRect();
271 : }
272 0 : }
273 :
274 : void
275 0 : nsSVGFilterProperty::DoUpdate()
276 : {
277 0 : nsSVGIDRenderingObserver::DoUpdate();
278 0 : if (!mFrame)
279 0 : return;
280 :
281 : // Repaint asynchronously in case the filter frame is being torn down
282 : nsChangeHint changeHint =
283 0 : nsChangeHint(nsChangeHint_RepaintFrame | nsChangeHint_UpdateEffects);
284 :
285 : // Don't need to request a reflow if the frame is already being reflowed.
286 0 : if (!mFrame->IsFrameOfType(nsIFrame::eSVG) &&
287 0 : !(mFrame->GetStateBits() & NS_FRAME_IN_REFLOW)) {
288 0 : NS_UpdateHint(changeHint, nsChangeHint_ReflowFrame);
289 : }
290 : mFramePresShell->FrameConstructor()->PostRestyleEvent(
291 0 : mFrame->GetContent()->AsElement(), nsRestyleHint(0), changeHint);
292 : }
293 :
294 : void
295 0 : nsSVGMarkerProperty::DoUpdate()
296 : {
297 0 : nsSVGIDRenderingObserver::DoUpdate();
298 0 : if (!mFrame)
299 0 : return;
300 :
301 0 : NS_ASSERTION(mFrame->IsFrameOfType(nsIFrame::eSVG), "SVG frame expected");
302 :
303 : // Repaint asynchronously
304 : nsChangeHint changeHint =
305 0 : nsChangeHint(nsChangeHint_RepaintFrame | nsChangeHint_UpdateEffects);
306 :
307 : mFramePresShell->FrameConstructor()->PostRestyleEvent(
308 0 : mFrame->GetContent()->AsElement(), nsRestyleHint(0), changeHint);
309 : }
310 :
311 : void
312 0 : nsSVGTextPathProperty::DoUpdate()
313 : {
314 0 : nsSVGIDRenderingObserver::DoUpdate();
315 0 : if (!mFrame)
316 0 : return;
317 :
318 0 : NS_ASSERTION(mFrame->IsFrameOfType(nsIFrame::eSVG), "SVG frame expected");
319 :
320 0 : if (mFrame->GetType() == nsGkAtoms::svgTextPathFrame) {
321 0 : nsSVGTextPathFrame* textPathFrame = static_cast<nsSVGTextPathFrame*>(mFrame);
322 0 : textPathFrame->NotifyGlyphMetricsChange();
323 : }
324 : }
325 :
326 : void
327 0 : nsSVGPaintingProperty::DoUpdate()
328 : {
329 0 : nsSVGIDRenderingObserver::DoUpdate();
330 0 : if (!mFrame)
331 0 : return;
332 :
333 0 : if (mFrame->IsFrameOfType(nsIFrame::eSVG)) {
334 0 : nsSVGUtils::InvalidateCoveredRegion(mFrame);
335 : } else {
336 0 : InvalidateAllContinuations(mFrame);
337 : }
338 : }
339 :
340 : static nsSVGRenderingObserver *
341 0 : CreateFilterProperty(nsIURI *aURI, nsIFrame *aFrame, bool aReferenceImage)
342 0 : { return new nsSVGFilterProperty(aURI, aFrame, aReferenceImage); }
343 :
344 : static nsSVGRenderingObserver *
345 0 : CreateMarkerProperty(nsIURI *aURI, nsIFrame *aFrame, bool aReferenceImage)
346 0 : { return new nsSVGMarkerProperty(aURI, aFrame, aReferenceImage); }
347 :
348 : static nsSVGRenderingObserver *
349 0 : CreateTextPathProperty(nsIURI *aURI, nsIFrame *aFrame, bool aReferenceImage)
350 0 : { return new nsSVGTextPathProperty(aURI, aFrame, aReferenceImage); }
351 :
352 : static nsSVGRenderingObserver *
353 0 : CreatePaintingProperty(nsIURI *aURI, nsIFrame *aFrame, bool aReferenceImage)
354 0 : { return new nsSVGPaintingProperty(aURI, aFrame, aReferenceImage); }
355 :
356 : static nsSVGRenderingObserver *
357 0 : GetEffectProperty(nsIURI *aURI, nsIFrame *aFrame,
358 : const FramePropertyDescriptor *aProperty,
359 : nsSVGRenderingObserver * (* aCreate)(nsIURI *, nsIFrame *, bool))
360 : {
361 0 : if (!aURI)
362 0 : return nsnull;
363 :
364 0 : FrameProperties props = aFrame->Properties();
365 : nsSVGRenderingObserver *prop =
366 0 : static_cast<nsSVGRenderingObserver*>(props.Get(aProperty));
367 0 : if (prop)
368 0 : return prop;
369 0 : prop = aCreate(aURI, aFrame, false);
370 0 : if (!prop)
371 0 : return nsnull;
372 0 : NS_ADDREF(prop);
373 0 : props.Set(aProperty, static_cast<nsISupports*>(prop));
374 0 : return prop;
375 : }
376 :
377 : nsSVGMarkerProperty *
378 0 : nsSVGEffects::GetMarkerProperty(nsIURI *aURI, nsIFrame *aFrame,
379 : const FramePropertyDescriptor *aProp)
380 : {
381 : return static_cast<nsSVGMarkerProperty*>(
382 0 : GetEffectProperty(aURI, aFrame, aProp, CreateMarkerProperty));
383 : }
384 :
385 : nsSVGTextPathProperty *
386 0 : nsSVGEffects::GetTextPathProperty(nsIURI *aURI, nsIFrame *aFrame,
387 : const FramePropertyDescriptor *aProp)
388 : {
389 : return static_cast<nsSVGTextPathProperty*>(
390 0 : GetEffectProperty(aURI, aFrame, aProp, CreateTextPathProperty));
391 : }
392 :
393 : nsSVGPaintingProperty *
394 0 : nsSVGEffects::GetPaintingProperty(nsIURI *aURI, nsIFrame *aFrame,
395 : const FramePropertyDescriptor *aProp)
396 : {
397 : return static_cast<nsSVGPaintingProperty*>(
398 0 : GetEffectProperty(aURI, aFrame, aProp, CreatePaintingProperty));
399 : }
400 :
401 : static nsSVGRenderingObserver *
402 0 : GetEffectPropertyForURI(nsIURI *aURI, nsIFrame *aFrame,
403 : const FramePropertyDescriptor *aProperty,
404 : nsSVGRenderingObserver * (* aCreate)(nsIURI *, nsIFrame *, bool))
405 : {
406 0 : if (!aURI)
407 0 : return nsnull;
408 :
409 0 : FrameProperties props = aFrame->Properties();
410 : nsSVGEffects::URIObserverHashtable *hashtable =
411 0 : static_cast<nsSVGEffects::URIObserverHashtable*>(props.Get(aProperty));
412 0 : if (!hashtable) {
413 0 : hashtable = new nsSVGEffects::URIObserverHashtable();
414 0 : hashtable->Init();
415 0 : props.Set(aProperty, hashtable);
416 : }
417 : nsSVGRenderingObserver* prop =
418 0 : static_cast<nsSVGRenderingObserver*>(hashtable->GetWeak(aURI));
419 0 : if (!prop) {
420 0 : bool watchImage = aProperty == nsSVGEffects::BackgroundImageProperty();
421 0 : prop = aCreate(aURI, aFrame, watchImage);
422 0 : hashtable->Put(aURI, prop);
423 : }
424 0 : return prop;
425 : }
426 :
427 : nsSVGPaintingProperty *
428 0 : nsSVGEffects::GetPaintingPropertyForURI(nsIURI *aURI, nsIFrame *aFrame,
429 : const FramePropertyDescriptor *aProp)
430 : {
431 : return static_cast<nsSVGPaintingProperty*>(
432 0 : GetEffectPropertyForURI(aURI, aFrame, aProp, CreatePaintingProperty));
433 : }
434 :
435 : nsSVGEffects::EffectProperties
436 0 : nsSVGEffects::GetEffectProperties(nsIFrame *aFrame)
437 : {
438 0 : NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame should be first continuation");
439 :
440 : EffectProperties result;
441 0 : const nsStyleSVGReset *style = aFrame->GetStyleSVGReset();
442 : result.mFilter = static_cast<nsSVGFilterProperty*>
443 : (GetEffectProperty(style->mFilter, aFrame, FilterProperty(),
444 0 : CreateFilterProperty));
445 : result.mClipPath =
446 0 : GetPaintingProperty(style->mClipPath, aFrame, ClipPathProperty());
447 : result.mMask =
448 0 : GetPaintingProperty(style->mMask, aFrame, MaskProperty());
449 : return result;
450 : }
451 :
452 : nsSVGClipPathFrame *
453 0 : nsSVGEffects::EffectProperties::GetClipPathFrame(bool *aOK)
454 : {
455 0 : if (!mClipPath)
456 0 : return nsnull;
457 : nsSVGClipPathFrame *frame = static_cast<nsSVGClipPathFrame *>
458 0 : (mClipPath->GetReferencedFrame(nsGkAtoms::svgClipPathFrame, aOK));
459 0 : if (frame && aOK && *aOK) {
460 0 : *aOK = frame->IsValid();
461 : }
462 0 : return frame;
463 : }
464 :
465 : nsSVGMaskFrame *
466 0 : nsSVGEffects::EffectProperties::GetMaskFrame(bool *aOK)
467 : {
468 0 : if (!mMask)
469 0 : return nsnull;
470 : return static_cast<nsSVGMaskFrame *>
471 0 : (mMask->GetReferencedFrame(nsGkAtoms::svgMaskFrame, aOK));
472 : }
473 :
474 : void
475 0 : nsSVGEffects::UpdateEffects(nsIFrame *aFrame)
476 : {
477 0 : NS_ASSERTION(aFrame->GetContent()->IsElement(),
478 : "aFrame's content should be an element");
479 :
480 0 : FrameProperties props = aFrame->Properties();
481 0 : props.Delete(FilterProperty());
482 0 : props.Delete(MaskProperty());
483 0 : props.Delete(ClipPathProperty());
484 0 : props.Delete(MarkerBeginProperty());
485 0 : props.Delete(MarkerMiddleProperty());
486 0 : props.Delete(MarkerEndProperty());
487 0 : props.Delete(FillProperty());
488 0 : props.Delete(StrokeProperty());
489 0 : props.Delete(BackgroundImageProperty());
490 :
491 : // Ensure that the filter is repainted correctly
492 : // We can't do that in DoUpdate as the referenced frame may not be valid
493 0 : GetEffectProperty(aFrame->GetStyleSVGReset()->mFilter,
494 0 : aFrame, FilterProperty(), CreateFilterProperty);
495 :
496 0 : if (aFrame->IsFrameOfType(nsIFrame::eSVG)) {
497 : // Set marker properties here to avoid reference loops
498 0 : const nsStyleSVG *style = aFrame->GetStyleSVG();
499 : GetEffectProperty(style->mMarkerStart, aFrame, MarkerBeginProperty(),
500 0 : CreateMarkerProperty);
501 : GetEffectProperty(style->mMarkerMid, aFrame, MarkerMiddleProperty(),
502 0 : CreateMarkerProperty);
503 : GetEffectProperty(style->mMarkerEnd, aFrame, MarkerEndProperty(),
504 0 : CreateMarkerProperty);
505 : }
506 :
507 0 : nsIFrame *kid = aFrame->GetFirstPrincipalChild();
508 0 : while (kid) {
509 0 : if (kid->GetContent()->IsElement()) {
510 0 : UpdateEffects(kid);
511 : }
512 0 : kid = kid->GetNextSibling();
513 : }
514 0 : }
515 :
516 : nsSVGFilterProperty *
517 0 : nsSVGEffects::GetFilterProperty(nsIFrame *aFrame)
518 : {
519 0 : NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame should be first continuation");
520 :
521 0 : if (!aFrame->GetStyleSVGReset()->mFilter)
522 0 : return nsnull;
523 :
524 : return static_cast<nsSVGFilterProperty *>
525 0 : (aFrame->Properties().Get(FilterProperty()));
526 : }
527 :
528 : static PLDHashOperator
529 0 : GatherEnumerator(nsVoidPtrHashKey* aEntry, void* aArg)
530 : {
531 : nsTArray<nsSVGRenderingObserver*>* array =
532 0 : static_cast<nsTArray<nsSVGRenderingObserver*>*>(aArg);
533 : array->AppendElement(static_cast<nsSVGRenderingObserver*>(
534 0 : const_cast<void*>(aEntry->GetKey())));
535 0 : return PL_DHASH_REMOVE;
536 : }
537 :
538 : void
539 0 : nsSVGRenderingObserverList::InvalidateAll()
540 : {
541 0 : if (mObservers.Count() == 0)
542 0 : return;
543 :
544 0 : nsAutoTArray<nsSVGRenderingObserver*,10> observers;
545 :
546 : // The PL_DHASH_REMOVE in GatherEnumerator drops all our observers here:
547 0 : mObservers.EnumerateEntries(GatherEnumerator, &observers);
548 :
549 0 : for (PRUint32 i = 0; i < observers.Length(); ++i) {
550 0 : observers[i]->InvalidateViaReferencedElement();
551 : }
552 : }
553 :
554 : void
555 0 : nsSVGRenderingObserverList::RemoveAll()
556 : {
557 0 : nsAutoTArray<nsSVGRenderingObserver*,10> observers;
558 :
559 : // The PL_DHASH_REMOVE in GatherEnumerator drops all our observers here:
560 0 : mObservers.EnumerateEntries(GatherEnumerator, &observers);
561 :
562 : // Our list is now cleared. We need to notify the observers we've removed,
563 : // so they can update their state & remove themselves as mutation-observers.
564 0 : for (PRUint32 i = 0; i < observers.Length(); ++i) {
565 0 : observers[i]->NotifyEvictedFromRenderingObserverList();
566 : }
567 0 : }
568 :
569 : static void
570 0 : DestroyObservers(void *aObject, nsIAtom *aPropertyName,
571 : void *aPropertyValue, void *aData)
572 : {
573 0 : delete static_cast<nsSVGRenderingObserverList*>(aPropertyValue);
574 0 : }
575 :
576 : void
577 0 : nsSVGEffects::AddRenderingObserver(Element *aElement, nsSVGRenderingObserver *aObserver)
578 : {
579 0 : nsSVGRenderingObserverList *observerList = GetObserverList(aElement);
580 0 : if (!observerList) {
581 0 : observerList = new nsSVGRenderingObserverList();
582 0 : if (!observerList)
583 0 : return;
584 0 : aElement->SetProperty(nsGkAtoms::renderingobserverlist, observerList, DestroyObservers);
585 : }
586 0 : aElement->SetHasRenderingObservers(true);
587 0 : observerList->Add(aObserver);
588 : }
589 :
590 : void
591 0 : nsSVGEffects::RemoveRenderingObserver(Element *aElement, nsSVGRenderingObserver *aObserver)
592 : {
593 0 : nsSVGRenderingObserverList *observerList = GetObserverList(aElement);
594 0 : if (observerList) {
595 0 : NS_ASSERTION(observerList->Contains(aObserver),
596 : "removing observer from an element we're not observing?");
597 0 : observerList->Remove(aObserver);
598 0 : if (observerList->IsEmpty()) {
599 0 : aElement->SetHasRenderingObservers(false);
600 : }
601 : }
602 0 : }
603 :
604 : void
605 0 : nsSVGEffects::RemoveAllRenderingObservers(Element *aElement)
606 : {
607 0 : nsSVGRenderingObserverList *observerList = GetObserverList(aElement);
608 0 : if (observerList) {
609 0 : observerList->RemoveAll();
610 0 : aElement->SetHasRenderingObservers(false);
611 : }
612 0 : }
613 :
614 : void
615 0 : nsSVGEffects::InvalidateRenderingObservers(nsIFrame *aFrame)
616 : {
617 0 : NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame must be first continuation");
618 :
619 0 : if (!aFrame->GetContent()->IsElement())
620 0 : return;
621 :
622 : nsSVGRenderingObserverList *observerList =
623 0 : GetObserverList(aFrame->GetContent()->AsElement());
624 0 : if (observerList) {
625 0 : observerList->InvalidateAll();
626 0 : return;
627 : }
628 :
629 : // Check ancestor SVG containers. The root frame cannot be of type
630 : // eSVGContainer so we don't have to check f for null here.
631 0 : for (nsIFrame *f = aFrame->GetParent();
632 0 : f->IsFrameOfType(nsIFrame::eSVGContainer); f = f->GetParent()) {
633 0 : if (f->GetContent()->IsElement()) {
634 0 : observerList = GetObserverList(f->GetContent()->AsElement());
635 0 : if (observerList) {
636 0 : observerList->InvalidateAll();
637 0 : return;
638 : }
639 : }
640 : }
641 : }
642 :
643 : void
644 0 : nsSVGEffects::InvalidateDirectRenderingObservers(Element *aElement)
645 : {
646 0 : if (aElement->HasRenderingObservers()) {
647 0 : nsSVGRenderingObserverList *observerList = GetObserverList(aElement);
648 0 : if (observerList) {
649 0 : observerList->InvalidateAll();
650 : }
651 : }
652 0 : }
653 :
654 : void
655 0 : nsSVGEffects::InvalidateDirectRenderingObservers(nsIFrame *aFrame)
656 : {
657 0 : if (aFrame->GetContent() && aFrame->GetContent()->IsElement()) {
658 0 : InvalidateDirectRenderingObservers(aFrame->GetContent()->AsElement());
659 : }
660 0 : }
|