Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / layout / svg / base / src / nsSVGInnerSVGFrame.cpp
blob317fefc61055556c2b077c82fab69b7a3ea30509
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
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/
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.
15 * The Original Code is the Mozilla SVG project.
17 * The Initial Developer of the Original Code is
18 * Crocodile Clips Ltd..
19 * Portions created by the Initial Developer are Copyright (C) 2001
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Alex Fritze <alex.fritze@crocodile-clips.com> (original author)
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 "nsIFrame.h"
40 #include "nsISVGChildFrame.h"
41 #include "nsSVGOuterSVGFrame.h"
42 #include "nsIDOMSVGAnimatedRect.h"
43 #include "nsSVGMatrix.h"
44 #include "nsSVGSVGElement.h"
45 #include "nsSVGContainerFrame.h"
46 #include "gfxContext.h"
48 typedef nsSVGDisplayContainerFrame nsSVGInnerSVGFrameBase;
50 class nsSVGInnerSVGFrame : public nsSVGInnerSVGFrameBase,
51 public nsISVGValueObserver,
52 public nsISVGSVGFrame
54 friend nsIFrame*
55 NS_NewSVGInnerSVGFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsStyleContext* aContext);
56 protected:
57 nsSVGInnerSVGFrame(nsStyleContext* aContext) :
58 nsSVGInnerSVGFrameBase(aContext) {}
60 // nsISupports interface:
61 NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
62 private:
63 NS_IMETHOD_(nsrefcnt) AddRef() { return 1; }
64 NS_IMETHOD_(nsrefcnt) Release() { return 1; }
66 public:
67 // We don't define an AttributeChanged method since changes to the
68 // 'x', 'y', 'width' and 'height' attributes of our content object
69 // are handled in nsSVGSVGElement::DidModifySVGObservable
71 /**
72 * Get the "type" of the frame
74 * @see nsGkAtoms::svgInnerSVGFrame
76 virtual nsIAtom* GetType() const;
78 #ifdef DEBUG
79 NS_IMETHOD GetFrameName(nsAString& aResult) const
81 return MakeFrameName(NS_LITERAL_STRING("SVGInnerSVG"), aResult);
83 #endif
85 // nsISVGChildFrame interface:
86 NS_IMETHOD PaintSVG(nsSVGRenderState *aContext, const nsIntRect *aDirtyRect);
87 virtual void NotifySVGChanged(PRUint32 aFlags);
88 NS_IMETHOD_(nsIFrame*) GetFrameForPoint(const nsPoint &aPoint);
90 // nsSVGContainerFrame methods:
91 virtual already_AddRefed<nsIDOMSVGMatrix> GetCanvasTM();
93 // nsISVGValueObserver
94 NS_IMETHOD WillModifySVGObservable(nsISVGValue* observable,
95 nsISVGValue::modificationType aModType);
96 NS_IMETHOD DidModifySVGObservable (nsISVGValue* observable,
97 nsISVGValue::modificationType aModType);
99 // nsISupportsWeakReference
100 // implementation inherited from nsSupportsWeakReference
102 // nsISVGSVGFrame interface:
103 NS_IMETHOD SuspendRedraw();
104 NS_IMETHOD UnsuspendRedraw();
105 NS_IMETHOD NotifyViewportChange();
107 protected:
109 nsCOMPtr<nsIDOMSVGMatrix> mCanvasTM;
112 //----------------------------------------------------------------------
113 // Implementation
115 nsIFrame*
116 NS_NewSVGInnerSVGFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsStyleContext* aContext)
118 nsCOMPtr<nsIDOMSVGSVGElement> svg = do_QueryInterface(aContent);
119 if (!svg) {
120 NS_ERROR("Can't create frame! Content is not an SVG 'svg' element!");
121 return nsnull;
124 return new (aPresShell) nsSVGInnerSVGFrame(aContext);
127 //----------------------------------------------------------------------
128 // nsISupports methods
130 NS_INTERFACE_MAP_BEGIN(nsSVGInnerSVGFrame)
131 NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver)
132 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
133 NS_INTERFACE_MAP_ENTRY(nsISVGSVGFrame)
134 NS_INTERFACE_MAP_END_INHERITING(nsSVGInnerSVGFrameBase)
137 //----------------------------------------------------------------------
138 // nsIFrame methods
140 nsIAtom *
141 nsSVGInnerSVGFrame::GetType() const
143 return nsGkAtoms::svgInnerSVGFrame;
146 //----------------------------------------------------------------------
147 // nsISVGChildFrame methods
149 NS_IMETHODIMP
150 nsSVGInnerSVGFrame::PaintSVG(nsSVGRenderState *aContext,
151 const nsIntRect *aDirtyRect)
153 gfxContextAutoSaveRestore autoSR;
155 if (GetStyleDisplay()->IsScrollableOverflow()) {
156 float x, y, width, height;
157 static_cast<nsSVGSVGElement*>(mContent)->
158 GetAnimatedLengthValues(&x, &y, &width, &height, nsnull);
160 if (width <= 0 || height <= 0) {
161 return NS_OK;
164 nsCOMPtr<nsIDOMSVGMatrix> clipTransform;
165 if (!GetMatrixPropagation()) {
166 NS_NewSVGMatrix(getter_AddRefs(clipTransform));
167 } else {
168 clipTransform = static_cast<nsSVGContainerFrame*>(mParent)->GetCanvasTM();
171 if (clipTransform) {
172 gfxContext *gfx = aContext->GetGfxContext();
173 autoSR.SetContext(gfx);
174 nsSVGUtils::SetClipRect(gfx, clipTransform, x, y, width, height);
178 return nsSVGInnerSVGFrameBase::PaintSVG(aContext, aDirtyRect);
181 void
182 nsSVGInnerSVGFrame::NotifySVGChanged(PRUint32 aFlags)
184 if (aFlags & COORD_CONTEXT_CHANGED) {
186 nsSVGSVGElement *svg = static_cast<nsSVGSVGElement*>(mContent);
188 // Coordinate context changes affect mCanvasTM if we have a
189 // percentage 'x' or 'y', or if we have a percentage 'width' or 'height' AND
190 // a 'viewBox'.
192 if (!(aFlags & TRANSFORM_CHANGED) &&
193 (svg->mLengthAttributes[nsSVGSVGElement::X].IsPercentage() ||
194 svg->mLengthAttributes[nsSVGSVGElement::Y].IsPercentage() ||
195 (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::viewBox) &&
196 (svg->mLengthAttributes[nsSVGSVGElement::WIDTH].IsPercentage() ||
197 svg->mLengthAttributes[nsSVGSVGElement::HEIGHT].IsPercentage())))) {
199 aFlags |= TRANSFORM_CHANGED;
202 // XXX We could clear the COORD_CONTEXT_CHANGED flag in some circumstances
203 // if we have a non-percentage 'width' AND 'height, or if we have a 'viewBox'
204 // rect. This is because, when we have a viewBox rect, the viewBox rect
205 // is the coordinate context for our children, and it isn't changing.
206 // Percentage lengths on our children will continue to resolve to the
207 // same number of user units because they're relative to our viewBox rect. The
208 // same is true if we have a non-percentage width and height and don't have a
209 // viewBox. We (the <svg>) establish the coordinate context for our children. Our
210 // children don't care about changes to our parent coordinate context unless that
211 // change results in a change to the coordinate context that _we_ establish. Hence
212 // we can (should, really) stop propagating COORD_CONTEXT_CHANGED in these cases.
213 // We'd actually need to check that we have a viewBox rect and not just
214 // that viewBox is set, since it could be set to none.
215 // Take care not to break the testcase for bug 394463 when implementing this
218 if (aFlags & TRANSFORM_CHANGED) {
219 // make sure our cached transform matrix gets (lazily) updated
220 mCanvasTM = nsnull;
223 nsSVGInnerSVGFrameBase::NotifySVGChanged(aFlags);
226 NS_IMETHODIMP_(nsIFrame*)
227 nsSVGInnerSVGFrame::GetFrameForPoint(const nsPoint &aPoint)
229 if (GetStyleDisplay()->IsScrollableOverflow()) {
230 float clipX, clipY, clipWidth, clipHeight;
231 nsCOMPtr<nsIDOMSVGMatrix> clipTransform;
233 nsSVGElement *svg = static_cast<nsSVGElement*>(mContent);
234 svg->GetAnimatedLengthValues(&clipX, &clipY, &clipWidth, &clipHeight, nsnull);
236 nsSVGContainerFrame *parent = static_cast<nsSVGContainerFrame*>
237 (mParent);
238 clipTransform = parent->GetCanvasTM();
240 if (!nsSVGUtils::HitTestRect(clipTransform,
241 clipX, clipY, clipWidth, clipHeight,
242 PresContext()->AppUnitsToDevPixels(aPoint.x),
243 PresContext()->AppUnitsToDevPixels(aPoint.y))) {
244 return nsnull;
248 return nsSVGInnerSVGFrameBase::GetFrameForPoint(aPoint);
251 //----------------------------------------------------------------------
252 // nsISVGSVGFrame methods:
254 NS_IMETHODIMP
255 nsSVGInnerSVGFrame::SuspendRedraw()
257 nsSVGOuterSVGFrame *outerSVGFrame = nsSVGUtils::GetOuterSVGFrame(this);
258 if (!outerSVGFrame) {
259 NS_ERROR("no outer svg frame");
260 return NS_ERROR_FAILURE;
262 return outerSVGFrame->SuspendRedraw();
265 NS_IMETHODIMP
266 nsSVGInnerSVGFrame::UnsuspendRedraw()
268 nsSVGOuterSVGFrame *outerSVGFrame = nsSVGUtils::GetOuterSVGFrame(this);
269 if (!outerSVGFrame) {
270 NS_ERROR("no outer svg frame");
271 return NS_ERROR_FAILURE;
273 return outerSVGFrame->UnsuspendRedraw();
276 NS_IMETHODIMP
277 nsSVGInnerSVGFrame::NotifyViewportChange()
279 PRUint32 flags = COORD_CONTEXT_CHANGED;
281 #if 1
282 // XXX nsSVGSVGElement::InvalidateTransformNotifyFrame calls us for changes
283 // to 'x' and 'y'. Until this is fixed, add TRANSFORM_CHANGED to flags
284 // unconditionally.
286 flags |= TRANSFORM_CHANGED;
288 // make sure canvas transform matrix gets (lazily) recalculated:
289 mCanvasTM = nsnull;
290 #else
291 // viewport changes only affect our transform if we have a viewBox attribute
292 if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::viewBox)) {
293 // make sure canvas transform matrix gets (lazily) recalculated:
294 mCanvasTM = nsnull;
296 flags |= TRANSFORM_CHANGED;
298 #endif
300 // inform children
301 SuspendRedraw();
302 nsSVGUtils::NotifyChildrenOfSVGChange(this, flags);
303 UnsuspendRedraw();
304 return NS_OK;
307 //----------------------------------------------------------------------
308 // nsSVGContainerFrame methods:
310 already_AddRefed<nsIDOMSVGMatrix>
311 nsSVGInnerSVGFrame::GetCanvasTM()
313 if (!GetMatrixPropagation()) {
314 nsIDOMSVGMatrix *retval;
315 NS_NewSVGMatrix(&retval);
316 return retval;
319 // parentTM * Translate(x,y) * viewBoxTM
321 if (!mCanvasTM) {
322 // get the transform from our parent's coordinate system to ours:
323 NS_ASSERTION(mParent, "null parent");
324 nsSVGContainerFrame *containerFrame = static_cast<nsSVGContainerFrame*>
325 (mParent);
326 nsCOMPtr<nsIDOMSVGMatrix> parentTM = containerFrame->GetCanvasTM();
327 NS_ASSERTION(parentTM, "null TM");
329 // append the transform due to the 'x' and 'y' attributes:
330 float x, y;
331 nsSVGSVGElement *svg = static_cast<nsSVGSVGElement*>(mContent);
332 svg->GetAnimatedLengthValues(&x, &y, nsnull);
334 nsCOMPtr<nsIDOMSVGMatrix> xyTM;
335 parentTM->Translate(x, y, getter_AddRefs(xyTM));
337 // append the viewbox to viewport transform:
338 nsCOMPtr<nsIDOMSVGMatrix> viewBoxTM;
339 nsSVGSVGElement *svgElement = static_cast<nsSVGSVGElement*>(mContent);
340 nsresult res =
341 svgElement->GetViewboxToViewportTransform(getter_AddRefs(viewBoxTM));
342 if (NS_SUCCEEDED(res) && viewBoxTM) {
343 xyTM->Multiply(viewBoxTM, getter_AddRefs(mCanvasTM));
344 } else {
345 NS_WARNING("We should propagate the fact that the viewBox is invalid.");
346 mCanvasTM = xyTM;
350 nsIDOMSVGMatrix* retval = mCanvasTM.get();
351 NS_IF_ADDREF(retval);
352 return retval;
355 //----------------------------------------------------------------------
356 // nsISVGValueObserver methods:
358 NS_IMETHODIMP
359 nsSVGInnerSVGFrame::WillModifySVGObservable(nsISVGValue* observable,
360 nsISVGValue::modificationType aModType)
362 return NS_OK;
365 NS_IMETHODIMP
366 nsSVGInnerSVGFrame::DidModifySVGObservable (nsISVGValue* observable,
367 nsISVGValue::modificationType aModType)
369 NotifyViewportChange();
370 return NS_OK;