LCOV - code coverage report
Current view: top level - layout/generic - nsImageFrame.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 1121 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 102 0.0 %
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             : /* rendering object for replaced elements with image data */
       7             : 
       8             : #include "nsImageFrame.h"
       9             : 
      10             : #include "gfx2DGlue.h"
      11             : #include "gfxContext.h"
      12             : #include "gfxUtils.h"
      13             : #include "mozilla/DebugOnly.h"
      14             : #include "mozilla/Encoding.h"
      15             : #include "mozilla/EventStates.h"
      16             : #include "mozilla/gfx/2D.h"
      17             : #include "mozilla/gfx/Helpers.h"
      18             : #include "mozilla/gfx/PathHelpers.h"
      19             : #include "mozilla/layers/WebRenderLayerManager.h"
      20             : #include "mozilla/MouseEvents.h"
      21             : #include "mozilla/Unused.h"
      22             : 
      23             : #include "nsCOMPtr.h"
      24             : #include "nsFontMetrics.h"
      25             : #include "nsIImageLoadingContent.h"
      26             : #include "nsString.h"
      27             : #include "nsPrintfCString.h"
      28             : #include "nsPresContext.h"
      29             : #include "nsIPresShell.h"
      30             : #include "nsGkAtoms.h"
      31             : #include "nsIDocument.h"
      32             : #include "nsContentUtils.h"
      33             : #include "nsCSSAnonBoxes.h"
      34             : #include "nsStyleContext.h"
      35             : #include "nsStyleConsts.h"
      36             : #include "nsStyleCoord.h"
      37             : #include "nsStyleUtil.h"
      38             : #include "nsTransform2D.h"
      39             : #include "nsImageMap.h"
      40             : #include "nsIIOService.h"
      41             : #include "nsILoadGroup.h"
      42             : #include "nsISupportsPriority.h"
      43             : #include "nsNetUtil.h"
      44             : #include "nsNetCID.h"
      45             : #include "nsCSSRendering.h"
      46             : #include "nsIDOMHTMLAnchorElement.h"
      47             : #include "nsNameSpaceManager.h"
      48             : #include <algorithm>
      49             : #ifdef ACCESSIBILITY
      50             : #include "nsAccessibilityService.h"
      51             : #endif
      52             : #include "nsIDOMNode.h"
      53             : #include "nsLayoutUtils.h"
      54             : #include "nsDisplayList.h"
      55             : #include "nsIContent.h"
      56             : #include "nsIDocument.h"
      57             : #include "FrameLayerBuilder.h"
      58             : #include "nsISelectionController.h"
      59             : #include "nsISelection.h"
      60             : 
      61             : #include "imgIContainer.h"
      62             : #include "imgLoader.h"
      63             : #include "imgRequestProxy.h"
      64             : 
      65             : #include "nsCSSFrameConstructor.h"
      66             : #include "nsIDOMRange.h"
      67             : 
      68             : #include "nsError.h"
      69             : #include "nsBidiUtils.h"
      70             : #include "nsBidiPresUtils.h"
      71             : 
      72             : #include "gfxRect.h"
      73             : #include "ImageLayers.h"
      74             : #include "ImageContainer.h"
      75             : #include "mozilla/StyleSetHandle.h"
      76             : #include "mozilla/StyleSetHandleInlines.h"
      77             : #include "nsBlockFrame.h"
      78             : #include "nsStyleStructInlines.h"
      79             : 
      80             : #include "mozilla/Preferences.h"
      81             : 
      82             : #include "mozilla/dom/Link.h"
      83             : #include "SVGImageContext.h"
      84             : 
      85             : using namespace mozilla;
      86             : using namespace mozilla::dom;
      87             : using namespace mozilla::gfx;
      88             : using namespace mozilla::image;
      89             : using namespace mozilla::layers;
      90             : 
      91             : // sizes (pixels) for image icon, padding and border frame
      92             : #define ICON_SIZE        (16)
      93             : #define ICON_PADDING     (3)
      94             : #define ALT_BORDER_WIDTH (1)
      95             : 
      96             : //we must add hooks soon
      97             : #define IMAGE_EDITOR_CHECK 1
      98             : 
      99             : // Default alignment value (so we can tell an unset value from a set value)
     100             : #define ALIGN_UNSET uint8_t(-1)
     101             : 
     102             : // static icon information
     103             : nsImageFrame::IconLoad* nsImageFrame::gIconLoad = nullptr;
     104             : 
     105             : // cached IO service for loading icons
     106             : nsIIOService* nsImageFrame::sIOService;
     107             : 
     108             : // test if the width and height are fixed, looking at the style data
     109             : // This is used by nsImageFrame::ShouldCreateImageFrameFor and should
     110             : // not be used for layout decisions.
     111           0 : static bool HaveSpecifiedSize(const nsStylePosition* aStylePosition)
     112             : {
     113             :   // check the width and height values in the reflow state's style struct
     114             :   // - if width and height are specified as either coord or percentage, then
     115             :   //   the size of the image frame is constrained
     116           0 :   return aStylePosition->mWidth.IsCoordPercentCalcUnit() &&
     117           0 :          aStylePosition->mHeight.IsCoordPercentCalcUnit();
     118             : }
     119             : 
     120             : // Decide whether we can optimize away reflows that result from the
     121             : // image's intrinsic size changing.
     122           0 : inline bool HaveFixedSize(const ReflowInput& aReflowInput)
     123             : {
     124           0 :   NS_ASSERTION(aReflowInput.mStylePosition, "crappy reflowInput - null stylePosition");
     125             :   // Don't try to make this optimization when an image has percentages
     126             :   // in its 'width' or 'height'.  The percentages might be treated like
     127             :   // auto (especially for intrinsic width calculations and for heights).
     128           0 :   return aReflowInput.mStylePosition->mHeight.ConvertsToLength() &&
     129           0 :          aReflowInput.mStylePosition->mWidth.ConvertsToLength();
     130             : }
     131             : 
     132             : nsIFrame*
     133           0 : NS_NewImageFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
     134             : {
     135           0 :   return new (aPresShell) nsImageFrame(aContext);
     136             : }
     137             : 
     138           0 : NS_IMPL_FRAMEARENA_HELPERS(nsImageFrame)
     139             : 
     140           0 : nsImageFrame::nsImageFrame(nsStyleContext* aContext, ClassID aID)
     141             :   : nsAtomicContainerFrame(aContext, aID)
     142             :   , mComputedSize(0, 0)
     143             :   , mIntrinsicRatio(0, 0)
     144             :   , mDisplayingIcon(false)
     145             :   , mFirstFrameComplete(false)
     146             :   , mReflowCallbackPosted(false)
     147           0 :   , mForceSyncDecoding(false)
     148             : {
     149           0 :   EnableVisibilityTracking();
     150             : 
     151             :   // We assume our size is not constrained and we haven't gotten an
     152             :   // initial reflow yet, so don't touch those flags.
     153           0 :   mIntrinsicSize.width.SetCoordValue(0);
     154           0 :   mIntrinsicSize.height.SetCoordValue(0);
     155           0 : }
     156             : 
     157           0 : nsImageFrame::~nsImageFrame()
     158             : {
     159           0 : }
     160             : 
     161           0 : NS_QUERYFRAME_HEAD(nsImageFrame)
     162           0 :   NS_QUERYFRAME_ENTRY(nsImageFrame)
     163           0 : NS_QUERYFRAME_TAIL_INHERITING(nsAtomicContainerFrame)
     164             : 
     165             : #ifdef ACCESSIBILITY
     166             : a11y::AccType
     167           0 : nsImageFrame::AccessibleType()
     168             : {
     169             :   // Don't use GetImageMap() to avoid reentrancy into accessibility.
     170           0 :   if (HasImageMap()) {
     171           0 :     return a11y::eHTMLImageMapType;
     172             :   }
     173             : 
     174           0 :   return a11y::eImageType;
     175             : }
     176             : #endif
     177             : 
     178             : void
     179           0 : nsImageFrame::DisconnectMap()
     180             : {
     181           0 :   if (mImageMap) {
     182           0 :     mImageMap->Destroy();
     183           0 :     mImageMap = nullptr;
     184             : 
     185             : #ifdef ACCESSIBILITY
     186           0 :   nsAccessibilityService* accService = GetAccService();
     187           0 :   if (accService) {
     188           0 :     accService->RecreateAccessible(PresContext()->PresShell(), mContent);
     189             :   }
     190             : #endif
     191             :   }
     192           0 : }
     193             : 
     194             : void
     195           0 : nsImageFrame::DestroyFrom(nsIFrame* aDestructRoot)
     196             : {
     197           0 :   if (mReflowCallbackPosted) {
     198           0 :     PresContext()->PresShell()->CancelReflowCallback(this);
     199           0 :     mReflowCallbackPosted = false;
     200             :   }
     201             : 
     202             :   // Tell our image map, if there is one, to clean up
     203             :   // This causes the nsImageMap to unregister itself as
     204             :   // a DOM listener.
     205           0 :   DisconnectMap();
     206             : 
     207             :   // set the frame to null so we don't send messages to a dead object.
     208           0 :   if (mListener) {
     209           0 :     nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
     210           0 :     if (imageLoader) {
     211             :       // Notify our image loading content that we are going away so it can
     212             :       // deregister with our refresh driver.
     213           0 :       imageLoader->FrameDestroyed(this);
     214             : 
     215           0 :       imageLoader->RemoveObserver(mListener);
     216             :     }
     217             : 
     218           0 :     reinterpret_cast<nsImageListener*>(mListener.get())->SetFrame(nullptr);
     219             :   }
     220             : 
     221           0 :   mListener = nullptr;
     222             : 
     223             :   // If we were displaying an icon, take ourselves off the list
     224           0 :   if (mDisplayingIcon)
     225           0 :     gIconLoad->RemoveIconObserver(this);
     226             : 
     227           0 :   nsAtomicContainerFrame::DestroyFrom(aDestructRoot);
     228           0 : }
     229             : 
     230             : void
     231           0 : nsImageFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
     232             : {
     233           0 :   nsAtomicContainerFrame::DidSetStyleContext(aOldStyleContext);
     234             : 
     235           0 :   if (!mImage) {
     236             :     // We'll pick this change up whenever we do get an image.
     237           0 :     return;
     238             :   }
     239             : 
     240           0 :   nsStyleImageOrientation newOrientation = StyleVisibility()->mImageOrientation;
     241             : 
     242             :   // We need to update our orientation either if we had no style context before
     243             :   // because this is the first time it's been set, or if the image-orientation
     244             :   // property changed from its previous value.
     245             :   bool shouldUpdateOrientation =
     246           0 :     !aOldStyleContext ||
     247           0 :     aOldStyleContext->StyleVisibility()->mImageOrientation != newOrientation;
     248             : 
     249           0 :   if (shouldUpdateOrientation) {
     250           0 :     nsCOMPtr<imgIContainer> image(mImage->Unwrap());
     251           0 :     mImage = nsLayoutUtils::OrientImage(image, newOrientation);
     252             : 
     253           0 :     UpdateIntrinsicSize(mImage);
     254           0 :     UpdateIntrinsicRatio(mImage);
     255             :   }
     256             : }
     257             : 
     258             : void
     259           0 : nsImageFrame::Init(nsIContent*       aContent,
     260             :                    nsContainerFrame* aParent,
     261             :                    nsIFrame*         aPrevInFlow)
     262             : {
     263           0 :   nsAtomicContainerFrame::Init(aContent, aParent, aPrevInFlow);
     264             : 
     265           0 :   mListener = new nsImageListener(this);
     266             : 
     267           0 :   nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(aContent);
     268           0 :   if (!imageLoader) {
     269           0 :     MOZ_CRASH("Why do we have an nsImageFrame here at all?");
     270             :   }
     271             : 
     272           0 :   imageLoader->AddObserver(mListener);
     273             : 
     274           0 :   nsPresContext *aPresContext = PresContext();
     275             : 
     276           0 :   if (!gIconLoad)
     277           0 :     LoadIcons(aPresContext);
     278             : 
     279             :   // We have a PresContext now, so we need to notify the image content node
     280             :   // that it can register images.
     281           0 :   imageLoader->FrameCreated(this);
     282             : 
     283             :   // Give image loads associated with an image frame a small priority boost!
     284           0 :   nsCOMPtr<imgIRequest> currentRequest;
     285           0 :   imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
     286           0 :                           getter_AddRefs(currentRequest));
     287             : 
     288           0 :   if (currentRequest) {
     289           0 :     uint32_t categoryToBoostPriority = imgIRequest::CATEGORY_FRAME_INIT;
     290             : 
     291             :     // Increase load priority further if intrinsic size might be important for layout.
     292           0 :     if (!HaveSpecifiedSize(StylePosition())) {
     293           0 :       categoryToBoostPriority |= imgIRequest::CATEGORY_SIZE_QUERY;
     294             :     }
     295             : 
     296           0 :     currentRequest->BoostPriority(categoryToBoostPriority);
     297             :   }
     298           0 : }
     299             : 
     300             : bool
     301           0 : nsImageFrame::UpdateIntrinsicSize(imgIContainer* aImage)
     302             : {
     303           0 :   NS_PRECONDITION(aImage, "null image");
     304           0 :   if (!aImage)
     305           0 :     return false;
     306             : 
     307           0 :   IntrinsicSize oldIntrinsicSize = mIntrinsicSize;
     308           0 :   mIntrinsicSize = IntrinsicSize();
     309             : 
     310             :   // Set intrinsic size to match aImage's reported intrinsic width & height.
     311           0 :   nsSize intrinsicSize;
     312           0 :   if (NS_SUCCEEDED(aImage->GetIntrinsicSize(&intrinsicSize))) {
     313             :     // If the image has no intrinsic width, intrinsicSize.width will be -1, and
     314             :     // we can leave mIntrinsicSize.width at its default value of eStyleUnit_None.
     315             :     // Otherwise we use intrinsicSize.width. Height works the same way.
     316           0 :     if (intrinsicSize.width != -1)
     317           0 :       mIntrinsicSize.width.SetCoordValue(intrinsicSize.width);
     318           0 :     if (intrinsicSize.height != -1)
     319           0 :       mIntrinsicSize.height.SetCoordValue(intrinsicSize.height);
     320             :   } else {
     321             :     // Failure means that the image hasn't loaded enough to report a result. We
     322             :     // treat this case as if the image's intrinsic size was 0x0.
     323           0 :     mIntrinsicSize.width.SetCoordValue(0);
     324           0 :     mIntrinsicSize.height.SetCoordValue(0);
     325             :   }
     326             : 
     327           0 :   return mIntrinsicSize != oldIntrinsicSize;
     328             : }
     329             : 
     330             : bool
     331           0 : nsImageFrame::UpdateIntrinsicRatio(imgIContainer* aImage)
     332             : {
     333           0 :   NS_PRECONDITION(aImage, "null image");
     334             : 
     335           0 :   if (!aImage)
     336           0 :     return false;
     337             : 
     338           0 :   nsSize oldIntrinsicRatio = mIntrinsicRatio;
     339             : 
     340             :   // Set intrinsic ratio to match aImage's reported intrinsic ratio.
     341           0 :   if (NS_FAILED(aImage->GetIntrinsicRatio(&mIntrinsicRatio)))
     342           0 :     mIntrinsicRatio.SizeTo(0, 0);
     343             : 
     344           0 :   return mIntrinsicRatio != oldIntrinsicRatio;
     345             : }
     346             : 
     347             : bool
     348           0 : nsImageFrame::GetSourceToDestTransform(nsTransform2D& aTransform)
     349             : {
     350             :   // First, figure out destRect (the rect we're rendering into).
     351             :   // NOTE: We use mComputedSize instead of just GetInnerArea()'s own size here,
     352             :   // because GetInnerArea() might be smaller if we're fragmented, whereas
     353             :   // mComputedSize has our full content-box size (which we need for
     354             :   // ComputeObjectDestRect to work correctly).
     355           0 :   nsRect constraintRect(GetInnerArea().TopLeft(), mComputedSize);
     356           0 :   constraintRect.y -= GetContinuationOffset();
     357             : 
     358             :   nsRect destRect = nsLayoutUtils::ComputeObjectDestRect(constraintRect,
     359             :                                                          mIntrinsicSize,
     360             :                                                          mIntrinsicRatio,
     361           0 :                                                          StylePosition());
     362             :   // Set the translation components, based on destRect
     363             :   // XXXbz does this introduce rounding errors because of the cast to
     364             :   // float?  Should we just manually add that stuff in every time
     365             :   // instead?
     366           0 :   aTransform.SetToTranslate(float(destRect.x),
     367           0 :                             float(destRect.y));
     368             : 
     369             :   // Set the scale factors, based on destRect and intrinsic size.
     370           0 :   if (mIntrinsicSize.width.GetUnit() == eStyleUnit_Coord &&
     371           0 :       mIntrinsicSize.width.GetCoordValue() != 0 &&
     372           0 :       mIntrinsicSize.height.GetUnit() == eStyleUnit_Coord &&
     373           0 :       mIntrinsicSize.height.GetCoordValue() != 0 &&
     374           0 :       mIntrinsicSize.width.GetCoordValue() != destRect.width &&
     375           0 :       mIntrinsicSize.height.GetCoordValue() != destRect.height) {
     376             : 
     377           0 :     aTransform.SetScale(float(destRect.width)  /
     378           0 :                         float(mIntrinsicSize.width.GetCoordValue()),
     379           0 :                         float(destRect.height) /
     380           0 :                         float(mIntrinsicSize.height.GetCoordValue()));
     381           0 :     return true;
     382             :   }
     383             : 
     384           0 :   return false;
     385             : }
     386             : 
     387             : // This function checks whether the given request is the current request for our
     388             : // mContent.
     389             : bool
     390           0 : nsImageFrame::IsPendingLoad(imgIRequest* aRequest) const
     391             : {
     392             :   // Default to pending load in case of errors
     393           0 :   nsCOMPtr<nsIImageLoadingContent> imageLoader(do_QueryInterface(mContent));
     394           0 :   NS_ASSERTION(imageLoader, "No image loading content?");
     395             : 
     396           0 :   int32_t requestType = nsIImageLoadingContent::UNKNOWN_REQUEST;
     397           0 :   imageLoader->GetRequestType(aRequest, &requestType);
     398             : 
     399           0 :   return requestType != nsIImageLoadingContent::CURRENT_REQUEST;
     400             : }
     401             : 
     402             : nsRect
     403           0 : nsImageFrame::SourceRectToDest(const nsIntRect& aRect)
     404             : {
     405             :   // When scaling the image, row N of the source image may (depending on
     406             :   // the scaling function) be used to draw any row in the destination image
     407             :   // between floor(F * (N-1)) and ceil(F * (N+1)), where F is the
     408             :   // floating-point scaling factor.  The same holds true for columns.
     409             :   // So, we start by computing that bound without the floor and ceiling.
     410             : 
     411           0 :   nsRect r(nsPresContext::CSSPixelsToAppUnits(aRect.x - 1),
     412           0 :            nsPresContext::CSSPixelsToAppUnits(aRect.y - 1),
     413           0 :            nsPresContext::CSSPixelsToAppUnits(aRect.width + 2),
     414           0 :            nsPresContext::CSSPixelsToAppUnits(aRect.height + 2));
     415             : 
     416           0 :   nsTransform2D sourceToDest;
     417           0 :   if (!GetSourceToDestTransform(sourceToDest)) {
     418             :     // Failed to generate transform matrix. Return our whole inner area,
     419             :     // to be on the safe side (since this method is used for generating
     420             :     // invalidation rects).
     421           0 :     return GetInnerArea();
     422             :   }
     423             : 
     424           0 :   sourceToDest.TransformCoord(&r.x, &r.y, &r.width, &r.height);
     425             : 
     426             :   // Now, round the edges out to the pixel boundary.
     427           0 :   nscoord scale = nsPresContext::CSSPixelsToAppUnits(1);
     428           0 :   nscoord right = r.x + r.width;
     429           0 :   nscoord bottom = r.y + r.height;
     430             : 
     431           0 :   r.x -= (scale + (r.x % scale)) % scale;
     432           0 :   r.y -= (scale + (r.y % scale)) % scale;
     433           0 :   r.width = right + ((scale - (right % scale)) % scale) - r.x;
     434           0 :   r.height = bottom + ((scale - (bottom % scale)) % scale) - r.y;
     435             : 
     436           0 :   return r;
     437             : }
     438             : 
     439             : // Note that we treat NS_EVENT_STATE_SUPPRESSED images as "OK".  This means
     440             : // that we'll construct image frames for them as needed if their display is
     441             : // toggled from "none" (though we won't paint them, unless their visibility
     442             : // is changed too).
     443             : #define BAD_STATES (NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_USERDISABLED | \
     444             :                     NS_EVENT_STATE_LOADING)
     445             : 
     446             : // This is a macro so that we don't evaluate the boolean last arg
     447             : // unless we have to; it can be expensive
     448             : #define IMAGE_OK(_state, _loadingOK)                                           \
     449             :    (!(_state).HasAtLeastOneOfStates(BAD_STATES) ||                                    \
     450             :     (!(_state).HasAtLeastOneOfStates(NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_USERDISABLED) && \
     451             :      (_state).HasState(NS_EVENT_STATE_LOADING) && (_loadingOK)))
     452             : 
     453             : /* static */
     454             : bool
     455           0 : nsImageFrame::ShouldCreateImageFrameFor(Element* aElement,
     456             :                                         nsStyleContext* aStyleContext)
     457             : {
     458           0 :   EventStates state = aElement->State();
     459           0 :   if (IMAGE_OK(state,
     460             :                HaveSpecifiedSize(aStyleContext->StylePosition()))) {
     461             :     // Image is fine; do the image frame thing
     462           0 :     return true;
     463             :   }
     464             : 
     465             :   // Check if we want to use a placeholder box with an icon or just
     466             :   // let the presShell make us into inline text.  Decide as follows:
     467             :   //
     468             :   //  - if our special "force icons" style is set, show an icon
     469             :   //  - else if our "do not show placeholders" pref is set, skip the icon
     470             :   //  - else:
     471             :   //  - if there is a src attribute, there is no alt attribute,
     472             :   //    and this is not an <object> (which could not possibly have
     473             :   //    such an attribute), show an icon.
     474             :   //  - if QuirksMode, and the IMG has a size show an icon.
     475             :   //  - otherwise, skip the icon
     476             :   bool useSizedBox;
     477             : 
     478           0 :   if (aStyleContext->StyleUIReset()->mForceBrokenImageIcon) {
     479           0 :     useSizedBox = true;
     480             :   }
     481           0 :   else if (gIconLoad && gIconLoad->mPrefForceInlineAltText) {
     482           0 :     useSizedBox = false;
     483             :   }
     484           0 :   else if (aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::src) &&
     485           0 :            !aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::alt) &&
     486           0 :            !aElement->IsHTMLElement(nsGkAtoms::object) &&
     487           0 :            !aElement->IsHTMLElement(nsGkAtoms::input)) {
     488             :     // Use a sized box if we have no alt text.  This means no alt attribute
     489             :     // and the node is not an object or an input (since those always have alt
     490             :     // text).
     491           0 :     useSizedBox = true;
     492             :   }
     493           0 :   else if (aStyleContext->PresContext()->CompatibilityMode() !=
     494             :            eCompatibility_NavQuirks) {
     495           0 :     useSizedBox = false;
     496             :   }
     497             :   else {
     498             :     // check whether we have specified size
     499           0 :     useSizedBox = HaveSpecifiedSize(aStyleContext->StylePosition());
     500             :   }
     501             : 
     502           0 :   return useSizedBox;
     503             : }
     504             : 
     505             : nsresult
     506           0 : nsImageFrame::Notify(imgIRequest* aRequest,
     507             :                      int32_t aType,
     508             :                      const nsIntRect* aRect)
     509             : {
     510           0 :   if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
     511           0 :     nsCOMPtr<imgIContainer> image;
     512           0 :     aRequest->GetImage(getter_AddRefs(image));
     513           0 :     return OnSizeAvailable(aRequest, image);
     514             :   }
     515             : 
     516           0 :   if (aType == imgINotificationObserver::FRAME_UPDATE) {
     517           0 :     return OnFrameUpdate(aRequest, aRect);
     518             :   }
     519             : 
     520           0 :   if (aType == imgINotificationObserver::FRAME_COMPLETE) {
     521           0 :     mFirstFrameComplete = true;
     522             :   }
     523             : 
     524           0 :   if (aType == imgINotificationObserver::LOAD_COMPLETE) {
     525             :     uint32_t imgStatus;
     526           0 :     aRequest->GetImageStatus(&imgStatus);
     527             :     nsresult status =
     528           0 :         imgStatus & imgIRequest::STATUS_ERROR ? NS_ERROR_FAILURE : NS_OK;
     529           0 :     return OnLoadComplete(aRequest, status);
     530             :   }
     531             : 
     532           0 :   return NS_OK;
     533             : }
     534             : 
     535             : static bool
     536           0 : SizeIsAvailable(imgIRequest* aRequest)
     537             : {
     538           0 :   if (!aRequest)
     539           0 :     return false;
     540             : 
     541           0 :   uint32_t imageStatus = 0;
     542           0 :   nsresult rv = aRequest->GetImageStatus(&imageStatus);
     543             : 
     544           0 :   return NS_SUCCEEDED(rv) && (imageStatus & imgIRequest::STATUS_SIZE_AVAILABLE);
     545             : }
     546             : 
     547             : nsresult
     548           0 : nsImageFrame::OnSizeAvailable(imgIRequest* aRequest, imgIContainer* aImage)
     549             : {
     550           0 :   if (!aImage) return NS_ERROR_INVALID_ARG;
     551             : 
     552             :   /* Get requested animation policy from the pres context:
     553             :    *   normal = 0
     554             :    *   one frame = 1
     555             :    *   one loop = 2
     556             :    */
     557           0 :   nsPresContext *presContext = PresContext();
     558           0 :   aImage->SetAnimationMode(presContext->ImageAnimationMode());
     559             : 
     560           0 :   if (IsPendingLoad(aRequest)) {
     561             :     // We don't care
     562           0 :     return NS_OK;
     563             :   }
     564             : 
     565           0 :   bool intrinsicSizeChanged = false;
     566           0 :   if (SizeIsAvailable(aRequest)) {
     567             :     // This is valid and for the current request, so update our stored image
     568             :     // container, orienting according to our style.
     569           0 :     mImage = nsLayoutUtils::OrientImage(aImage, StyleVisibility()->mImageOrientation);
     570             : 
     571           0 :     intrinsicSizeChanged = UpdateIntrinsicSize(mImage);
     572           0 :     intrinsicSizeChanged = UpdateIntrinsicRatio(mImage) || intrinsicSizeChanged;
     573             :   } else {
     574             :     // We no longer have a valid image, so release our stored image container.
     575           0 :     mImage = mPrevImage = nullptr;
     576             : 
     577             :     // Have to size to 0,0 so that GetDesiredSize recalculates the size.
     578           0 :     mIntrinsicSize.width.SetCoordValue(0);
     579           0 :     mIntrinsicSize.height.SetCoordValue(0);
     580           0 :     mIntrinsicRatio.SizeTo(0, 0);
     581           0 :     intrinsicSizeChanged = true;
     582             :   }
     583             : 
     584           0 :   if (intrinsicSizeChanged && (mState & IMAGE_GOTINITIALREFLOW)) {
     585             :     // Now we need to reflow if we have an unconstrained size and have
     586             :     // already gotten the initial reflow
     587           0 :     if (!(mState & IMAGE_SIZECONSTRAINED)) {
     588           0 :       nsIPresShell *presShell = presContext->GetPresShell();
     589           0 :       NS_ASSERTION(presShell, "No PresShell.");
     590           0 :       if (presShell) {
     591           0 :         presShell->FrameNeedsReflow(this, nsIPresShell::eStyleChange,
     592           0 :                                     NS_FRAME_IS_DIRTY);
     593             :       }
     594             :     } else {
     595             :       // We've already gotten the initial reflow, and our size hasn't changed,
     596             :       // so we're ready to request a decode.
     597           0 :       MaybeDecodeForPredictedSize();
     598             :     }
     599             : 
     600           0 :     mPrevImage = nullptr;
     601             :   }
     602             : 
     603           0 :   return NS_OK;
     604             : }
     605             : 
     606             : nsresult
     607           0 : nsImageFrame::OnFrameUpdate(imgIRequest* aRequest, const nsIntRect* aRect)
     608             : {
     609           0 :   NS_ENSURE_ARG_POINTER(aRect);
     610             : 
     611           0 :   if (!(mState & IMAGE_GOTINITIALREFLOW)) {
     612             :     // Don't bother to do anything; we have a reflow coming up!
     613           0 :     return NS_OK;
     614             :   }
     615             : 
     616           0 :   if (mFirstFrameComplete && !StyleVisibility()->IsVisible()) {
     617           0 :     return NS_OK;
     618             :   }
     619             : 
     620           0 :   if (IsPendingLoad(aRequest)) {
     621             :     // We don't care
     622           0 :     return NS_OK;
     623             :   }
     624             : 
     625             :   nsIntRect layerInvalidRect = mImage
     626           0 :                              ? mImage->GetImageSpaceInvalidationRect(*aRect)
     627           0 :                              : *aRect;
     628             : 
     629           0 :   if (layerInvalidRect.IsEqualInterior(GetMaxSizedIntRect())) {
     630             :     // Invalidate our entire area.
     631           0 :     InvalidateSelf(nullptr, nullptr);
     632           0 :     return NS_OK;
     633             :   }
     634             : 
     635           0 :   nsRect frameInvalidRect = SourceRectToDest(layerInvalidRect);
     636           0 :   InvalidateSelf(&layerInvalidRect, &frameInvalidRect);
     637           0 :   return NS_OK;
     638             : }
     639             : 
     640             : void
     641           0 : nsImageFrame::InvalidateSelf(const nsIntRect* aLayerInvalidRect,
     642             :                              const nsRect* aFrameInvalidRect)
     643             : {
     644           0 :   InvalidateLayer(nsDisplayItem::TYPE_IMAGE,
     645             :                   aLayerInvalidRect,
     646           0 :                   aFrameInvalidRect);
     647             : 
     648           0 :   if (!mFirstFrameComplete) {
     649           0 :     InvalidateLayer(nsDisplayItem::TYPE_ALT_FEEDBACK,
     650             :                     aLayerInvalidRect,
     651           0 :                     aFrameInvalidRect);
     652             :   }
     653           0 : }
     654             : 
     655             : nsresult
     656           0 : nsImageFrame::OnLoadComplete(imgIRequest* aRequest, nsresult aStatus)
     657             : {
     658             :   // Check what request type we're dealing with
     659           0 :   nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
     660           0 :   NS_ASSERTION(imageLoader, "Who's notifying us??");
     661           0 :   int32_t loadType = nsIImageLoadingContent::UNKNOWN_REQUEST;
     662           0 :   imageLoader->GetRequestType(aRequest, &loadType);
     663           0 :   if (loadType != nsIImageLoadingContent::CURRENT_REQUEST &&
     664           0 :       loadType != nsIImageLoadingContent::PENDING_REQUEST) {
     665           0 :     return NS_ERROR_FAILURE;
     666             :   }
     667             : 
     668           0 :   NotifyNewCurrentRequest(aRequest, aStatus);
     669           0 :   return NS_OK;
     670             : }
     671             : 
     672             : void
     673           0 : nsImageFrame::NotifyNewCurrentRequest(imgIRequest *aRequest,
     674             :                                       nsresult aStatus)
     675             : {
     676           0 :   nsCOMPtr<imgIContainer> image;
     677           0 :   aRequest->GetImage(getter_AddRefs(image));
     678           0 :   NS_ASSERTION(image || NS_FAILED(aStatus), "Successful load with no container?");
     679             : 
     680             :   // May have to switch sizes here!
     681           0 :   bool intrinsicSizeChanged = true;
     682           0 :   if (NS_SUCCEEDED(aStatus) && image && SizeIsAvailable(aRequest)) {
     683             :     // Update our stored image container, orienting according to our style.
     684           0 :     mImage = nsLayoutUtils::OrientImage(image, StyleVisibility()->mImageOrientation);
     685             : 
     686           0 :     intrinsicSizeChanged = UpdateIntrinsicSize(mImage);
     687           0 :     intrinsicSizeChanged = UpdateIntrinsicRatio(mImage) || intrinsicSizeChanged;
     688             :   } else {
     689             :     // We no longer have a valid image, so release our stored image container.
     690           0 :     mImage = mPrevImage = nullptr;
     691             : 
     692             :     // Have to size to 0,0 so that GetDesiredSize recalculates the size
     693           0 :     mIntrinsicSize.width.SetCoordValue(0);
     694           0 :     mIntrinsicSize.height.SetCoordValue(0);
     695           0 :     mIntrinsicRatio.SizeTo(0, 0);
     696             :   }
     697             : 
     698           0 :   if (mState & IMAGE_GOTINITIALREFLOW) { // do nothing if we haven't gotten the initial reflow yet
     699           0 :     if (intrinsicSizeChanged) {
     700           0 :       if (!(mState & IMAGE_SIZECONSTRAINED)) {
     701           0 :         nsIPresShell *presShell = PresContext()->GetPresShell();
     702           0 :         if (presShell) {
     703           0 :           presShell->FrameNeedsReflow(this, nsIPresShell::eStyleChange,
     704           0 :                                       NS_FRAME_IS_DIRTY);
     705             :         }
     706             :       } else {
     707             :         // We've already gotten the initial reflow, and our size hasn't changed,
     708             :         // so we're ready to request a decode.
     709           0 :         MaybeDecodeForPredictedSize();
     710             :       }
     711             : 
     712           0 :       mPrevImage = nullptr;
     713             :     }
     714             :     // Update border+content to account for image change
     715           0 :     InvalidateFrame();
     716             :   }
     717           0 : }
     718             : 
     719             : void
     720           0 : nsImageFrame::MaybeDecodeForPredictedSize()
     721             : {
     722             :   // Check that we're ready to decode.
     723           0 :   if (!mImage) {
     724           0 :     return;  // Nothing to do yet.
     725             :   }
     726             : 
     727           0 :   if (mComputedSize.IsEmpty()) {
     728           0 :     return;  // We won't draw anything, so no point in decoding.
     729             :   }
     730             : 
     731           0 :   if (GetVisibility() != Visibility::APPROXIMATELY_VISIBLE) {
     732           0 :     return;  // We're not visible, so don't decode.
     733             :   }
     734             : 
     735             :   // OK, we're ready to decode. Compute the scale to the screen...
     736           0 :   nsIPresShell* presShell = PresContext()->GetPresShell();
     737             :   LayoutDeviceToScreenScale2D resolutionToScreen(
     738           0 :       presShell->GetCumulativeResolution()
     739           0 :     * nsLayoutUtils::GetTransformToAncestorScaleExcludingAnimated(this));
     740             : 
     741             :   // ...and this frame's content box...
     742             :   const nsPoint offset =
     743           0 :     GetOffsetToCrossDoc(nsLayoutUtils::GetReferenceFrame(this));
     744           0 :   const nsRect frameContentBox = GetInnerArea() + offset;
     745             : 
     746             :   // ...and our predicted dest rect...
     747           0 :   const int32_t factor = PresContext()->AppUnitsPerDevPixel();
     748             :   const LayoutDeviceRect destRect =
     749           0 :     LayoutDeviceRect::FromAppUnits(PredictedDestRect(frameContentBox), factor);
     750             : 
     751             :   // ...and use them to compute our predicted size in screen pixels.
     752           0 :   const ScreenSize predictedScreenSize = destRect.Size() * resolutionToScreen;
     753           0 :   const ScreenIntSize predictedScreenIntSize = RoundedToInt(predictedScreenSize);
     754           0 :   if (predictedScreenIntSize.IsEmpty()) {
     755           0 :     return;
     756             :   }
     757             : 
     758             :   // Determine the optimal image size to use.
     759             :   uint32_t flags = imgIContainer::FLAG_HIGH_QUALITY_SCALING
     760           0 :                  | imgIContainer::FLAG_ASYNC_NOTIFY;
     761             :   SamplingFilter samplingFilter =
     762           0 :     nsLayoutUtils::GetSamplingFilterForFrame(this);
     763           0 :   gfxSize gfxPredictedScreenSize = gfxSize(predictedScreenIntSize.width,
     764           0 :                                            predictedScreenIntSize.height);
     765             :   nsIntSize predictedImageSize =
     766           0 :     mImage->OptimalImageSizeForDest(gfxPredictedScreenSize,
     767             :                                     imgIContainer::FRAME_CURRENT,
     768           0 :                                     samplingFilter, flags);
     769             : 
     770             :   // Request a decode.
     771           0 :   mImage->RequestDecodeForSize(predictedImageSize, flags);
     772             : }
     773             : 
     774             : nsRect
     775           0 : nsImageFrame::PredictedDestRect(const nsRect& aFrameContentBox)
     776             : {
     777             :   // Note: To get the "dest rect", we have to provide the "constraint rect"
     778             :   // (which is the content-box, with the effects of fragmentation undone).
     779           0 :   nsRect constraintRect(aFrameContentBox.TopLeft(), mComputedSize);
     780           0 :   constraintRect.y -= GetContinuationOffset();
     781             : 
     782             :   return nsLayoutUtils::ComputeObjectDestRect(constraintRect,
     783             :                                               mIntrinsicSize,
     784             :                                               mIntrinsicRatio,
     785           0 :                                               StylePosition());
     786             : }
     787             : 
     788             : void
     789           0 : nsImageFrame::EnsureIntrinsicSizeAndRatio()
     790             : {
     791             :   // If mIntrinsicSize.width and height are 0, then we need to update from the
     792             :   // image container.
     793           0 :   if (mIntrinsicSize.width.GetUnit() == eStyleUnit_Coord &&
     794           0 :       mIntrinsicSize.width.GetCoordValue() == 0 &&
     795           0 :       mIntrinsicSize.height.GetUnit() == eStyleUnit_Coord &&
     796           0 :       mIntrinsicSize.height.GetCoordValue() == 0) {
     797             : 
     798           0 :     if (mImage) {
     799           0 :       UpdateIntrinsicSize(mImage);
     800           0 :       UpdateIntrinsicRatio(mImage);
     801             :     } else {
     802             :       // image request is null or image size not known, probably an
     803             :       // invalid image specified
     804           0 :       if (!(GetStateBits() & NS_FRAME_GENERATED_CONTENT)) {
     805           0 :         bool imageInvalid = false;
     806             :         // check for broken images. valid null images (eg. img src="") are
     807             :         // not considered broken because they have no image requests
     808           0 :         nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
     809           0 :         if (imageLoader) {
     810           0 :           nsCOMPtr<imgIRequest> currentRequest;
     811           0 :           imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
     812           0 :                                   getter_AddRefs(currentRequest));
     813           0 :           if (currentRequest) {
     814             :             uint32_t imageStatus;
     815           0 :             imageInvalid =
     816           0 :               NS_SUCCEEDED(currentRequest->GetImageStatus(&imageStatus)) &&
     817           0 :               (imageStatus & imgIRequest::STATUS_ERROR);
     818             :           } else {
     819             :             // check if images are user-disabled (or blocked for other
     820             :             // reasons)
     821             :             int16_t imageBlockingStatus;
     822           0 :             imageLoader->GetImageBlockingStatus(&imageBlockingStatus);
     823           0 :             imageInvalid = imageBlockingStatus != nsIContentPolicy::ACCEPT;
     824             :           }
     825             :         }
     826             :         // invalid image specified. make the image big enough for the "broken" icon
     827           0 :         if (imageInvalid) {
     828             :           nscoord edgeLengthToUse =
     829             :             nsPresContext::CSSPixelsToAppUnits(
     830           0 :               ICON_SIZE + (2 * (ICON_PADDING + ALT_BORDER_WIDTH)));
     831           0 :           mIntrinsicSize.width.SetCoordValue(edgeLengthToUse);
     832           0 :           mIntrinsicSize.height.SetCoordValue(edgeLengthToUse);
     833           0 :           mIntrinsicRatio.SizeTo(1, 1);
     834             :         }
     835             :       }
     836             :     }
     837             :   }
     838           0 : }
     839             : 
     840             : /* virtual */
     841             : LogicalSize
     842           0 : nsImageFrame::ComputeSize(gfxContext *aRenderingContext,
     843             :                           WritingMode aWM,
     844             :                           const LogicalSize& aCBSize,
     845             :                           nscoord aAvailableISize,
     846             :                           const LogicalSize& aMargin,
     847             :                           const LogicalSize& aBorder,
     848             :                           const LogicalSize& aPadding,
     849             :                           ComputeSizeFlags aFlags)
     850             : {
     851           0 :   EnsureIntrinsicSizeAndRatio();
     852             : 
     853           0 :   nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
     854           0 :   NS_ASSERTION(imageLoader, "No content node??");
     855           0 :   mozilla::IntrinsicSize intrinsicSize(mIntrinsicSize);
     856             : 
     857             :   // XXX(seth): We may sometimes find ourselves in the situation where we have
     858             :   // mImage, but imageLoader's current request does not have a size yet.
     859             :   // This can happen when we load an image speculatively from cache, it fails
     860             :   // to validate, and the new image load hasn't fired SIZE_AVAILABLE yet. In
     861             :   // this situation we should always use mIntrinsicSize, because
     862             :   // GetNaturalWidth/Height will return 0, so we check CurrentRequestHasSize()
     863             :   // below. See bug 1019840. We will fix this in bug 1141395.
     864             : 
     865             :   // Content may override our default dimensions. This is termed as overriding
     866             :   // the intrinsic size by the spec, but all other consumers of mIntrinsic*
     867             :   // values are being used to refer to the real/true size of the image data.
     868           0 :   if (imageLoader && imageLoader->CurrentRequestHasSize() && mImage &&
     869           0 :       intrinsicSize.width.GetUnit() == eStyleUnit_Coord &&
     870           0 :       intrinsicSize.height.GetUnit() == eStyleUnit_Coord) {
     871             :     uint32_t width;
     872             :     uint32_t height;
     873           0 :     if (NS_SUCCEEDED(imageLoader->GetNaturalWidth(&width)) &&
     874           0 :         NS_SUCCEEDED(imageLoader->GetNaturalHeight(&height))) {
     875           0 :       nscoord appWidth = nsPresContext::CSSPixelsToAppUnits((int32_t)width);
     876           0 :       nscoord appHeight = nsPresContext::CSSPixelsToAppUnits((int32_t)height);
     877             :       // If this image is rotated, we'll need to transpose the natural
     878             :       // width/height.
     879             :       bool coordFlip;
     880           0 :       if (StyleVisibility()->mImageOrientation.IsFromImage()) {
     881           0 :         coordFlip = mImage->GetOrientation().SwapsWidthAndHeight();
     882             :       } else {
     883           0 :         coordFlip = StyleVisibility()->mImageOrientation.SwapsWidthAndHeight();
     884             :       }
     885           0 :       intrinsicSize.width.SetCoordValue(coordFlip ? appHeight : appWidth);
     886           0 :       intrinsicSize.height.SetCoordValue(coordFlip ? appWidth : appHeight);
     887             :     }
     888             :   }
     889             : 
     890             :   return ComputeSizeWithIntrinsicDimensions(aRenderingContext, aWM,
     891             :                                             intrinsicSize, mIntrinsicRatio,
     892             :                                             aCBSize, aMargin, aBorder, aPadding,
     893           0 :                                             aFlags);
     894             : }
     895             : 
     896             : // XXXdholbert This function's clients should probably just be calling
     897             : // GetContentRectRelativeToSelf() directly.
     898             : nsRect
     899           0 : nsImageFrame::GetInnerArea() const
     900             : {
     901           0 :   return GetContentRectRelativeToSelf();
     902             : }
     903             : 
     904             : Element*
     905           0 : nsImageFrame::GetMapElement() const
     906             : {
     907           0 :   nsAutoString usemap;
     908           0 :   if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::usemap, usemap)) {
     909           0 :     return mContent->OwnerDoc()->FindImageMap(usemap);
     910             :   }
     911           0 :   return nullptr;
     912             : }
     913             : 
     914             : // get the offset into the content area of the image where aImg starts if it is a continuation.
     915             : nscoord
     916           0 : nsImageFrame::GetContinuationOffset() const
     917             : {
     918           0 :   nscoord offset = 0;
     919           0 :   for (nsIFrame *f = GetPrevInFlow(); f; f = f->GetPrevInFlow()) {
     920           0 :     offset += f->GetContentRect().height;
     921             :   }
     922           0 :   NS_ASSERTION(offset >= 0, "bogus GetContentRect");
     923           0 :   return offset;
     924             : }
     925             : 
     926             : /* virtual */ nscoord
     927           0 : nsImageFrame::GetMinISize(gfxContext *aRenderingContext)
     928             : {
     929             :   // XXX The caller doesn't account for constraints of the height,
     930             :   // min-height, and max-height properties.
     931           0 :   DebugOnly<nscoord> result;
     932           0 :   DISPLAY_MIN_WIDTH(this, result);
     933           0 :   EnsureIntrinsicSizeAndRatio();
     934           0 :   return mIntrinsicSize.width.GetUnit() == eStyleUnit_Coord ?
     935           0 :     mIntrinsicSize.width.GetCoordValue() : 0;
     936             : }
     937             : 
     938             : /* virtual */ nscoord
     939           0 : nsImageFrame::GetPrefISize(gfxContext *aRenderingContext)
     940             : {
     941             :   // XXX The caller doesn't account for constraints of the height,
     942             :   // min-height, and max-height properties.
     943           0 :   DebugOnly<nscoord> result;
     944           0 :   DISPLAY_PREF_WIDTH(this, result);
     945           0 :   EnsureIntrinsicSizeAndRatio();
     946             :   // convert from normal twips to scaled twips (printing...)
     947           0 :   return mIntrinsicSize.width.GetUnit() == eStyleUnit_Coord ?
     948           0 :     mIntrinsicSize.width.GetCoordValue() : 0;
     949             : }
     950             : 
     951             : /* virtual */ IntrinsicSize
     952           0 : nsImageFrame::GetIntrinsicSize()
     953             : {
     954           0 :   return mIntrinsicSize;
     955             : }
     956             : 
     957             : /* virtual */ nsSize
     958           0 : nsImageFrame::GetIntrinsicRatio()
     959             : {
     960           0 :   return mIntrinsicRatio;
     961             : }
     962             : 
     963             : void
     964           0 : nsImageFrame::Reflow(nsPresContext*          aPresContext,
     965             :                      ReflowOutput&     aMetrics,
     966             :                      const ReflowInput& aReflowInput,
     967             :                      nsReflowStatus&          aStatus)
     968             : {
     969           0 :   MarkInReflow();
     970           0 :   DO_GLOBAL_REFLOW_COUNT("nsImageFrame");
     971           0 :   DISPLAY_REFLOW(aPresContext, this, aReflowInput, aMetrics, aStatus);
     972           0 :   NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
     973             :                   ("enter nsImageFrame::Reflow: availSize=%d,%d",
     974             :                   aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight()));
     975             : 
     976           0 :   NS_PRECONDITION(mState & NS_FRAME_IN_REFLOW, "frame is not in reflow");
     977             : 
     978           0 :   aStatus.Reset();
     979             : 
     980             :   // see if we have a frozen size (i.e. a fixed width and height)
     981           0 :   if (HaveFixedSize(aReflowInput)) {
     982           0 :     mState |= IMAGE_SIZECONSTRAINED;
     983             :   } else {
     984           0 :     mState &= ~IMAGE_SIZECONSTRAINED;
     985             :   }
     986             : 
     987             :   // XXXldb These two bits are almost exact opposites (except in the
     988             :   // middle of the initial reflow); remove IMAGE_GOTINITIALREFLOW.
     989           0 :   if (GetStateBits() & NS_FRAME_FIRST_REFLOW) {
     990           0 :     mState |= IMAGE_GOTINITIALREFLOW;
     991             :   }
     992             : 
     993           0 :   mComputedSize =
     994           0 :     nsSize(aReflowInput.ComputedWidth(), aReflowInput.ComputedHeight());
     995             : 
     996           0 :   aMetrics.Width() = mComputedSize.width;
     997           0 :   aMetrics.Height() = mComputedSize.height;
     998             : 
     999             :   // add borders and padding
    1000           0 :   aMetrics.Width()  += aReflowInput.ComputedPhysicalBorderPadding().LeftRight();
    1001           0 :   aMetrics.Height() += aReflowInput.ComputedPhysicalBorderPadding().TopBottom();
    1002             : 
    1003           0 :   if (GetPrevInFlow()) {
    1004           0 :     aMetrics.Width() = GetPrevInFlow()->GetSize().width;
    1005           0 :     nscoord y = GetContinuationOffset();
    1006           0 :     aMetrics.Height() -= y + aReflowInput.ComputedPhysicalBorderPadding().top;
    1007           0 :     aMetrics.Height() = std::max(0, aMetrics.Height());
    1008             :   }
    1009             : 
    1010             : 
    1011             :   // we have to split images if we are:
    1012             :   //  in Paginated mode, we need to have a constrained height, and have a height larger than our available height
    1013           0 :   uint32_t loadStatus = imgIRequest::STATUS_NONE;
    1014           0 :   nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
    1015           0 :   NS_ASSERTION(imageLoader, "No content node??");
    1016           0 :   if (imageLoader) {
    1017           0 :     nsCOMPtr<imgIRequest> currentRequest;
    1018           0 :     imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
    1019           0 :                             getter_AddRefs(currentRequest));
    1020           0 :     if (currentRequest) {
    1021           0 :       currentRequest->GetImageStatus(&loadStatus);
    1022             :     }
    1023             :   }
    1024           0 :   if (aPresContext->IsPaginated() &&
    1025           0 :       ((loadStatus & imgIRequest::STATUS_SIZE_AVAILABLE) || (mState & IMAGE_SIZECONSTRAINED)) &&
    1026           0 :       NS_UNCONSTRAINEDSIZE != aReflowInput.AvailableHeight() &&
    1027           0 :       aMetrics.Height() > aReflowInput.AvailableHeight()) {
    1028             :     // our desired height was greater than 0, so to avoid infinite
    1029             :     // splitting, use 1 pixel as the min
    1030           0 :     aMetrics.Height() = std::max(nsPresContext::CSSPixelsToAppUnits(1), aReflowInput.AvailableHeight());
    1031           0 :     aStatus.Reset();
    1032           0 :     aStatus.SetIncomplete();
    1033             :   }
    1034             : 
    1035           0 :   aMetrics.SetOverflowAreasToDesiredBounds();
    1036           0 :   EventStates contentState = mContent->AsElement()->State();
    1037           0 :   bool imageOK = IMAGE_OK(contentState, true);
    1038             : 
    1039             :   // Determine if the size is available
    1040           0 :   bool haveSize = false;
    1041           0 :   if (loadStatus & imgIRequest::STATUS_SIZE_AVAILABLE) {
    1042           0 :     haveSize = true;
    1043             :   }
    1044             : 
    1045           0 :   if (!imageOK || !haveSize) {
    1046             :     nsRect altFeedbackSize(0, 0,
    1047             :                            nsPresContext::CSSPixelsToAppUnits(ICON_SIZE+2*(ICON_PADDING+ALT_BORDER_WIDTH)),
    1048           0 :                            nsPresContext::CSSPixelsToAppUnits(ICON_SIZE+2*(ICON_PADDING+ALT_BORDER_WIDTH)));
    1049             :     // We include the altFeedbackSize in our visual overflow, but not in our
    1050             :     // scrollable overflow, since it doesn't really need to be scrolled to
    1051             :     // outside the image.
    1052             :     static_assert(eOverflowType_LENGTH == 2, "Unknown overflow types?");
    1053           0 :     nsRect& visualOverflow = aMetrics.VisualOverflow();
    1054           0 :     visualOverflow.UnionRect(visualOverflow, altFeedbackSize);
    1055             :   } else {
    1056             :     // We've just reflowed and we should have an accurate size, so we're ready
    1057             :     // to request a decode.
    1058           0 :     MaybeDecodeForPredictedSize();
    1059             :   }
    1060           0 :   FinishAndStoreOverflow(&aMetrics, aReflowInput.mStyleDisplay);
    1061             : 
    1062           0 :   if ((GetStateBits() & NS_FRAME_FIRST_REFLOW) && !mReflowCallbackPosted) {
    1063           0 :     nsIPresShell* shell = PresContext()->PresShell();
    1064           0 :     mReflowCallbackPosted = true;
    1065           0 :     shell->PostReflowCallback(this);
    1066             :   }
    1067             : 
    1068           0 :   NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
    1069             :                   ("exit nsImageFrame::Reflow: size=%d,%d",
    1070             :                   aMetrics.Width(), aMetrics.Height()));
    1071           0 :   NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aMetrics);
    1072           0 : }
    1073             : 
    1074             : bool
    1075           0 : nsImageFrame::ReflowFinished()
    1076             : {
    1077           0 :   mReflowCallbackPosted = false;
    1078             : 
    1079             :   // XXX(seth): We don't need this. The purpose of updating visibility
    1080             :   // synchronously is to ensure that animated images start animating
    1081             :   // immediately. In the short term, however,
    1082             :   // nsImageLoadingContent::OnUnlockedDraw() is enough to ensure that
    1083             :   // animations start as soon as the image is painted for the first time, and in
    1084             :   // the long term we want to update visibility information from the display
    1085             :   // list whenever we paint, so we don't actually need to do this. However, to
    1086             :   // avoid behavior changes during the transition from the old image visibility
    1087             :   // code, we'll leave it in for now.
    1088           0 :   UpdateVisibilitySynchronously();
    1089             : 
    1090           0 :   return false;
    1091             : }
    1092             : 
    1093             : void
    1094           0 : nsImageFrame::ReflowCallbackCanceled()
    1095             : {
    1096           0 :   mReflowCallbackPosted = false;
    1097           0 : }
    1098             : 
    1099             : // Computes the width of the specified string. aMaxWidth specifies the maximum
    1100             : // width available. Once this limit is reached no more characters are measured.
    1101             : // The number of characters that fit within the maximum width are returned in
    1102             : // aMaxFit. NOTE: it is assumed that the fontmetrics have already been selected
    1103             : // into the rendering context before this is called (for performance). MMP
    1104             : nscoord
    1105           0 : nsImageFrame::MeasureString(const char16_t*     aString,
    1106             :                             int32_t              aLength,
    1107             :                             nscoord              aMaxWidth,
    1108             :                             uint32_t&            aMaxFit,
    1109             :                             gfxContext& aContext,
    1110             :                             nsFontMetrics& aFontMetrics)
    1111             : {
    1112           0 :   nscoord totalWidth = 0;
    1113           0 :   aFontMetrics.SetTextRunRTL(false);
    1114           0 :   nscoord spaceWidth = aFontMetrics.SpaceWidth();
    1115             : 
    1116           0 :   aMaxFit = 0;
    1117           0 :   while (aLength > 0) {
    1118             :     // Find the next place we can line break
    1119           0 :     uint32_t  len = aLength;
    1120           0 :     bool      trailingSpace = false;
    1121           0 :     for (int32_t i = 0; i < aLength; i++) {
    1122           0 :       if (dom::IsSpaceCharacter(aString[i]) && (i > 0)) {
    1123           0 :         len = i;  // don't include the space when measuring
    1124           0 :         trailingSpace = true;
    1125           0 :         break;
    1126             :       }
    1127             :     }
    1128             : 
    1129             :     // Measure this chunk of text, and see if it fits
    1130             :     nscoord width =
    1131           0 :       nsLayoutUtils::AppUnitWidthOfStringBidi(aString, len, this, aFontMetrics,
    1132           0 :                                               aContext);
    1133           0 :     bool    fits = (totalWidth + width) <= aMaxWidth;
    1134             : 
    1135             :     // If it fits on the line, or it's the first word we've processed then
    1136             :     // include it
    1137           0 :     if (fits || (0 == totalWidth)) {
    1138             :       // New piece fits
    1139           0 :       totalWidth += width;
    1140             : 
    1141             :       // If there's a trailing space then see if it fits as well
    1142           0 :       if (trailingSpace) {
    1143           0 :         if ((totalWidth + spaceWidth) <= aMaxWidth) {
    1144           0 :           totalWidth += spaceWidth;
    1145             :         } else {
    1146             :           // Space won't fit. Leave it at the end but don't include it in
    1147             :           // the width
    1148           0 :           fits = false;
    1149             :         }
    1150             : 
    1151           0 :         len++;
    1152             :       }
    1153             : 
    1154           0 :       aMaxFit += len;
    1155           0 :       aString += len;
    1156           0 :       aLength -= len;
    1157             :     }
    1158             : 
    1159           0 :     if (!fits) {
    1160           0 :       break;
    1161             :     }
    1162             :   }
    1163           0 :   return totalWidth;
    1164             : }
    1165             : 
    1166             : // Formats the alt-text to fit within the specified rectangle. Breaks lines
    1167             : // between words if a word would extend past the edge of the rectangle
    1168             : void
    1169           0 : nsImageFrame::DisplayAltText(nsPresContext*      aPresContext,
    1170             :                              gfxContext&          aRenderingContext,
    1171             :                              const nsString&      aAltText,
    1172             :                              const nsRect&        aRect)
    1173             : {
    1174             :   // Set font and color
    1175           0 :   aRenderingContext.SetColor(Color::FromABGR(StyleColor()->mColor));
    1176             :   RefPtr<nsFontMetrics> fm =
    1177           0 :     nsLayoutUtils::GetInflatedFontMetricsForFrame(this);
    1178             : 
    1179             :   // Format the text to display within the formatting rect
    1180             : 
    1181           0 :   nscoord maxAscent = fm->MaxAscent();
    1182           0 :   nscoord maxDescent = fm->MaxDescent();
    1183           0 :   nscoord lineHeight = fm->MaxHeight(); // line-relative, so an x-coordinate
    1184             :                                         // length if writing mode is vertical
    1185             : 
    1186           0 :   WritingMode wm = GetWritingMode();
    1187           0 :   bool isVertical = wm.IsVertical();
    1188             : 
    1189           0 :   fm->SetVertical(isVertical);
    1190           0 :   fm->SetTextOrientation(StyleVisibility()->mTextOrientation);
    1191             : 
    1192             :   // XXX It would be nice if there was a way to have the font metrics tell
    1193             :   // use where to break the text given a maximum width. At a minimum we need
    1194             :   // to be able to get the break character...
    1195           0 :   const char16_t* str = aAltText.get();
    1196           0 :   int32_t strLen = aAltText.Length();
    1197           0 :   nsPoint pt = wm.IsVerticalRL() ? aRect.TopRight() - nsPoint(lineHeight, 0)
    1198           0 :                                  : aRect.TopLeft();
    1199           0 :   nscoord iSize = isVertical ? aRect.height : aRect.width;
    1200             : 
    1201           0 :   if (!aPresContext->BidiEnabled() && HasRTLChars(aAltText)) {
    1202           0 :     aPresContext->SetBidiEnabled();
    1203             :   }
    1204             : 
    1205             :   // Always show the first line, even if we have to clip it below
    1206           0 :   bool firstLine = true;
    1207           0 :   while (strLen > 0) {
    1208           0 :     if (!firstLine) {
    1209             :       // If we've run out of space, break out of the loop
    1210           0 :       if ((!isVertical && (pt.y + maxDescent) >= aRect.YMost()) ||
    1211           0 :           (wm.IsVerticalRL() && (pt.x + maxDescent < aRect.x)) ||
    1212           0 :           (wm.IsVerticalLR() && (pt.x + maxDescent >= aRect.XMost()))) {
    1213           0 :         break;
    1214             :       }
    1215             :     }
    1216             : 
    1217             :     // Determine how much of the text to display on this line
    1218             :     uint32_t  maxFit;  // number of characters that fit
    1219           0 :     nscoord strWidth = MeasureString(str, strLen, iSize, maxFit,
    1220           0 :                                      aRenderingContext, *fm);
    1221             : 
    1222             :     // Display the text
    1223           0 :     nsresult rv = NS_ERROR_FAILURE;
    1224             : 
    1225           0 :     if (aPresContext->BidiEnabled()) {
    1226             :       nsBidiDirection dir;
    1227             :       nscoord x, y;
    1228             : 
    1229           0 :       if (isVertical) {
    1230           0 :         x = pt.x + maxDescent;
    1231           0 :         if (wm.IsBidiLTR()) {
    1232           0 :           y = aRect.y;
    1233           0 :           dir = NSBIDI_LTR;
    1234             :         } else {
    1235           0 :           y = aRect.YMost() - strWidth;
    1236           0 :           dir = NSBIDI_RTL;
    1237             :         }
    1238             :       } else {
    1239           0 :         y = pt.y + maxAscent;
    1240           0 :         if (wm.IsBidiLTR()) {
    1241           0 :           x = aRect.x;
    1242           0 :           dir = NSBIDI_LTR;
    1243             :         } else {
    1244           0 :           x = aRect.XMost() - strWidth;
    1245           0 :           dir = NSBIDI_RTL;
    1246             :         }
    1247             :       }
    1248             : 
    1249           0 :       rv = nsBidiPresUtils::RenderText(str, maxFit, dir,
    1250             :                                        aPresContext, aRenderingContext,
    1251             :                                        aRenderingContext.GetDrawTarget(),
    1252           0 :                                        *fm, x, y);
    1253             :     }
    1254           0 :     if (NS_FAILED(rv)) {
    1255           0 :       nsLayoutUtils::DrawUniDirString(str, maxFit,
    1256             :                                       isVertical
    1257           0 :                                         ? nsPoint(pt.x + maxDescent, pt.y)
    1258           0 :                                         : nsPoint(pt.x, pt.y + maxAscent),
    1259           0 :                                       *fm, aRenderingContext);
    1260             :     }
    1261             : 
    1262             :     // Move to the next line
    1263           0 :     str += maxFit;
    1264           0 :     strLen -= maxFit;
    1265           0 :     if (wm.IsVerticalRL()) {
    1266           0 :       pt.x -= lineHeight;
    1267           0 :     } else if (wm.IsVerticalLR()) {
    1268           0 :       pt.x += lineHeight;
    1269             :     } else {
    1270           0 :       pt.y += lineHeight;
    1271             :     }
    1272             : 
    1273           0 :     firstLine = false;
    1274             :   }
    1275           0 : }
    1276             : 
    1277           0 : struct nsRecessedBorder : public nsStyleBorder {
    1278           0 :   nsRecessedBorder(nscoord aBorderWidth, nsPresContext* aPresContext)
    1279           0 :     : nsStyleBorder(aPresContext)
    1280             :   {
    1281           0 :     NS_FOR_CSS_SIDES(side) {
    1282           0 :       mBorderColor[side] = StyleComplexColor::FromColor(NS_RGB(0, 0, 0));
    1283           0 :       mBorder.Side(side) = aBorderWidth;
    1284             :       // Note: use SetBorderStyle here because we want to affect
    1285             :       // mComputedBorder
    1286           0 :       SetBorderStyle(side, NS_STYLE_BORDER_STYLE_INSET);
    1287             :     }
    1288           0 :   }
    1289             : };
    1290             : 
    1291           0 : class nsDisplayAltFeedback : public nsDisplayItem {
    1292             : public:
    1293           0 :   nsDisplayAltFeedback(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
    1294           0 :     : nsDisplayItem(aBuilder, aFrame) {}
    1295             : 
    1296             :   virtual nsDisplayItemGeometry*
    1297           0 :   AllocateGeometry(nsDisplayListBuilder* aBuilder) override
    1298             :   {
    1299           0 :     return new nsDisplayItemGenericImageGeometry(this, aBuilder);
    1300             :   }
    1301             : 
    1302           0 :   virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
    1303             :                                          const nsDisplayItemGeometry* aGeometry,
    1304             :                                          nsRegion* aInvalidRegion) override
    1305             :   {
    1306             :     auto geometry =
    1307           0 :       static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
    1308             : 
    1309           0 :     if (aBuilder->ShouldSyncDecodeImages() &&
    1310           0 :         geometry->ShouldInvalidateToSyncDecodeImages()) {
    1311             :       bool snap;
    1312           0 :       aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
    1313             :     }
    1314             : 
    1315           0 :     nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
    1316           0 :   }
    1317             : 
    1318           0 :   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
    1319             :                            bool* aSnap) override
    1320             :   {
    1321           0 :     *aSnap = false;
    1322           0 :     return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
    1323             :   }
    1324             : 
    1325           0 :   virtual void Paint(nsDisplayListBuilder* aBuilder,
    1326             :                      gfxContext* aCtx) override
    1327             :   {
    1328             :     // Always sync decode, because these icons are UI, and since they're not
    1329             :     // discardable we'll pay the price of sync decoding at most once.
    1330           0 :     uint32_t flags = imgIContainer::FLAG_SYNC_DECODE;
    1331             : 
    1332           0 :     nsImageFrame* f = static_cast<nsImageFrame*>(mFrame);
    1333             :     DrawResult result =
    1334           0 :       f->DisplayAltFeedback(*aCtx,
    1335             :                             mVisibleRect,
    1336             :                             ToReferenceFrame(),
    1337           0 :                             flags);
    1338             : 
    1339           0 :     nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
    1340           0 :   }
    1341             : 
    1342           0 :   NS_DISPLAY_DECL_NAME("AltFeedback", TYPE_ALT_FEEDBACK)
    1343             : };
    1344             : 
    1345             : DrawResult
    1346           0 : nsImageFrame::DisplayAltFeedback(gfxContext& aRenderingContext,
    1347             :                                  const nsRect& aDirtyRect,
    1348             :                                  nsPoint aPt,
    1349             :                                  uint32_t aFlags)
    1350             : {
    1351             :   // We should definitely have a gIconLoad here.
    1352           0 :   MOZ_ASSERT(gIconLoad, "How did we succeed in Init then?");
    1353             : 
    1354             :   // Whether we draw the broken or loading icon.
    1355           0 :   bool isLoading = IMAGE_OK(GetContent()->AsElement()->State(), true);
    1356             : 
    1357             :   // Calculate the inner area
    1358           0 :   nsRect  inner = GetInnerArea() + aPt;
    1359             : 
    1360             :   // Display a recessed one pixel border
    1361           0 :   nscoord borderEdgeWidth = nsPresContext::CSSPixelsToAppUnits(ALT_BORDER_WIDTH);
    1362             : 
    1363             :   // if inner area is empty, then make it big enough for at least the icon
    1364           0 :   if (inner.IsEmpty()){
    1365           0 :     inner.SizeTo(2*(nsPresContext::CSSPixelsToAppUnits(ICON_SIZE+ICON_PADDING+ALT_BORDER_WIDTH)),
    1366           0 :                  2*(nsPresContext::CSSPixelsToAppUnits(ICON_SIZE+ICON_PADDING+ALT_BORDER_WIDTH)));
    1367             :   }
    1368             : 
    1369             :   // Make sure we have enough room to actually render the border within
    1370             :   // our frame bounds
    1371           0 :   if ((inner.width < 2 * borderEdgeWidth) || (inner.height < 2 * borderEdgeWidth)) {
    1372           0 :     return DrawResult::SUCCESS;
    1373             :   }
    1374             : 
    1375             :   // Paint the border
    1376           0 :   if (!isLoading || gIconLoad->mPrefShowLoadingPlaceholder) {
    1377           0 :     nsRecessedBorder recessedBorder(borderEdgeWidth, PresContext());
    1378             : 
    1379             :     // Assert that we're not drawing a border-image here; if we were, we
    1380             :     // couldn't ignore the DrawResult that PaintBorderWithStyleBorder returns.
    1381           0 :     MOZ_ASSERT(recessedBorder.mBorderImageSource.GetType() == eStyleImageType_Null);
    1382             : 
    1383             :     Unused <<
    1384           0 :       nsCSSRendering::PaintBorderWithStyleBorder(PresContext(), aRenderingContext,
    1385             :                                                  this, inner, inner,
    1386             :                                                  recessedBorder, mStyleContext,
    1387             :                                                  PaintBorderFlags::SYNC_DECODE_IMAGES);
    1388             :   }
    1389             : 
    1390             :   // Adjust the inner rect to account for the one pixel recessed border,
    1391             :   // and a six pixel padding on each edge
    1392           0 :   inner.Deflate(nsPresContext::CSSPixelsToAppUnits(ICON_PADDING+ALT_BORDER_WIDTH),
    1393           0 :                 nsPresContext::CSSPixelsToAppUnits(ICON_PADDING+ALT_BORDER_WIDTH));
    1394           0 :   if (inner.IsEmpty()) {
    1395           0 :     return DrawResult::SUCCESS;
    1396             :   }
    1397             : 
    1398           0 :   DrawTarget* drawTarget = aRenderingContext.GetDrawTarget();
    1399             : 
    1400             :   // Clip so we don't render outside the inner rect
    1401           0 :   aRenderingContext.Save();
    1402             :   aRenderingContext.Clip(
    1403           0 :     NSRectToSnappedRect(inner, PresContext()->AppUnitsPerDevPixel(), *drawTarget));
    1404             : 
    1405           0 :   DrawResult result = DrawResult::NOT_READY;
    1406             : 
    1407             :   // Check if we should display image placeholders
    1408           0 :   if (!gIconLoad->mPrefShowPlaceholders ||
    1409           0 :       (isLoading && !gIconLoad->mPrefShowLoadingPlaceholder)) {
    1410           0 :     result = DrawResult::SUCCESS;
    1411             :   } else {
    1412           0 :     nscoord size = nsPresContext::CSSPixelsToAppUnits(ICON_SIZE);
    1413             : 
    1414             :     imgIRequest* request = isLoading
    1415           0 :                               ? nsImageFrame::gIconLoad->mLoadingImage
    1416           0 :                               : nsImageFrame::gIconLoad->mBrokenImage;
    1417             : 
    1418             :     // If we weren't previously displaying an icon, register ourselves
    1419             :     // as an observer for load and animation updates and flag that we're
    1420             :     // doing so now.
    1421           0 :     if (request && !mDisplayingIcon) {
    1422           0 :       gIconLoad->AddIconObserver(this);
    1423           0 :       mDisplayingIcon = true;
    1424             :     }
    1425             : 
    1426           0 :     WritingMode wm = GetWritingMode();
    1427             :     bool flushRight =
    1428           0 :       (!wm.IsVertical() && !wm.IsBidiLTR()) || wm.IsVerticalRL();
    1429             : 
    1430             :     // If the icon in question is loaded, draw it.
    1431           0 :     uint32_t imageStatus = 0;
    1432           0 :     if (request)
    1433           0 :       request->GetImageStatus(&imageStatus);
    1434           0 :     if (imageStatus & imgIRequest::STATUS_LOAD_COMPLETE) {
    1435           0 :       nsCOMPtr<imgIContainer> imgCon;
    1436           0 :       request->GetImage(getter_AddRefs(imgCon));
    1437           0 :       MOZ_ASSERT(imgCon, "Load complete, but no image container?");
    1438           0 :       nsRect dest(flushRight ? inner.XMost() - size : inner.x,
    1439           0 :                   inner.y, size, size);
    1440           0 :       result = nsLayoutUtils::DrawSingleImage(aRenderingContext, PresContext(), imgCon,
    1441             :         nsLayoutUtils::GetSamplingFilterForFrame(this), dest, aDirtyRect,
    1442           0 :         /* no SVGImageContext */ Nothing(), aFlags);
    1443             :     }
    1444             : 
    1445             :     // If we could not draw the icon, just draw some graffiti in the mean time.
    1446           0 :     if (result == DrawResult::NOT_READY) {
    1447           0 :       ColorPattern color(ToDeviceColor(Color(1.f, 0.f, 0.f, 1.f)));
    1448             : 
    1449           0 :       nscoord iconXPos = flushRight ? inner.XMost() - size : inner.x;
    1450             : 
    1451             :       // stroked rect:
    1452           0 :       nsRect rect(iconXPos, inner.y, size, size);
    1453             :       Rect devPxRect =
    1454           0 :         ToRect(nsLayoutUtils::RectToGfxRect(rect, PresContext()->AppUnitsPerDevPixel()));
    1455           0 :       drawTarget->StrokeRect(devPxRect, color);
    1456             : 
    1457             :       // filled circle in bottom right quadrant of stroked rect:
    1458           0 :       nscoord twoPX = nsPresContext::CSSPixelsToAppUnits(2);
    1459           0 :       rect = nsRect(iconXPos + size/2, inner.y + size/2,
    1460           0 :                     size/2 - twoPX, size/2 - twoPX);
    1461             :       devPxRect =
    1462           0 :         ToRect(nsLayoutUtils::RectToGfxRect(rect, PresContext()->AppUnitsPerDevPixel()));
    1463           0 :       RefPtr<PathBuilder> builder = drawTarget->CreatePathBuilder();
    1464           0 :       AppendEllipseToPath(builder, devPxRect.Center(), devPxRect.Size());
    1465           0 :       RefPtr<Path> ellipse = builder->Finish();
    1466           0 :       drawTarget->Fill(ellipse, color);
    1467             :     }
    1468             : 
    1469             :     // Reduce the inner rect by the width of the icon, and leave an
    1470             :     // additional ICON_PADDING pixels for padding
    1471             :     int32_t paddedIconSize =
    1472           0 :       nsPresContext::CSSPixelsToAppUnits(ICON_SIZE + ICON_PADDING);
    1473           0 :     if (wm.IsVertical()) {
    1474           0 :       inner.y += paddedIconSize;
    1475           0 :       inner.height -= paddedIconSize;
    1476             :     } else {
    1477           0 :       if (!flushRight) {
    1478           0 :         inner.x += paddedIconSize;
    1479             :       }
    1480           0 :       inner.width -= paddedIconSize;
    1481             :     }
    1482             :   }
    1483             : 
    1484             :   // If there's still room, display the alt-text
    1485           0 :   if (!inner.IsEmpty()) {
    1486           0 :     nsIContent* content = GetContent();
    1487           0 :     if (content) {
    1488           0 :       nsXPIDLString altText;
    1489           0 :       nsCSSFrameConstructor::GetAlternateTextFor(content,
    1490             :                                                  content->NodeInfo()->NameAtom(),
    1491           0 :                                                  altText);
    1492           0 :       DisplayAltText(PresContext(), aRenderingContext, altText, inner);
    1493             :     }
    1494             :   }
    1495             : 
    1496           0 :   aRenderingContext.Restore();
    1497             : 
    1498           0 :   return result;
    1499             : }
    1500             : 
    1501             : #ifdef DEBUG
    1502           0 : static void PaintDebugImageMap(nsIFrame* aFrame, DrawTarget* aDrawTarget,
    1503             :                                const nsRect& aDirtyRect, nsPoint aPt)
    1504             : {
    1505           0 :   nsImageFrame* f = static_cast<nsImageFrame*>(aFrame);
    1506           0 :   nsRect inner = f->GetInnerArea() + aPt;
    1507             :   gfxPoint devPixelOffset =
    1508           0 :     nsLayoutUtils::PointToGfxPoint(inner.TopLeft(),
    1509           0 :                                    aFrame->PresContext()->AppUnitsPerDevPixel());
    1510           0 :   AutoRestoreTransform autoRestoreTransform(aDrawTarget);
    1511             :   aDrawTarget->SetTransform(
    1512           0 :     aDrawTarget->GetTransform().PreTranslate(ToPoint(devPixelOffset)));
    1513           0 :   f->GetImageMap()->Draw(aFrame, *aDrawTarget,
    1514           0 :                          ColorPattern(ToDeviceColor(Color(0.f, 0.f, 0.f, 1.f))));
    1515           0 : }
    1516             : #endif
    1517             : 
    1518             : void
    1519           0 : nsDisplayImage::Paint(nsDisplayListBuilder* aBuilder,
    1520             :                       gfxContext* aCtx)
    1521             : {
    1522           0 :   uint32_t flags = imgIContainer::FLAG_NONE;
    1523           0 :   if (aBuilder->ShouldSyncDecodeImages()) {
    1524           0 :     flags |= imgIContainer::FLAG_SYNC_DECODE;
    1525             :   }
    1526           0 :   if (aBuilder->IsPaintingToWindow()) {
    1527           0 :     flags |= imgIContainer::FLAG_HIGH_QUALITY_SCALING;
    1528             :   }
    1529             : 
    1530           0 :   DrawResult result = static_cast<nsImageFrame*>(mFrame)->
    1531           0 :     PaintImage(*aCtx, ToReferenceFrame(), mVisibleRect, mImage, flags);
    1532             : 
    1533           0 :   if (result == DrawResult::NOT_READY ||
    1534           0 :       result == DrawResult::INCOMPLETE ||
    1535             :       result == DrawResult::TEMPORARY_ERROR) {
    1536             :     // If the current image failed to paint because it's still loading or
    1537             :     // decoding, try painting the previous image.
    1538           0 :     if (mPrevImage) {
    1539           0 :       result = static_cast<nsImageFrame*>(mFrame)->
    1540           0 :         PaintImage(*aCtx, ToReferenceFrame(), mVisibleRect, mPrevImage, flags);
    1541             :     }
    1542             :   }
    1543             : 
    1544           0 :   nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
    1545           0 : }
    1546             : 
    1547             : nsDisplayItemGeometry*
    1548           0 : nsDisplayImage::AllocateGeometry(nsDisplayListBuilder* aBuilder)
    1549             : {
    1550           0 :   return new nsDisplayItemGenericImageGeometry(this, aBuilder);
    1551             : }
    1552             : 
    1553             : void
    1554           0 : nsDisplayImage::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
    1555             :                                           const nsDisplayItemGeometry* aGeometry,
    1556             :                                           nsRegion* aInvalidRegion)
    1557             : {
    1558             :   auto geometry =
    1559           0 :     static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
    1560             : 
    1561           0 :   if (aBuilder->ShouldSyncDecodeImages() &&
    1562           0 :       geometry->ShouldInvalidateToSyncDecodeImages()) {
    1563             :     bool snap;
    1564           0 :     aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
    1565             :   }
    1566             : 
    1567           0 :   nsDisplayImageContainer::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
    1568           0 : }
    1569             : 
    1570             : already_AddRefed<imgIContainer>
    1571           0 : nsDisplayImage::GetImage()
    1572             : {
    1573           0 :   nsCOMPtr<imgIContainer> image = mImage;
    1574           0 :   return image.forget();
    1575             : }
    1576             : 
    1577             : nsRect
    1578           0 : nsDisplayImage::GetDestRect()
    1579             : {
    1580           0 :   bool snap = true;
    1581           0 :   const nsRect frameContentBox = GetBounds(&snap);
    1582             : 
    1583           0 :   nsImageFrame* imageFrame = static_cast<nsImageFrame*>(mFrame);
    1584           0 :   return imageFrame->PredictedDestRect(frameContentBox);
    1585             : }
    1586             : 
    1587             : LayerState
    1588           0 : nsDisplayImage::GetLayerState(nsDisplayListBuilder* aBuilder,
    1589             :                               LayerManager* aManager,
    1590             :                               const ContainerLayerParameters& aParameters)
    1591             : {
    1592           0 :   if (!nsDisplayItem::ForceActiveLayers() &&
    1593           0 :       !ShouldUseAdvancedLayer(aManager, gfxPrefs::LayersAllowImageLayers)) {
    1594           0 :     bool animated = false;
    1595           0 :     if (!nsLayoutUtils::AnimatedImageLayersEnabled() ||
    1596           0 :         mImage->GetType() != imgIContainer::TYPE_RASTER ||
    1597           0 :         NS_FAILED(mImage->GetAnimated(&animated)) ||
    1598           0 :         !animated) {
    1599           0 :       if (!aManager->IsCompositingCheap() ||
    1600           0 :           !nsLayoutUtils::GPUImageScalingEnabled()) {
    1601           0 :         return LAYER_NONE;
    1602             :       }
    1603             :     }
    1604             : 
    1605           0 :     if (!animated) {
    1606             :       int32_t imageWidth;
    1607             :       int32_t imageHeight;
    1608           0 :       mImage->GetWidth(&imageWidth);
    1609           0 :       mImage->GetHeight(&imageHeight);
    1610             : 
    1611           0 :       NS_ASSERTION(imageWidth != 0 && imageHeight != 0, "Invalid image size!");
    1612             : 
    1613           0 :       const int32_t factor = mFrame->PresContext()->AppUnitsPerDevPixel();
    1614             :       const LayoutDeviceRect destRect =
    1615           0 :         LayoutDeviceRect::FromAppUnits(GetDestRect(), factor);
    1616           0 :       const LayerRect destLayerRect = destRect * aParameters.Scale();
    1617             : 
    1618             :       // Calculate the scaling factor for the frame.
    1619           0 :       const gfxSize scale = gfxSize(destLayerRect.width / imageWidth,
    1620           0 :                                     destLayerRect.height / imageHeight);
    1621             : 
    1622             :       // If we are not scaling at all, no point in separating this into a layer.
    1623           0 :       if (scale.width == 1.0f && scale.height == 1.0f) {
    1624           0 :         return LAYER_NONE;
    1625             :       }
    1626             : 
    1627             :       // If the target size is pretty small, no point in using a layer.
    1628           0 :       if (destLayerRect.width * destLayerRect.height < 64 * 64) {
    1629           0 :         return LAYER_NONE;
    1630             :       }
    1631             :     }
    1632             :   }
    1633             : 
    1634             : 
    1635           0 :   if (!CanOptimizeToImageLayer(aManager, aBuilder)) {
    1636           0 :     return LAYER_NONE;
    1637             :   }
    1638             : 
    1639             :   // Image layer doesn't support draw focus ring for image map.
    1640           0 :   nsImageFrame* f = static_cast<nsImageFrame*>(mFrame);
    1641           0 :   if (f->HasImageMap()) {
    1642           0 :     return LAYER_NONE;
    1643             :   }
    1644             : 
    1645           0 :   return LAYER_ACTIVE;
    1646             : }
    1647             : 
    1648             : 
    1649             : /* virtual */ nsRegion
    1650           0 : nsDisplayImage::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
    1651             :                                 bool* aSnap)
    1652             : {
    1653           0 :   *aSnap = false;
    1654           0 :   if (mImage && mImage->WillDrawOpaqueNow()) {
    1655           0 :     const nsRect frameContentBox = GetBounds(aSnap);
    1656           0 :     return GetDestRect().Intersect(frameContentBox);
    1657             :   }
    1658           0 :   return nsRegion();
    1659             : }
    1660             : 
    1661             : already_AddRefed<Layer>
    1662           0 : nsDisplayImage::BuildLayer(nsDisplayListBuilder* aBuilder,
    1663             :                            LayerManager* aManager,
    1664             :                            const ContainerLayerParameters& aParameters)
    1665             : {
    1666           0 :   uint32_t flags = imgIContainer::FLAG_ASYNC_NOTIFY;
    1667           0 :   if (aBuilder->ShouldSyncDecodeImages()) {
    1668           0 :     flags |= imgIContainer::FLAG_SYNC_DECODE;
    1669             :   }
    1670             : 
    1671             :   RefPtr<ImageContainer> container =
    1672           0 :     mImage->GetImageContainer(aManager, flags);
    1673           0 :   if (!container) {
    1674           0 :     return nullptr;
    1675             :   }
    1676             : 
    1677             :   RefPtr<ImageLayer> layer = static_cast<ImageLayer*>
    1678           0 :     (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, this));
    1679           0 :   if (!layer) {
    1680           0 :     layer = aManager->CreateImageLayer();
    1681           0 :     if (!layer)
    1682           0 :       return nullptr;
    1683             :   }
    1684           0 :   layer->SetContainer(container);
    1685           0 :   ConfigureLayer(layer, aParameters);
    1686           0 :   return layer.forget();
    1687             : }
    1688             : 
    1689             : bool
    1690           0 : nsDisplayImage::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
    1691             :                                         const StackingContextHelper& aSc,
    1692             :                                         nsTArray<WebRenderParentCommand>& aParentCommands,
    1693             :                                         WebRenderLayerManager* aManager,
    1694             :                                         nsDisplayListBuilder* aDisplayListBuilder)
    1695             : {
    1696           0 :   if (!CanOptimizeToImageLayer(aManager, aDisplayListBuilder)) {
    1697           0 :     return false;
    1698             :   }
    1699             : 
    1700           0 :   uint32_t flags = imgIContainer::FLAG_ASYNC_NOTIFY;
    1701           0 :   if (aDisplayListBuilder->ShouldSyncDecodeImages()) {
    1702           0 :     flags |= imgIContainer::FLAG_SYNC_DECODE;
    1703             :   }
    1704             : 
    1705             :   RefPtr<ImageContainer> container =
    1706           0 :     mImage->GetImageContainer(aManager, flags);
    1707           0 :   if (!container) {
    1708           0 :     return false;
    1709             :   }
    1710             : 
    1711             : 
    1712           0 :   const int32_t factor = mFrame->PresContext()->AppUnitsPerDevPixel();
    1713             :   const LayoutDeviceRect destRect(
    1714           0 :     LayoutDeviceIntRect::FromAppUnits(GetDestRect(), factor));
    1715           0 :   const LayerRect dest = ViewAs<LayerPixel>(destRect, PixelCastJustification::WebRenderHasUnitResolution);
    1716           0 :   return aManager->PushImage(this, container, aBuilder, aSc, dest);
    1717             : }
    1718             : 
    1719             : DrawResult
    1720           0 : nsImageFrame::PaintImage(gfxContext& aRenderingContext, nsPoint aPt,
    1721             :                          const nsRect& aDirtyRect, imgIContainer* aImage,
    1722             :                          uint32_t aFlags)
    1723             : {
    1724           0 :   DrawTarget* drawTarget = aRenderingContext.GetDrawTarget();
    1725             : 
    1726             :   // Render the image into our content area (the area inside
    1727             :   // the borders and padding)
    1728           0 :   NS_ASSERTION(GetInnerArea().width == mComputedSize.width, "bad width");
    1729             : 
    1730             :   // NOTE: We use mComputedSize instead of just GetInnerArea()'s own size here,
    1731             :   // because GetInnerArea() might be smaller if we're fragmented, whereas
    1732             :   // mComputedSize has our full content-box size (which we need for
    1733             :   // ComputeObjectDestRect to work correctly).
    1734           0 :   nsRect constraintRect(aPt + GetInnerArea().TopLeft(), mComputedSize);
    1735           0 :   constraintRect.y -= GetContinuationOffset();
    1736             : 
    1737           0 :   nsPoint anchorPoint;
    1738             :   nsRect dest = nsLayoutUtils::ComputeObjectDestRect(constraintRect,
    1739             :                                                      mIntrinsicSize,
    1740             :                                                      mIntrinsicRatio,
    1741             :                                                      StylePosition(),
    1742           0 :                                                      &anchorPoint);
    1743             : 
    1744           0 :   uint32_t flags = aFlags;
    1745           0 :   if (mForceSyncDecoding) {
    1746           0 :     flags |= imgIContainer::FLAG_SYNC_DECODE;
    1747             :   }
    1748             : 
    1749           0 :   Maybe<SVGImageContext> svgContext;
    1750           0 :   SVGImageContext::MaybeStoreContextPaint(svgContext, this, aImage);
    1751             : 
    1752             :   DrawResult result =
    1753           0 :     nsLayoutUtils::DrawSingleImage(aRenderingContext,
    1754             :       PresContext(), aImage,
    1755             :       nsLayoutUtils::GetSamplingFilterForFrame(this), dest, aDirtyRect,
    1756           0 :       svgContext, flags, &anchorPoint);
    1757             : 
    1758           0 :   nsImageMap* map = GetImageMap();
    1759           0 :   if (map) {
    1760             :     gfxPoint devPixelOffset =
    1761           0 :       nsLayoutUtils::PointToGfxPoint(dest.TopLeft(),
    1762           0 :                                      PresContext()->AppUnitsPerDevPixel());
    1763           0 :     AutoRestoreTransform autoRestoreTransform(drawTarget);
    1764             :     drawTarget->SetTransform(
    1765           0 :       drawTarget->GetTransform().PreTranslate(ToPoint(devPixelOffset)));
    1766             : 
    1767             :     // solid white stroke:
    1768           0 :     ColorPattern white(ToDeviceColor(Color(1.f, 1.f, 1.f, 1.f)));
    1769           0 :     map->Draw(this, *drawTarget, white);
    1770             : 
    1771             :     // then dashed black stroke over the top:
    1772           0 :     ColorPattern black(ToDeviceColor(Color(0.f, 0.f, 0.f, 1.f)));
    1773           0 :     StrokeOptions strokeOptions;
    1774           0 :     nsLayoutUtils::InitDashPattern(strokeOptions, NS_STYLE_BORDER_STYLE_DOTTED);
    1775           0 :     map->Draw(this, *drawTarget, black, strokeOptions);
    1776             :   }
    1777             : 
    1778           0 :   if (result == DrawResult::SUCCESS) {
    1779           0 :     mPrevImage = aImage;
    1780           0 :   } else if (result == DrawResult::BAD_IMAGE) {
    1781           0 :     mPrevImage = nullptr;
    1782             :   }
    1783             : 
    1784           0 :   return result;
    1785             : }
    1786             : 
    1787             : void
    1788           0 : nsImageFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
    1789             :                                const nsRect&           aDirtyRect,
    1790             :                                const nsDisplayListSet& aLists)
    1791             : {
    1792           0 :   if (!IsVisibleForPainting(aBuilder))
    1793           0 :     return;
    1794             : 
    1795           0 :   DisplayBorderBackgroundOutline(aBuilder, aLists);
    1796             : 
    1797             :   uint32_t clipFlags =
    1798           0 :     nsStyleUtil::ObjectPropsMightCauseOverflow(StylePosition()) ?
    1799           0 :     0 : DisplayListClipState::ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT;
    1800             : 
    1801             :   DisplayListClipState::AutoClipContainingBlockDescendantsToContentBox
    1802           0 :     clip(aBuilder, this, clipFlags);
    1803             : 
    1804           0 :   if (mComputedSize.width != 0 && mComputedSize.height != 0) {
    1805           0 :     nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
    1806           0 :     NS_ASSERTION(imageLoader, "Not an image loading content?");
    1807             : 
    1808           0 :     nsCOMPtr<imgIRequest> currentRequest;
    1809           0 :     if (imageLoader) {
    1810           0 :       imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
    1811           0 :                               getter_AddRefs(currentRequest));
    1812             :     }
    1813             : 
    1814           0 :     EventStates contentState = mContent->AsElement()->State();
    1815           0 :     bool imageOK = IMAGE_OK(contentState, true);
    1816             : 
    1817             :     // XXX(seth): The SizeIsAvailable check here should not be necessary - the
    1818             :     // intention is that a non-null mImage means we have a size, but there is
    1819             :     // currently some code that violates this invariant.
    1820           0 :     if (!imageOK || !mImage || !SizeIsAvailable(currentRequest)) {
    1821             :       // No image yet, or image load failed. Draw the alt-text and an icon
    1822             :       // indicating the status
    1823           0 :       aLists.Content()->AppendNewToTop(new (aBuilder)
    1824           0 :         nsDisplayAltFeedback(aBuilder, this));
    1825             : 
    1826             :       // This image is visible (we are being asked to paint it) but it's not
    1827             :       // decoded yet. And we are not going to ask the image to draw, so this
    1828             :       // may be the only chance to tell it that it should decode.
    1829           0 :       if (currentRequest) {
    1830           0 :         uint32_t status = 0;
    1831           0 :         currentRequest->GetImageStatus(&status);
    1832           0 :         if (!(status & imgIRequest::STATUS_DECODE_COMPLETE)) {
    1833           0 :           MaybeDecodeForPredictedSize();
    1834             :         }
    1835             :         // Increase loading priority if the image is ready to be displayed.
    1836           0 :         if (!(status & imgIRequest::STATUS_LOAD_COMPLETE)){
    1837           0 :           currentRequest->BoostPriority(imgIRequest::CATEGORY_DISPLAY);
    1838             :         }
    1839             :       }
    1840             :     } else {
    1841           0 :       aLists.Content()->AppendNewToTop(new (aBuilder)
    1842           0 :         nsDisplayImage(aBuilder, this, mImage, mPrevImage));
    1843             : 
    1844             :       // If we were previously displaying an icon, we're not anymore
    1845           0 :       if (mDisplayingIcon) {
    1846           0 :         gIconLoad->RemoveIconObserver(this);
    1847           0 :         mDisplayingIcon = false;
    1848             :       }
    1849             : 
    1850             : #ifdef DEBUG
    1851           0 :       if (GetShowFrameBorders() && GetImageMap()) {
    1852           0 :         aLists.Outlines()->AppendNewToTop(new (aBuilder)
    1853             :           nsDisplayGeneric(aBuilder, this, PaintDebugImageMap, "DebugImageMap",
    1854           0 :                            nsDisplayItem::TYPE_DEBUG_IMAGE_MAP));
    1855             :       }
    1856             : #endif
    1857             :     }
    1858             :   }
    1859             : 
    1860           0 :   if (ShouldDisplaySelection()) {
    1861           0 :     DisplaySelectionOverlay(aBuilder, aLists.Content(),
    1862           0 :                             nsISelectionDisplay::DISPLAY_IMAGES);
    1863             :   }
    1864             : }
    1865             : 
    1866             : bool
    1867           0 : nsImageFrame::ShouldDisplaySelection()
    1868             : {
    1869             :   // XXX what on EARTH is this code for?
    1870             :   nsresult result;
    1871           0 :   nsPresContext* presContext = PresContext();
    1872           0 :   int16_t displaySelection = presContext->PresShell()->GetSelectionFlags();
    1873           0 :   if (!(displaySelection & nsISelectionDisplay::DISPLAY_IMAGES))
    1874           0 :     return false;//no need to check the blue border, we cannot be drawn selected
    1875             : //insert hook here for image selection drawing
    1876             : #if IMAGE_EDITOR_CHECK
    1877             :   //check to see if this frame is in an editor context
    1878             :   //isEditor check. this needs to be changed to have better way to check
    1879           0 :   if (displaySelection == nsISelectionDisplay::DISPLAY_ALL)
    1880             :   {
    1881           0 :     nsCOMPtr<nsISelectionController> selCon;
    1882           0 :     result = GetSelectionController(presContext, getter_AddRefs(selCon));
    1883           0 :     if (NS_SUCCEEDED(result) && selCon)
    1884             :     {
    1885           0 :       nsCOMPtr<nsISelection> selection;
    1886           0 :       result = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
    1887           0 :       if (NS_SUCCEEDED(result) && selection)
    1888             :       {
    1889             :         int32_t rangeCount;
    1890           0 :         selection->GetRangeCount(&rangeCount);
    1891           0 :         if (rangeCount == 1) //if not one then let code drop to nsFrame::Paint
    1892             :         {
    1893           0 :           nsCOMPtr<nsIContent> parentContent = mContent->GetParent();
    1894           0 :           if (parentContent)
    1895             :           {
    1896           0 :             int32_t thisOffset = parentContent->IndexOf(mContent);
    1897           0 :             nsCOMPtr<nsIDOMNode> parentNode = do_QueryInterface(parentContent);
    1898           0 :             nsCOMPtr<nsIDOMNode> rangeNode;
    1899             :             int32_t rangeOffset;
    1900           0 :             nsCOMPtr<nsIDOMRange> range;
    1901           0 :             selection->GetRangeAt(0,getter_AddRefs(range));
    1902           0 :             if (range)
    1903             :             {
    1904           0 :               range->GetStartContainer(getter_AddRefs(rangeNode));
    1905           0 :               range->GetStartOffset(&rangeOffset);
    1906             : 
    1907           0 :               if (parentNode && rangeNode && (rangeNode == parentNode) && rangeOffset == thisOffset)
    1908             :               {
    1909           0 :                 range->GetEndContainer(getter_AddRefs(rangeNode));
    1910           0 :                 range->GetEndOffset(&rangeOffset);
    1911           0 :                 if ((rangeNode == parentNode) && (rangeOffset == (thisOffset +1))) //+1 since that would mean this whole content is selected only
    1912           0 :                   return false; //do not allow nsFrame do draw any further selection
    1913             :               }
    1914             :             }
    1915             :           }
    1916             :         }
    1917             :       }
    1918             :     }
    1919             :   }
    1920             : #endif
    1921           0 :   return true;
    1922             : }
    1923             : 
    1924             : nsImageMap*
    1925           0 : nsImageFrame::GetImageMap()
    1926             : {
    1927           0 :   if (!mImageMap) {
    1928           0 :     nsIContent* map = GetMapElement();
    1929           0 :     if (map) {
    1930           0 :       mImageMap = new nsImageMap();
    1931           0 :       mImageMap->Init(this, map);
    1932             :     }
    1933             :   }
    1934             : 
    1935           0 :   return mImageMap;
    1936             : }
    1937             : 
    1938             : bool
    1939           0 : nsImageFrame::IsServerImageMap()
    1940             : {
    1941           0 :   return mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::ismap);
    1942             : }
    1943             : 
    1944             : // Translate an point that is relative to our frame
    1945             : // into a localized pixel coordinate that is relative to the
    1946             : // content area of this frame (inside the border+padding).
    1947             : void
    1948           0 : nsImageFrame::TranslateEventCoords(const nsPoint& aPoint,
    1949             :                                    nsIntPoint&     aResult)
    1950             : {
    1951           0 :   nscoord x = aPoint.x;
    1952           0 :   nscoord y = aPoint.y;
    1953             : 
    1954             :   // Subtract out border and padding here so that the coordinates are
    1955             :   // now relative to the content area of this frame.
    1956           0 :   nsRect inner = GetInnerArea();
    1957           0 :   x -= inner.x;
    1958           0 :   y -= inner.y;
    1959             : 
    1960           0 :   aResult.x = nsPresContext::AppUnitsToIntCSSPixels(x);
    1961           0 :   aResult.y = nsPresContext::AppUnitsToIntCSSPixels(y);
    1962           0 : }
    1963             : 
    1964             : bool
    1965           0 : nsImageFrame::GetAnchorHREFTargetAndNode(nsIURI** aHref, nsString& aTarget,
    1966             :                                          nsIContent** aNode)
    1967             : {
    1968           0 :   bool status = false;
    1969           0 :   aTarget.Truncate();
    1970           0 :   *aHref = nullptr;
    1971           0 :   *aNode = nullptr;
    1972             : 
    1973             :   // Walk up the content tree, looking for an nsIDOMAnchorElement
    1974           0 :   for (nsIContent* content = mContent->GetParent();
    1975           0 :        content; content = content->GetParent()) {
    1976           0 :     nsCOMPtr<dom::Link> link(do_QueryInterface(content));
    1977           0 :     if (link) {
    1978           0 :       nsCOMPtr<nsIURI> href = content->GetHrefURI();
    1979           0 :       if (href) {
    1980           0 :         href->Clone(aHref);
    1981             :       }
    1982           0 :       status = (*aHref != nullptr);
    1983             : 
    1984           0 :       nsCOMPtr<nsIDOMHTMLAnchorElement> anchor(do_QueryInterface(content));
    1985           0 :       if (anchor) {
    1986           0 :         anchor->GetTarget(aTarget);
    1987             :       }
    1988           0 :       NS_ADDREF(*aNode = content);
    1989           0 :       break;
    1990             :     }
    1991             :   }
    1992           0 :   return status;
    1993             : }
    1994             : 
    1995             : nsresult
    1996           0 : nsImageFrame::GetContentForEvent(WidgetEvent* aEvent,
    1997             :                                  nsIContent** aContent)
    1998             : {
    1999           0 :   NS_ENSURE_ARG_POINTER(aContent);
    2000             : 
    2001           0 :   nsIFrame* f = nsLayoutUtils::GetNonGeneratedAncestor(this);
    2002           0 :   if (f != this) {
    2003           0 :     return f->GetContentForEvent(aEvent, aContent);
    2004             :   }
    2005             : 
    2006             :   // XXX We need to make this special check for area element's capturing the
    2007             :   // mouse due to bug 135040. Remove it once that's fixed.
    2008             :   nsIContent* capturingContent =
    2009           0 :     aEvent->HasMouseEventMessage() ? nsIPresShell::GetCapturingContent() :
    2010           0 :                                      nullptr;
    2011           0 :   if (capturingContent && capturingContent->GetPrimaryFrame() == this) {
    2012           0 :     *aContent = capturingContent;
    2013           0 :     NS_IF_ADDREF(*aContent);
    2014           0 :     return NS_OK;
    2015             :   }
    2016             : 
    2017           0 :   nsImageMap* map = GetImageMap();
    2018             : 
    2019           0 :   if (nullptr != map) {
    2020           0 :     nsIntPoint p;
    2021             :     TranslateEventCoords(
    2022           0 :       nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this), p);
    2023           0 :     nsCOMPtr<nsIContent> area = map->GetArea(p.x, p.y);
    2024           0 :     if (area) {
    2025           0 :       area.forget(aContent);
    2026           0 :       return NS_OK;
    2027             :     }
    2028             :   }
    2029             : 
    2030           0 :   *aContent = GetContent();
    2031           0 :   NS_IF_ADDREF(*aContent);
    2032           0 :   return NS_OK;
    2033             : }
    2034             : 
    2035             : // XXX what should clicks on transparent pixels do?
    2036             : nsresult
    2037           0 : nsImageFrame::HandleEvent(nsPresContext* aPresContext,
    2038             :                           WidgetGUIEvent* aEvent,
    2039             :                           nsEventStatus* aEventStatus)
    2040             : {
    2041           0 :   NS_ENSURE_ARG_POINTER(aEventStatus);
    2042             : 
    2043           0 :   if ((aEvent->mMessage == eMouseClick &&
    2044           0 :        aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) ||
    2045           0 :       aEvent->mMessage == eMouseMove) {
    2046           0 :     nsImageMap* map = GetImageMap();
    2047           0 :     bool isServerMap = IsServerImageMap();
    2048           0 :     if ((nullptr != map) || isServerMap) {
    2049           0 :       nsIntPoint p;
    2050             :       TranslateEventCoords(
    2051           0 :         nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this), p);
    2052           0 :       bool inside = false;
    2053             :       // Even though client-side image map triggering happens
    2054             :       // through content, we need to make sure we're not inside
    2055             :       // (in case we deal with a case of both client-side and
    2056             :       // sever-side on the same image - it happens!)
    2057           0 :       if (nullptr != map) {
    2058           0 :         inside = !!map->GetArea(p.x, p.y);
    2059             :       }
    2060             : 
    2061           0 :       if (!inside && isServerMap) {
    2062             : 
    2063             :         // Server side image maps use the href in a containing anchor
    2064             :         // element to provide the basis for the destination url.
    2065           0 :         nsCOMPtr<nsIURI> uri;
    2066           0 :         nsAutoString target;
    2067           0 :         nsCOMPtr<nsIContent> anchorNode;
    2068           0 :         if (GetAnchorHREFTargetAndNode(getter_AddRefs(uri), target,
    2069           0 :                                        getter_AddRefs(anchorNode))) {
    2070             :           // XXX if the mouse is over/clicked in the border/padding area
    2071             :           // we should probably just pretend nothing happened. Nav4
    2072             :           // keeps the x,y coordinates positive as we do; IE doesn't
    2073             :           // bother. Both of them send the click through even when the
    2074             :           // mouse is over the border.
    2075           0 :           if (p.x < 0) p.x = 0;
    2076           0 :           if (p.y < 0) p.y = 0;
    2077             : 
    2078           0 :           nsAutoCString spec;
    2079           0 :           nsresult rv = uri->GetSpec(spec);
    2080           0 :           NS_ENSURE_SUCCESS(rv, rv);
    2081             : 
    2082           0 :           spec += nsPrintfCString("?%d,%d", p.x, p.y);
    2083           0 :           rv = uri->SetSpec(spec);
    2084           0 :           NS_ENSURE_SUCCESS(rv, rv);
    2085             : 
    2086           0 :           bool clicked = false;
    2087           0 :           if (aEvent->mMessage == eMouseClick && !aEvent->DefaultPrevented()) {
    2088           0 :             *aEventStatus = nsEventStatus_eConsumeDoDefault;
    2089           0 :             clicked = true;
    2090             :           }
    2091           0 :           nsContentUtils::TriggerLink(anchorNode, aPresContext, uri, target,
    2092           0 :                                       clicked, true, true);
    2093             :         }
    2094             :       }
    2095             :     }
    2096             :   }
    2097             : 
    2098           0 :   return nsAtomicContainerFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
    2099             : }
    2100             : 
    2101             : nsresult
    2102           0 : nsImageFrame::GetCursor(const nsPoint& aPoint,
    2103             :                         nsIFrame::Cursor& aCursor)
    2104             : {
    2105           0 :   nsImageMap* map = GetImageMap();
    2106           0 :   if (nullptr != map) {
    2107           0 :     nsIntPoint p;
    2108           0 :     TranslateEventCoords(aPoint, p);
    2109           0 :     nsCOMPtr<nsIContent> area = map->GetArea(p.x, p.y);
    2110           0 :     if (area) {
    2111             :       // Use the cursor from the style of the *area* element.
    2112             :       // XXX Using the image as the parent style context isn't
    2113             :       // technically correct, but it's probably the right thing to do
    2114             :       // here, since it means that areas on which the cursor isn't
    2115             :       // specified will inherit the style from the image.
    2116             :       RefPtr<nsStyleContext> areaStyle =
    2117           0 :         PresContext()->PresShell()->StyleSet()->
    2118           0 :           ResolveStyleFor(area->AsElement(), StyleContext(),
    2119           0 :                           LazyComputeBehavior::Allow);
    2120           0 :       FillCursorInformationFromStyle(areaStyle->StyleUserInterface(),
    2121           0 :                                      aCursor);
    2122           0 :       if (NS_STYLE_CURSOR_AUTO == aCursor.mCursor) {
    2123           0 :         aCursor.mCursor = NS_STYLE_CURSOR_DEFAULT;
    2124             :       }
    2125           0 :       return NS_OK;
    2126             :     }
    2127             :   }
    2128           0 :   return nsFrame::GetCursor(aPoint, aCursor);
    2129             : }
    2130             : 
    2131             : nsresult
    2132           0 : nsImageFrame::AttributeChanged(int32_t aNameSpaceID,
    2133             :                                nsIAtom* aAttribute,
    2134             :                                int32_t aModType)
    2135             : {
    2136           0 :   nsresult rv = nsAtomicContainerFrame::AttributeChanged(aNameSpaceID,
    2137           0 :                                                          aAttribute, aModType);
    2138           0 :   if (NS_FAILED(rv)) {
    2139           0 :     return rv;
    2140             :   }
    2141           0 :   if (nsGkAtoms::alt == aAttribute)
    2142             :   {
    2143           0 :     PresContext()->PresShell()->FrameNeedsReflow(this,
    2144             :                                                  nsIPresShell::eStyleChange,
    2145           0 :                                                  NS_FRAME_IS_DIRTY);
    2146             :   }
    2147             : 
    2148           0 :   return NS_OK;
    2149             : }
    2150             : 
    2151             : void
    2152           0 : nsImageFrame::OnVisibilityChange(Visibility aNewVisibility,
    2153             :                                  const Maybe<OnNonvisible>& aNonvisibleAction)
    2154             : {
    2155           0 :   nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
    2156           0 :   if (!imageLoader) {
    2157           0 :     MOZ_ASSERT_UNREACHABLE("Should have an nsIImageLoadingContent");
    2158             :     nsAtomicContainerFrame::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
    2159             :     return;
    2160             :   }
    2161             : 
    2162           0 :   imageLoader->OnVisibilityChange(aNewVisibility, aNonvisibleAction);
    2163             : 
    2164           0 :   if (aNewVisibility == Visibility::APPROXIMATELY_VISIBLE) {
    2165           0 :     MaybeDecodeForPredictedSize();
    2166             :   }
    2167             : 
    2168           0 :   nsAtomicContainerFrame::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
    2169             : }
    2170             : 
    2171             : #ifdef DEBUG_FRAME_DUMP
    2172             : nsresult
    2173           0 : nsImageFrame::GetFrameName(nsAString& aResult) const
    2174             : {
    2175           0 :   return MakeFrameName(NS_LITERAL_STRING("ImageFrame"), aResult);
    2176             : }
    2177             : 
    2178             : void
    2179           0 : nsImageFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
    2180             : {
    2181           0 :   nsCString str;
    2182           0 :   ListGeneric(str, aPrefix, aFlags);
    2183             : 
    2184             :   // output the img src url
    2185           0 :   nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
    2186           0 :   if (imageLoader) {
    2187           0 :     nsCOMPtr<imgIRequest> currentRequest;
    2188           0 :     imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
    2189           0 :                             getter_AddRefs(currentRequest));
    2190           0 :     if (currentRequest) {
    2191           0 :       nsCOMPtr<nsIURI> uri;
    2192           0 :       currentRequest->GetURI(getter_AddRefs(uri));
    2193           0 :       nsAutoCString uristr;
    2194           0 :       uri->GetAsciiSpec(uristr);
    2195           0 :       str += nsPrintfCString(" [src=%s]", uristr.get());
    2196             :     }
    2197             :   }
    2198           0 :   fprintf_stderr(out, "%s\n", str.get());
    2199           0 : }
    2200             : #endif
    2201             : 
    2202             : nsIFrame::LogicalSides
    2203           0 : nsImageFrame::GetLogicalSkipSides(const ReflowInput* aReflowInput) const
    2204             : {
    2205           0 :   if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
    2206             :                      StyleBoxDecorationBreak::Clone)) {
    2207           0 :     return LogicalSides();
    2208             :   }
    2209           0 :   LogicalSides skip;
    2210           0 :   if (nullptr != GetPrevInFlow()) {
    2211           0 :     skip |= eLogicalSideBitsBStart;
    2212             :   }
    2213           0 :   if (nullptr != GetNextInFlow()) {
    2214           0 :     skip |= eLogicalSideBitsBEnd;
    2215             :   }
    2216           0 :   return skip;
    2217             : }
    2218             : 
    2219             : nsresult
    2220           0 : nsImageFrame::GetIntrinsicImageSize(nsSize& aSize)
    2221             : {
    2222           0 :   if (mIntrinsicSize.width.GetUnit() == eStyleUnit_Coord &&
    2223           0 :       mIntrinsicSize.height.GetUnit() == eStyleUnit_Coord) {
    2224           0 :     aSize.SizeTo(mIntrinsicSize.width.GetCoordValue(),
    2225           0 :                  mIntrinsicSize.height.GetCoordValue());
    2226           0 :     return NS_OK;
    2227             :   }
    2228             : 
    2229           0 :   return NS_ERROR_FAILURE;
    2230             : }
    2231             : 
    2232             : nsresult
    2233           0 : nsImageFrame::LoadIcon(const nsAString& aSpec,
    2234             :                        nsPresContext *aPresContext,
    2235             :                        imgRequestProxy** aRequest)
    2236             : {
    2237           0 :   nsresult rv = NS_OK;
    2238           0 :   NS_PRECONDITION(!aSpec.IsEmpty(), "What happened??");
    2239             : 
    2240           0 :   if (!sIOService) {
    2241           0 :     rv = CallGetService(NS_IOSERVICE_CONTRACTID, &sIOService);
    2242           0 :     NS_ENSURE_SUCCESS(rv, rv);
    2243             :   }
    2244             : 
    2245           0 :   nsCOMPtr<nsIURI> realURI;
    2246           0 :   SpecToURI(aSpec, sIOService, getter_AddRefs(realURI));
    2247             : 
    2248             :   RefPtr<imgLoader> il =
    2249           0 :     nsContentUtils::GetImgLoaderForDocument(aPresContext->Document());
    2250             : 
    2251           0 :   nsCOMPtr<nsILoadGroup> loadGroup;
    2252           0 :   GetLoadGroup(aPresContext, getter_AddRefs(loadGroup));
    2253             : 
    2254             :   // For icon loads, we don't need to merge with the loadgroup flags
    2255           0 :   nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL;
    2256           0 :   nsContentPolicyType contentPolicyType = nsIContentPolicy::TYPE_INTERNAL_IMAGE;
    2257             : 
    2258           0 :   return il->LoadImage(realURI,     /* icon URI */
    2259             :                        nullptr,      /* initial document URI; this is only
    2260             :                                        relevant for cookies, so does not
    2261             :                                        apply to icons. */
    2262             :                        nullptr,      /* referrer (not relevant for icons) */
    2263             :                        mozilla::net::RP_Unset,
    2264             :                        nullptr,      /* principal (not relevant for icons) */
    2265             :                        loadGroup,
    2266             :                        gIconLoad,
    2267             :                        nullptr,      /* No context */
    2268             :                        nullptr,      /* Not associated with any particular document */
    2269             :                        loadFlags,
    2270             :                        nullptr,
    2271             :                        contentPolicyType,
    2272           0 :                        EmptyString(),
    2273             :                        false,        /* aUseUrgentStartForChannel */
    2274           0 :                        aRequest);
    2275             : }
    2276             : 
    2277             : void
    2278           0 : nsImageFrame::GetDocumentCharacterSet(nsACString& aCharset) const
    2279             : {
    2280           0 :   if (mContent) {
    2281           0 :     NS_ASSERTION(mContent->GetComposedDoc(),
    2282             :                  "Frame still alive after content removed from document!");
    2283           0 :     mContent->GetComposedDoc()->GetDocumentCharacterSet()->Name(aCharset);
    2284             :   }
    2285           0 : }
    2286             : 
    2287             : void
    2288           0 : nsImageFrame::SpecToURI(const nsAString& aSpec, nsIIOService *aIOService,
    2289             :                          nsIURI **aURI)
    2290             : {
    2291           0 :   nsCOMPtr<nsIURI> baseURI;
    2292           0 :   if (mContent) {
    2293           0 :     baseURI = mContent->GetBaseURI();
    2294             :   }
    2295           0 :   nsAutoCString charset;
    2296           0 :   GetDocumentCharacterSet(charset);
    2297           0 :   NS_NewURI(aURI, aSpec,
    2298           0 :             charset.IsEmpty() ? nullptr : charset.get(),
    2299           0 :             baseURI, aIOService);
    2300           0 : }
    2301             : 
    2302             : void
    2303           0 : nsImageFrame::GetLoadGroup(nsPresContext *aPresContext, nsILoadGroup **aLoadGroup)
    2304             : {
    2305           0 :   if (!aPresContext)
    2306           0 :     return;
    2307             : 
    2308           0 :   NS_PRECONDITION(nullptr != aLoadGroup, "null OUT parameter pointer");
    2309             : 
    2310           0 :   nsIPresShell *shell = aPresContext->GetPresShell();
    2311             : 
    2312           0 :   if (!shell)
    2313           0 :     return;
    2314             : 
    2315           0 :   nsIDocument *doc = shell->GetDocument();
    2316           0 :   if (!doc)
    2317           0 :     return;
    2318             : 
    2319           0 :   *aLoadGroup = doc->GetDocumentLoadGroup().take();
    2320             : }
    2321             : 
    2322           0 : nsresult nsImageFrame::LoadIcons(nsPresContext *aPresContext)
    2323             : {
    2324           0 :   NS_ASSERTION(!gIconLoad, "called LoadIcons twice");
    2325             : 
    2326           0 :   NS_NAMED_LITERAL_STRING(loadingSrc,"resource://gre-resources/loading-image.png");
    2327           0 :   NS_NAMED_LITERAL_STRING(brokenSrc,"resource://gre-resources/broken-image.png");
    2328             : 
    2329           0 :   gIconLoad = new IconLoad();
    2330           0 :   NS_ADDREF(gIconLoad);
    2331             : 
    2332             :   nsresult rv;
    2333             :   // create a loader and load the images
    2334           0 :   rv = LoadIcon(loadingSrc,
    2335             :                 aPresContext,
    2336           0 :                 getter_AddRefs(gIconLoad->mLoadingImage));
    2337           0 :   if (NS_FAILED(rv)) {
    2338           0 :     return rv;
    2339             :   }
    2340             : 
    2341           0 :   rv = LoadIcon(brokenSrc,
    2342             :                 aPresContext,
    2343           0 :                 getter_AddRefs(gIconLoad->mBrokenImage));
    2344           0 :   if (NS_FAILED(rv)) {
    2345           0 :     return rv;
    2346             :   }
    2347             : 
    2348           0 :   return rv;
    2349             : }
    2350             : 
    2351           0 : NS_IMPL_ISUPPORTS(nsImageFrame::IconLoad, nsIObserver,
    2352             :                   imgINotificationObserver)
    2353             : 
    2354             : static const char* kIconLoadPrefs[] = {
    2355             :   "browser.display.force_inline_alttext",
    2356             :   "browser.display.show_image_placeholders",
    2357             :   "browser.display.show_loading_image_placeholder",
    2358             :   nullptr
    2359             : };
    2360             : 
    2361           0 : nsImageFrame::IconLoad::IconLoad()
    2362             : {
    2363             :   // register observers
    2364           0 :   Preferences::AddStrongObservers(this, kIconLoadPrefs);
    2365           0 :   GetPrefs();
    2366           0 : }
    2367             : 
    2368             : void
    2369           0 : nsImageFrame::IconLoad::Shutdown()
    2370             : {
    2371           0 :   Preferences::RemoveObservers(this, kIconLoadPrefs);
    2372             :   // in case the pref service releases us later
    2373           0 :   if (mLoadingImage) {
    2374           0 :     mLoadingImage->CancelAndForgetObserver(NS_ERROR_FAILURE);
    2375           0 :     mLoadingImage = nullptr;
    2376             :   }
    2377           0 :   if (mBrokenImage) {
    2378           0 :     mBrokenImage->CancelAndForgetObserver(NS_ERROR_FAILURE);
    2379           0 :     mBrokenImage = nullptr;
    2380             :   }
    2381           0 : }
    2382             : 
    2383             : NS_IMETHODIMP
    2384           0 : nsImageFrame::IconLoad::Observe(nsISupports *aSubject, const char* aTopic,
    2385             :                                 const char16_t* aData)
    2386             : {
    2387           0 :   NS_ASSERTION(!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID),
    2388             :                "wrong topic");
    2389             : #ifdef DEBUG
    2390             :   // assert |aData| is one of our prefs.
    2391           0 :   uint32_t i = 0;
    2392           0 :   for (; i < ArrayLength(kIconLoadPrefs); ++i) {
    2393           0 :     if (NS_ConvertASCIItoUTF16(kIconLoadPrefs[i]) == nsDependentString(aData))
    2394           0 :       break;
    2395             :   }
    2396           0 :   MOZ_ASSERT(i < ArrayLength(kIconLoadPrefs));
    2397             : #endif
    2398             : 
    2399           0 :   GetPrefs();
    2400           0 :   return NS_OK;
    2401             : }
    2402             : 
    2403           0 : void nsImageFrame::IconLoad::GetPrefs()
    2404             : {
    2405           0 :   mPrefForceInlineAltText =
    2406           0 :     Preferences::GetBool("browser.display.force_inline_alttext");
    2407             : 
    2408           0 :   mPrefShowPlaceholders =
    2409           0 :     Preferences::GetBool("browser.display.show_image_placeholders", true);
    2410             : 
    2411           0 :   mPrefShowLoadingPlaceholder =
    2412           0 :     Preferences::GetBool("browser.display.show_loading_image_placeholder", true);
    2413           0 : }
    2414             : 
    2415             : NS_IMETHODIMP
    2416           0 : nsImageFrame::IconLoad::Notify(imgIRequest* aRequest,
    2417             :                                int32_t aType,
    2418             :                                const nsIntRect* aData)
    2419             : {
    2420           0 :   MOZ_ASSERT(aRequest);
    2421             : 
    2422           0 :   if (aType != imgINotificationObserver::LOAD_COMPLETE &&
    2423             :       aType != imgINotificationObserver::FRAME_UPDATE) {
    2424           0 :     return NS_OK;
    2425             :   }
    2426             : 
    2427           0 :   if (aType == imgINotificationObserver::LOAD_COMPLETE) {
    2428           0 :     nsCOMPtr<imgIContainer> image;
    2429           0 :     aRequest->GetImage(getter_AddRefs(image));
    2430           0 :     if (!image) {
    2431           0 :       return NS_ERROR_FAILURE;
    2432             :     }
    2433             : 
    2434             :     // Retrieve the image's intrinsic size.
    2435           0 :     int32_t width = 0;
    2436           0 :     int32_t height = 0;
    2437           0 :     image->GetWidth(&width);
    2438           0 :     image->GetHeight(&height);
    2439             : 
    2440             :     // Request a decode at that size.
    2441           0 :     image->RequestDecodeForSize(IntSize(width, height),
    2442           0 :                                 imgIContainer::DECODE_FLAGS_DEFAULT);
    2443             :   }
    2444             : 
    2445           0 :   nsTObserverArray<nsImageFrame*>::ForwardIterator iter(mIconObservers);
    2446             :   nsImageFrame *frame;
    2447           0 :   while (iter.HasMore()) {
    2448           0 :     frame = iter.GetNext();
    2449           0 :     frame->InvalidateFrame();
    2450             :   }
    2451             : 
    2452           0 :   return NS_OK;
    2453             : }
    2454             : 
    2455           0 : NS_IMPL_ISUPPORTS(nsImageListener, imgINotificationObserver)
    2456             : 
    2457           0 : nsImageListener::nsImageListener(nsImageFrame *aFrame) :
    2458           0 :   mFrame(aFrame)
    2459             : {
    2460           0 : }
    2461             : 
    2462           0 : nsImageListener::~nsImageListener()
    2463             : {
    2464           0 : }
    2465             : 
    2466             : NS_IMETHODIMP
    2467           0 : nsImageListener::Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData)
    2468             : {
    2469           0 :   if (!mFrame)
    2470           0 :     return NS_ERROR_FAILURE;
    2471             : 
    2472           0 :   return mFrame->Notify(aRequest, aType, aData);
    2473             : }
    2474             : 
    2475             : static bool
    2476           0 : IsInAutoWidthTableCellForQuirk(nsIFrame *aFrame)
    2477             : {
    2478           0 :   if (eCompatibility_NavQuirks != aFrame->PresContext()->CompatibilityMode())
    2479           0 :     return false;
    2480             :   // Check if the parent of the closest nsBlockFrame has auto width.
    2481           0 :   nsBlockFrame *ancestor = nsLayoutUtils::FindNearestBlockAncestor(aFrame);
    2482           0 :   if (ancestor->StyleContext()->GetPseudo() == nsCSSAnonBoxes::cellContent) {
    2483             :     // Assume direct parent is a table cell frame.
    2484           0 :     nsFrame *grandAncestor = static_cast<nsFrame*>(ancestor->GetParent());
    2485           0 :     return grandAncestor &&
    2486           0 :       grandAncestor->StylePosition()->mWidth.GetUnit() == eStyleUnit_Auto;
    2487             :   }
    2488           0 :   return false;
    2489             : }
    2490             : 
    2491             : /* virtual */ void
    2492           0 : nsImageFrame::AddInlineMinISize(gfxContext* aRenderingContext,
    2493             :                                 nsIFrame::InlineMinISizeData* aData)
    2494             : {
    2495           0 :   nscoord isize = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
    2496           0 :                     this, nsLayoutUtils::MIN_ISIZE);
    2497           0 :   bool canBreak = !IsInAutoWidthTableCellForQuirk(this);
    2498           0 :   aData->DefaultAddInlineMinISize(this, isize, canBreak);
    2499           0 : }

Generated by: LCOV version 1.13