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
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.
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
,
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
);
61 mElement
.get()->AddMutationObserver(this);
65 nsSVGRenderingObserver::~nsSVGRenderingObserver()
68 mElement
.get()->RemoveMutationObserver(this);
70 if (mReferencedFrame
&& !mReferencedFramePresShell
->IsDestroying()) {
71 nsSVGEffects::RemoveRenderingObserver(mReferencedFrame
, this);
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
;
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());
91 mReferencedFrame
= frame
;
92 mReferencedFramePresShell
= shell
;
93 nsSVGEffects::AddRenderingObserver(mReferencedFrame
, this);
102 nsSVGRenderingObserver::GetReferencedFrame(nsIAtom
* aFrameType
, PRBool
* aOK
)
104 nsIFrame
* frame
= GetReferencedFrame();
105 if (frame
&& frame
->GetType() == aFrameType
)
114 nsSVGRenderingObserver::DoUpdate()
116 if (mFramePresShell
->IsDestroying()) {
117 // mFrame is no longer valid. Bail out.
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
);
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
;
144 nsSVGRenderingObserver::AttributeChanged(nsIDocument
*aDocument
,
145 nsIContent
*aContent
,
146 PRInt32 aNameSpaceID
,
155 nsSVGRenderingObserver::ContentAppended(nsIDocument
*aDocument
,
156 nsIContent
*aContainer
,
157 PRInt32 aNewIndexInContainer
)
163 nsSVGRenderingObserver::ContentInserted(nsIDocument
*aDocument
,
164 nsIContent
*aContainer
,
166 PRInt32 aIndexInContainer
)
172 nsSVGRenderingObserver::ContentRemoved(nsIDocument
*aDocument
,
173 nsIContent
*aContainer
,
175 PRInt32 aIndexInContainer
)
180 NS_IMPL_ISUPPORTS_INHERITED1(nsSVGFilterProperty
,
181 nsSVGRenderingObserver
,
182 nsISVGFilterProperty
)
185 nsSVGFilterProperty::GetFilterFrame()
187 return static_cast<nsSVGFilterFrame
*>
188 (GetReferencedFrame(nsGkAtoms::svgFilterFrame
, nsnull
));
192 InvalidateAllContinuations(nsIFrame
* aFrame
)
194 for (nsIFrame
* f
= aFrame
; f
; f
= f
->GetNextContinuation()) {
195 f
->InvalidateOverflowRect();
200 nsSVGFilterProperty::DoUpdate()
202 nsSVGRenderingObserver::DoUpdate();
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
);
218 nsSVGMarkerProperty::DoUpdate()
220 nsSVGRenderingObserver::DoUpdate();
224 if (mFrame
->IsFrameOfType(nsIFrame::eSVG
)) {
225 if (!(mFrame
->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD
)) {
226 nsSVGOuterSVGFrame
*outerSVGFrame
= nsSVGUtils::GetOuterSVGFrame(mFrame
);
228 // marker changes can change the covered region
229 outerSVGFrame
->UpdateAndInvalidateCoveredRegion(mFrame
);
233 InvalidateAllContinuations(mFrame
);
238 nsSVGTextPathProperty::DoUpdate()
240 nsSVGRenderingObserver::DoUpdate();
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();
253 nsSVGPaintingProperty::DoUpdate()
255 nsSVGRenderingObserver::DoUpdate();
259 if (mFrame
->IsFrameOfType(nsIFrame::eSVG
)) {
260 nsSVGUtils::InvalidateCoveredRegion(mFrame
);
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
*))
288 nsSVGRenderingObserver
*prop
=
289 static_cast<nsSVGRenderingObserver
*>(aFrame
->GetProperty(aProp
));
292 prop
= aCreate(aURI
, aFrame
);
296 aFrame
->SetProperty(aProp
,
297 static_cast<nsISupports
*>(prop
),
298 nsPropertyTable::SupportsDtorFunc
);
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
);
338 nsSVGEffects::EffectProperties::GetClipPathFrame(PRBool
*aOK
)
342 return static_cast<nsSVGClipPathFrame
*>
343 (mClipPath
->GetReferencedFrame(nsGkAtoms::svgClipPathFrame
, aOK
));
347 nsSVGEffects::EffectProperties::GetMaskFrame(PRBool
*aOK
)
351 return static_cast<nsSVGMaskFrame
*>
352 (mMask
->GetReferencedFrame(nsGkAtoms::svgMaskFrame
, aOK
));
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
)
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
;
399 nsSVGRenderingObserverList::InvalidateAll()
401 if (mObservers
.Count() == 0)
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
))
416 return static_cast<nsSVGRenderingObserverList
*>(aFrame
->GetProperty(nsGkAtoms::observer
));
420 nsSVGEffects::AddRenderingObserver(nsIFrame
*aFrame
, nsSVGRenderingObserver
*aObserver
)
422 NS_ASSERTION(!aFrame
->GetPrevContinuation(), "aFrame must be first continuation");
424 nsSVGRenderingObserverList
*observerList
= GetObserverList(aFrame
);
426 observerList
= new nsSVGRenderingObserverList();
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
);
438 nsSVGEffects::RemoveRenderingObserver(nsIFrame
*aFrame
, nsSVGRenderingObserver
*aObserver
)
440 NS_ASSERTION(!aFrame
->GetPrevContinuation(), "aFrame must be first continuation");
442 nsSVGRenderingObserverList
*observerList
= GetObserverList(aFrame
);
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
452 nsSVGEffects::InvalidateRenderingObservers(nsIFrame
*aFrame
)
454 NS_ASSERTION(!aFrame
->GetPrevContinuation(), "aFrame must be first continuation");
456 nsSVGRenderingObserverList
*observerList
= GetObserverList(aFrame
);
458 observerList
->InvalidateAll();
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
);
468 observerList
->InvalidateAll();
475 nsSVGEffects::InvalidateDirectRenderingObservers(nsIFrame
*aFrame
)
477 nsSVGRenderingObserverList
*observerList
= GetObserverList(aFrame
);
479 observerList
->InvalidateAll();