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) 2004
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : *
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.
34 : *
35 : * ***** END LICENSE BLOCK ***** */
36 :
37 : #include "nsSVGPathGeometryFrame.h"
38 : #include "imgIContainer.h"
39 : #include "nsStubImageDecoderObserver.h"
40 : #include "nsImageLoadingContent.h"
41 : #include "nsIDOMSVGImageElement.h"
42 : #include "nsLayoutUtils.h"
43 : #include "nsSVGImageElement.h"
44 : #include "nsSVGUtils.h"
45 : #include "gfxContext.h"
46 : #include "gfxMatrix.h"
47 : #include "nsIInterfaceRequestorUtils.h"
48 : #include "gfxPlatform.h"
49 : #include "nsSVGSVGElement.h"
50 :
51 : using namespace mozilla;
52 :
53 : class nsRenderingContext;
54 : class nsSVGImageFrame;
55 :
56 : class nsSVGImageListener MOZ_FINAL : public nsStubImageDecoderObserver
57 : {
58 : public:
59 : nsSVGImageListener(nsSVGImageFrame *aFrame);
60 :
61 : NS_DECL_ISUPPORTS
62 : // imgIDecoderObserver (override nsStubImageDecoderObserver)
63 : NS_IMETHOD OnStopDecode(imgIRequest *aRequest, nsresult status,
64 : const PRUnichar *statusArg);
65 : // imgIContainerObserver (override nsStubImageDecoderObserver)
66 : NS_IMETHOD FrameChanged(imgIRequest *aRequest,
67 : imgIContainer *aContainer,
68 : const nsIntRect *aDirtyRect);
69 : // imgIContainerObserver (override nsStubImageDecoderObserver)
70 : NS_IMETHOD OnStartContainer(imgIRequest *aRequest,
71 : imgIContainer *aContainer);
72 :
73 0 : void SetFrame(nsSVGImageFrame *frame) { mFrame = frame; }
74 :
75 : private:
76 : nsSVGImageFrame *mFrame;
77 : };
78 :
79 : typedef nsSVGPathGeometryFrame nsSVGImageFrameBase;
80 :
81 : class nsSVGImageFrame : public nsSVGImageFrameBase
82 : {
83 : friend nsIFrame*
84 : NS_NewSVGImageFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
85 :
86 : protected:
87 0 : nsSVGImageFrame(nsStyleContext* aContext) : nsSVGImageFrameBase(aContext) {}
88 : virtual ~nsSVGImageFrame();
89 :
90 : public:
91 : NS_DECL_FRAMEARENA_HELPERS
92 :
93 : // nsISVGChildFrame interface:
94 : NS_IMETHOD PaintSVG(nsRenderingContext *aContext, const nsIntRect *aDirtyRect);
95 : NS_IMETHOD_(nsIFrame*) GetFrameForPoint(const nsPoint &aPoint);
96 :
97 : // nsSVGPathGeometryFrame methods:
98 : NS_IMETHOD UpdateCoveredRegion();
99 : virtual PRUint16 GetHitTestFlags();
100 :
101 : // nsIFrame interface:
102 : NS_IMETHOD AttributeChanged(PRInt32 aNameSpaceID,
103 : nsIAtom* aAttribute,
104 : PRInt32 aModType);
105 : NS_IMETHOD Init(nsIContent* aContent,
106 : nsIFrame* aParent,
107 : nsIFrame* aPrevInFlow);
108 : virtual void DestroyFrom(nsIFrame* aDestructRoot);
109 :
110 : /**
111 : * Get the "type" of the frame
112 : *
113 : * @see nsGkAtoms::svgImageFrame
114 : */
115 : virtual nsIAtom* GetType() const;
116 :
117 : #ifdef DEBUG
118 0 : NS_IMETHOD GetFrameName(nsAString& aResult) const
119 : {
120 0 : return MakeFrameName(NS_LITERAL_STRING("SVGImage"), aResult);
121 : }
122 : #endif
123 :
124 : private:
125 : gfxMatrix GetRasterImageTransform(PRInt32 aNativeWidth,
126 : PRInt32 aNativeHeight);
127 : gfxMatrix GetVectorImageTransform();
128 : bool TransformContextForPainting(gfxContext* aGfxContext);
129 :
130 : nsCOMPtr<imgIDecoderObserver> mListener;
131 :
132 : nsCOMPtr<imgIContainer> mImageContainer;
133 :
134 : friend class nsSVGImageListener;
135 : };
136 :
137 : //----------------------------------------------------------------------
138 : // Implementation
139 :
140 : nsIFrame*
141 0 : NS_NewSVGImageFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
142 : {
143 0 : return new (aPresShell) nsSVGImageFrame(aContext);
144 : }
145 :
146 0 : NS_IMPL_FRAMEARENA_HELPERS(nsSVGImageFrame)
147 :
148 0 : nsSVGImageFrame::~nsSVGImageFrame()
149 : {
150 : // set the frame to null so we don't send messages to a dead object.
151 0 : if (mListener) {
152 0 : nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
153 0 : if (imageLoader) {
154 : // Push a null JSContext on the stack so that code that runs
155 : // within the below code doesn't think it's being called by
156 : // JS. See bug 604262.
157 0 : nsCxPusher pusher;
158 0 : pusher.PushNull();
159 :
160 0 : imageLoader->RemoveObserver(mListener);
161 : }
162 0 : reinterpret_cast<nsSVGImageListener*>(mListener.get())->SetFrame(nsnull);
163 : }
164 0 : mListener = nsnull;
165 0 : }
166 :
167 : NS_IMETHODIMP
168 0 : nsSVGImageFrame::Init(nsIContent* aContent,
169 : nsIFrame* aParent,
170 : nsIFrame* aPrevInFlow)
171 : {
172 : #ifdef DEBUG
173 0 : nsCOMPtr<nsIDOMSVGImageElement> image = do_QueryInterface(aContent);
174 0 : NS_ASSERTION(image, "Content is not an SVG image!");
175 : #endif
176 :
177 0 : nsresult rv = nsSVGImageFrameBase::Init(aContent, aParent, aPrevInFlow);
178 0 : if (NS_FAILED(rv)) return rv;
179 :
180 0 : mListener = new nsSVGImageListener(this);
181 0 : if (!mListener) return NS_ERROR_OUT_OF_MEMORY;
182 0 : nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
183 0 : NS_ENSURE_TRUE(imageLoader, NS_ERROR_UNEXPECTED);
184 :
185 : // We should have a PresContext now, so let's notify our image loader that
186 : // we need to register any image animations with the refresh driver.
187 0 : imageLoader->FrameCreated(this);
188 :
189 : // Push a null JSContext on the stack so that code that runs within
190 : // the below code doesn't think it's being called by JS. See bug
191 : // 604262.
192 0 : nsCxPusher pusher;
193 0 : pusher.PushNull();
194 :
195 0 : imageLoader->AddObserver(mListener);
196 :
197 0 : return NS_OK;
198 : }
199 :
200 : /* virtual */ void
201 0 : nsSVGImageFrame::DestroyFrom(nsIFrame* aDestructRoot)
202 : {
203 : nsCOMPtr<nsIImageLoadingContent> imageLoader =
204 0 : do_QueryInterface(nsFrame::mContent);
205 :
206 0 : if (imageLoader) {
207 0 : imageLoader->FrameDestroyed(this);
208 : }
209 :
210 0 : nsFrame::DestroyFrom(aDestructRoot);
211 0 : }
212 :
213 : //----------------------------------------------------------------------
214 : // nsIFrame methods:
215 :
216 : NS_IMETHODIMP
217 0 : nsSVGImageFrame::AttributeChanged(PRInt32 aNameSpaceID,
218 : nsIAtom* aAttribute,
219 : PRInt32 aModType)
220 : {
221 0 : if (aNameSpaceID == kNameSpaceID_None &&
222 : (aAttribute == nsGkAtoms::x ||
223 : aAttribute == nsGkAtoms::y ||
224 : aAttribute == nsGkAtoms::width ||
225 : aAttribute == nsGkAtoms::height ||
226 : aAttribute == nsGkAtoms::preserveAspectRatio)) {
227 0 : nsSVGUtils::UpdateGraphic(this);
228 0 : return NS_OK;
229 : }
230 0 : if (aNameSpaceID == kNameSpaceID_XLink &&
231 : aAttribute == nsGkAtoms::href) {
232 :
233 : // Prevent setting image.src by exiting early
234 0 : if (nsContentUtils::IsImageSrcSetDisabled()) {
235 0 : return NS_OK;
236 : }
237 0 : nsSVGImageElement *element = static_cast<nsSVGImageElement*>(mContent);
238 :
239 0 : if (element->mStringAttributes[nsSVGImageElement::HREF].IsExplicitlySet()) {
240 0 : element->LoadSVGImage(true, true);
241 : } else {
242 0 : element->CancelImageRequests(true);
243 : }
244 : }
245 :
246 : return nsSVGImageFrameBase::AttributeChanged(aNameSpaceID,
247 0 : aAttribute, aModType);
248 : }
249 :
250 : gfxMatrix
251 0 : nsSVGImageFrame::GetRasterImageTransform(PRInt32 aNativeWidth, PRInt32 aNativeHeight)
252 : {
253 : float x, y, width, height;
254 0 : nsSVGImageElement *element = static_cast<nsSVGImageElement*>(mContent);
255 0 : element->GetAnimatedLengthValues(&x, &y, &width, &height, nsnull);
256 :
257 : gfxMatrix viewBoxTM =
258 : nsSVGUtils::GetViewBoxTransform(element,
259 : width, height,
260 : 0, 0, aNativeWidth, aNativeHeight,
261 0 : element->mPreserveAspectRatio);
262 :
263 0 : return viewBoxTM * gfxMatrix().Translate(gfxPoint(x, y)) * GetCanvasTM();
264 : }
265 :
266 : gfxMatrix
267 0 : nsSVGImageFrame::GetVectorImageTransform()
268 : {
269 : float x, y, width, height;
270 0 : nsSVGImageElement *element = static_cast<nsSVGImageElement*>(mContent);
271 0 : element->GetAnimatedLengthValues(&x, &y, &width, &height, nsnull);
272 :
273 : // No viewBoxTM needed here -- our height/width overrides any concept of
274 : // "native size" that the SVG image has, and it will handle viewBox and
275 : // preserveAspectRatio on its own once we give it a region to draw into.
276 :
277 0 : return gfxMatrix().Translate(gfxPoint(x, y)) * GetCanvasTM();
278 : }
279 :
280 : bool
281 0 : nsSVGImageFrame::TransformContextForPainting(gfxContext* aGfxContext)
282 : {
283 0 : gfxMatrix imageTransform;
284 0 : if (mImageContainer->GetType() == imgIContainer::TYPE_VECTOR) {
285 0 : imageTransform = GetVectorImageTransform();
286 : } else {
287 : PRInt32 nativeWidth, nativeHeight;
288 0 : if (NS_FAILED(mImageContainer->GetWidth(&nativeWidth)) ||
289 0 : NS_FAILED(mImageContainer->GetHeight(&nativeHeight)) ||
290 : nativeWidth == 0 || nativeHeight == 0) {
291 0 : return false;
292 : }
293 0 : imageTransform = GetRasterImageTransform(nativeWidth, nativeHeight);
294 : }
295 :
296 0 : if (imageTransform.IsSingular()) {
297 0 : return false;
298 : }
299 :
300 : // NOTE: We need to cancel out the effects of Full-Page-Zoom, or else
301 : // it'll get applied an extra time by DrawSingleUnscaledImage.
302 0 : nscoord appUnitsPerDevPx = PresContext()->AppUnitsPerDevPixel();
303 : gfxFloat pageZoomFactor =
304 0 : nsPresContext::AppUnitsToFloatCSSPixels(appUnitsPerDevPx);
305 0 : aGfxContext->Multiply(imageTransform.Scale(pageZoomFactor, pageZoomFactor));
306 :
307 0 : return true;
308 : }
309 :
310 : //----------------------------------------------------------------------
311 : // nsISVGChildFrame methods:
312 : NS_IMETHODIMP
313 0 : nsSVGImageFrame::PaintSVG(nsRenderingContext *aContext,
314 : const nsIntRect *aDirtyRect)
315 : {
316 0 : nsresult rv = NS_OK;
317 :
318 0 : if (!GetStyleVisibility()->IsVisible())
319 0 : return NS_OK;
320 :
321 : float x, y, width, height;
322 0 : nsSVGImageElement *imgElem = static_cast<nsSVGImageElement*>(mContent);
323 0 : imgElem->GetAnimatedLengthValues(&x, &y, &width, &height, nsnull);
324 0 : NS_ASSERTION(width > 0 && height > 0,
325 : "Should only be painting things with valid width/height");
326 :
327 0 : if (!mImageContainer) {
328 0 : nsCOMPtr<imgIRequest> currentRequest;
329 0 : nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
330 0 : if (imageLoader)
331 0 : imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
332 0 : getter_AddRefs(currentRequest));
333 :
334 0 : if (currentRequest)
335 0 : currentRequest->GetImage(getter_AddRefs(mImageContainer));
336 : }
337 :
338 0 : if (mImageContainer) {
339 0 : gfxContext* ctx = aContext->ThebesContext();
340 0 : gfxContextAutoSaveRestore autoRestorer(ctx);
341 :
342 0 : if (GetStyleDisplay()->IsScrollableOverflow()) {
343 : gfxRect clipRect = nsSVGUtils::GetClipRectForFrame(this, x, y,
344 0 : width, height);
345 0 : nsSVGUtils::SetClipRect(ctx, GetCanvasTM(), clipRect);
346 : }
347 :
348 0 : if (!TransformContextForPainting(ctx)) {
349 0 : return NS_ERROR_FAILURE;
350 : }
351 :
352 : // fill-opacity doesn't affect <image>, so if we're allowed to
353 : // optimize group opacity, the opacity used for compositing the
354 : // image into the current canvas is just the group opacity.
355 0 : float opacity = 1.0f;
356 0 : if (nsSVGUtils::CanOptimizeOpacity(this)) {
357 0 : opacity = GetStyleDisplay()->mOpacity;
358 : }
359 :
360 0 : if (opacity != 1.0f) {
361 0 : ctx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
362 : }
363 :
364 0 : nscoord appUnitsPerDevPx = PresContext()->AppUnitsPerDevPixel();
365 0 : nsRect dirtyRect; // only used if aDirtyRect is non-null
366 0 : if (aDirtyRect) {
367 0 : dirtyRect = aDirtyRect->ToAppUnits(appUnitsPerDevPx);
368 : // Adjust dirtyRect to match our local coordinate system.
369 : nsRect rootRect =
370 0 : nsSVGUtils::TransformFrameRectToOuterSVG(mRect, GetCanvasTM(), PresContext());
371 0 : dirtyRect.MoveBy(-rootRect.TopLeft());
372 : }
373 :
374 : // XXXbholley - I don't think huge images in SVGs are common enough to
375 : // warrant worrying about the responsiveness impact of doing synchronous
376 : // decodes. The extra code complexity of determinining when we want to
377 : // force sync probably just isn't worth it, so always pass FLAG_SYNC_DECODE
378 0 : PRUint32 drawFlags = imgIContainer::FLAG_SYNC_DECODE;
379 :
380 0 : if (mImageContainer->GetType() == imgIContainer::TYPE_VECTOR) {
381 0 : nsIFrame* imgRootFrame = mImageContainer->GetRootLayoutFrame();
382 0 : if (!imgRootFrame) {
383 : // bad image (e.g. XML parse error in image's SVG file)
384 0 : return NS_OK;
385 : }
386 :
387 : // Grab root node (w/ sanity-check to make sure it exists & is <svg>)
388 : nsSVGSVGElement* rootSVGElem =
389 0 : static_cast<nsSVGSVGElement*>(imgRootFrame->GetContent());
390 0 : if (!rootSVGElem || !rootSVGElem->IsSVG(nsGkAtoms::svg)) {
391 0 : NS_ABORT_IF_FALSE(false, "missing or non-<svg> root node!!");
392 0 : return false;
393 : }
394 :
395 : // Override preserveAspectRatio in our helper document
396 : // XXXdholbert We should technically be overriding the helper doc's clip
397 : // and overflow properties here, too. See bug 272288 comment 36.
398 : rootSVGElem->SetImageOverridePreserveAspectRatio(
399 0 : imgElem->mPreserveAspectRatio.GetAnimValue());
400 : nsRect destRect(0, 0,
401 : appUnitsPerDevPx * width,
402 0 : appUnitsPerDevPx * height);
403 :
404 : // Note: Can't use DrawSingleUnscaledImage for the TYPE_VECTOR case.
405 : // That method needs our image to have a fixed native width & height,
406 : // and that's not always true for TYPE_VECTOR images.
407 : nsLayoutUtils::DrawSingleImage(
408 : aContext,
409 : mImageContainer,
410 : nsLayoutUtils::GetGraphicsFilterForFrame(this),
411 : destRect,
412 : aDirtyRect ? dirtyRect : destRect,
413 0 : drawFlags);
414 :
415 0 : rootSVGElem->ClearImageOverridePreserveAspectRatio();
416 : } else { // mImageContainer->GetType() == TYPE_RASTER
417 : nsLayoutUtils::DrawSingleUnscaledImage(
418 : aContext,
419 : mImageContainer,
420 : nsLayoutUtils::GetGraphicsFilterForFrame(this),
421 : nsPoint(0, 0),
422 : aDirtyRect ? &dirtyRect : nsnull,
423 0 : drawFlags);
424 : }
425 :
426 0 : if (opacity != 1.0f) {
427 0 : ctx->PopGroupToSource();
428 0 : ctx->SetOperator(gfxContext::OPERATOR_OVER);
429 0 : ctx->Paint(opacity);
430 : }
431 : // gfxContextAutoSaveRestore goes out of scope & cleans up our gfxContext
432 : }
433 :
434 0 : return rv;
435 : }
436 :
437 : NS_IMETHODIMP_(nsIFrame*)
438 0 : nsSVGImageFrame::GetFrameForPoint(const nsPoint &aPoint)
439 : {
440 : // Special case for raster images -- we only want to accept points that fall
441 : // in the underlying image's (transformed) native bounds. That region
442 : // doesn't necessarily map to our <image> element's [x,y,width,height]. So,
443 : // we have to look up the native image size & our image transform in order
444 : // to filter out points that fall outside that area.
445 0 : if (GetStyleDisplay()->IsScrollableOverflow() && mImageContainer) {
446 0 : if (mImageContainer->GetType() == imgIContainer::TYPE_RASTER) {
447 : PRInt32 nativeWidth, nativeHeight;
448 0 : if (NS_FAILED(mImageContainer->GetWidth(&nativeWidth)) ||
449 0 : NS_FAILED(mImageContainer->GetHeight(&nativeHeight)) ||
450 : nativeWidth == 0 || nativeHeight == 0) {
451 0 : return nsnull;
452 : }
453 :
454 0 : if (!nsSVGUtils::HitTestRect(
455 0 : GetRasterImageTransform(nativeWidth, nativeHeight),
456 : 0, 0, nativeWidth, nativeHeight,
457 0 : PresContext()->AppUnitsToDevPixels(aPoint.x),
458 0 : PresContext()->AppUnitsToDevPixels(aPoint.y))) {
459 0 : return nsnull;
460 : }
461 : }
462 : // The special case above doesn't apply to vector images, because they
463 : // don't limit their drawing to explicit "native bounds" -- they have
464 : // an infinite canvas on which to place content. So it's reasonable to
465 : // just fall back on our <image> element's own bounds here.
466 : }
467 :
468 0 : return nsSVGImageFrameBase::GetFrameForPoint(aPoint);
469 : }
470 :
471 : nsIAtom *
472 0 : nsSVGImageFrame::GetType() const
473 : {
474 0 : return nsGkAtoms::svgImageFrame;
475 : }
476 :
477 : //----------------------------------------------------------------------
478 : // nsSVGPathGeometryFrame methods:
479 :
480 : // Lie about our fill/stroke so that covered region and hit detection work properly
481 :
482 : NS_IMETHODIMP
483 0 : nsSVGImageFrame::UpdateCoveredRegion()
484 : {
485 0 : mRect.SetEmpty();
486 :
487 0 : gfxContext context(gfxPlatform::GetPlatform()->ScreenReferenceSurface());
488 :
489 0 : gfxMatrix identity;
490 0 : GeneratePath(&context, &identity);
491 :
492 0 : gfxRect extent = context.GetUserPathExtent();
493 :
494 0 : if (!extent.IsEmpty()) {
495 : mRect = nsLayoutUtils::RoundGfxRectToAppRect(extent,
496 0 : PresContext()->AppUnitsPerCSSPixel());
497 : }
498 :
499 : // See bug 614732 comment 32.
500 : mCoveredRegion = nsSVGUtils::TransformFrameRectToOuterSVG(
501 0 : mRect, GetCanvasTM(), PresContext());
502 :
503 0 : return NS_OK;
504 : }
505 :
506 : PRUint16
507 0 : nsSVGImageFrame::GetHitTestFlags()
508 : {
509 0 : PRUint16 flags = 0;
510 :
511 0 : switch(GetStyleVisibility()->mPointerEvents) {
512 : case NS_STYLE_POINTER_EVENTS_NONE:
513 0 : break;
514 : case NS_STYLE_POINTER_EVENTS_VISIBLEPAINTED:
515 : case NS_STYLE_POINTER_EVENTS_AUTO:
516 0 : if (GetStyleVisibility()->IsVisible()) {
517 : /* XXX: should check pixel transparency */
518 0 : flags |= SVG_HIT_TEST_FILL;
519 : }
520 0 : break;
521 : case NS_STYLE_POINTER_EVENTS_VISIBLEFILL:
522 : case NS_STYLE_POINTER_EVENTS_VISIBLESTROKE:
523 : case NS_STYLE_POINTER_EVENTS_VISIBLE:
524 0 : if (GetStyleVisibility()->IsVisible()) {
525 0 : flags |= SVG_HIT_TEST_FILL;
526 : }
527 0 : break;
528 : case NS_STYLE_POINTER_EVENTS_PAINTED:
529 : /* XXX: should check pixel transparency */
530 0 : flags |= SVG_HIT_TEST_FILL;
531 0 : break;
532 : case NS_STYLE_POINTER_EVENTS_FILL:
533 : case NS_STYLE_POINTER_EVENTS_STROKE:
534 : case NS_STYLE_POINTER_EVENTS_ALL:
535 0 : flags |= SVG_HIT_TEST_FILL;
536 0 : break;
537 : default:
538 0 : NS_ERROR("not reached");
539 0 : break;
540 : }
541 :
542 0 : return flags;
543 : }
544 :
545 : //----------------------------------------------------------------------
546 : // nsSVGImageListener implementation
547 :
548 0 : NS_IMPL_ISUPPORTS2(nsSVGImageListener,
549 : imgIDecoderObserver,
550 : imgIContainerObserver)
551 :
552 0 : nsSVGImageListener::nsSVGImageListener(nsSVGImageFrame *aFrame) : mFrame(aFrame)
553 : {
554 0 : }
555 :
556 0 : NS_IMETHODIMP nsSVGImageListener::OnStopDecode(imgIRequest *aRequest,
557 : nsresult status,
558 : const PRUnichar *statusArg)
559 : {
560 0 : if (!mFrame)
561 0 : return NS_ERROR_FAILURE;
562 :
563 0 : nsSVGUtils::UpdateGraphic(mFrame);
564 0 : return NS_OK;
565 : }
566 :
567 0 : NS_IMETHODIMP nsSVGImageListener::FrameChanged(imgIRequest *aRequest,
568 : imgIContainer *aContainer,
569 : const nsIntRect *aDirtyRect)
570 : {
571 0 : if (!mFrame)
572 0 : return NS_ERROR_FAILURE;
573 :
574 0 : nsSVGUtils::UpdateGraphic(mFrame);
575 0 : return NS_OK;
576 : }
577 :
578 0 : NS_IMETHODIMP nsSVGImageListener::OnStartContainer(imgIRequest *aRequest,
579 : imgIContainer *aContainer)
580 : {
581 0 : if (!mFrame)
582 0 : return NS_ERROR_FAILURE;
583 :
584 0 : mFrame->mImageContainer = aContainer;
585 0 : nsSVGUtils::UpdateGraphic(mFrame);
586 :
587 0 : return NS_OK;
588 : }
589 :
|