content/base/src/nsImageLoadingContent.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 // vim: ft=cpp tw=78 sw=2 et ts=2
     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/. */
     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  */
    13 #ifndef nsImageLoadingContent_h__
    14 #define nsImageLoadingContent_h__
    16 #include "imgINotificationObserver.h"
    17 #include "imgIOnloadBlocker.h"
    18 #include "mozilla/CORSMode.h"
    19 #include "mozilla/EventStates.h"
    20 #include "nsCOMPtr.h"
    21 #include "nsIImageLoadingContent.h"
    22 #include "nsIRequest.h"
    23 #include "mozilla/ErrorResult.h"
    24 #include "nsAutoPtr.h"
    26 class nsIURI;
    27 class nsIDocument;
    28 class imgILoader;
    29 class nsIIOService;
    30 class nsPresContext;
    31 class nsIContent;
    32 class imgRequestProxy;
    34 #ifdef LoadImage
    35 // Undefine LoadImage to prevent naming conflict with Windows.
    36 #undef LoadImage
    37 #endif
    39 class nsImageLoadingContent : public nsIImageLoadingContent,
    40                               public imgIOnloadBlocker
    41 {
    42   /* METHODS */
    43 public:
    44   nsImageLoadingContent();
    45   virtual ~nsImageLoadingContent();
    47   NS_DECL_IMGINOTIFICATIONOBSERVER
    48   NS_DECL_NSIIMAGELOADINGCONTENT
    49   NS_DECL_IMGIONLOADBLOCKER
    51   // Web IDL binding methods.
    52   // Note that the XPCOM SetLoadingEnabled, AddObserver, RemoveObserver,
    53   // ForceImageState methods are OK for Web IDL bindings to use as well,
    54   // since none of them throw when called via the Web IDL bindings.
    56   bool LoadingEnabled() const { return mLoadingEnabled; }
    57   int16_t ImageBlockingStatus() const
    58   {
    59     return mImageBlockingStatus;
    60   }
    61   already_AddRefed<imgIRequest>
    62     GetRequest(int32_t aRequestType, mozilla::ErrorResult& aError);
    63   int32_t
    64     GetRequestType(imgIRequest* aRequest, mozilla::ErrorResult& aError);
    65   already_AddRefed<nsIURI> GetCurrentURI(mozilla::ErrorResult& aError);
    66   already_AddRefed<nsIStreamListener>
    67     LoadImageWithChannel(nsIChannel* aChannel, mozilla::ErrorResult& aError);
    68   void ForceReload(mozilla::ErrorResult& aError);
    72 protected:
    73   /**
    74    * LoadImage is called by subclasses when the appropriate
    75    * attributes (eg 'src' for <img> tags) change.  The string passed
    76    * in is the new uri string; this consolidates the code for getting
    77    * the charset, constructing URI objects, and any other incidentals
    78    * into this superclass.   
    79    *
    80    * @param aNewURI the URI spec to be loaded (may be a relative URI)
    81    * @param aForce If true, make sure to load the URI.  If false, only
    82    *        load if the URI is different from the currently loaded URI.
    83    * @param aNotify If true, nsIDocumentObserver state change notifications
    84    *                will be sent as needed.
    85    */
    86   nsresult LoadImage(const nsAString& aNewURI, bool aForce,
    87                      bool aNotify);
    89   /**
    90    * ImageState is called by subclasses that are computing their content state.
    91    * The return value will have the NS_EVENT_STATE_BROKEN,
    92    * NS_EVENT_STATE_USERDISABLED, and NS_EVENT_STATE_SUPPRESSED bits set as
    93    * needed.  Note that this state assumes that this node is "trying" to be an
    94    * image (so for example complete lack of attempt to load an image will lead
    95    * to NS_EVENT_STATE_BROKEN being set).  Subclasses that are not "trying" to
    96    * be an image (eg an HTML <input> of type other than "image") should just
    97    * not call this method when computing their intrinsic state.
    98    */
    99   mozilla::EventStates ImageState() const;
   101   /**
   102    * LoadImage is called by subclasses when the appropriate
   103    * attributes (eg 'src' for <img> tags) change. If callers have an
   104    * URI object already available, they should use this method.
   105    *
   106    * @param aNewURI the URI to be loaded
   107    * @param aForce If true, make sure to load the URI.  If false, only
   108    *        load if the URI is different from the currently loaded URI.
   109    * @param aNotify If true, nsIDocumentObserver state change notifications
   110    *                will be sent as needed.
   111    * @param aDocument Optional parameter giving the document this node is in.
   112    *        This is purely a performance optimization.
   113    * @param aLoadFlags Optional parameter specifying load flags to use for
   114    *        the image load
   115    */
   116   nsresult LoadImage(nsIURI* aNewURI, bool aForce, bool aNotify,
   117                      nsIDocument* aDocument = nullptr,
   118                      nsLoadFlags aLoadFlags = nsIRequest::LOAD_NORMAL);
   120   /**
   121    * helpers to get the document for this content (from the nodeinfo
   122    * and such).  Not named GetOwnerDoc/GetCurrentDoc to prevent ambiguous
   123    * method names in subclasses
   124    *
   125    * @return the document we belong to
   126    */
   127   nsIDocument* GetOurOwnerDoc();
   128   nsIDocument* GetOurCurrentDoc();
   130   /**
   131    * Helper function to get the frame associated with this content. Not named
   132    * GetPrimaryFrame to prevent ambiguous method names in subclasses.
   133    *
   134    * @return The frame which we belong to, or nullptr if it doesn't exist.
   135    */
   136   nsIFrame* GetOurPrimaryFrame();
   138   /**
   139    * Helper function to get the PresContext associated with this content's
   140    * frame. Not named GetPresContext to prevent ambiguous method names in
   141    * subclasses.
   142    *
   143    * @return The nsPresContext associated with our frame, or nullptr if either
   144    *         the frame doesn't exist, or the frame's prescontext doesn't exist.
   145    */
   146   nsPresContext* GetFramePresContext();
   148   /**
   149    * CancelImageRequests is called by subclasses when they want to
   150    * cancel all image requests (for example when the subclass is
   151    * somehow not an image anymore).
   152    */
   153   void CancelImageRequests(bool aNotify);
   155   /**
   156    * UseAsPrimaryRequest is called by subclasses when they have an existing
   157    * imgRequestProxy that they want this nsImageLoadingContent to use.  This may
   158    * effectively be called instead of LoadImage or LoadImageWithChannel.
   159    * If aNotify is true, this method will notify on state changes.
   160    */
   161   nsresult UseAsPrimaryRequest(imgRequestProxy* aRequest, bool aNotify);
   163   /**
   164    * Derived classes of nsImageLoadingContent MUST call
   165    * DestroyImageLoadingContent from their destructor, or earlier.  It
   166    * does things that cannot be done in ~nsImageLoadingContent because
   167    * they rely on being able to QueryInterface to other derived classes,
   168    * which cannot happen once the derived class destructor has started
   169    * calling the base class destructors.
   170    */
   171   void DestroyImageLoadingContent();
   173   void ClearBrokenState() { mBroken = false; }
   175   // Sets blocking state only if the desired state is different from the
   176   // current one. See the comment for mBlockingOnload for more information.
   177   void SetBlockingOnload(bool aBlocking);
   179   /**
   180    * Returns the CORS mode that will be used for all future image loads. The
   181    * default implementation returns CORS_NONE unconditionally.
   182    */
   183   virtual mozilla::CORSMode GetCORSMode();
   185   // Subclasses are *required* to call BindToTree/UnbindFromTree.
   186   void BindToTree(nsIDocument* aDocument, nsIContent* aParent,
   187                   nsIContent* aBindingParent, bool aCompileEventHandlers);
   188   void UnbindFromTree(bool aDeep, bool aNullParent);
   190   nsresult OnStopRequest(imgIRequest* aRequest, nsresult aStatus);
   191   void OnUnlockedDraw();
   192   nsresult OnImageIsAnimated(imgIRequest *aRequest);
   194 private:
   195   /**
   196    * Struct used to manage the image observers.
   197    */
   198   struct ImageObserver {
   199     ImageObserver(imgINotificationObserver* aObserver);
   200     ~ImageObserver();
   202     nsCOMPtr<imgINotificationObserver> mObserver;
   203     ImageObserver* mNext;
   204   };
   206   /**
   207    * Struct to report state changes
   208    */
   209   struct AutoStateChanger {
   210     AutoStateChanger(nsImageLoadingContent* aImageContent,
   211                      bool aNotify) :
   212       mImageContent(aImageContent),
   213       mNotify(aNotify)
   214     {
   215       mImageContent->mStateChangerDepth++;
   216     }
   217     ~AutoStateChanger()
   218     {
   219       mImageContent->mStateChangerDepth--;
   220       mImageContent->UpdateImageState(mNotify);
   221     }
   223     nsImageLoadingContent* mImageContent;
   224     bool mNotify;
   225   };
   227   friend struct AutoStateChanger;
   229   /**
   230    * UpdateImageState recomputes the current state of this image loading
   231    * content and updates what ImageState() returns accordingly.  It will also
   232    * fire a ContentStatesChanged() notification as needed if aNotify is true.
   233    */
   234   void UpdateImageState(bool aNotify);
   236   /**
   237    * Method to fire an event once we know what's going on with the image load.
   238    *
   239    * @param aEventType "load" or "error" depending on how things went
   240    */
   241   nsresult FireEvent(const nsAString& aEventType);
   243 protected:
   244   /**
   245    * Method to create an nsIURI object from the given string (will
   246    * handle getting the right charset, base, etc).  You MUST pass in a
   247    * non-null document to this function.
   248    *
   249    * @param aSpec the string spec (from an HTML attribute, eg)
   250    * @param aDocument the document we belong to
   251    * @return the URI we want to be loading
   252    */
   253   nsresult StringToURI(const nsAString& aSpec, nsIDocument* aDocument,
   254                        nsIURI** aURI);
   256   void CreateStaticImageClone(nsImageLoadingContent* aDest) const;
   258   /**
   259    * Prepare and returns a reference to the "next request". If there's already
   260    * a _usable_ current request (one with SIZE_AVAILABLE), this request is
   261    * "pending" until it becomes usable. Otherwise, this becomes the current
   262    * request.
   263    */
   264    nsRefPtr<imgRequestProxy>& PrepareNextRequest();
   266   /**
   267    * Called when we would normally call PrepareNextRequest(), but the request was
   268    * blocked.
   269    */
   270   void SetBlockedRequest(nsIURI* aURI, int16_t aContentDecision);
   272   /**
   273    * Returns a COMPtr reference to the current/pending image requests, cleaning
   274    * up and canceling anything that was there before. Note that if you just want
   275    * to get rid of one of the requests, you should call
   276    * Clear*Request(NS_BINDING_ABORTED) instead, since it passes a more appropriate
   277    * aReason than Prepare*Request() does (NS_ERROR_IMAGE_SRC_CHANGED).
   278    */
   279   nsRefPtr<imgRequestProxy>& PrepareCurrentRequest();
   280   nsRefPtr<imgRequestProxy>& PreparePendingRequest();
   282   /**
   283    * Switch our pending request to be our current request.
   284    * mPendingRequest must be non-null!
   285    */
   286   void MakePendingRequestCurrent();
   288   /**
   289    * Cancels and nulls-out the "current" and "pending" requests if they exist.
   290    */
   291   void ClearCurrentRequest(nsresult aReason, uint32_t aFlags);
   292   void ClearPendingRequest(nsresult aReason, uint32_t aFlags);
   294   /**
   295    * Retrieve a pointer to the 'registered with the refresh driver' flag for
   296    * which a particular image request corresponds.
   297    *
   298    * @returns A pointer to the boolean flag for a given image request, or
   299    *          |nullptr| if the request is not either |mPendingRequest| or
   300    *          |mCurrentRequest|.
   301    */
   302   bool* GetRegisteredFlagForRequest(imgIRequest* aRequest);
   304   /**
   305    * Reset animation of the current request if |mNewRequestsWillNeedAnimationReset|
   306    * was true when the request was prepared.
   307    */
   308   void ResetAnimationIfNeeded();
   310   /**
   311    * Static helper method to tell us if we have the size of a request. The
   312    * image may be null.
   313    */
   314   static bool HaveSize(imgIRequest *aImage);
   316   /**
   317    * Adds/Removes a given imgIRequest from our document's tracker.
   318    *
   319    * No-op if aImage is null.
   320    *
   321    * REQUEST_DISCARD passed to UntrackImage means we request the discard of the
   322    * decoded data of the image.
   323    */
   324   void TrackImage(imgIRequest* aImage);
   325   enum {
   326     REQUEST_DISCARD = 0x1
   327   };
   328   void UntrackImage(imgIRequest* aImage, uint32_t aFlags = 0);
   330   /* MEMBERS */
   331   nsRefPtr<imgRequestProxy> mCurrentRequest;
   332   nsRefPtr<imgRequestProxy> mPendingRequest;
   333   uint32_t mCurrentRequestFlags;
   334   uint32_t mPendingRequestFlags;
   336   enum {
   337     // Set if the request needs ResetAnimation called on it.
   338     REQUEST_NEEDS_ANIMATION_RESET = 0x00000001U,
   339     // Set if the request is blocking onload.
   340     REQUEST_BLOCKS_ONLOAD = 0x00000002U,
   341     // Set if the request is currently tracked with the document.
   342     REQUEST_IS_TRACKED = 0x00000004U
   343   };
   345   // If the image was blocked or if there was an error loading, it's nice to
   346   // still keep track of what the URI was despite not having an imgIRequest.
   347   // We only maintain this in those situations (in the common case, this is
   348   // always null).
   349   nsCOMPtr<nsIURI>      mCurrentURI;
   351 private:
   352   /**
   353    * Typically we will have only one observer (our frame in the screen
   354    * prescontext), so we want to only make space for one and to
   355    * heap-allocate anything past that (saves memory and malloc churn
   356    * in the common case).  The storage is a linked list, we just
   357    * happen to actually hold the first observer instead of a pointer
   358    * to it.
   359    */
   360   ImageObserver mObserverList;
   362   /**
   363    * When mIsImageStateForced is true, this holds the ImageState that we'll
   364    * return in ImageState().
   365    */
   366   mozilla::EventStates mForcedImageState;
   368   int16_t mImageBlockingStatus;
   369   bool mLoadingEnabled : 1;
   371   /**
   372    * When true, we return mForcedImageState from ImageState().
   373    */
   374   bool mIsImageStateForced : 1;
   376   /**
   377    * The state we had the last time we checked whether we needed to notify the
   378    * document of a state change.  These are maintained by UpdateImageState.
   379    */
   380   bool mLoading : 1;
   381   bool mBroken : 1;
   382   bool mUserDisabled : 1;
   383   bool mSuppressed : 1;
   384   bool mFireEventsOnDecode : 1;
   386 protected:
   387   /**
   388    * A hack to get animations to reset, see bug 594771. On requests
   389    * that originate from setting .src, we mark them for needing their animation
   390    * reset when they are ready. mNewRequestsWillNeedAnimationReset is set to
   391    * true while preparing such requests (as a hack around needing to change an
   392    * interface), and the other two booleans store which of the current
   393    * and pending requests are of the sort that need their animation restarted.
   394    */
   395   bool mNewRequestsWillNeedAnimationReset : 1;
   397 private:
   398   /* The number of nested AutoStateChangers currently tracking our state. */
   399   uint8_t mStateChangerDepth;
   401   // Flags to indicate whether each of the current and pending requests are
   402   // registered with the refresh driver.
   403   bool mCurrentRequestRegistered;
   404   bool mPendingRequestRegistered;
   406   // True when FrameCreate has been called but FrameDestroy has not.
   407   bool mFrameCreateCalled;
   409   uint32_t mVisibleCount;
   410 };
   412 #endif // nsImageLoadingContent_h__

mercurial