layout/xul/nsImageBoxFrame.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     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 }

mercurial