Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / layout / svg / base / src / nsSVGImageFrame.cpp
blob03b6e2a3f48f115941cfea3273a87b4c8ba17186
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 IBM Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 2004
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
23 * Alternatively, the contents of this file may be used under the terms of
24 * either of the GNU General Public License Version 2 or later (the "GPL"),
25 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
37 #include "nsSVGPathGeometryFrame.h"
38 #include "nsIDOMSVGMatrix.h"
39 #include "nsIDOMSVGAnimPresAspRatio.h"
40 #include "imgIContainer.h"
41 #include "gfxIImageFrame.h"
42 #include "nsStubImageDecoderObserver.h"
43 #include "nsImageLoadingContent.h"
44 #include "nsIDOMSVGImageElement.h"
45 #include "nsSVGElement.h"
46 #include "nsSVGUtils.h"
47 #include "nsSVGMatrix.h"
48 #include "gfxContext.h"
49 #include "nsIInterfaceRequestorUtils.h"
50 #include "nsIImage.h"
52 class nsSVGImageFrame;
54 class nsSVGImageListener : public nsStubImageDecoderObserver
56 public:
57 nsSVGImageListener(nsSVGImageFrame *aFrame);
59 NS_DECL_ISUPPORTS
60 // imgIDecoderObserver (override nsStubImageDecoderObserver)
61 NS_IMETHOD OnStopDecode(imgIRequest *aRequest, nsresult status,
62 const PRUnichar *statusArg);
63 // imgIContainerObserver (override nsStubImageDecoderObserver)
64 NS_IMETHOD FrameChanged(imgIContainer *aContainer, gfxIImageFrame *newframe,
65 nsRect * dirtyRect);
66 // imgIContainerObserver (override nsStubImageDecoderObserver)
67 NS_IMETHOD OnStartContainer(imgIRequest *aRequest,
68 imgIContainer *aContainer);
70 void SetFrame(nsSVGImageFrame *frame) { mFrame = frame; }
72 private:
73 nsSVGImageFrame *mFrame;
77 class nsSVGImageFrame : public nsSVGPathGeometryFrame
79 friend nsIFrame*
80 NS_NewSVGImageFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsStyleContext* aContext);
82 protected:
83 nsSVGImageFrame(nsStyleContext* aContext) : nsSVGPathGeometryFrame(aContext) {}
84 virtual ~nsSVGImageFrame();
86 public:
87 // nsISVGChildFrame interface:
88 NS_IMETHOD PaintSVG(nsSVGRenderState *aContext, const nsIntRect *aDirtyRect);
89 NS_IMETHOD_(nsIFrame*) GetFrameForPoint(const nsPoint &aPoint);
91 // nsSVGPathGeometryFrame methods:
92 virtual PRUint16 GetHittestMask();
94 // nsIFrame interface:
95 NS_IMETHOD AttributeChanged(PRInt32 aNameSpaceID,
96 nsIAtom* aAttribute,
97 PRInt32 aModType);
98 NS_IMETHOD Init(nsIContent* aContent,
99 nsIFrame* aParent,
100 nsIFrame* aPrevInFlow);
103 * Get the "type" of the frame
105 * @see nsGkAtoms::svgImageFrame
107 virtual nsIAtom* GetType() const;
109 #ifdef DEBUG
110 NS_IMETHOD GetFrameName(nsAString& aResult) const
112 return MakeFrameName(NS_LITERAL_STRING("SVGImage"), aResult);
114 #endif
116 private:
117 already_AddRefed<nsIDOMSVGMatrix> GetImageTransform();
119 nsCOMPtr<imgIDecoderObserver> mListener;
121 nsCOMPtr<imgIContainer> mImageContainer;
123 friend class nsSVGImageListener;
126 //----------------------------------------------------------------------
127 // Implementation
129 nsIFrame*
130 NS_NewSVGImageFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsStyleContext* aContext)
132 nsCOMPtr<nsIDOMSVGImageElement> Rect = do_QueryInterface(aContent);
133 if (!Rect) {
134 NS_ERROR("Can't create frame! Content is not an SVG image!");
135 return nsnull;
138 return new (aPresShell) nsSVGImageFrame(aContext);
141 nsSVGImageFrame::~nsSVGImageFrame()
143 // set the frame to null so we don't send messages to a dead object.
144 if (mListener) {
145 nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
146 if (imageLoader) {
147 imageLoader->RemoveObserver(mListener);
149 reinterpret_cast<nsSVGImageListener*>(mListener.get())->SetFrame(nsnull);
151 mListener = nsnull;
154 NS_IMETHODIMP
155 nsSVGImageFrame::Init(nsIContent* aContent,
156 nsIFrame* aParent,
157 nsIFrame* aPrevInFlow)
159 nsresult rv = nsSVGPathGeometryFrame::Init(aContent, aParent, aPrevInFlow);
160 if (NS_FAILED(rv)) return rv;
162 mListener = new nsSVGImageListener(this);
163 if (!mListener) return NS_ERROR_OUT_OF_MEMORY;
164 nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
165 NS_ENSURE_TRUE(imageLoader, NS_ERROR_UNEXPECTED);
166 imageLoader->AddObserver(mListener);
168 return NS_OK;
171 //----------------------------------------------------------------------
172 // nsIFrame methods:
174 NS_IMETHODIMP
175 nsSVGImageFrame::AttributeChanged(PRInt32 aNameSpaceID,
176 nsIAtom* aAttribute,
177 PRInt32 aModType)
179 if (aNameSpaceID == kNameSpaceID_None &&
180 (aAttribute == nsGkAtoms::x ||
181 aAttribute == nsGkAtoms::y ||
182 aAttribute == nsGkAtoms::width ||
183 aAttribute == nsGkAtoms::height ||
184 aAttribute == nsGkAtoms::preserveAspectRatio)) {
185 nsSVGUtils::UpdateGraphic(this);
186 return NS_OK;
189 return nsSVGPathGeometryFrame::AttributeChanged(aNameSpaceID,
190 aAttribute, aModType);
193 already_AddRefed<nsIDOMSVGMatrix>
194 nsSVGImageFrame::GetImageTransform()
196 nsCOMPtr<nsIDOMSVGMatrix> ctm;
197 GetCanvasTM(getter_AddRefs(ctm));
199 float x, y, width, height;
200 nsSVGElement *element = static_cast<nsSVGElement*>(mContent);
201 element->GetAnimatedLengthValues(&x, &y, &width, &height, nsnull);
203 PRInt32 nativeWidth, nativeHeight;
204 mImageContainer->GetWidth(&nativeWidth);
205 mImageContainer->GetHeight(&nativeHeight);
207 nsCOMPtr<nsIDOMSVGImageElement> image = do_QueryInterface(mContent);
208 nsCOMPtr<nsIDOMSVGAnimatedPreserveAspectRatio> ratio;
209 image->GetPreserveAspectRatio(getter_AddRefs(ratio));
211 nsCOMPtr<nsIDOMSVGMatrix> trans, ctmXY, fini;
212 trans = nsSVGUtils::GetViewBoxTransform(width, height,
213 0, 0,
214 nativeWidth, nativeHeight,
215 ratio);
216 ctm->Translate(x, y, getter_AddRefs(ctmXY));
217 ctmXY->Multiply(trans, getter_AddRefs(fini));
219 nsIDOMSVGMatrix *retval = nsnull;
220 fini.swap(retval);
221 return retval;
224 //----------------------------------------------------------------------
225 // nsISVGChildFrame methods:
226 NS_IMETHODIMP
227 nsSVGImageFrame::PaintSVG(nsSVGRenderState *aContext,
228 const nsIntRect *aDirtyRect)
230 nsresult rv = NS_OK;
232 if (!GetStyleVisibility()->IsVisible())
233 return NS_OK;
235 float x, y, width, height;
236 nsSVGElement *element = static_cast<nsSVGElement*>(mContent);
237 element->GetAnimatedLengthValues(&x, &y, &width, &height, nsnull);
238 if (width <= 0 || height <= 0)
239 return NS_OK;
241 if (!mImageContainer) {
242 nsCOMPtr<imgIRequest> currentRequest;
243 nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
244 if (imageLoader)
245 imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
246 getter_AddRefs(currentRequest));
248 if (currentRequest)
249 currentRequest->GetImage(getter_AddRefs(mImageContainer));
252 nsCOMPtr<gfxIImageFrame> currentFrame;
253 if (mImageContainer)
254 mImageContainer->GetCurrentFrame(getter_AddRefs(currentFrame));
256 nsRefPtr<gfxPattern> thebesPattern = nsnull;
257 if (currentFrame) {
258 nsCOMPtr<nsIImage> img(do_GetInterface(currentFrame));
260 img->GetPattern(getter_AddRefs(thebesPattern));
263 if (thebesPattern) {
264 gfxContext *gfx = aContext->GetGfxContext();
266 if (GetStyleDisplay()->IsScrollableOverflow()) {
267 gfx->Save();
269 nsCOMPtr<nsIDOMSVGMatrix> ctm;
270 GetCanvasTM(getter_AddRefs(ctm));
272 if (ctm) {
273 nsSVGUtils::SetClipRect(gfx, ctm, x, y, width, height);
277 nsCOMPtr<nsIDOMSVGMatrix> fini = GetImageTransform();
279 // fill-opacity doesn't affect <image>, so if we're allowed to
280 // optimize group opacity, the opacity used for compositing the
281 // image into the current canvas is just the group opacity.
282 float opacity = 1.0f;
283 if (nsSVGUtils::CanOptimizeOpacity(this)) {
284 opacity = GetStyleDisplay()->mOpacity;
287 PRInt32 nativeWidth, nativeHeight;
288 currentFrame->GetWidth(&nativeWidth);
289 currentFrame->GetHeight(&nativeHeight);
291 nsSVGUtils::CompositePatternMatrix(gfx, thebesPattern, fini, nativeWidth, nativeHeight, opacity);
293 if (GetStyleDisplay()->IsScrollableOverflow())
294 gfx->Restore();
297 return rv;
300 NS_IMETHODIMP_(nsIFrame*)
301 nsSVGImageFrame::GetFrameForPoint(const nsPoint &aPoint)
303 if (GetStyleDisplay()->IsScrollableOverflow() && mImageContainer) {
304 PRInt32 nativeWidth, nativeHeight;
305 mImageContainer->GetWidth(&nativeWidth);
306 mImageContainer->GetHeight(&nativeHeight);
308 nsCOMPtr<nsIDOMSVGMatrix> fini = GetImageTransform();
310 if (!nsSVGUtils::HitTestRect(fini,
311 0, 0, nativeWidth, nativeHeight,
312 PresContext()->AppUnitsToDevPixels(aPoint.x),
313 PresContext()->AppUnitsToDevPixels(aPoint.y))) {
314 return nsnull;
318 return nsSVGPathGeometryFrame::GetFrameForPoint(aPoint);
321 nsIAtom *
322 nsSVGImageFrame::GetType() const
324 return nsGkAtoms::svgImageFrame;
327 //----------------------------------------------------------------------
328 // nsSVGPathGeometryFrame methods:
330 // Lie about our fill/stroke so that hit detection works properly
332 PRUint16
333 nsSVGImageFrame::GetHittestMask()
335 PRUint16 mask = 0;
337 switch(GetStyleSVG()->mPointerEvents) {
338 case NS_STYLE_POINTER_EVENTS_NONE:
339 break;
340 case NS_STYLE_POINTER_EVENTS_VISIBLEPAINTED:
341 if (GetStyleVisibility()->IsVisible()) {
342 /* XXX: should check pixel transparency */
343 mask |= HITTEST_MASK_FILL;
345 break;
346 case NS_STYLE_POINTER_EVENTS_VISIBLEFILL:
347 case NS_STYLE_POINTER_EVENTS_VISIBLESTROKE:
348 case NS_STYLE_POINTER_EVENTS_VISIBLE:
349 if (GetStyleVisibility()->IsVisible()) {
350 mask |= HITTEST_MASK_FILL;
352 break;
353 case NS_STYLE_POINTER_EVENTS_PAINTED:
354 /* XXX: should check pixel transparency */
355 mask |= HITTEST_MASK_FILL;
356 break;
357 case NS_STYLE_POINTER_EVENTS_FILL:
358 case NS_STYLE_POINTER_EVENTS_STROKE:
359 case NS_STYLE_POINTER_EVENTS_ALL:
360 mask |= HITTEST_MASK_FILL;
361 break;
362 default:
363 NS_ERROR("not reached");
364 break;
367 return mask;
370 //----------------------------------------------------------------------
371 // nsSVGImageListener implementation
373 NS_IMPL_ISUPPORTS2(nsSVGImageListener,
374 imgIDecoderObserver,
375 imgIContainerObserver)
377 nsSVGImageListener::nsSVGImageListener(nsSVGImageFrame *aFrame) : mFrame(aFrame)
381 NS_IMETHODIMP nsSVGImageListener::OnStopDecode(imgIRequest *aRequest,
382 nsresult status,
383 const PRUnichar *statusArg)
385 if (!mFrame)
386 return NS_ERROR_FAILURE;
388 nsSVGUtils::UpdateGraphic(mFrame);
389 return NS_OK;
392 NS_IMETHODIMP nsSVGImageListener::FrameChanged(imgIContainer *aContainer,
393 gfxIImageFrame *newframe,
394 nsRect * dirtyRect)
396 if (!mFrame)
397 return NS_ERROR_FAILURE;
399 nsSVGUtils::UpdateGraphic(mFrame);
400 return NS_OK;
403 NS_IMETHODIMP nsSVGImageListener::OnStartContainer(imgIRequest *aRequest,
404 imgIContainer *aContainer)
406 if (!mFrame)
407 return NS_ERROR_FAILURE;
409 mFrame->mImageContainer = aContainer;
410 nsSVGUtils::UpdateGraphic(mFrame);
412 return NS_OK;