Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / layout / svg / base / src / nsSVGEffects.cpp
blobe15d33c4ae7ef09b0b26938642b387250c857a94
2 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is the Mozilla SVG project.
18 * The Initial Developer of the Original Code is IBM Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 2005
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * rocallahan@mozilla.com
25 * Alternatively, the contents of this file may be used under the terms of
26 * either of the GNU General Public License Version 2 or later (the "GPL"),
27 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #include "nsSVGEffects.h"
40 #include "nsISupportsImpl.h"
41 #include "nsSVGOuterSVGFrame.h"
42 #include "nsSVGFilterFrame.h"
43 #include "nsSVGClipPathFrame.h"
44 #include "nsSVGMaskFrame.h"
45 #include "nsSVGTextPathFrame.h"
46 #include "nsCSSFrameConstructor.h"
47 #include "nsFrameManager.h"
49 NS_IMPL_ISUPPORTS1(nsSVGRenderingObserver, nsIMutationObserver)
51 nsSVGRenderingObserver::nsSVGRenderingObserver(nsIURI *aURI,
52 nsIFrame *aFrame)
53 : mElement(this), mFrame(aFrame),
54 mFramePresShell(aFrame->PresContext()->PresShell()),
55 mReferencedFrame(nsnull),
56 mReferencedFramePresShell(nsnull)
58 // Start watching the target element
59 mElement.Reset(aFrame->GetContent(), aURI);
60 if (mElement.get()) {
61 mElement.get()->AddMutationObserver(this);
65 nsSVGRenderingObserver::~nsSVGRenderingObserver()
67 if (mElement.get()) {
68 mElement.get()->RemoveMutationObserver(this);
70 if (mReferencedFrame && !mReferencedFramePresShell->IsDestroying()) {
71 nsSVGEffects::RemoveRenderingObserver(mReferencedFrame, this);
75 nsIFrame*
76 nsSVGRenderingObserver::GetReferencedFrame()
78 if (mReferencedFrame && !mReferencedFramePresShell->IsDestroying()) {
79 NS_ASSERTION(mElement.get() &&
80 static_cast<nsGenericElement*>(mElement.get())->GetPrimaryFrame() == mReferencedFrame,
81 "Cached frame is incorrect!");
82 return mReferencedFrame;
85 if (mElement.get()) {
86 nsIDocument* doc = mElement.get()->GetCurrentDoc();
87 nsIPresShell* shell = doc ? doc->GetPrimaryShell() : nsnull;
88 if (shell && !shell->FrameManager()->IsDestroyingFrames()) {
89 nsIFrame* frame = shell->GetPrimaryFrameFor(mElement.get());
90 if (frame) {
91 mReferencedFrame = frame;
92 mReferencedFramePresShell = shell;
93 nsSVGEffects::AddRenderingObserver(mReferencedFrame, this);
94 return frame;
98 return nsnull;
101 nsIFrame*
102 nsSVGRenderingObserver::GetReferencedFrame(nsIAtom* aFrameType, PRBool* aOK)
104 nsIFrame* frame = GetReferencedFrame();
105 if (frame && frame->GetType() == aFrameType)
106 return frame;
107 if (aOK) {
108 *aOK = PR_FALSE;
110 return nsnull;
113 void
114 nsSVGRenderingObserver::DoUpdate()
116 if (mFramePresShell->IsDestroying()) {
117 // mFrame is no longer valid. Bail out.
118 mFrame = nsnull;
119 return;
121 if (mReferencedFrame) {
122 nsSVGEffects::RemoveRenderingObserver(mReferencedFrame, this);
123 mReferencedFrame = nsnull;
124 mReferencedFramePresShell = nsnull;
126 if (mFrame && mFrame->IsFrameOfType(nsIFrame::eSVG)) {
127 // Changes should propagate out to things that might be observing
128 // the referencing frame or its ancestors.
129 nsSVGEffects::InvalidateRenderingObservers(mFrame);
133 void
134 nsSVGRenderingObserver::InvalidateViaReferencedFrame()
136 // Clear mReferencedFrame since the referenced frame has already
137 // dropped its reference back to us
138 mReferencedFrame = nsnull;
139 mReferencedFramePresShell = nsnull;
140 DoUpdate();
143 void
144 nsSVGRenderingObserver::AttributeChanged(nsIDocument *aDocument,
145 nsIContent *aContent,
146 PRInt32 aNameSpaceID,
147 nsIAtom *aAttribute,
148 PRInt32 aModType,
149 PRUint32 aStateMask)
151 DoUpdate();
154 void
155 nsSVGRenderingObserver::ContentAppended(nsIDocument *aDocument,
156 nsIContent *aContainer,
157 PRInt32 aNewIndexInContainer)
159 DoUpdate();
162 void
163 nsSVGRenderingObserver::ContentInserted(nsIDocument *aDocument,
164 nsIContent *aContainer,
165 nsIContent *aChild,
166 PRInt32 aIndexInContainer)
168 DoUpdate();
171 void
172 nsSVGRenderingObserver::ContentRemoved(nsIDocument *aDocument,
173 nsIContent *aContainer,
174 nsIContent *aChild,
175 PRInt32 aIndexInContainer)
177 DoUpdate();
180 NS_IMPL_ISUPPORTS_INHERITED1(nsSVGFilterProperty,
181 nsSVGRenderingObserver,
182 nsISVGFilterProperty)
184 nsSVGFilterFrame *
185 nsSVGFilterProperty::GetFilterFrame()
187 return static_cast<nsSVGFilterFrame *>
188 (GetReferencedFrame(nsGkAtoms::svgFilterFrame, nsnull));
191 static void
192 InvalidateAllContinuations(nsIFrame* aFrame)
194 for (nsIFrame* f = aFrame; f; f = f->GetNextContinuation()) {
195 f->InvalidateOverflowRect();
199 void
200 nsSVGFilterProperty::DoUpdate()
202 nsSVGRenderingObserver::DoUpdate();
203 if (!mFrame)
204 return;
206 // Repaint asynchronously in case the filter frame is being torn down
207 nsChangeHint changeHint =
208 nsChangeHint(nsChangeHint_RepaintFrame | nsChangeHint_UpdateEffects);
210 if (!mFrame->IsFrameOfType(nsIFrame::eSVG)) {
211 NS_UpdateHint(changeHint, nsChangeHint_ReflowFrame);
213 mFramePresShell->FrameConstructor()->PostRestyleEvent(
214 mFrame->GetContent(), nsReStyleHint(0), changeHint);
217 void
218 nsSVGMarkerProperty::DoUpdate()
220 nsSVGRenderingObserver::DoUpdate();
221 if (!mFrame)
222 return;
224 if (mFrame->IsFrameOfType(nsIFrame::eSVG)) {
225 if (!(mFrame->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)) {
226 nsSVGOuterSVGFrame *outerSVGFrame = nsSVGUtils::GetOuterSVGFrame(mFrame);
227 if (outerSVGFrame) {
228 // marker changes can change the covered region
229 outerSVGFrame->UpdateAndInvalidateCoveredRegion(mFrame);
232 } else {
233 InvalidateAllContinuations(mFrame);
237 void
238 nsSVGTextPathProperty::DoUpdate()
240 nsSVGRenderingObserver::DoUpdate();
241 if (!mFrame)
242 return;
244 NS_ASSERTION(mFrame->IsFrameOfType(nsIFrame::eSVG), "SVG frame expected");
246 if (mFrame->GetType() == nsGkAtoms::svgTextPathFrame) {
247 nsSVGTextPathFrame* textPathFrame = static_cast<nsSVGTextPathFrame*>(mFrame);
248 textPathFrame->NotifyGlyphMetricsChange();
252 void
253 nsSVGPaintingProperty::DoUpdate()
255 nsSVGRenderingObserver::DoUpdate();
256 if (!mFrame)
257 return;
259 if (mFrame->IsFrameOfType(nsIFrame::eSVG)) {
260 nsSVGUtils::InvalidateCoveredRegion(mFrame);
261 } else {
262 InvalidateAllContinuations(mFrame);
266 static nsSVGRenderingObserver *
267 CreateFilterProperty(nsIURI *aURI, nsIFrame *aFrame)
268 { return new nsSVGFilterProperty(aURI, aFrame); }
270 static nsSVGRenderingObserver *
271 CreateMarkerProperty(nsIURI *aURI, nsIFrame *aFrame)
272 { return new nsSVGMarkerProperty(aURI, aFrame); }
274 static nsSVGRenderingObserver *
275 CreateTextPathProperty(nsIURI *aURI, nsIFrame *aFrame)
276 { return new nsSVGTextPathProperty(aURI, aFrame); }
278 static nsSVGRenderingObserver *
279 CreatePaintingProperty(nsIURI *aURI, nsIFrame *aFrame)
280 { return new nsSVGPaintingProperty(aURI, aFrame); }
282 static nsSVGRenderingObserver *
283 GetEffectProperty(nsIURI *aURI, nsIFrame *aFrame, nsIAtom *aProp,
284 nsSVGRenderingObserver * (* aCreate)(nsIURI *, nsIFrame *))
286 if (!aURI)
287 return nsnull;
288 nsSVGRenderingObserver *prop =
289 static_cast<nsSVGRenderingObserver*>(aFrame->GetProperty(aProp));
290 if (prop)
291 return prop;
292 prop = aCreate(aURI, aFrame);
293 if (!prop)
294 return nsnull;
295 NS_ADDREF(prop);
296 aFrame->SetProperty(aProp,
297 static_cast<nsISupports*>(prop),
298 nsPropertyTable::SupportsDtorFunc);
299 return prop;
302 nsSVGMarkerProperty *
303 nsSVGEffects::GetMarkerProperty(nsIURI *aURI, nsIFrame *aFrame, nsIAtom *aProp)
305 return static_cast<nsSVGMarkerProperty*>(
306 GetEffectProperty(aURI, aFrame, aProp, CreateMarkerProperty));
309 nsSVGTextPathProperty *
310 nsSVGEffects::GetTextPathProperty(nsIURI *aURI, nsIFrame *aFrame, nsIAtom *aProp)
312 return static_cast<nsSVGTextPathProperty*>(
313 GetEffectProperty(aURI, aFrame, aProp, CreateTextPathProperty));
316 nsSVGPaintingProperty *
317 nsSVGEffects::GetPaintingProperty(nsIURI *aURI, nsIFrame *aFrame, nsIAtom *aProp)
319 return static_cast<nsSVGPaintingProperty*>(
320 GetEffectProperty(aURI, aFrame, aProp, CreatePaintingProperty));
323 nsSVGEffects::EffectProperties
324 nsSVGEffects::GetEffectProperties(nsIFrame *aFrame)
326 NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame should be first continuation");
328 EffectProperties result;
329 const nsStyleSVGReset *style = aFrame->GetStyleSVGReset();
330 result.mFilter = static_cast<nsSVGFilterProperty*>
331 (GetEffectProperty(style->mFilter, aFrame, nsGkAtoms::filter, CreateFilterProperty));
332 result.mClipPath = GetPaintingProperty(style->mClipPath, aFrame, nsGkAtoms::clipPath);
333 result.mMask = GetPaintingProperty(style->mMask, aFrame, nsGkAtoms::mask);
334 return result;
337 nsSVGClipPathFrame *
338 nsSVGEffects::EffectProperties::GetClipPathFrame(PRBool *aOK)
340 if (!mClipPath)
341 return nsnull;
342 return static_cast<nsSVGClipPathFrame *>
343 (mClipPath->GetReferencedFrame(nsGkAtoms::svgClipPathFrame, aOK));
346 nsSVGMaskFrame *
347 nsSVGEffects::EffectProperties::GetMaskFrame(PRBool *aOK)
349 if (!mMask)
350 return nsnull;
351 return static_cast<nsSVGMaskFrame *>
352 (mMask->GetReferencedFrame(nsGkAtoms::svgMaskFrame, aOK));
355 void
356 nsSVGEffects::UpdateEffects(nsIFrame *aFrame)
358 aFrame->DeleteProperty(nsGkAtoms::filter);
359 aFrame->DeleteProperty(nsGkAtoms::mask);
360 aFrame->DeleteProperty(nsGkAtoms::clipPath);
362 aFrame->DeleteProperty(nsGkAtoms::marker_start);
363 aFrame->DeleteProperty(nsGkAtoms::marker_mid);
364 aFrame->DeleteProperty(nsGkAtoms::marker_end);
366 aFrame->DeleteProperty(nsGkAtoms::stroke);
367 aFrame->DeleteProperty(nsGkAtoms::fill);
369 // Ensure that the filter is repainted correctly
370 // We can't do that in DoUpdate as the referenced frame may not be valid
371 const nsStyleSVGReset *style = aFrame->GetStyleSVGReset();
372 if (style->mFilter) {
373 GetEffectProperty(style->mFilter, aFrame, nsGkAtoms::filter, CreateFilterProperty);
377 nsSVGFilterProperty *
378 nsSVGEffects::GetFilterProperty(nsIFrame *aFrame)
380 NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame should be first continuation");
382 if (!aFrame->GetStyleSVGReset()->mFilter)
383 return nsnull;
385 return static_cast<nsSVGFilterProperty *>(aFrame->GetProperty(nsGkAtoms::filter));
388 static PLDHashOperator
389 GatherEnumerator(nsVoidPtrHashKey* aEntry, void* aArg)
391 nsTArray<nsSVGRenderingObserver*>* array =
392 static_cast<nsTArray<nsSVGRenderingObserver*>*>(aArg);
393 array->AppendElement(static_cast<nsSVGRenderingObserver*>(
394 const_cast<void*>(aEntry->GetKey())));
395 return PL_DHASH_REMOVE;
398 void
399 nsSVGRenderingObserverList::InvalidateAll()
401 if (mObservers.Count() == 0)
402 return;
404 nsAutoTArray<nsSVGRenderingObserver*,10> observers;
405 mObservers.EnumerateEntries(GatherEnumerator, &observers);
406 for (PRUint32 i = 0; i < observers.Length(); ++i) {
407 observers[i]->InvalidateViaReferencedFrame();
411 static nsSVGRenderingObserverList *
412 GetObserverList(nsIFrame *aFrame)
414 if (!(aFrame->GetStateBits() & NS_FRAME_MAY_BE_TRANSFORMED_OR_HAVE_RENDERING_OBSERVERS))
415 return nsnull;
416 return static_cast<nsSVGRenderingObserverList*>(aFrame->GetProperty(nsGkAtoms::observer));
419 void
420 nsSVGEffects::AddRenderingObserver(nsIFrame *aFrame, nsSVGRenderingObserver *aObserver)
422 NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame must be first continuation");
424 nsSVGRenderingObserverList *observerList = GetObserverList(aFrame);
425 if (!observerList) {
426 observerList = new nsSVGRenderingObserverList();
427 if (!observerList)
428 return;
429 for (nsIFrame* f = aFrame; f; f = f->GetNextContinuation()) {
430 f->AddStateBits(NS_FRAME_MAY_BE_TRANSFORMED_OR_HAVE_RENDERING_OBSERVERS);
432 aFrame->SetProperty(nsGkAtoms::observer, observerList);
434 observerList->Add(aObserver);
437 void
438 nsSVGEffects::RemoveRenderingObserver(nsIFrame *aFrame, nsSVGRenderingObserver *aObserver)
440 NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame must be first continuation");
442 nsSVGRenderingObserverList *observerList = GetObserverList(aFrame);
443 if (observerList) {
444 observerList->Remove(aObserver);
445 // Don't remove the property even if the observer list is empty.
446 // This might not be a good time to modify the frame property
447 // hashtables.
451 void
452 nsSVGEffects::InvalidateRenderingObservers(nsIFrame *aFrame)
454 NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame must be first continuation");
456 nsSVGRenderingObserverList *observerList = GetObserverList(aFrame);
457 if (observerList) {
458 observerList->InvalidateAll();
459 return;
462 // Check ancestor SVG containers. The root frame cannot be of type
463 // eSVGContainer so we don't have to check f for null here.
464 for (nsIFrame *f = aFrame->GetParent();
465 f->IsFrameOfType(nsIFrame::eSVGContainer); f = f->GetParent()) {
466 observerList = GetObserverList(f);
467 if (observerList) {
468 observerList->InvalidateAll();
469 return;
474 void
475 nsSVGEffects::InvalidateDirectRenderingObservers(nsIFrame *aFrame)
477 nsSVGRenderingObserverList *observerList = GetObserverList(aFrame);
478 if (observerList) {
479 observerList->InvalidateAll();