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 : #ifndef NSSVGEFFECTS_H_
39 : #define NSSVGEFFECTS_H_
40 :
41 : #include "nsIContent.h"
42 : #include "nsIFrame.h"
43 : #include "nsReferencedElement.h"
44 : #include "nsStubMutationObserver.h"
45 : #include "nsSVGUtils.h"
46 : #include "nsInterfaceHashtable.h"
47 : #include "nsURIHashKey.h"
48 :
49 : class nsSVGClipPathFrame;
50 : class nsSVGFilterFrame;
51 : class nsSVGMaskFrame;
52 :
53 : /*
54 : * This interface allows us to be notified when a piece of SVG content is
55 : * re-rendered.
56 : *
57 : * Concrete implementations of this interface need to implement
58 : * "GetTarget()" to specify the piece of SVG content that they'd like to
59 : * monitor, and they need to implement "DoUpdate" to specify how we'll react
60 : * when that content gets re-rendered. They also need to implement a
61 : * constructor and destructor, which should call StartListening and
62 : * StopListening, respectively.
63 : */
64 : class nsSVGRenderingObserver : public nsStubMutationObserver {
65 : public:
66 : typedef mozilla::dom::Element Element;
67 0 : nsSVGRenderingObserver()
68 0 : : mInObserverList(false)
69 0 : {}
70 0 : virtual ~nsSVGRenderingObserver()
71 0 : {}
72 :
73 : // nsISupports
74 : NS_DECL_ISUPPORTS
75 :
76 : // nsIMutationObserver
77 : NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
78 : NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
79 : NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
80 : NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
81 :
82 : void InvalidateViaReferencedElement();
83 :
84 : // When a nsSVGRenderingObserver list gets forcibly cleared, it uses this
85 : // callback to notify every observer that's cleared from it, so they can
86 : // react.
87 : void NotifyEvictedFromRenderingObserverList();
88 :
89 0 : bool IsInObserverList() const { return mInObserverList; }
90 :
91 : nsIFrame* GetReferencedFrame();
92 : /**
93 : * @param aOK this is only for the convenience of callers. We set *aOK to false
94 : * if the frame is the wrong type
95 : */
96 : nsIFrame* GetReferencedFrame(nsIAtom* aFrameType, bool* aOK);
97 :
98 : Element* GetReferencedElement();
99 :
100 : protected:
101 : // Non-virtual protected methods
102 : void StartListening();
103 : void StopListening();
104 :
105 : // Virtual protected methods
106 : virtual void DoUpdate() = 0; // called when the referenced resource changes.
107 :
108 : // This is an internally-used version of GetReferencedElement that doesn't
109 : // forcibly add us as an observer. (whereas GetReferencedElement does)
110 : virtual Element* GetTarget() = 0;
111 :
112 : // Whether we're in our referenced element's observer list at this time.
113 : bool mInObserverList;
114 : };
115 :
116 :
117 : /*
118 : * SVG elements reference supporting resources by element ID. We need to
119 : * track when those resources change and when the DOM changes in ways
120 : * that affect which element is referenced by a given ID (e.g., when
121 : * element IDs change). The code here is responsible for that.
122 : *
123 : * When a frame references a supporting resource, we create a property
124 : * object derived from nsSVGIDRenderingObserver to manage the relationship. The
125 : * property object is attached to the referencing frame.
126 : */
127 : class nsSVGIDRenderingObserver : public nsSVGRenderingObserver {
128 : public:
129 : typedef mozilla::dom::Element Element;
130 : nsSVGIDRenderingObserver(nsIURI* aURI, nsIFrame *aFrame,
131 : bool aReferenceImage);
132 : virtual ~nsSVGIDRenderingObserver();
133 :
134 : protected:
135 0 : Element* GetTarget() { return mElement.get(); }
136 :
137 : // This is called when the referenced resource changes.
138 : virtual void DoUpdate();
139 :
140 0 : class SourceReference : public nsReferencedElement {
141 : public:
142 0 : SourceReference(nsSVGIDRenderingObserver* aContainer) : mContainer(aContainer) {}
143 : protected:
144 0 : virtual void ElementChanged(Element* aFrom, Element* aTo) {
145 0 : mContainer->StopListening();
146 0 : nsReferencedElement::ElementChanged(aFrom, aTo);
147 0 : mContainer->StartListening();
148 0 : mContainer->DoUpdate();
149 0 : }
150 : /**
151 : * Override IsPersistent because we want to keep tracking the element
152 : * for the ID even when it changes.
153 : */
154 0 : virtual bool IsPersistent() { return true; }
155 : private:
156 : nsSVGIDRenderingObserver* mContainer;
157 : };
158 :
159 : SourceReference mElement;
160 : // The frame that this property is attached to
161 : nsIFrame *mFrame;
162 : // When a presshell is torn down, we don't delete the properties for
163 : // each frame until after the frames are destroyed. So here we remember
164 : // the presshell for the frames we care about and, before we use the frame,
165 : // we test the presshell to see if it's destroying itself. If it is,
166 : // then the frame pointer is not valid and we know the frame has gone away.
167 : nsIPresShell *mFramePresShell;
168 : };
169 :
170 : class nsSVGFilterProperty :
171 0 : public nsSVGIDRenderingObserver, public nsISVGFilterProperty {
172 : public:
173 0 : nsSVGFilterProperty(nsIURI *aURI, nsIFrame *aFilteredFrame,
174 : bool aReferenceImage)
175 0 : : nsSVGIDRenderingObserver(aURI, aFilteredFrame, aReferenceImage) {}
176 :
177 : /**
178 : * @return the filter frame, or null if there is no filter frame
179 : */
180 : nsSVGFilterFrame *GetFilterFrame();
181 :
182 : // nsISupports
183 : NS_DECL_ISUPPORTS
184 :
185 : // nsISVGFilterProperty
186 0 : virtual void Invalidate() { DoUpdate(); }
187 :
188 : private:
189 : // nsSVGRenderingObserver
190 : virtual void DoUpdate();
191 : };
192 :
193 0 : class nsSVGMarkerProperty : public nsSVGIDRenderingObserver {
194 : public:
195 0 : nsSVGMarkerProperty(nsIURI *aURI, nsIFrame *aFrame, bool aReferenceImage)
196 0 : : nsSVGIDRenderingObserver(aURI, aFrame, aReferenceImage) {}
197 :
198 : protected:
199 : virtual void DoUpdate();
200 : };
201 :
202 0 : class nsSVGTextPathProperty : public nsSVGIDRenderingObserver {
203 : public:
204 0 : nsSVGTextPathProperty(nsIURI *aURI, nsIFrame *aFrame, bool aReferenceImage)
205 0 : : nsSVGIDRenderingObserver(aURI, aFrame, aReferenceImage) {}
206 :
207 : protected:
208 : virtual void DoUpdate();
209 : };
210 :
211 0 : class nsSVGPaintingProperty : public nsSVGIDRenderingObserver {
212 : public:
213 0 : nsSVGPaintingProperty(nsIURI *aURI, nsIFrame *aFrame, bool aReferenceImage)
214 0 : : nsSVGIDRenderingObserver(aURI, aFrame, aReferenceImage) {}
215 :
216 : protected:
217 : virtual void DoUpdate();
218 : };
219 :
220 : /**
221 : * A manager for one-shot nsSVGRenderingObserver tracking.
222 : * nsSVGRenderingObservers can be added or removed. They are not strongly
223 : * referenced so an observer must be removed before it dies.
224 : * When InvalidateAll is called, all outstanding references get
225 : * InvalidateViaReferencedElement()
226 : * called on them and the list is cleared. The intent is that
227 : * the observer will force repainting of whatever part of the document
228 : * is needed, and then at paint time the observer will do a clean lookup
229 : * of the referenced element and [re-]add itself to the element's observer list.
230 : *
231 : * InvalidateAll must be called before this object is destroyed, i.e.
232 : * before the referenced frame is destroyed. This should normally happen
233 : * via nsSVGContainerFrame::RemoveFrame, since only frames in the frame
234 : * tree should be referenced.
235 : */
236 : class nsSVGRenderingObserverList {
237 : public:
238 0 : nsSVGRenderingObserverList() {
239 0 : MOZ_COUNT_CTOR(nsSVGRenderingObserverList);
240 0 : mObservers.Init(5);
241 0 : }
242 :
243 0 : ~nsSVGRenderingObserverList() {
244 0 : InvalidateAll();
245 0 : MOZ_COUNT_DTOR(nsSVGRenderingObserverList);
246 0 : }
247 :
248 0 : void Add(nsSVGRenderingObserver* aObserver)
249 0 : { mObservers.PutEntry(aObserver); }
250 0 : void Remove(nsSVGRenderingObserver* aObserver)
251 0 : { mObservers.RemoveEntry(aObserver); }
252 : #ifdef DEBUG
253 0 : bool Contains(nsSVGRenderingObserver* aObserver)
254 0 : { return (mObservers.GetEntry(aObserver) != nsnull); }
255 : #endif
256 0 : bool IsEmpty()
257 0 : { return mObservers.Count() == 0; }
258 :
259 : /**
260 : * Drop all our observers, and notify them that we have changed and dropped
261 : * our reference to them.
262 : */
263 : void InvalidateAll();
264 :
265 : /**
266 : * Drop all our observers, and notify them that we have dropped our reference
267 : * to them.
268 : */
269 : void RemoveAll();
270 :
271 : private:
272 : nsTHashtable<nsVoidPtrHashKey> mObservers;
273 : };
274 :
275 : class nsSVGEffects {
276 : public:
277 : typedef mozilla::dom::Element Element;
278 : typedef mozilla::FramePropertyDescriptor FramePropertyDescriptor;
279 : typedef nsInterfaceHashtable<nsURIHashKey, nsIMutationObserver>
280 : URIObserverHashtable;
281 :
282 0 : static void DestroySupports(void* aPropertyValue)
283 : {
284 0 : (static_cast<nsISupports*>(aPropertyValue))->Release();
285 0 : }
286 :
287 0 : static void DestroyHashtable(void* aPropertyValue)
288 : {
289 0 : delete static_cast<URIObserverHashtable*> (aPropertyValue);
290 0 : }
291 :
292 0 : NS_DECLARE_FRAME_PROPERTY(FilterProperty, DestroySupports)
293 0 : NS_DECLARE_FRAME_PROPERTY(MaskProperty, DestroySupports)
294 0 : NS_DECLARE_FRAME_PROPERTY(ClipPathProperty, DestroySupports)
295 0 : NS_DECLARE_FRAME_PROPERTY(MarkerBeginProperty, DestroySupports)
296 0 : NS_DECLARE_FRAME_PROPERTY(MarkerMiddleProperty, DestroySupports)
297 0 : NS_DECLARE_FRAME_PROPERTY(MarkerEndProperty, DestroySupports)
298 0 : NS_DECLARE_FRAME_PROPERTY(FillProperty, DestroySupports)
299 0 : NS_DECLARE_FRAME_PROPERTY(StrokeProperty, DestroySupports)
300 0 : NS_DECLARE_FRAME_PROPERTY(HrefProperty, DestroySupports)
301 0 : NS_DECLARE_FRAME_PROPERTY(BackgroundImageProperty, DestroyHashtable)
302 :
303 : struct EffectProperties {
304 : nsSVGFilterProperty* mFilter;
305 : nsSVGPaintingProperty* mMask;
306 : nsSVGPaintingProperty* mClipPath;
307 :
308 : /**
309 : * @return the clip-path frame, or null if there is no clip-path frame
310 : * @param aOK if a clip-path was specified and the designated element
311 : * exists but is an element of the wrong type, *aOK is set to false.
312 : * Otherwise *aOK is untouched.
313 : */
314 : nsSVGClipPathFrame *GetClipPathFrame(bool *aOK);
315 : /**
316 : * @return the mask frame, or null if there is no mask frame
317 : * @param aOK if a mask was specified and the designated element
318 : * exists but is an element of the wrong type, *aOK is set to false.
319 : * Otherwise *aOK is untouched.
320 : */
321 : nsSVGMaskFrame *GetMaskFrame(bool *aOK);
322 : /**
323 : * @return the filter frame, or null if there is no filter frame
324 : * @param aOK if a filter was specified but the designated element
325 : * does not exist or is an element of the wrong type, *aOK is set
326 : * to false. Otherwise *aOK is untouched.
327 : */
328 0 : nsSVGFilterFrame *GetFilterFrame(bool *aOK) {
329 0 : if (!mFilter)
330 0 : return nsnull;
331 0 : nsSVGFilterFrame *filter = mFilter->GetFilterFrame();
332 0 : if (!filter) {
333 0 : *aOK = false;
334 : }
335 0 : return filter;
336 : }
337 : };
338 :
339 : /**
340 : * @param aFrame should be the first continuation
341 : */
342 : static EffectProperties GetEffectProperties(nsIFrame *aFrame);
343 : /**
344 : * Called by nsCSSFrameConstructor when style changes require the
345 : * effect properties on aFrame to be updated
346 : */
347 : static void UpdateEffects(nsIFrame *aFrame);
348 : /**
349 : * @param aFrame should be the first continuation
350 : */
351 : static nsSVGFilterProperty *GetFilterProperty(nsIFrame *aFrame);
352 0 : static nsSVGFilterFrame *GetFilterFrame(nsIFrame *aFrame) {
353 0 : nsSVGFilterProperty *prop = GetFilterProperty(aFrame);
354 0 : return prop ? prop->GetFilterFrame() : nsnull;
355 : }
356 :
357 : /**
358 : * @param aFrame must be a first-continuation.
359 : */
360 : static void AddRenderingObserver(Element *aElement, nsSVGRenderingObserver *aObserver);
361 : /**
362 : * @param aFrame must be a first-continuation.
363 : */
364 : static void RemoveRenderingObserver(Element *aElement, nsSVGRenderingObserver *aObserver);
365 :
366 : /**
367 : * Removes all rendering observers from aElement.
368 : */
369 : static void RemoveAllRenderingObservers(Element *aElement);
370 :
371 : /**
372 : * This can be called on any frame. We invalidate the observers of aFrame's
373 : * element, if any, or else walk up to the nearest observable SVG parent
374 : * frame with observers and invalidate them instead.
375 : *
376 : * Note that this method is very different to e.g.
377 : * nsNodeUtils::AttributeChanged which walks up the content node tree all the
378 : * way to the root node (not stopping if it encounters a non-container SVG
379 : * node) invalidating all mutation observers (not just
380 : * nsSVGRenderingObservers) on all nodes along the way (not just the first
381 : * node it finds with observers). In other words, by doing all the
382 : * things in parentheses in the preceding sentence, this method uses
383 : * knowledge about our implementation and what can be affected by SVG effects
384 : * to make invalidation relatively lightweight when an SVG effect changes.
385 : */
386 : static void InvalidateRenderingObservers(nsIFrame *aFrame);
387 : /**
388 : * This can be called on any element or frame. Only direct observers of this
389 : * (frame's) element, if any, are invalidated.
390 : */
391 : static void InvalidateDirectRenderingObservers(Element *aElement);
392 : static void InvalidateDirectRenderingObservers(nsIFrame *aFrame);
393 :
394 : /**
395 : * Get an nsSVGMarkerProperty for the frame, creating a fresh one if necessary
396 : */
397 : static nsSVGMarkerProperty *
398 : GetMarkerProperty(nsIURI *aURI, nsIFrame *aFrame,
399 : const FramePropertyDescriptor *aProperty);
400 : /**
401 : * Get an nsSVGTextPathProperty for the frame, creating a fresh one if necessary
402 : */
403 : static nsSVGTextPathProperty *
404 : GetTextPathProperty(nsIURI *aURI, nsIFrame *aFrame,
405 : const FramePropertyDescriptor *aProperty);
406 : /**
407 : * Get an nsSVGPaintingProperty for the frame, creating a fresh one if necessary
408 : */
409 : static nsSVGPaintingProperty *
410 : GetPaintingProperty(nsIURI *aURI, nsIFrame *aFrame,
411 : const FramePropertyDescriptor *aProperty);
412 : /**
413 : * Get an nsSVGPaintingProperty for the frame for that URI, creating a fresh
414 : * one if necessary
415 : */
416 : static nsSVGPaintingProperty *
417 : GetPaintingPropertyForURI(nsIURI *aURI, nsIFrame *aFrame,
418 : const FramePropertyDescriptor *aProp);
419 : };
420 :
421 : #endif /*NSSVGEFFECTS_H_*/
|