LCOV - code coverage report
Current view: top level - dom/base - nsImageLoadingContent.h (source / functions) Hit Total Coverage
Test: output.info Lines: 12 16 75.0 %
Date: 2017-07-14 16:53:18 Functions: 4 6 66.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /*
       8             :  * A base class which implements nsIImageLoadingContent and can be
       9             :  * subclassed by various content nodes that want to provide image
      10             :  * loading functionality (eg <img>, <object>, etc).
      11             :  */
      12             : 
      13             : #ifndef nsImageLoadingContent_h__
      14             : #define nsImageLoadingContent_h__
      15             : 
      16             : #include "imgINotificationObserver.h"
      17             : #include "imgIOnloadBlocker.h"
      18             : #include "mozilla/CORSMode.h"
      19             : #include "mozilla/EventStates.h"
      20             : #include "mozilla/TimeStamp.h"
      21             : #include "nsCOMPtr.h"
      22             : #include "nsIImageLoadingContent.h"
      23             : #include "nsIRequest.h"
      24             : #include "mozilla/ErrorResult.h"
      25             : #include "nsIContentPolicy.h"
      26             : #include "mozilla/dom/BindingDeclarations.h"
      27             : #include "mozilla/net/ReferrerPolicy.h"
      28             : 
      29             : class nsIURI;
      30             : class nsIDocument;
      31             : class nsPresContext;
      32             : class nsIContent;
      33             : class imgRequestProxy;
      34             : 
      35             : namespace mozilla {
      36             : class AsyncEventDispatcher;
      37             : } // namespace mozilla
      38             : 
      39             : #ifdef LoadImage
      40             : // Undefine LoadImage to prevent naming conflict with Windows.
      41             : #undef LoadImage
      42             : #endif
      43             : 
      44             : class nsImageLoadingContent : public nsIImageLoadingContent,
      45             :                               public imgIOnloadBlocker
      46             : {
      47             :   template <typename T> using Maybe = mozilla::Maybe<T>;
      48             :   using Nothing = mozilla::Nothing;
      49             :   using OnNonvisible = mozilla::OnNonvisible;
      50             :   using Visibility = mozilla::Visibility;
      51             : 
      52             :   /* METHODS */
      53             : public:
      54             :   nsImageLoadingContent();
      55             :   virtual ~nsImageLoadingContent();
      56             : 
      57             :   NS_DECL_IMGINOTIFICATIONOBSERVER
      58             :   NS_DECL_NSIIMAGELOADINGCONTENT
      59             :   NS_DECL_IMGIONLOADBLOCKER
      60             : 
      61             :   // Web IDL binding methods.
      62             :   // Note that the XPCOM SetLoadingEnabled, AddObserver, RemoveObserver,
      63             :   // ForceImageState methods are OK for Web IDL bindings to use as well,
      64             :   // since none of them throw when called via the Web IDL bindings.
      65             : 
      66           8 :   bool LoadingEnabled() const { return mLoadingEnabled; }
      67           0 :   int16_t ImageBlockingStatus() const
      68             :   {
      69           0 :     return mImageBlockingStatus;
      70             :   }
      71             :   already_AddRefed<imgIRequest>
      72             :     GetRequest(int32_t aRequestType, mozilla::ErrorResult& aError);
      73             :   int32_t
      74             :     GetRequestType(imgIRequest* aRequest, mozilla::ErrorResult& aError);
      75             :   already_AddRefed<nsIURI> GetCurrentURI(mozilla::ErrorResult& aError);
      76             :   void ForceReload(const mozilla::dom::Optional<bool>& aNotify,
      77             :                    mozilla::ErrorResult& aError);
      78             : 
      79             :   // XPCOM [optional] syntax helper
      80           0 :   nsresult ForceReload(bool aNotify = true) {
      81           0 :     return ForceReload(aNotify, 1);
      82             :   }
      83             : 
      84             : protected:
      85             :   enum ImageLoadType {
      86             :     // Most normal image loads
      87             :     eImageLoadType_Normal,
      88             :     // From a <img srcset> or <picture> context. Affects type given to content
      89             :     // policy.
      90             :     eImageLoadType_Imageset
      91             :   };
      92             : 
      93             :   /**
      94             :    * LoadImage is called by subclasses when the appropriate
      95             :    * attributes (eg 'src' for <img> tags) change.  The string passed
      96             :    * in is the new uri string; this consolidates the code for getting
      97             :    * the charset, constructing URI objects, and any other incidentals
      98             :    * into this superclass.
      99             :    *
     100             :    * @param aNewURI the URI spec to be loaded (may be a relative URI)
     101             :    * @param aForce If true, make sure to load the URI.  If false, only
     102             :    *        load if the URI is different from the currently loaded URI.
     103             :    * @param aNotify If true, nsIDocumentObserver state change notifications
     104             :    *                will be sent as needed.
     105             :    * @param aImageLoadType The ImageLoadType for this request
     106             :    */
     107             :   nsresult LoadImage(const nsAString& aNewURI, bool aForce,
     108             :                      bool aNotify, ImageLoadType aImageLoadType);
     109             : 
     110             :   /**
     111             :    * ImageState is called by subclasses that are computing their content state.
     112             :    * The return value will have the NS_EVENT_STATE_BROKEN,
     113             :    * NS_EVENT_STATE_USERDISABLED, and NS_EVENT_STATE_SUPPRESSED bits set as
     114             :    * needed.  Note that this state assumes that this node is "trying" to be an
     115             :    * image (so for example complete lack of attempt to load an image will lead
     116             :    * to NS_EVENT_STATE_BROKEN being set).  Subclasses that are not "trying" to
     117             :    * be an image (eg an HTML <input> of type other than "image") should just
     118             :    * not call this method when computing their intrinsic state.
     119             :    */
     120             :   mozilla::EventStates ImageState() const;
     121             : 
     122             :   /**
     123             :    * LoadImage is called by subclasses when the appropriate
     124             :    * attributes (eg 'src' for <img> tags) change. If callers have an
     125             :    * URI object already available, they should use this method.
     126             :    *
     127             :    * @param aNewURI the URI to be loaded
     128             :    * @param aForce If true, make sure to load the URI.  If false, only
     129             :    *        load if the URI is different from the currently loaded URI.
     130             :    * @param aNotify If true, nsIDocumentObserver state change notifications
     131             :    *                will be sent as needed.
     132             :    * @param aImageLoadType The ImageLoadType for this request
     133             :    * @param aLoadStart If true, dispatch "loadstart" event.
     134             :    * @param aDocument Optional parameter giving the document this node is in.
     135             :    *        This is purely a performance optimization.
     136             :    * @param aLoadFlags Optional parameter specifying load flags to use for
     137             :    *        the image load
     138             :    */
     139             :   nsresult LoadImage(nsIURI* aNewURI, bool aForce, bool aNotify,
     140             :                      ImageLoadType aImageLoadType, bool aLoadStart = true,
     141             :                      nsIDocument* aDocument = nullptr,
     142             :                      nsLoadFlags aLoadFlags = nsIRequest::LOAD_NORMAL);
     143             : 
     144             :   /**
     145             :    * helpers to get the document for this content (from the nodeinfo
     146             :    * and such).  Not named GetOwnerDoc/GetCurrentDoc to prevent ambiguous
     147             :    * method names in subclasses
     148             :    *
     149             :    * @return the document we belong to
     150             :    */
     151             :   nsIDocument* GetOurOwnerDoc();
     152             :   nsIDocument* GetOurCurrentDoc();
     153             : 
     154             :   /**
     155             :    * Helper function to get the frame associated with this content. Not named
     156             :    * GetPrimaryFrame to prevent ambiguous method names in subclasses.
     157             :    *
     158             :    * @return The frame which we belong to, or nullptr if it doesn't exist.
     159             :    */
     160             :   nsIFrame* GetOurPrimaryFrame();
     161             : 
     162             :   /**
     163             :    * Helper function to get the PresContext associated with this content's
     164             :    * frame. Not named GetPresContext to prevent ambiguous method names in
     165             :    * subclasses.
     166             :    *
     167             :    * @return The nsPresContext associated with our frame, or nullptr if either
     168             :    *         the frame doesn't exist, or the frame's prescontext doesn't exist.
     169             :    */
     170             :   nsPresContext* GetFramePresContext();
     171             : 
     172             :   /**
     173             :    * CancelImageRequests is called by subclasses when they want to
     174             :    * cancel all image requests (for example when the subclass is
     175             :    * somehow not an image anymore).
     176             :    */
     177             :   void CancelImageRequests(bool aNotify);
     178             : 
     179             :   /**
     180             :    * UseAsPrimaryRequest is called by subclasses when they have an existing
     181             :    * imgRequestProxy that they want this nsImageLoadingContent to use.  This may
     182             :    * effectively be called instead of LoadImage or LoadImageWithChannel.
     183             :    * If aNotify is true, this method will notify on state changes.
     184             :    */
     185             :   nsresult UseAsPrimaryRequest(imgRequestProxy* aRequest, bool aNotify,
     186             :                                ImageLoadType aImageLoadType);
     187             : 
     188             :   /**
     189             :    * Derived classes of nsImageLoadingContent MUST call
     190             :    * DestroyImageLoadingContent from their destructor, or earlier.  It
     191             :    * does things that cannot be done in ~nsImageLoadingContent because
     192             :    * they rely on being able to QueryInterface to other derived classes,
     193             :    * which cannot happen once the derived class destructor has started
     194             :    * calling the base class destructors.
     195             :    */
     196             :   void DestroyImageLoadingContent();
     197             : 
     198           4 :   void ClearBrokenState() { mBroken = false; }
     199             : 
     200             :   /**
     201             :    * Returns the CORS mode that will be used for all future image loads. The
     202             :    * default implementation returns CORS_NONE unconditionally.
     203             :    */
     204             :   virtual mozilla::CORSMode GetCORSMode();
     205             : 
     206             :   virtual mozilla::net::ReferrerPolicy GetImageReferrerPolicy();
     207             : 
     208             :   // Subclasses are *required* to call BindToTree/UnbindFromTree.
     209             :   void BindToTree(nsIDocument* aDocument, nsIContent* aParent,
     210             :                   nsIContent* aBindingParent, bool aCompileEventHandlers);
     211             :   void UnbindFromTree(bool aDeep, bool aNullParent);
     212             : 
     213             :   nsresult OnLoadComplete(imgIRequest* aRequest, nsresult aStatus);
     214             :   void OnUnlockedDraw();
     215             :   nsresult OnImageIsAnimated(imgIRequest *aRequest);
     216             : 
     217             :   // The nsContentPolicyType we would use for this ImageLoadType
     218             :   static nsContentPolicyType PolicyTypeForLoad(ImageLoadType aImageLoadType);
     219             : 
     220             :   void AsyncEventRunning(mozilla::AsyncEventDispatcher* aEvent);
     221             : 
     222             :   // Get ourselves as an nsIContent*.  Not const because some of the callers
     223             :   // want a non-const nsIContent.
     224             :   virtual nsIContent* AsContent() = 0;
     225             : 
     226             : private:
     227             :   /**
     228             :    * Struct used to manage the image observers.
     229             :    */
     230             :   struct ImageObserver {
     231             :     explicit ImageObserver(imgINotificationObserver* aObserver);
     232             :     ~ImageObserver();
     233             : 
     234             :     nsCOMPtr<imgINotificationObserver> mObserver;
     235             :     ImageObserver* mNext;
     236             :   };
     237             : 
     238             :   /**
     239             :    * Struct to report state changes
     240             :    */
     241             :   struct AutoStateChanger {
     242           8 :     AutoStateChanger(nsImageLoadingContent* aImageContent,
     243           8 :                      bool aNotify) :
     244             :       mImageContent(aImageContent),
     245           8 :       mNotify(aNotify)
     246             :     {
     247           8 :       mImageContent->mStateChangerDepth++;
     248           8 :     }
     249           8 :     ~AutoStateChanger()
     250           8 :     {
     251           8 :       mImageContent->mStateChangerDepth--;
     252           8 :       mImageContent->UpdateImageState(mNotify);
     253           8 :     }
     254             : 
     255             :     nsImageLoadingContent* mImageContent;
     256             :     bool mNotify;
     257             :   };
     258             : 
     259             :   friend struct AutoStateChanger;
     260             : 
     261             :   /**
     262             :    * UpdateImageState recomputes the current state of this image loading
     263             :    * content and updates what ImageState() returns accordingly.  It will also
     264             :    * fire a ContentStatesChanged() notification as needed if aNotify is true.
     265             :    */
     266             :   void UpdateImageState(bool aNotify);
     267             : 
     268             :   /**
     269             :    * Method to fire an event once we know what's going on with the image load.
     270             :    *
     271             :    * @param aEventType "loadstart", "loadend", "load", or "error" depending on
     272             :    *                   how things went
     273             :    * @param aIsCancelable true if event is cancelable.
     274             :    */
     275             :   nsresult FireEvent(const nsAString& aEventType, bool aIsCancelable = false);
     276             : 
     277             :   /**
     278             :    * Method to cancel and null-out pending event if they exist.
     279             :    */
     280             :   void CancelPendingEvent();
     281             : 
     282             :   RefPtr<mozilla::AsyncEventDispatcher> mPendingEvent;
     283             : 
     284             : protected:
     285             :   /**
     286             :    * Method to create an nsIURI object from the given string (will
     287             :    * handle getting the right charset, base, etc).  You MUST pass in a
     288             :    * non-null document to this function.
     289             :    *
     290             :    * @param aSpec the string spec (from an HTML attribute, eg)
     291             :    * @param aDocument the document we belong to
     292             :    * @return the URI we want to be loading
     293             :    */
     294             :   nsresult StringToURI(const nsAString& aSpec, nsIDocument* aDocument,
     295             :                        nsIURI** aURI);
     296             : 
     297             :   void CreateStaticImageClone(nsImageLoadingContent* aDest) const;
     298             : 
     299             :   /**
     300             :    * Prepare and returns a reference to the "next request". If there's already
     301             :    * a _usable_ current request (one with SIZE_AVAILABLE), this request is
     302             :    * "pending" until it becomes usable. Otherwise, this becomes the current
     303             :    * request.
     304             :    *
     305             :    * @param aImageLoadType The ImageLoadType for this request
     306             :    */
     307             :    RefPtr<imgRequestProxy>& PrepareNextRequest(ImageLoadType aImageLoadType);
     308             : 
     309             :   /**
     310             :    * Returns a COMPtr reference to the current/pending image requests, cleaning
     311             :    * up and canceling anything that was there before. Note that if you just want
     312             :    * to get rid of one of the requests, you should call
     313             :    * Clear*Request(NS_BINDING_ABORTED) instead.
     314             :    *
     315             :    * @param aImageLoadType The ImageLoadType for this request
     316             :    */
     317             :   RefPtr<imgRequestProxy>& PrepareCurrentRequest(ImageLoadType aImageLoadType);
     318             :   RefPtr<imgRequestProxy>& PreparePendingRequest(ImageLoadType aImageLoadType);
     319             : 
     320             :   /**
     321             :    * Switch our pending request to be our current request.
     322             :    * mPendingRequest must be non-null!
     323             :    */
     324             :   void MakePendingRequestCurrent();
     325             : 
     326             :   /**
     327             :    * Cancels and nulls-out the "current" and "pending" requests if they exist.
     328             :    *
     329             :    * @param aNonvisibleAction An action to take if the image is no longer
     330             :    *                          visible as a result; see |UntrackImage|.
     331             :    */
     332             :   void ClearCurrentRequest(nsresult aReason,
     333             :                            const Maybe<OnNonvisible>& aNonvisibleAction = Nothing());
     334             :   void ClearPendingRequest(nsresult aReason,
     335             :                            const Maybe<OnNonvisible>& aNonvisibleAction = Nothing());
     336             : 
     337             :   /**
     338             :    * Retrieve a pointer to the 'registered with the refresh driver' flag for
     339             :    * which a particular image request corresponds.
     340             :    *
     341             :    * @returns A pointer to the boolean flag for a given image request, or
     342             :    *          |nullptr| if the request is not either |mPendingRequest| or
     343             :    *          |mCurrentRequest|.
     344             :    */
     345             :   bool* GetRegisteredFlagForRequest(imgIRequest* aRequest);
     346             : 
     347             :   /**
     348             :    * Reset animation of the current request if |mNewRequestsWillNeedAnimationReset|
     349             :    * was true when the request was prepared.
     350             :    */
     351             :   void ResetAnimationIfNeeded();
     352             : 
     353             :   /**
     354             :    * Static helper method to tell us if we have the size of a request. The
     355             :    * image may be null.
     356             :    */
     357             :   static bool HaveSize(imgIRequest *aImage);
     358             : 
     359             :   /**
     360             :    * Adds/Removes a given imgIRequest from our document's tracker.
     361             :    *
     362             :    * No-op if aImage is null.
     363             :    *
     364             :    * @param aFrame If called from FrameCreated the frame passed to FrameCreated.
     365             :    *               This is our frame, but at the time of the FrameCreated call
     366             :    *               our primary frame pointer hasn't been set yet, so this is
     367             :    *               only way to get our frame.
     368             :    *
     369             :    * @param aNonvisibleAction A requested action if the frame has become
     370             :    *                          nonvisible. If Nothing(), no action is
     371             :    *                          requested. If DISCARD_IMAGES is specified, the
     372             :    *                          frame is requested to ask any images it's
     373             :    *                          associated with to discard their surfaces if
     374             :    *                          possible.
     375             :    */
     376             :   void TrackImage(imgIRequest* aImage, nsIFrame* aFrame = nullptr);
     377             :   void UntrackImage(imgIRequest* aImage,
     378             :                     const Maybe<OnNonvisible>& aNonvisibleAction = Nothing());
     379             : 
     380             :   /* MEMBERS */
     381             :   RefPtr<imgRequestProxy> mCurrentRequest;
     382             :   RefPtr<imgRequestProxy> mPendingRequest;
     383             :   uint32_t mCurrentRequestFlags;
     384             :   uint32_t mPendingRequestFlags;
     385             : 
     386             :   enum {
     387             :     // Set if the request needs ResetAnimation called on it.
     388             :     REQUEST_NEEDS_ANIMATION_RESET = 0x00000001U,
     389             :     // Set if the request is blocking onload.
     390             :     REQUEST_BLOCKS_ONLOAD = 0x00000002U,
     391             :     // Set if the request is currently tracked with the document.
     392             :     REQUEST_IS_TRACKED = 0x00000004U,
     393             :     // Set if this is an imageset request, such as from <img srcset> or
     394             :     // <picture>
     395             :     REQUEST_IS_IMAGESET = 0x00000008U
     396             :   };
     397             : 
     398             :   // If the image was blocked or if there was an error loading, it's nice to
     399             :   // still keep track of what the URI was despite not having an imgIRequest.
     400             :   // We only maintain this in those situations (in the common case, this is
     401             :   // always null).
     402             :   nsCOMPtr<nsIURI>      mCurrentURI;
     403             : 
     404             : private:
     405             :   /**
     406             :    * Typically we will have only one observer (our frame in the screen
     407             :    * prescontext), so we want to only make space for one and to
     408             :    * heap-allocate anything past that (saves memory and malloc churn
     409             :    * in the common case).  The storage is a linked list, we just
     410             :    * happen to actually hold the first observer instead of a pointer
     411             :    * to it.
     412             :    */
     413             :   ImageObserver mObserverList;
     414             : 
     415             :   /**
     416             :    * When mIsImageStateForced is true, this holds the ImageState that we'll
     417             :    * return in ImageState().
     418             :    */
     419             :   mozilla::EventStates mForcedImageState;
     420             : 
     421             :   mozilla::TimeStamp mMostRecentRequestChange;
     422             : 
     423             :   int16_t mImageBlockingStatus;
     424             :   bool mLoadingEnabled : 1;
     425             : 
     426             :   /**
     427             :    * When true, we return mForcedImageState from ImageState().
     428             :    */
     429             :   bool mIsImageStateForced : 1;
     430             : 
     431             :   /**
     432             :    * The state we had the last time we checked whether we needed to notify the
     433             :    * document of a state change.  These are maintained by UpdateImageState.
     434             :    */
     435             :   bool mLoading : 1;
     436             :   bool mBroken : 1;
     437             :   bool mUserDisabled : 1;
     438             :   bool mSuppressed : 1;
     439             : 
     440             : protected:
     441             :   /**
     442             :    * A hack to get animations to reset, see bug 594771. On requests
     443             :    * that originate from setting .src, we mark them for needing their animation
     444             :    * reset when they are ready. mNewRequestsWillNeedAnimationReset is set to
     445             :    * true while preparing such requests (as a hack around needing to change an
     446             :    * interface), and the other two booleans store which of the current
     447             :    * and pending requests are of the sort that need their animation restarted.
     448             :    */
     449             :   bool mNewRequestsWillNeedAnimationReset : 1;
     450             : 
     451             :   /**
     452             :    * Flag to indicate whether the channel should be mark as urgent-start.
     453             :    * It should be set in *Element and passed to nsContentUtils::LoadImage.
     454             :    * True if we want to set nsIClassOfService::UrgentStart to the channel to
     455             :    * get the response ASAP for better user responsiveness.
     456             :    */
     457             :   bool mUseUrgentStartForChannel;
     458             : private:
     459             :   /* The number of nested AutoStateChangers currently tracking our state. */
     460             :   uint8_t mStateChangerDepth;
     461             : 
     462             :   // Flags to indicate whether each of the current and pending requests are
     463             :   // registered with the refresh driver.
     464             :   bool mCurrentRequestRegistered;
     465             :   bool mPendingRequestRegistered;
     466             : 
     467             :   // TODO:
     468             :   // Bug 1353685: Should ServiceWorker call SetBlockedRequest?
     469             :   //
     470             :   // This member is used in SetBlockedRequest, if it's true, then this call is
     471             :   // triggered from LoadImage.
     472             :   // If this is false, it means this call is from other places like
     473             :   // ServiceWorker, then we will ignore call to SetBlockedRequest for now.
     474             :   //
     475             :   // Also we use this variable to check if some evil code is reentering LoadImage.
     476             :   bool mIsStartingImageLoad;
     477             : };
     478             : 
     479             : #endif // nsImageLoadingContent_h__

Generated by: LCOV version 1.13