Wed, 31 Dec 2014 06:55:50 +0100
Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 //
7 // Eric Vaughan
8 // Netscape Communications
9 //
10 // See documentation in associated header file
11 //
13 #include "nsImageBoxFrame.h"
14 #include "nsGkAtoms.h"
15 #include "nsStyleContext.h"
16 #include "nsStyleConsts.h"
17 #include "nsCOMPtr.h"
18 #include "nsPresContext.h"
19 #include "nsBoxLayoutState.h"
21 #include "nsHTMLParts.h"
22 #include "nsString.h"
23 #include "nsLeafFrame.h"
24 #include "nsIPresShell.h"
25 #include "nsIDocument.h"
26 #include "nsImageMap.h"
27 #include "nsILinkHandler.h"
28 #include "nsIURL.h"
29 #include "nsILoadGroup.h"
30 #include "nsContainerFrame.h"
31 #include "prprf.h"
32 #include "nsCSSRendering.h"
33 #include "nsIDOMHTMLImageElement.h"
34 #include "nsNameSpaceManager.h"
35 #include "nsTextFragment.h"
36 #include "nsIDOMHTMLMapElement.h"
37 #include "nsTransform2D.h"
38 #include "nsITheme.h"
40 #include "nsIServiceManager.h"
41 #include "nsIURI.h"
42 #include "nsNetUtil.h"
43 #include "nsThreadUtils.h"
44 #include "nsDisplayList.h"
45 #include "ImageLayers.h"
46 #include "ImageContainer.h"
48 #include "nsContentUtils.h"
50 #include "mozilla/BasicEvents.h"
51 #include "mozilla/EventDispatcher.h"
53 #define ONLOAD_CALLED_TOO_EARLY 1
55 using namespace mozilla;
56 using namespace mozilla::layers;
58 class nsImageBoxFrameEvent : public nsRunnable
59 {
60 public:
61 nsImageBoxFrameEvent(nsIContent *content, uint32_t message)
62 : mContent(content), mMessage(message) {}
64 NS_IMETHOD Run() MOZ_OVERRIDE;
66 private:
67 nsCOMPtr<nsIContent> mContent;
68 uint32_t mMessage;
69 };
71 NS_IMETHODIMP
72 nsImageBoxFrameEvent::Run()
73 {
74 nsIPresShell *pres_shell = mContent->OwnerDoc()->GetShell();
75 if (!pres_shell) {
76 return NS_OK;
77 }
79 nsRefPtr<nsPresContext> pres_context = pres_shell->GetPresContext();
80 if (!pres_context) {
81 return NS_OK;
82 }
84 nsEventStatus status = nsEventStatus_eIgnore;
85 WidgetEvent event(true, mMessage);
87 event.mFlags.mBubbles = false;
88 EventDispatcher::Dispatch(mContent, pres_context, &event, nullptr, &status);
89 return NS_OK;
90 }
92 // Fire off an event that'll asynchronously call the image elements
93 // onload handler once handled. This is needed since the image library
94 // can't decide if it wants to call it's observer methods
95 // synchronously or asynchronously. If an image is loaded from the
96 // cache the notifications come back synchronously, but if the image
97 // is loaded from the netswork the notifications come back
98 // asynchronously.
100 void
101 FireImageDOMEvent(nsIContent* aContent, uint32_t aMessage)
102 {
103 NS_ASSERTION(aMessage == NS_LOAD || aMessage == NS_LOAD_ERROR,
104 "invalid message");
106 nsCOMPtr<nsIRunnable> event = new nsImageBoxFrameEvent(aContent, aMessage);
107 if (NS_FAILED(NS_DispatchToCurrentThread(event)))
108 NS_WARNING("failed to dispatch image event");
109 }
111 //
112 // NS_NewImageBoxFrame
113 //
114 // Creates a new image frame and returns it
115 //
116 nsIFrame*
117 NS_NewImageBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext)
118 {
119 return new (aPresShell) nsImageBoxFrame (aPresShell, aContext);
120 }
122 NS_IMPL_FRAMEARENA_HELPERS(nsImageBoxFrame)
124 nsresult
125 nsImageBoxFrame::AttributeChanged(int32_t aNameSpaceID,
126 nsIAtom* aAttribute,
127 int32_t aModType)
128 {
129 nsresult rv = nsLeafBoxFrame::AttributeChanged(aNameSpaceID, aAttribute,
130 aModType);
132 if (aAttribute == nsGkAtoms::src) {
133 UpdateImage();
134 PresContext()->PresShell()->
135 FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
136 }
137 else if (aAttribute == nsGkAtoms::validate)
138 UpdateLoadFlags();
140 return rv;
141 }
143 nsImageBoxFrame::nsImageBoxFrame(nsIPresShell* aShell, nsStyleContext* aContext):
144 nsLeafBoxFrame(aShell, aContext),
145 mIntrinsicSize(0,0),
146 mRequestRegistered(false),
147 mLoadFlags(nsIRequest::LOAD_NORMAL),
148 mUseSrcAttr(false),
149 mSuppressStyleCheck(false),
150 mFireEventOnDecode(false)
151 {
152 MarkIntrinsicWidthsDirty();
153 }
155 nsImageBoxFrame::~nsImageBoxFrame()
156 {
157 }
160 /* virtual */ void
161 nsImageBoxFrame::MarkIntrinsicWidthsDirty()
162 {
163 SizeNeedsRecalc(mImageSize);
164 nsLeafBoxFrame::MarkIntrinsicWidthsDirty();
165 }
167 void
168 nsImageBoxFrame::DestroyFrom(nsIFrame* aDestructRoot)
169 {
170 if (mImageRequest) {
171 nsLayoutUtils::DeregisterImageRequest(PresContext(), mImageRequest,
172 &mRequestRegistered);
174 // Release image loader first so that it's refcnt can go to zero
175 mImageRequest->CancelAndForgetObserver(NS_ERROR_FAILURE);
176 }
178 if (mListener)
179 reinterpret_cast<nsImageBoxListener*>(mListener.get())->SetFrame(nullptr); // set the frame to null so we don't send messages to a dead object.
181 nsLeafBoxFrame::DestroyFrom(aDestructRoot);
182 }
185 void
186 nsImageBoxFrame::Init(nsIContent* aContent,
187 nsIFrame* aParent,
188 nsIFrame* aPrevInFlow)
189 {
190 if (!mListener) {
191 nsImageBoxListener *listener = new nsImageBoxListener();
192 NS_ADDREF(listener);
193 listener->SetFrame(this);
194 listener->QueryInterface(NS_GET_IID(imgINotificationObserver), getter_AddRefs(mListener));
195 NS_RELEASE(listener);
196 }
198 mSuppressStyleCheck = true;
199 nsLeafBoxFrame::Init(aContent, aParent, aPrevInFlow);
200 mSuppressStyleCheck = false;
202 UpdateLoadFlags();
203 UpdateImage();
204 }
206 void
207 nsImageBoxFrame::UpdateImage()
208 {
209 nsPresContext* presContext = PresContext();
211 if (mImageRequest) {
212 nsLayoutUtils::DeregisterImageRequest(presContext, mImageRequest,
213 &mRequestRegistered);
214 mImageRequest->CancelAndForgetObserver(NS_ERROR_FAILURE);
215 mImageRequest = nullptr;
216 }
218 // get the new image src
219 nsAutoString src;
220 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::src, src);
221 mUseSrcAttr = !src.IsEmpty();
222 if (mUseSrcAttr) {
223 nsIDocument* doc = mContent->GetDocument();
224 if (!doc) {
225 // No need to do anything here...
226 return;
227 }
228 nsCOMPtr<nsIURI> baseURI = mContent->GetBaseURI();
229 nsCOMPtr<nsIURI> uri;
230 nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(uri),
231 src,
232 doc,
233 baseURI);
235 if (uri && nsContentUtils::CanLoadImage(uri, mContent, doc,
236 mContent->NodePrincipal())) {
237 nsContentUtils::LoadImage(uri, doc, mContent->NodePrincipal(),
238 doc->GetDocumentURI(), mListener, mLoadFlags,
239 EmptyString(), getter_AddRefs(mImageRequest));
241 if (mImageRequest) {
242 nsLayoutUtils::RegisterImageRequestIfAnimated(presContext,
243 mImageRequest,
244 &mRequestRegistered);
245 }
246 }
247 } else {
248 // Only get the list-style-image if we aren't being drawn
249 // by a native theme.
250 uint8_t appearance = StyleDisplay()->mAppearance;
251 if (!(appearance && nsBox::gTheme &&
252 nsBox::gTheme->ThemeSupportsWidget(nullptr, this, appearance))) {
253 // get the list-style-image
254 imgRequestProxy *styleRequest = StyleList()->GetListStyleImage();
255 if (styleRequest) {
256 styleRequest->Clone(mListener, getter_AddRefs(mImageRequest));
257 }
258 }
259 }
261 if (!mImageRequest) {
262 // We have no image, so size to 0
263 mIntrinsicSize.SizeTo(0, 0);
264 } else {
265 // We don't want discarding or decode-on-draw for xul images.
266 mImageRequest->StartDecoding();
267 mImageRequest->LockImage();
268 }
269 }
271 void
272 nsImageBoxFrame::UpdateLoadFlags()
273 {
274 static nsIContent::AttrValuesArray strings[] =
275 {&nsGkAtoms::always, &nsGkAtoms::never, nullptr};
276 switch (mContent->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::validate,
277 strings, eCaseMatters)) {
278 case 0:
279 mLoadFlags = nsIRequest::VALIDATE_ALWAYS;
280 break;
281 case 1:
282 mLoadFlags = nsIRequest::VALIDATE_NEVER|nsIRequest::LOAD_FROM_CACHE;
283 break;
284 default:
285 mLoadFlags = nsIRequest::LOAD_NORMAL;
286 break;
287 }
288 }
290 void
291 nsImageBoxFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
292 const nsRect& aDirtyRect,
293 const nsDisplayListSet& aLists)
294 {
295 nsLeafBoxFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists);
297 if ((0 == mRect.width) || (0 == mRect.height)) {
298 // Do not render when given a zero area. This avoids some useless
299 // scaling work while we wait for our image dimensions to arrive
300 // asynchronously.
301 return;
302 }
304 if (!IsVisibleForPainting(aBuilder))
305 return;
307 nsDisplayList list;
308 list.AppendNewToTop(
309 new (aBuilder) nsDisplayXULImage(aBuilder, this));
311 CreateOwnLayerIfNeeded(aBuilder, &list);
313 aLists.Content()->AppendToTop(&list);
314 }
316 void
317 nsImageBoxFrame::PaintImage(nsRenderingContext& aRenderingContext,
318 const nsRect& aDirtyRect, nsPoint aPt,
319 uint32_t aFlags)
320 {
321 nsRect rect;
322 GetClientRect(rect);
324 rect += aPt;
326 if (!mImageRequest)
327 return;
329 // don't draw if the image is not dirty
330 nsRect dirty;
331 if (!dirty.IntersectRect(aDirtyRect, rect))
332 return;
334 nsCOMPtr<imgIContainer> imgCon;
335 mImageRequest->GetImage(getter_AddRefs(imgCon));
337 if (imgCon) {
338 bool hasSubRect = !mUseSrcAttr && (mSubRect.width > 0 || mSubRect.height > 0);
339 nsLayoutUtils::DrawSingleImage(&aRenderingContext, imgCon,
340 nsLayoutUtils::GetGraphicsFilterForFrame(this),
341 rect, dirty, nullptr, aFlags, hasSubRect ? &mSubRect : nullptr);
342 }
343 }
345 void nsDisplayXULImage::Paint(nsDisplayListBuilder* aBuilder,
346 nsRenderingContext* aCtx)
347 {
348 uint32_t flags = imgIContainer::FLAG_NONE;
349 if (aBuilder->ShouldSyncDecodeImages())
350 flags |= imgIContainer::FLAG_SYNC_DECODE;
351 if (aBuilder->IsPaintingToWindow())
352 flags |= imgIContainer::FLAG_HIGH_QUALITY_SCALING;
354 static_cast<nsImageBoxFrame*>(mFrame)->
355 PaintImage(*aCtx, mVisibleRect, ToReferenceFrame(), flags);
356 }
358 void
359 nsDisplayXULImage::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
360 const nsDisplayItemGeometry* aGeometry,
361 nsRegion* aInvalidRegion)
362 {
364 if (aBuilder->ShouldSyncDecodeImages()) {
365 nsImageBoxFrame* boxFrame = static_cast<nsImageBoxFrame*>(mFrame);
366 nsCOMPtr<imgIContainer> image;
367 if (boxFrame->mImageRequest) {
368 boxFrame->mImageRequest->GetImage(getter_AddRefs(image));
369 }
371 if (image && !image->IsDecoded()) {
372 bool snap;
373 aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
374 }
375 }
377 nsDisplayImageContainer::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
378 }
380 void
381 nsDisplayXULImage::ConfigureLayer(ImageLayer* aLayer, const nsIntPoint& aOffset)
382 {
383 aLayer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(mFrame));
385 int32_t factor = mFrame->PresContext()->AppUnitsPerDevPixel();
386 nsImageBoxFrame* imageFrame = static_cast<nsImageBoxFrame*>(mFrame);
388 nsRect dest;
389 imageFrame->GetClientRect(dest);
390 dest += ToReferenceFrame();
391 gfxRect destRect(dest.x, dest.y, dest.width, dest.height);
392 destRect.ScaleInverse(factor);
394 nsCOMPtr<imgIContainer> imgCon;
395 imageFrame->mImageRequest->GetImage(getter_AddRefs(imgCon));
396 int32_t imageWidth;
397 int32_t imageHeight;
398 imgCon->GetWidth(&imageWidth);
399 imgCon->GetHeight(&imageHeight);
401 NS_ASSERTION(imageWidth != 0 && imageHeight != 0, "Invalid image size!");
403 gfxPoint p = destRect.TopLeft() + aOffset;
404 gfx::Matrix transform;
405 transform.Translate(p.x, p.y);
406 transform.Scale(destRect.Width()/imageWidth,
407 destRect.Height()/imageHeight);
408 aLayer->SetBaseTransform(gfx::Matrix4x4::From2D(transform));
410 aLayer->SetVisibleRegion(nsIntRect(0, 0, imageWidth, imageHeight));
411 }
413 already_AddRefed<ImageContainer>
414 nsDisplayXULImage::GetContainer(LayerManager* aManager, nsDisplayListBuilder* aBuilder)
415 {
416 return static_cast<nsImageBoxFrame*>(mFrame)->GetContainer(aManager);
417 }
419 already_AddRefed<ImageContainer>
420 nsImageBoxFrame::GetContainer(LayerManager* aManager)
421 {
422 bool hasSubRect = !mUseSrcAttr && (mSubRect.width > 0 || mSubRect.height > 0);
423 if (hasSubRect || !mImageRequest) {
424 return nullptr;
425 }
427 nsCOMPtr<imgIContainer> imgCon;
428 mImageRequest->GetImage(getter_AddRefs(imgCon));
429 if (!imgCon) {
430 return nullptr;
431 }
433 nsRefPtr<ImageContainer> container;
434 nsresult rv = imgCon->GetImageContainer(aManager, getter_AddRefs(container));
435 NS_ENSURE_SUCCESS(rv, nullptr);
436 return container.forget();
437 }
440 //
441 // DidSetStyleContext
442 //
443 // When the style context changes, make sure that all of our image is up to date.
444 //
445 /* virtual */ void
446 nsImageBoxFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
447 {
448 nsLeafBoxFrame::DidSetStyleContext(aOldStyleContext);
450 // Fetch our subrect.
451 const nsStyleList* myList = StyleList();
452 mSubRect = myList->mImageRegion; // before |mSuppressStyleCheck| test!
454 if (mUseSrcAttr || mSuppressStyleCheck)
455 return; // No more work required, since the image isn't specified by style.
457 // If we're using a native theme implementation, we shouldn't draw anything.
458 const nsStyleDisplay* disp = StyleDisplay();
459 if (disp->mAppearance && nsBox::gTheme &&
460 nsBox::gTheme->ThemeSupportsWidget(nullptr, this, disp->mAppearance))
461 return;
463 // If list-style-image changes, we have a new image.
464 nsCOMPtr<nsIURI> oldURI, newURI;
465 if (mImageRequest)
466 mImageRequest->GetURI(getter_AddRefs(oldURI));
467 if (myList->GetListStyleImage())
468 myList->GetListStyleImage()->GetURI(getter_AddRefs(newURI));
469 bool equal;
470 if (newURI == oldURI || // handles null==null
471 (newURI && oldURI &&
472 NS_SUCCEEDED(newURI->Equals(oldURI, &equal)) && equal))
473 return;
475 UpdateImage();
476 } // DidSetStyleContext
478 void
479 nsImageBoxFrame::GetImageSize()
480 {
481 if (mIntrinsicSize.width > 0 && mIntrinsicSize.height > 0) {
482 mImageSize.width = mIntrinsicSize.width;
483 mImageSize.height = mIntrinsicSize.height;
484 } else {
485 mImageSize.width = 0;
486 mImageSize.height = 0;
487 }
488 }
490 /**
491 * Ok return our dimensions
492 */
493 nsSize
494 nsImageBoxFrame::GetPrefSize(nsBoxLayoutState& aState)
495 {
496 nsSize size(0,0);
497 DISPLAY_PREF_SIZE(this, size);
498 if (DoesNeedRecalc(mImageSize))
499 GetImageSize();
501 if (!mUseSrcAttr && (mSubRect.width > 0 || mSubRect.height > 0))
502 size = mSubRect.Size();
503 else
504 size = mImageSize;
506 nsSize intrinsicSize = size;
508 nsMargin borderPadding(0,0,0,0);
509 GetBorderAndPadding(borderPadding);
510 size.width += borderPadding.LeftRight();
511 size.height += borderPadding.TopBottom();
513 bool widthSet, heightSet;
514 nsIFrame::AddCSSPrefSize(this, size, widthSet, heightSet);
515 NS_ASSERTION(size.width != NS_INTRINSICSIZE && size.height != NS_INTRINSICSIZE,
516 "non-intrinsic size expected");
518 nsSize minSize = GetMinSize(aState);
519 nsSize maxSize = GetMaxSize(aState);
521 if (!widthSet && !heightSet) {
522 if (minSize.width != NS_INTRINSICSIZE)
523 minSize.width -= borderPadding.LeftRight();
524 if (minSize.height != NS_INTRINSICSIZE)
525 minSize.height -= borderPadding.TopBottom();
526 if (maxSize.width != NS_INTRINSICSIZE)
527 maxSize.width -= borderPadding.LeftRight();
528 if (maxSize.height != NS_INTRINSICSIZE)
529 maxSize.height -= borderPadding.TopBottom();
531 size = nsLayoutUtils::ComputeAutoSizeWithIntrinsicDimensions(minSize.width, minSize.height,
532 maxSize.width, maxSize.height,
533 intrinsicSize.width, intrinsicSize.height);
534 NS_ASSERTION(size.width != NS_INTRINSICSIZE && size.height != NS_INTRINSICSIZE,
535 "non-intrinsic size expected");
536 size.width += borderPadding.LeftRight();
537 size.height += borderPadding.TopBottom();
538 return size;
539 }
541 if (!widthSet) {
542 if (intrinsicSize.height > 0) {
543 // Subtract off the border and padding from the height because the
544 // content-box needs to be used to determine the ratio
545 nscoord height = size.height - borderPadding.TopBottom();
546 size.width = nscoord(int64_t(height) * int64_t(intrinsicSize.width) /
547 int64_t(intrinsicSize.height));
548 }
549 else {
550 size.width = intrinsicSize.width;
551 }
553 size.width += borderPadding.LeftRight();
554 }
555 else if (!heightSet) {
556 if (intrinsicSize.width > 0) {
557 nscoord width = size.width - borderPadding.LeftRight();
558 size.height = nscoord(int64_t(width) * int64_t(intrinsicSize.height) /
559 int64_t(intrinsicSize.width));
560 }
561 else {
562 size.height = intrinsicSize.height;
563 }
565 size.height += borderPadding.TopBottom();
566 }
568 return BoundsCheck(minSize, size, maxSize);
569 }
571 nsSize
572 nsImageBoxFrame::GetMinSize(nsBoxLayoutState& aState)
573 {
574 // An image can always scale down to (0,0).
575 nsSize size(0,0);
576 DISPLAY_MIN_SIZE(this, size);
577 AddBorderAndPadding(size);
578 bool widthSet, heightSet;
579 nsIFrame::AddCSSMinSize(aState, this, size, widthSet, heightSet);
580 return size;
581 }
583 nscoord
584 nsImageBoxFrame::GetBoxAscent(nsBoxLayoutState& aState)
585 {
586 return GetPrefSize(aState).height;
587 }
589 nsIAtom*
590 nsImageBoxFrame::GetType() const
591 {
592 return nsGkAtoms::imageBoxFrame;
593 }
595 #ifdef DEBUG_FRAME_DUMP
596 nsresult
597 nsImageBoxFrame::GetFrameName(nsAString& aResult) const
598 {
599 return MakeFrameName(NS_LITERAL_STRING("ImageBox"), aResult);
600 }
601 #endif
603 nsresult
604 nsImageBoxFrame::Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData)
605 {
606 if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
607 nsCOMPtr<imgIContainer> image;
608 aRequest->GetImage(getter_AddRefs(image));
609 return OnStartContainer(aRequest, image);
610 }
612 if (aType == imgINotificationObserver::DECODE_COMPLETE) {
613 return OnStopDecode(aRequest);
614 }
616 if (aType == imgINotificationObserver::LOAD_COMPLETE) {
617 uint32_t imgStatus;
618 aRequest->GetImageStatus(&imgStatus);
619 nsresult status =
620 imgStatus & imgIRequest::STATUS_ERROR ? NS_ERROR_FAILURE : NS_OK;
621 return OnStopRequest(aRequest, status);
622 }
624 if (aType == imgINotificationObserver::IS_ANIMATED) {
625 return OnImageIsAnimated(aRequest);
626 }
628 if (aType == imgINotificationObserver::FRAME_UPDATE) {
629 return FrameChanged(aRequest);
630 }
632 return NS_OK;
633 }
635 nsresult nsImageBoxFrame::OnStartContainer(imgIRequest *request,
636 imgIContainer *image)
637 {
638 NS_ENSURE_ARG_POINTER(image);
640 // Ensure the animation (if any) is started. Note: There is no
641 // corresponding call to Decrement for this. This Increment will be
642 // 'cleaned up' by the Request when it is destroyed, but only then.
643 request->IncrementAnimationConsumers();
645 nscoord w, h;
646 image->GetWidth(&w);
647 image->GetHeight(&h);
649 mIntrinsicSize.SizeTo(nsPresContext::CSSPixelsToAppUnits(w),
650 nsPresContext::CSSPixelsToAppUnits(h));
652 if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
653 PresContext()->PresShell()->
654 FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
655 }
657 return NS_OK;
658 }
660 nsresult nsImageBoxFrame::OnStopDecode(imgIRequest *request)
661 {
662 if (mFireEventOnDecode) {
663 mFireEventOnDecode = false;
665 uint32_t reqStatus;
666 request->GetImageStatus(&reqStatus);
667 if (!(reqStatus & imgIRequest::STATUS_ERROR)) {
668 FireImageDOMEvent(mContent, NS_LOAD);
669 } else {
670 // Fire an onerror DOM event.
671 mIntrinsicSize.SizeTo(0, 0);
672 PresContext()->PresShell()->
673 FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
674 FireImageDOMEvent(mContent, NS_LOAD_ERROR);
675 }
676 }
678 nsBoxLayoutState state(PresContext());
679 this->Redraw(state);
681 return NS_OK;
682 }
684 nsresult nsImageBoxFrame::OnStopRequest(imgIRequest *request,
685 nsresult aStatus)
686 {
687 uint32_t reqStatus;
688 request->GetImageStatus(&reqStatus);
690 // We want to give the decoder a chance to find errors. If we haven't found
691 // an error yet and we've already started decoding, we must only fire these
692 // events after we finish decoding.
693 if (NS_SUCCEEDED(aStatus) && !(reqStatus & imgIRequest::STATUS_ERROR) &&
694 reqStatus & imgIRequest::STATUS_DECODE_STARTED) {
695 mFireEventOnDecode = true;
696 } else {
697 if (NS_SUCCEEDED(aStatus)) {
698 // Fire an onload DOM event.
699 FireImageDOMEvent(mContent, NS_LOAD);
700 } else {
701 // Fire an onerror DOM event.
702 mIntrinsicSize.SizeTo(0, 0);
703 PresContext()->PresShell()->
704 FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
705 FireImageDOMEvent(mContent, NS_LOAD_ERROR);
706 }
707 }
709 return NS_OK;
710 }
712 nsresult nsImageBoxFrame::OnImageIsAnimated(imgIRequest *aRequest)
713 {
714 // Register with our refresh driver, if we're animated.
715 nsLayoutUtils::RegisterImageRequest(PresContext(), aRequest,
716 &mRequestRegistered);
718 return NS_OK;
719 }
721 nsresult nsImageBoxFrame::FrameChanged(imgIRequest *aRequest)
722 {
723 if ((0 == mRect.width) || (0 == mRect.height)) {
724 return NS_OK;
725 }
727 InvalidateLayer(nsDisplayItem::TYPE_XUL_IMAGE);
729 return NS_OK;
730 }
732 NS_IMPL_ISUPPORTS(nsImageBoxListener, imgINotificationObserver, imgIOnloadBlocker)
734 nsImageBoxListener::nsImageBoxListener()
735 {
736 }
738 nsImageBoxListener::~nsImageBoxListener()
739 {
740 }
742 NS_IMETHODIMP
743 nsImageBoxListener::Notify(imgIRequest *request, int32_t aType, const nsIntRect* aData)
744 {
745 if (!mFrame)
746 return NS_OK;
748 return mFrame->Notify(request, aType, aData);
749 }
751 /* void blockOnload (in imgIRequest aRequest); */
752 NS_IMETHODIMP
753 nsImageBoxListener::BlockOnload(imgIRequest *aRequest)
754 {
755 if (mFrame && mFrame->GetContent() && mFrame->GetContent()->GetCurrentDoc()) {
756 mFrame->GetContent()->GetCurrentDoc()->BlockOnload();
757 }
759 return NS_OK;
760 }
762 /* void unblockOnload (in imgIRequest aRequest); */
763 NS_IMETHODIMP
764 nsImageBoxListener::UnblockOnload(imgIRequest *aRequest)
765 {
766 if (mFrame && mFrame->GetContent() && mFrame->GetContent()->GetCurrentDoc()) {
767 mFrame->GetContent()->GetCurrentDoc()->UnblockOnload(false);
768 }
770 return NS_OK;
771 }