LCOV - code coverage report
Current view: top level - layout/xul - nsImageBoxFrame.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 329 363 90.6 %
Date: 2017-07-14 16:53:18 Functions: 45 47 95.7 %
Legend: Lines: hit not hit

          Line data    Source code
       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/. */
       5             : 
       6             : //
       7             : // Eric Vaughan
       8             : // Netscape Communications
       9             : //
      10             : // See documentation in associated header file
      11             : //
      12             : 
      13             : #include "gfxContext.h"
      14             : #include "nsImageBoxFrame.h"
      15             : #include "nsGkAtoms.h"
      16             : #include "nsStyleContext.h"
      17             : #include "nsStyleConsts.h"
      18             : #include "nsStyleUtil.h"
      19             : #include "nsCOMPtr.h"
      20             : #include "nsPresContext.h"
      21             : #include "nsBoxLayoutState.h"
      22             : 
      23             : #include "nsHTMLParts.h"
      24             : #include "nsString.h"
      25             : #include "nsLeafFrame.h"
      26             : #include "nsIPresShell.h"
      27             : #include "nsIDocument.h"
      28             : #include "nsImageMap.h"
      29             : #include "nsILinkHandler.h"
      30             : #include "nsIURL.h"
      31             : #include "nsILoadGroup.h"
      32             : #include "nsContainerFrame.h"
      33             : #include "nsCSSRendering.h"
      34             : #include "nsIDOMHTMLImageElement.h"
      35             : #include "nsNameSpaceManager.h"
      36             : #include "nsTextFragment.h"
      37             : #include "nsIDOMHTMLMapElement.h"
      38             : #include "nsTransform2D.h"
      39             : #include "nsITheme.h"
      40             : 
      41             : #include "nsIServiceManager.h"
      42             : #include "nsIURI.h"
      43             : #include "nsThreadUtils.h"
      44             : #include "nsDisplayList.h"
      45             : #include "ImageLayers.h"
      46             : #include "ImageContainer.h"
      47             : #include "nsIContent.h"
      48             : 
      49             : #include "nsContentUtils.h"
      50             : 
      51             : #include "mozilla/BasicEvents.h"
      52             : #include "mozilla/EventDispatcher.h"
      53             : #include "mozilla/Maybe.h"
      54             : #include "SVGImageContext.h"
      55             : #include "Units.h"
      56             : 
      57             : #define ONLOAD_CALLED_TOO_EARLY 1
      58             : 
      59             : using namespace mozilla;
      60             : using namespace mozilla::gfx;
      61             : using namespace mozilla::image;
      62             : using namespace mozilla::layers;
      63             : 
      64         147 : class nsImageBoxFrameEvent : public Runnable
      65             : {
      66             : public:
      67          49 :   nsImageBoxFrameEvent(nsIContent* content, EventMessage message)
      68          49 :     : mozilla::Runnable("nsImageBoxFrameEvent")
      69             :     , mContent(content)
      70          49 :     , mMessage(message)
      71             :   {
      72          49 :   }
      73             : 
      74             :   NS_IMETHOD Run() override;
      75             : 
      76             : private:
      77             :   nsCOMPtr<nsIContent> mContent;
      78             :   EventMessage mMessage;
      79             : };
      80             : 
      81             : NS_IMETHODIMP
      82          49 : nsImageBoxFrameEvent::Run()
      83             : {
      84          49 :   nsIPresShell *pres_shell = mContent->OwnerDoc()->GetShell();
      85          49 :   if (!pres_shell) {
      86           0 :     return NS_OK;
      87             :   }
      88             : 
      89          98 :   RefPtr<nsPresContext> pres_context = pres_shell->GetPresContext();
      90          49 :   if (!pres_context) {
      91           0 :     return NS_OK;
      92             :   }
      93             : 
      94          49 :   nsEventStatus status = nsEventStatus_eIgnore;
      95          98 :   WidgetEvent event(true, mMessage);
      96             : 
      97          49 :   event.mFlags.mBubbles = false;
      98          49 :   EventDispatcher::Dispatch(mContent, pres_context, &event, nullptr, &status);
      99          49 :   return NS_OK;
     100             : }
     101             : 
     102             : // Fire off an event that'll asynchronously call the image elements
     103             : // onload handler once handled. This is needed since the image library
     104             : // can't decide if it wants to call its observer methods
     105             : // synchronously or asynchronously. If an image is loaded from the
     106             : // cache the notifications come back synchronously, but if the image
     107             : // is loaded from the network the notifications come back
     108             : // asynchronously.
     109             : 
     110             : void
     111          49 : FireImageDOMEvent(nsIContent* aContent, EventMessage aMessage)
     112             : {
     113          49 :   NS_ASSERTION(aMessage == eLoad || aMessage == eLoadError,
     114             :                "invalid message");
     115             : 
     116          98 :   nsCOMPtr<nsIRunnable> event = new nsImageBoxFrameEvent(aContent, aMessage);
     117          49 :   nsresult rv = aContent->OwnerDoc()->Dispatch("nsImageBoxFrameEvent",
     118             :                                                TaskCategory::Other,
     119          49 :                                                event.forget());
     120          49 :   if (NS_FAILED(rv)) {
     121           0 :     NS_WARNING("failed to dispatch image event");
     122             :   }
     123          49 : }
     124             : 
     125             : //
     126             : // NS_NewImageBoxFrame
     127             : //
     128             : // Creates a new image frame and returns it
     129             : //
     130             : nsIFrame*
     131          62 : NS_NewImageBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext)
     132             : {
     133          62 :   return new (aPresShell) nsImageBoxFrame(aContext);
     134             : }
     135             : 
     136          62 : NS_IMPL_FRAMEARENA_HELPERS(nsImageBoxFrame)
     137             : 
     138             : nsresult
     139           8 : nsImageBoxFrame::AttributeChanged(int32_t aNameSpaceID,
     140             :                                   nsIAtom* aAttribute,
     141             :                                   int32_t aModType)
     142             : {
     143           8 :   nsresult rv = nsLeafBoxFrame::AttributeChanged(aNameSpaceID, aAttribute,
     144           8 :                                                  aModType);
     145             : 
     146           8 :   if (aAttribute == nsGkAtoms::src) {
     147           1 :     UpdateImage();
     148           1 :     PresContext()->PresShell()->
     149           1 :       FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
     150             :   }
     151           7 :   else if (aAttribute == nsGkAtoms::validate)
     152           0 :     UpdateLoadFlags();
     153             : 
     154           8 :   return rv;
     155             : }
     156             : 
     157          62 : nsImageBoxFrame::nsImageBoxFrame(nsStyleContext* aContext)
     158             :   : nsLeafBoxFrame(aContext, kClassID)
     159             :   , mIntrinsicSize(0, 0)
     160             :   , mLoadFlags(nsIRequest::LOAD_NORMAL)
     161             :   , mRequestRegistered(false)
     162             :   , mUseSrcAttr(false)
     163          62 :   , mSuppressStyleCheck(false)
     164             : {
     165          62 :   MarkIntrinsicISizesDirty();
     166          62 : }
     167             : 
     168          30 : nsImageBoxFrame::~nsImageBoxFrame()
     169             : {
     170          30 : }
     171             : 
     172             : 
     173             : /* virtual */ void
     174         128 : nsImageBoxFrame::MarkIntrinsicISizesDirty()
     175             : {
     176         128 :   SizeNeedsRecalc(mImageSize);
     177         128 :   nsLeafBoxFrame::MarkIntrinsicISizesDirty();
     178         128 : }
     179             : 
     180             : void
     181          30 : nsImageBoxFrame::DestroyFrom(nsIFrame* aDestructRoot)
     182             : {
     183          30 :   if (mImageRequest) {
     184          44 :     nsLayoutUtils::DeregisterImageRequest(PresContext(), mImageRequest,
     185          44 :                                           &mRequestRegistered);
     186             : 
     187             :     // Release image loader first so that it's refcnt can go to zero
     188          22 :     mImageRequest->CancelAndForgetObserver(NS_ERROR_FAILURE);
     189             :   }
     190             : 
     191          30 :   if (mListener)
     192          30 :     reinterpret_cast<nsImageBoxListener*>(mListener.get())->SetFrame(nullptr); // set the frame to null so we don't send messages to a dead object.
     193             : 
     194          30 :   nsLeafBoxFrame::DestroyFrom(aDestructRoot);
     195          30 : }
     196             : 
     197             : 
     198             : void
     199          62 : nsImageBoxFrame::Init(nsIContent*       aContent,
     200             :                       nsContainerFrame* aParent,
     201             :                       nsIFrame*         aPrevInFlow)
     202             : {
     203          62 :   if (!mListener) {
     204         124 :     RefPtr<nsImageBoxListener> listener = new nsImageBoxListener();
     205          62 :     listener->SetFrame(this);
     206          62 :     mListener = listener.forget();
     207             :   }
     208             : 
     209          62 :   mSuppressStyleCheck = true;
     210          62 :   nsLeafBoxFrame::Init(aContent, aParent, aPrevInFlow);
     211          62 :   mSuppressStyleCheck = false;
     212             : 
     213          62 :   UpdateLoadFlags();
     214          62 :   UpdateImage();
     215          62 : }
     216             : 
     217             : void
     218          69 : nsImageBoxFrame::UpdateImage()
     219             : {
     220          69 :   nsPresContext* presContext = PresContext();
     221             : 
     222         138 :   RefPtr<imgRequestProxy> oldImageRequest = mImageRequest;
     223             : 
     224          69 :   if (mImageRequest) {
     225           7 :     nsLayoutUtils::DeregisterImageRequest(presContext, mImageRequest,
     226           7 :                                           &mRequestRegistered);
     227           7 :     mImageRequest->CancelAndForgetObserver(NS_ERROR_FAILURE);
     228           7 :     mImageRequest = nullptr;
     229             :   }
     230             : 
     231             :   // get the new image src
     232         138 :   nsAutoString src;
     233          69 :   mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::src, src);
     234          69 :   mUseSrcAttr = !src.IsEmpty();
     235          69 :   if (mUseSrcAttr) {
     236           1 :     nsIDocument* doc = mContent->GetComposedDoc();
     237           1 :     if (doc) {
     238             :       nsContentPolicyType contentPolicyType;
     239           2 :       nsCOMPtr<nsIPrincipal> loadingPrincipal;
     240           1 :       nsContentUtils::GetContentPolicyTypeForUIImageLoading(mContent,
     241           2 :                                                             getter_AddRefs(loadingPrincipal),
     242           1 :                                                             contentPolicyType);
     243             : 
     244           2 :       nsCOMPtr<nsIURI> baseURI = mContent->GetBaseURI();
     245           2 :       nsCOMPtr<nsIURI> uri;
     246           2 :       nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(uri),
     247             :                                                 src,
     248             :                                                 doc,
     249           1 :                                                 baseURI);
     250           1 :       if (uri) {
     251           3 :         nsresult rv = nsContentUtils::LoadImage(uri, mContent, doc, loadingPrincipal,
     252             :                                                 doc->GetDocumentURI(), doc->GetReferrerPolicy(),
     253             :                                                 mListener, mLoadFlags,
     254           3 :                                                 EmptyString(), getter_AddRefs(mImageRequest),
     255           1 :                                                 contentPolicyType);
     256             : 
     257           1 :         if (NS_SUCCEEDED(rv) && mImageRequest) {
     258           1 :           nsLayoutUtils::RegisterImageRequestIfAnimated(presContext,
     259             :                                                         mImageRequest,
     260           1 :                                                         &mRequestRegistered);
     261             :         }
     262             :       }
     263             :     }
     264             :   } else {
     265             :     // Only get the list-style-image if we aren't being drawn
     266             :     // by a native theme.
     267          68 :     uint8_t appearance = StyleDisplay()->mAppearance;
     268          68 :     if (!(appearance && nsBox::gTheme &&
     269           0 :           nsBox::gTheme->ThemeSupportsWidget(nullptr, this, appearance))) {
     270             :       // get the list-style-image
     271          68 :       imgRequestProxy *styleRequest = StyleList()->GetListStyleImage();
     272          68 :       if (styleRequest) {
     273          52 :         styleRequest->Clone(mListener, getter_AddRefs(mImageRequest));
     274             :       }
     275             :     }
     276             :   }
     277             : 
     278          69 :   if (!mImageRequest) {
     279             :     // We have no image, so size to 0
     280          16 :     mIntrinsicSize.SizeTo(0, 0);
     281             :   } else {
     282             :     // We don't want discarding or decode-on-draw for xul images.
     283          53 :     mImageRequest->StartDecoding(imgIContainer::FLAG_NONE);
     284          53 :     mImageRequest->LockImage();
     285             :   }
     286             : 
     287             :   // Do this _after_ locking the new image in case they are the same image.
     288          69 :   if (oldImageRequest) {
     289           7 :     oldImageRequest->UnlockImage();
     290             :   }
     291          69 : }
     292             : 
     293             : void
     294          62 : nsImageBoxFrame::UpdateLoadFlags()
     295             : {
     296             :   static nsIContent::AttrValuesArray strings[] =
     297             :     {&nsGkAtoms::always, &nsGkAtoms::never, nullptr};
     298         124 :   switch (mContent->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::validate,
     299          62 :                                     strings, eCaseMatters)) {
     300             :     case 0:
     301           0 :       mLoadFlags = nsIRequest::VALIDATE_ALWAYS;
     302           0 :       break;
     303             :     case 1:
     304           1 :       mLoadFlags = nsIRequest::VALIDATE_NEVER|nsIRequest::LOAD_FROM_CACHE;
     305           1 :       break;
     306             :     default:
     307          61 :       mLoadFlags = nsIRequest::LOAD_NORMAL;
     308          61 :       break;
     309             :   }
     310          62 : }
     311             : 
     312             : void
     313         365 : nsImageBoxFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
     314             :                                   const nsRect&           aDirtyRect,
     315             :                                   const nsDisplayListSet& aLists)
     316             : {
     317         365 :   nsLeafBoxFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists);
     318             : 
     319         365 :   if ((0 == mRect.width) || (0 == mRect.height)) {
     320             :     // Do not render when given a zero area. This avoids some useless
     321             :     // scaling work while we wait for our image dimensions to arrive
     322             :     // asynchronously.
     323          24 :     return;
     324             :   }
     325             : 
     326         365 :   if (!IsVisibleForPainting(aBuilder))
     327          24 :     return;
     328             : 
     329             :   uint32_t clipFlags =
     330         341 :     nsStyleUtil::ObjectPropsMightCauseOverflow(StylePosition()) ?
     331         341 :     0 : DisplayListClipState::ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT;
     332             : 
     333             :   DisplayListClipState::AutoClipContainingBlockDescendantsToContentBox
     334         682 :     clip(aBuilder, this, clipFlags);
     335             : 
     336         682 :   nsDisplayList list;
     337             :   list.AppendNewToTop(
     338         341 :     new (aBuilder) nsDisplayXULImage(aBuilder, this));
     339             : 
     340         341 :   CreateOwnLayerIfNeeded(aBuilder, &list);
     341             : 
     342         341 :   aLists.Content()->AppendToTop(&list);
     343             : }
     344             : 
     345             : DrawResult
     346          82 : nsImageBoxFrame::PaintImage(gfxContext& aRenderingContext,
     347             :                             const nsRect& aDirtyRect, nsPoint aPt,
     348             :                             uint32_t aFlags)
     349             : {
     350          82 :   if (!mImageRequest) {
     351             :     // This probably means we're drawn by a native theme.
     352           0 :     return DrawResult::SUCCESS;
     353             :   }
     354             : 
     355             :   // Don't draw if the image's size isn't available.
     356             :   uint32_t imgStatus;
     357         164 :   if (!NS_SUCCEEDED(mImageRequest->GetImageStatus(&imgStatus)) ||
     358          82 :       !(imgStatus & imgIRequest::STATUS_SIZE_AVAILABLE)) {
     359          10 :     return DrawResult::NOT_READY;
     360             :   }
     361             : 
     362         144 :   nsCOMPtr<imgIContainer> imgCon;
     363          72 :   mImageRequest->GetImage(getter_AddRefs(imgCon));
     364             : 
     365          72 :   if (!imgCon) {
     366           0 :     return DrawResult::NOT_READY;
     367             :   }
     368             : 
     369         144 :   Maybe<nsPoint> anchorPoint;
     370         144 :   nsRect dest = GetDestRect(aPt, anchorPoint);
     371             : 
     372             :   // don't draw if the image is not dirty
     373             :   // XXX(seth): Can this actually happen anymore?
     374         144 :   nsRect dirty;
     375          72 :   if (!dirty.IntersectRect(aDirtyRect, dest)) {
     376           0 :     return DrawResult::TEMPORARY_ERROR;
     377             :   }
     378             : 
     379          72 :   bool hasSubRect = !mUseSrcAttr && (mSubRect.width > 0 || mSubRect.height > 0);
     380             : 
     381         144 :   Maybe<SVGImageContext> svgContext;
     382          72 :   SVGImageContext::MaybeStoreContextPaint(svgContext, this, imgCon);
     383         144 :   return nsLayoutUtils::DrawSingleImage(
     384             :            aRenderingContext,
     385             :            PresContext(), imgCon,
     386             :            nsLayoutUtils::GetSamplingFilterForFrame(this),
     387             :            dest, dirty,
     388             :            svgContext, aFlags,
     389          72 :            anchorPoint.ptrOr(nullptr),
     390          72 :            hasSubRect ? &mSubRect : nullptr);
     391             : }
     392             : 
     393             : nsRect
     394          83 : nsImageBoxFrame::GetDestRect(const nsPoint& aOffset, Maybe<nsPoint>& aAnchorPoint)
     395             : {
     396         166 :   nsCOMPtr<imgIContainer> imgCon;
     397          83 :   mImageRequest->GetImage(getter_AddRefs(imgCon));
     398          83 :   MOZ_ASSERT(imgCon);
     399             : 
     400         166 :   nsRect clientRect;
     401          83 :   GetXULClientRect(clientRect);
     402          83 :   clientRect += aOffset;
     403          83 :   nsRect dest;
     404          83 :   if (!mUseSrcAttr) {
     405             :     // Our image (if we have one) is coming from the CSS property
     406             :     // 'list-style-image' (combined with '-moz-image-region'). For now, ignore
     407             :     // 'object-fit' & 'object-position' in this case, and just fill our rect.
     408             :     // XXXdholbert Should we even honor these properties in this case? They only
     409             :     // apply to replaced elements, and I'm not sure we count as a replaced
     410             :     // element when our image data is determined by CSS.
     411          83 :     dest = clientRect;
     412             :   } else {
     413             :     // Determine dest rect based on intrinsic size & ratio, along with
     414             :     // 'object-fit' & 'object-position' properties:
     415           0 :     IntrinsicSize intrinsicSize;
     416           0 :     nsSize intrinsicRatio;
     417           0 :     if (mIntrinsicSize.width > 0 && mIntrinsicSize.height > 0) {
     418             :       // Image has a valid size; use it as intrinsic size & ratio.
     419           0 :       intrinsicSize.width.SetCoordValue(mIntrinsicSize.width);
     420           0 :       intrinsicSize.height.SetCoordValue(mIntrinsicSize.height);
     421           0 :       intrinsicRatio = mIntrinsicSize;
     422             :     } else {
     423             :       // Image doesn't have a (valid) intrinsic size.
     424             :       // Try to look up intrinsic ratio and use that at least.
     425           0 :       imgCon->GetIntrinsicRatio(&intrinsicRatio);
     426             :     }
     427           0 :     aAnchorPoint.emplace();
     428           0 :     dest = nsLayoutUtils::ComputeObjectDestRect(clientRect,
     429             :                                                 intrinsicSize,
     430             :                                                 intrinsicRatio,
     431             :                                                 StylePosition(),
     432             :                                                 aAnchorPoint.ptr());
     433             :   }
     434             : 
     435         166 :   return dest;
     436             : }
     437             : 
     438          82 : void nsDisplayXULImage::Paint(nsDisplayListBuilder* aBuilder,
     439             :                               gfxContext* aCtx)
     440             : {
     441             :   // Even though we call StartDecoding when we get a new image we pass
     442             :   // FLAG_SYNC_DECODE_IF_FAST here for the case where the size we draw at is not
     443             :   // the intrinsic size of the image and we aren't likely to implement predictive
     444             :   // decoding at the correct size for this class like nsImageFrame has.
     445          82 :   uint32_t flags = imgIContainer::FLAG_SYNC_DECODE_IF_FAST;
     446          82 :   if (aBuilder->ShouldSyncDecodeImages())
     447           0 :     flags |= imgIContainer::FLAG_SYNC_DECODE;
     448          82 :   if (aBuilder->IsPaintingToWindow())
     449          82 :     flags |= imgIContainer::FLAG_HIGH_QUALITY_SCALING;
     450             : 
     451          82 :   DrawResult result = static_cast<nsImageBoxFrame*>(mFrame)->
     452         164 :     PaintImage(*aCtx, mVisibleRect, ToReferenceFrame(), flags);
     453             : 
     454          82 :   nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
     455          82 : }
     456             : 
     457             : nsDisplayItemGeometry*
     458          71 : nsDisplayXULImage::AllocateGeometry(nsDisplayListBuilder* aBuilder)
     459             : {
     460          71 :   return new nsDisplayItemGenericImageGeometry(this, aBuilder);
     461             : }
     462             : 
     463             : void
     464         288 : nsDisplayXULImage::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
     465             :                                              const nsDisplayItemGeometry* aGeometry,
     466             :                                              nsRegion* aInvalidRegion)
     467             : {
     468         288 :   auto boxFrame = static_cast<nsImageBoxFrame*>(mFrame);
     469             :   auto geometry =
     470         288 :     static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
     471             : 
     472         576 :   if (aBuilder->ShouldSyncDecodeImages() &&
     473         288 :       boxFrame->mImageRequest &&
     474           0 :       geometry->ShouldInvalidateToSyncDecodeImages()) {
     475             :       bool snap;
     476           0 :       aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
     477             :   }
     478             : 
     479         288 :   nsDisplayImageContainer::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
     480         288 : }
     481             : 
     482             : bool
     483          57 : nsDisplayXULImage::CanOptimizeToImageLayer(LayerManager* aManager,
     484             :                                            nsDisplayListBuilder* aBuilder)
     485             : {
     486          57 :   nsImageBoxFrame* imageFrame = static_cast<nsImageBoxFrame*>(mFrame);
     487          57 :   if (!imageFrame->CanOptimizeToImageLayer()) {
     488           0 :     return false;
     489             :   }
     490             : 
     491          57 :   return nsDisplayImageContainer::CanOptimizeToImageLayer(aManager, aBuilder);
     492             : }
     493             : 
     494             : already_AddRefed<imgIContainer>
     495          57 : nsDisplayXULImage::GetImage()
     496             : {
     497          57 :   nsImageBoxFrame* imageFrame = static_cast<nsImageBoxFrame*>(mFrame);
     498          57 :   if (!imageFrame->mImageRequest) {
     499           0 :     return nullptr;
     500             :   }
     501             : 
     502         114 :   nsCOMPtr<imgIContainer> imgCon;
     503          57 :   imageFrame->mImageRequest->GetImage(getter_AddRefs(imgCon));
     504             : 
     505          57 :   return imgCon.forget();
     506             : }
     507             : 
     508             : nsRect
     509          11 : nsDisplayXULImage::GetDestRect()
     510             : {
     511          22 :   Maybe<nsPoint> anchorPoint;
     512          22 :   return static_cast<nsImageBoxFrame*>(mFrame)->GetDestRect(ToReferenceFrame(), anchorPoint);
     513             : }
     514             : 
     515             : bool
     516          57 : nsImageBoxFrame::CanOptimizeToImageLayer()
     517             : {
     518          57 :   bool hasSubRect = !mUseSrcAttr && (mSubRect.width > 0 || mSubRect.height > 0);
     519          57 :   if (hasSubRect) {
     520           0 :     return false;
     521             :   }
     522          57 :   return true;
     523             : }
     524             : 
     525             : //
     526             : // DidSetStyleContext
     527             : //
     528             : // When the style context changes, make sure that all of our image is up to date.
     529             : //
     530             : /* virtual */ void
     531         139 : nsImageBoxFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
     532             : {
     533         139 :   nsLeafBoxFrame::DidSetStyleContext(aOldStyleContext);
     534             : 
     535             :   // Fetch our subrect.
     536         139 :   const nsStyleList* myList = StyleList();
     537         139 :   mSubRect = myList->mImageRegion; // before |mSuppressStyleCheck| test!
     538             : 
     539         139 :   if (mUseSrcAttr || mSuppressStyleCheck)
     540         195 :     return; // No more work required, since the image isn't specified by style.
     541             : 
     542             :   // If we're using a native theme implementation, we shouldn't draw anything.
     543          77 :   const nsStyleDisplay* disp = StyleDisplay();
     544          77 :   if (disp->mAppearance && nsBox::gTheme &&
     545           0 :       nsBox::gTheme->ThemeSupportsWidget(nullptr, this, disp->mAppearance))
     546           0 :     return;
     547             : 
     548             :   // If list-style-image changes, we have a new image.
     549          83 :   nsCOMPtr<nsIURI> oldURI, newURI;
     550          77 :   if (mImageRequest)
     551          55 :     mImageRequest->GetURI(getter_AddRefs(oldURI));
     552          77 :   if (myList->GetListStyleImage())
     553          55 :     myList->GetListStyleImage()->GetURI(getter_AddRefs(newURI));
     554             :   bool equal;
     555         154 :   if (newURI == oldURI ||   // handles null==null
     556          18 :       (newURI && oldURI &&
     557          12 :        NS_SUCCEEDED(newURI->Equals(oldURI, &equal)) && equal))
     558          71 :     return;
     559             : 
     560           6 :   UpdateImage();
     561             : } // DidSetStyleContext
     562             : 
     563             : void
     564          79 : nsImageBoxFrame::GetImageSize()
     565             : {
     566          79 :   if (mIntrinsicSize.width > 0 && mIntrinsicSize.height > 0) {
     567          42 :     mImageSize.width = mIntrinsicSize.width;
     568          42 :     mImageSize.height = mIntrinsicSize.height;
     569             :   } else {
     570          37 :     mImageSize.width = 0;
     571          37 :     mImageSize.height = 0;
     572             :   }
     573          79 : }
     574             : 
     575             : /**
     576             :  * Ok return our dimensions
     577             :  */
     578             : nsSize
     579         472 : nsImageBoxFrame::GetXULPrefSize(nsBoxLayoutState& aState)
     580             : {
     581         472 :   nsSize size(0,0);
     582         944 :   DISPLAY_PREF_SIZE(this, size);
     583         472 :   if (DoesNeedRecalc(mImageSize))
     584          79 :      GetImageSize();
     585             : 
     586         472 :   if (!mUseSrcAttr && (mSubRect.width > 0 || mSubRect.height > 0))
     587          42 :     size = mSubRect.Size();
     588             :   else
     589         430 :     size = mImageSize;
     590             : 
     591         472 :   nsSize intrinsicSize = size;
     592             : 
     593         472 :   nsMargin borderPadding(0,0,0,0);
     594         472 :   GetXULBorderAndPadding(borderPadding);
     595         472 :   size.width += borderPadding.LeftRight();
     596         472 :   size.height += borderPadding.TopBottom();
     597             : 
     598             :   bool widthSet, heightSet;
     599         472 :   nsIFrame::AddXULPrefSize(this, size, widthSet, heightSet);
     600         472 :   NS_ASSERTION(size.width != NS_INTRINSICSIZE && size.height != NS_INTRINSICSIZE,
     601             :                "non-intrinsic size expected");
     602             : 
     603         472 :   nsSize minSize = GetXULMinSize(aState);
     604         472 :   nsSize maxSize = GetXULMaxSize(aState);
     605             : 
     606         472 :   if (!widthSet && !heightSet) {
     607         255 :     if (minSize.width != NS_INTRINSICSIZE)
     608         255 :       minSize.width -= borderPadding.LeftRight();
     609         255 :     if (minSize.height != NS_INTRINSICSIZE)
     610         255 :       minSize.height -= borderPadding.TopBottom();
     611         255 :     if (maxSize.width != NS_INTRINSICSIZE)
     612         178 :       maxSize.width -= borderPadding.LeftRight();
     613         255 :     if (maxSize.height != NS_INTRINSICSIZE)
     614           0 :       maxSize.height -= borderPadding.TopBottom();
     615             : 
     616             :     size = nsLayoutUtils::ComputeAutoSizeWithIntrinsicDimensions(minSize.width, minSize.height,
     617             :                                                                  maxSize.width, maxSize.height,
     618         255 :                                                                  intrinsicSize.width, intrinsicSize.height);
     619         255 :     NS_ASSERTION(size.width != NS_INTRINSICSIZE && size.height != NS_INTRINSICSIZE,
     620             :                  "non-intrinsic size expected");
     621         255 :     size.width += borderPadding.LeftRight();
     622         255 :     size.height += borderPadding.TopBottom();
     623         255 :     return size;
     624             :   }
     625             : 
     626         217 :   if (!widthSet) {
     627          26 :     if (intrinsicSize.height > 0) {
     628             :       // Subtract off the border and padding from the height because the
     629             :       // content-box needs to be used to determine the ratio
     630           0 :       nscoord height = size.height - borderPadding.TopBottom();
     631           0 :       size.width = nscoord(int64_t(height) * int64_t(intrinsicSize.width) /
     632           0 :                            int64_t(intrinsicSize.height));
     633             :     }
     634             :     else {
     635          26 :       size.width = intrinsicSize.width;
     636             :     }
     637             : 
     638          26 :     size.width += borderPadding.LeftRight();
     639             :   }
     640         191 :   else if (!heightSet) {
     641          63 :     if (intrinsicSize.width > 0) {
     642          56 :       nscoord width = size.width - borderPadding.LeftRight();
     643         168 :       size.height = nscoord(int64_t(width) * int64_t(intrinsicSize.height) /
     644         112 :                             int64_t(intrinsicSize.width));
     645             :     }
     646             :     else {
     647           7 :       size.height = intrinsicSize.height;
     648             :     }
     649             : 
     650          63 :     size.height += borderPadding.TopBottom();
     651             :   }
     652             : 
     653         217 :   return BoundsCheck(minSize, size, maxSize);
     654             : }
     655             : 
     656             : nsSize
     657         783 : nsImageBoxFrame::GetXULMinSize(nsBoxLayoutState& aState)
     658             : {
     659             :   // An image can always scale down to (0,0).
     660         783 :   nsSize size(0,0);
     661        1566 :   DISPLAY_MIN_SIZE(this, size);
     662         783 :   AddBorderAndPadding(size);
     663             :   bool widthSet, heightSet;
     664         783 :   nsIFrame::AddXULMinSize(aState, this, size, widthSet, heightSet);
     665        1566 :   return size;
     666             : }
     667             : 
     668             : nscoord
     669         218 : nsImageBoxFrame::GetXULBoxAscent(nsBoxLayoutState& aState)
     670             : {
     671         218 :   return GetXULPrefSize(aState).height;
     672             : }
     673             : 
     674             : #ifdef DEBUG_FRAME_DUMP
     675             : nsresult
     676           0 : nsImageBoxFrame::GetFrameName(nsAString& aResult) const
     677             : {
     678           0 :   return MakeFrameName(NS_LITERAL_STRING("ImageBox"), aResult);
     679             : }
     680             : #endif
     681             : 
     682             : nsresult
     683         316 : nsImageBoxFrame::Notify(imgIRequest* aRequest,
     684             :                         int32_t aType,
     685             :                         const nsIntRect* aData)
     686             : {
     687         316 :   if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
     688          96 :     nsCOMPtr<imgIContainer> image;
     689          48 :     aRequest->GetImage(getter_AddRefs(image));
     690          48 :     return OnSizeAvailable(aRequest, image);
     691             :   }
     692             : 
     693         268 :   if (aType == imgINotificationObserver::DECODE_COMPLETE) {
     694          48 :     return OnDecodeComplete(aRequest);
     695             :   }
     696             : 
     697         220 :   if (aType == imgINotificationObserver::LOAD_COMPLETE) {
     698             :     uint32_t imgStatus;
     699          49 :     aRequest->GetImageStatus(&imgStatus);
     700             :     nsresult status =
     701          49 :         imgStatus & imgIRequest::STATUS_ERROR ? NS_ERROR_FAILURE : NS_OK;
     702          49 :     return OnLoadComplete(aRequest, status);
     703             :   }
     704             : 
     705         171 :   if (aType == imgINotificationObserver::IS_ANIMATED) {
     706           2 :     return OnImageIsAnimated(aRequest);
     707             :   }
     708             : 
     709         169 :   if (aType == imgINotificationObserver::FRAME_UPDATE) {
     710          73 :     return OnFrameUpdate(aRequest);
     711             :   }
     712             : 
     713          96 :   return NS_OK;
     714             : }
     715             : 
     716             : nsresult
     717          48 : nsImageBoxFrame::OnSizeAvailable(imgIRequest* aRequest, imgIContainer* aImage)
     718             : {
     719          48 :   NS_ENSURE_ARG_POINTER(aImage);
     720             : 
     721             :   // Ensure the animation (if any) is started. Note: There is no
     722             :   // corresponding call to Decrement for this. This Increment will be
     723             :   // 'cleaned up' by the Request when it is destroyed, but only then.
     724          48 :   aRequest->IncrementAnimationConsumers();
     725             : 
     726             :   nscoord w, h;
     727          48 :   aImage->GetWidth(&w);
     728          48 :   aImage->GetHeight(&h);
     729             : 
     730          48 :   mIntrinsicSize.SizeTo(nsPresContext::CSSPixelsToAppUnits(w),
     731          48 :                         nsPresContext::CSSPixelsToAppUnits(h));
     732             : 
     733          48 :   if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
     734          32 :     PresContext()->PresShell()->
     735          32 :       FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
     736             :   }
     737             : 
     738          48 :   return NS_OK;
     739             : }
     740             : 
     741             : nsresult
     742          48 : nsImageBoxFrame::OnDecodeComplete(imgIRequest* aRequest)
     743             : {
     744          96 :   nsBoxLayoutState state(PresContext());
     745          48 :   this->XULRedraw(state);
     746          96 :   return NS_OK;
     747             : }
     748             : 
     749             : nsresult
     750          49 : nsImageBoxFrame::OnLoadComplete(imgIRequest* aRequest, nsresult aStatus)
     751             : {
     752          49 :   if (NS_SUCCEEDED(aStatus)) {
     753             :     // Fire an onload DOM event.
     754          48 :     FireImageDOMEvent(mContent, eLoad);
     755             :   } else {
     756             :     // Fire an onerror DOM event.
     757           1 :     mIntrinsicSize.SizeTo(0, 0);
     758           1 :     PresContext()->PresShell()->
     759           1 :       FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
     760           1 :     FireImageDOMEvent(mContent, eLoadError);
     761             :   }
     762             : 
     763          49 :   return NS_OK;
     764             : }
     765             : 
     766             : nsresult
     767           2 : nsImageBoxFrame::OnImageIsAnimated(imgIRequest* aRequest)
     768             : {
     769             :   // Register with our refresh driver, if we're animated.
     770           2 :   nsLayoutUtils::RegisterImageRequest(PresContext(), aRequest,
     771           2 :                                       &mRequestRegistered);
     772             : 
     773           2 :   return NS_OK;
     774             : }
     775             : 
     776             : nsresult
     777          73 : nsImageBoxFrame::OnFrameUpdate(imgIRequest* aRequest)
     778             : {
     779          73 :   if ((0 == mRect.width) || (0 == mRect.height)) {
     780          36 :     return NS_OK;
     781             :   }
     782             : 
     783          37 :   InvalidateLayer(nsDisplayItem::TYPE_XUL_IMAGE);
     784             : 
     785          37 :   return NS_OK;
     786             : }
     787             : 
     788        2330 : NS_IMPL_ISUPPORTS(nsImageBoxListener, imgINotificationObserver, imgIOnloadBlocker)
     789             : 
     790          62 : nsImageBoxListener::nsImageBoxListener()
     791             : {
     792          62 : }
     793             : 
     794          60 : nsImageBoxListener::~nsImageBoxListener()
     795             : {
     796          90 : }
     797             : 
     798             : NS_IMETHODIMP
     799         316 : nsImageBoxListener::Notify(imgIRequest *request, int32_t aType, const nsIntRect* aData)
     800             : {
     801         316 :   if (!mFrame)
     802           0 :     return NS_OK;
     803             : 
     804         316 :   return mFrame->Notify(request, aType, aData);
     805             : }
     806             : 
     807             : NS_IMETHODIMP
     808          61 : nsImageBoxListener::BlockOnload(imgIRequest *aRequest)
     809             : {
     810          61 :   if (mFrame && mFrame->GetContent() && mFrame->GetContent()->GetUncomposedDoc()) {
     811          61 :     mFrame->GetContent()->GetUncomposedDoc()->BlockOnload();
     812             :   }
     813             : 
     814          61 :   return NS_OK;
     815             : }
     816             : 
     817             : NS_IMETHODIMP
     818          61 : nsImageBoxListener::UnblockOnload(imgIRequest *aRequest)
     819             : {
     820          61 :   if (mFrame && mFrame->GetContent() && mFrame->GetContent()->GetUncomposedDoc()) {
     821          61 :     mFrame->GetContent()->GetUncomposedDoc()->UnblockOnload(false);
     822             :   }
     823             : 
     824          61 :   return NS_OK;
     825             : }

Generated by: LCOV version 1.13