LCOV - code coverage report
Current view: directory - content/html/document/src - ImageDocument.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 349 3 0.9 %
Date: 2012-06-02 Functions: 43 3 7.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is Mozilla Communicator client code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Morten Nilsen <morten@nilsen.com>
      24                 :  *   Christian Biesinger <cbiesinger@web.de>
      25                 :  *   Jan Varga <varga@ku.sk>
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      29                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : 
      41                 : #include "MediaDocument.h"
      42                 : #include "nsRect.h"
      43                 : #include "nsHTMLDocument.h"
      44                 : #include "nsIImageDocument.h"
      45                 : #include "nsIImageLoadingContent.h"
      46                 : #include "nsGenericHTMLElement.h"
      47                 : #include "nsIDOMHTMLImageElement.h"
      48                 : #include "nsIDOMEvent.h"
      49                 : #include "nsIDOMKeyEvent.h"
      50                 : #include "nsIDOMMouseEvent.h"
      51                 : #include "nsIDOMEventListener.h"
      52                 : #include "nsGkAtoms.h"
      53                 : #include "imgIRequest.h"
      54                 : #include "imgILoader.h"
      55                 : #include "imgIContainer.h"
      56                 : #include "nsStubImageDecoderObserver.h"
      57                 : #include "nsIPresShell.h"
      58                 : #include "nsPresContext.h"
      59                 : #include "nsStyleContext.h"
      60                 : #include "nsAutoPtr.h"
      61                 : #include "nsStyleSet.h"
      62                 : #include "nsIChannel.h"
      63                 : #include "nsIContentPolicy.h"
      64                 : #include "nsContentPolicyUtils.h"
      65                 : #include "nsPIDOMWindow.h"
      66                 : #include "nsIDOMElement.h"
      67                 : #include "nsIDOMHTMLElement.h"
      68                 : #include "nsContentErrors.h"
      69                 : #include "nsURILoader.h"
      70                 : #include "nsIDocShell.h"
      71                 : #include "nsIContentViewer.h"
      72                 : #include "nsIMarkupDocumentViewer.h"
      73                 : #include "nsIDocShellTreeItem.h"
      74                 : #include "nsThreadUtils.h"
      75                 : #include "nsIScrollableFrame.h"
      76                 : #include "nsContentUtils.h"
      77                 : #include "mozilla/dom/Element.h"
      78                 : #include "mozilla/Preferences.h"
      79                 : 
      80                 : #define AUTOMATIC_IMAGE_RESIZING_PREF "browser.enable_automatic_image_resizing"
      81                 : #define CLICK_IMAGE_RESIZING_PREF "browser.enable_click_image_resizing"
      82                 : //XXX A hack needed for Firefox's site specific zoom.
      83                 : #define SITE_SPECIFIC_ZOOM "browser.zoom.siteSpecific"
      84                 : 
      85                 : namespace mozilla {
      86                 : namespace dom {
      87                 :  
      88                 : class ImageDocument;
      89                 : 
      90                 : class ImageListener : public MediaDocumentStreamListener
      91                 : {
      92                 : public:
      93                 :   ImageListener(ImageDocument* aDocument);
      94                 :   virtual ~ImageListener();
      95                 : 
      96                 :   /* nsIRequestObserver */
      97                 :   NS_IMETHOD OnStartRequest(nsIRequest* request, nsISupports *ctxt);
      98                 : };
      99                 : 
     100                 : class ImageDocument : public MediaDocument
     101                 :                     , public nsIImageDocument
     102                 :                     , public nsStubImageDecoderObserver
     103                 :                     , public nsIDOMEventListener
     104                 : {
     105                 : public:
     106                 :   ImageDocument();
     107                 :   virtual ~ImageDocument();
     108                 : 
     109                 :   NS_DECL_ISUPPORTS_INHERITED
     110                 : 
     111                 :   virtual nsresult Init();
     112                 : 
     113                 :   virtual nsresult StartDocumentLoad(const char*         aCommand,
     114                 :                                      nsIChannel*         aChannel,
     115                 :                                      nsILoadGroup*       aLoadGroup,
     116                 :                                      nsISupports*        aContainer,
     117                 :                                      nsIStreamListener** aDocListener,
     118                 :                                      bool                aReset = true,
     119                 :                                      nsIContentSink*     aSink = nsnull);
     120                 : 
     121                 :   virtual void SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject);
     122                 :   virtual void Destroy();
     123                 :   virtual void OnPageShow(bool aPersisted,
     124                 :                           nsIDOMEventTarget* aDispatchStartTarget);
     125                 : 
     126                 :   NS_DECL_NSIIMAGEDOCUMENT
     127                 : 
     128                 :   // imgIDecoderObserver (override nsStubImageDecoderObserver)
     129                 :   NS_IMETHOD OnStartContainer(imgIRequest* aRequest, imgIContainer* aImage);
     130                 :   NS_IMETHOD OnStopDecode(imgIRequest *aRequest, nsresult aStatus, const PRUnichar *aStatusArg);
     131                 : 
     132                 :   // nsIDOMEventListener
     133                 :   NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
     134                 : 
     135            1464 :   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ImageDocument, MediaDocument)
     136                 : 
     137                 :   friend class ImageListener;
     138                 : 
     139               0 :   void DefaultCheckOverflowing() { CheckOverflowing(mResizeImageByDefault); }
     140                 : 
     141                 :   virtual nsXPCClassInfo* GetClassInfo();
     142                 : protected:
     143                 :   virtual nsresult CreateSyntheticDocument();
     144                 : 
     145                 :   nsresult CheckOverflowing(bool changeState);
     146                 : 
     147                 :   void UpdateTitleAndCharset();
     148                 : 
     149                 :   nsresult ScrollImageTo(PRInt32 aX, PRInt32 aY, bool restoreImage);
     150                 : 
     151               0 :   float GetRatio() {
     152                 :     return NS_MIN((float)mVisibleWidth / mImageWidth,
     153               0 :                   (float)mVisibleHeight / mImageHeight);
     154                 :   }
     155                 : 
     156                 :   void ResetZoomLevel();
     157                 :   float GetZoomLevel();
     158                 : 
     159                 :   nsCOMPtr<nsIContent>          mImageContent;
     160                 : 
     161                 :   PRInt32                       mVisibleWidth;
     162                 :   PRInt32                       mVisibleHeight;
     163                 :   PRInt32                       mImageWidth;
     164                 :   PRInt32                       mImageHeight;
     165                 : 
     166                 :   bool                          mResizeImageByDefault;
     167                 :   bool                          mClickResizingEnabled;
     168                 :   bool                          mImageIsOverflowing;
     169                 :   // mImageIsResized is true if the image is currently resized
     170                 :   bool                          mImageIsResized;
     171                 :   // mShouldResize is true if the image should be resized when it doesn't fit
     172                 :   // mImageIsResized cannot be true when this is false, but mImageIsResized
     173                 :   // can be false when this is true
     174                 :   bool                          mShouldResize;
     175                 :   bool                          mFirstResize;
     176                 :   // mObservingImageLoader is true while the observer is set.
     177                 :   bool                          mObservingImageLoader;
     178                 : 
     179                 :   float                         mOriginalZoomLevel;
     180                 : };
     181                 : 
     182               0 : ImageListener::ImageListener(ImageDocument* aDocument)
     183               0 :   : MediaDocumentStreamListener(aDocument)
     184                 : {
     185               0 : }
     186                 : 
     187               0 : ImageListener::~ImageListener()
     188                 : {
     189               0 : }
     190                 : 
     191                 : NS_IMETHODIMP
     192               0 : ImageListener::OnStartRequest(nsIRequest* request, nsISupports *ctxt)
     193                 : {
     194               0 :   NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE);
     195                 : 
     196               0 :   ImageDocument *imgDoc = static_cast<ImageDocument*>(mDocument.get());
     197               0 :   nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
     198               0 :   if (!channel) {
     199               0 :     return NS_ERROR_FAILURE;
     200                 :   }
     201                 : 
     202                 :   nsCOMPtr<nsPIDOMWindow> domWindow =
     203               0 :     do_QueryInterface(imgDoc->GetScriptGlobalObject());
     204               0 :   NS_ENSURE_TRUE(domWindow, NS_ERROR_UNEXPECTED);
     205                 : 
     206                 :   // Do a ShouldProcess check to see whether to keep loading the image.
     207               0 :   nsCOMPtr<nsIURI> channelURI;
     208               0 :   channel->GetURI(getter_AddRefs(channelURI));
     209                 : 
     210               0 :   nsCAutoString mimeType;
     211               0 :   channel->GetContentType(mimeType);
     212                 : 
     213               0 :   nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
     214               0 :   nsCOMPtr<nsIPrincipal> channelPrincipal;
     215               0 :   if (secMan) {
     216               0 :     secMan->GetChannelPrincipal(channel, getter_AddRefs(channelPrincipal));
     217                 :   }
     218                 :   
     219               0 :   PRInt16 decision = nsIContentPolicy::ACCEPT;
     220                 :   nsresult rv = NS_CheckContentProcessPolicy(nsIContentPolicy::TYPE_IMAGE,
     221                 :                                              channelURI,
     222                 :                                              channelPrincipal,
     223               0 :                                              domWindow->GetFrameElementInternal(),
     224                 :                                              mimeType,
     225                 :                                              nsnull,
     226                 :                                              &decision,
     227                 :                                              nsContentUtils::GetContentPolicy(),
     228               0 :                                              secMan);
     229                 :                                                
     230               0 :   if (NS_FAILED(rv) || NS_CP_REJECTED(decision)) {
     231               0 :     request->Cancel(NS_ERROR_CONTENT_BLOCKED);
     232               0 :     return NS_OK;
     233                 :   }
     234                 : 
     235               0 :   nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(imgDoc->mImageContent);
     236               0 :   NS_ENSURE_TRUE(imageLoader, NS_ERROR_UNEXPECTED);
     237                 : 
     238               0 :   imageLoader->AddObserver(imgDoc);
     239               0 :   imgDoc->mObservingImageLoader = true;
     240               0 :   imageLoader->LoadImageWithChannel(channel, getter_AddRefs(mNextStream));
     241                 : 
     242               0 :   return MediaDocumentStreamListener::OnStartRequest(request, ctxt);
     243                 : }
     244                 : 
     245               0 : ImageDocument::ImageDocument()
     246               0 :   : mOriginalZoomLevel(1.0)
     247                 : {
     248                 :   // NOTE! nsDocument::operator new() zeroes out all members, so don't
     249                 :   // bother initializing members to 0.
     250               0 : }
     251                 : 
     252               0 : ImageDocument::~ImageDocument()
     253                 : {
     254               0 : }
     255                 : 
     256            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(ImageDocument)
     257                 : 
     258               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ImageDocument, MediaDocument)
     259               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mImageContent)
     260               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     261                 : 
     262               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ImageDocument, MediaDocument)
     263               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mImageContent)
     264               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     265                 : 
     266               0 : NS_IMPL_ADDREF_INHERITED(ImageDocument, MediaDocument)
     267               0 : NS_IMPL_RELEASE_INHERITED(ImageDocument, MediaDocument)
     268                 : 
     269               0 : DOMCI_NODE_DATA(ImageDocument, ImageDocument)
     270                 : 
     271               0 : NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(ImageDocument)
     272                 :   NS_HTML_DOCUMENT_INTERFACE_TABLE_BEGIN(ImageDocument)
     273                 :     NS_INTERFACE_TABLE_ENTRY(ImageDocument, nsIImageDocument)
     274                 :     NS_INTERFACE_TABLE_ENTRY(ImageDocument, imgIDecoderObserver)
     275                 :     NS_INTERFACE_TABLE_ENTRY(ImageDocument, imgIContainerObserver)
     276                 :     NS_INTERFACE_TABLE_ENTRY(ImageDocument, nsIDOMEventListener)
     277               0 :   NS_OFFSET_AND_INTERFACE_TABLE_END
     278               0 :   NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
     279               0 :   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ImageDocument)
     280               0 : NS_INTERFACE_MAP_END_INHERITING(MediaDocument)
     281                 : 
     282                 : 
     283                 : nsresult
     284               0 : ImageDocument::Init()
     285                 : {
     286               0 :   nsresult rv = MediaDocument::Init();
     287               0 :   NS_ENSURE_SUCCESS(rv, rv);
     288                 : 
     289               0 :   mResizeImageByDefault = Preferences::GetBool(AUTOMATIC_IMAGE_RESIZING_PREF);
     290               0 :   mClickResizingEnabled = Preferences::GetBool(CLICK_IMAGE_RESIZING_PREF);
     291               0 :   mShouldResize = mResizeImageByDefault;
     292               0 :   mFirstResize = true;
     293                 : 
     294               0 :   return NS_OK;
     295                 : }
     296                 : 
     297                 : nsresult
     298               0 : ImageDocument::StartDocumentLoad(const char*         aCommand,
     299                 :                                  nsIChannel*         aChannel,
     300                 :                                  nsILoadGroup*       aLoadGroup,
     301                 :                                  nsISupports*        aContainer,
     302                 :                                  nsIStreamListener** aDocListener,
     303                 :                                  bool                aReset,
     304                 :                                  nsIContentSink*     aSink)
     305                 : {
     306                 :   nsresult rv =
     307                 :     MediaDocument::StartDocumentLoad(aCommand, aChannel, aLoadGroup, aContainer,
     308               0 :                                      aDocListener, aReset, aSink);
     309               0 :   if (NS_FAILED(rv)) {
     310               0 :     return rv;
     311                 :   }
     312                 : 
     313                 :   mOriginalZoomLevel =
     314               0 :     Preferences::GetBool(SITE_SPECIFIC_ZOOM, false) ? 1.0 : GetZoomLevel();
     315                 : 
     316               0 :   NS_ASSERTION(aDocListener, "null aDocListener");
     317               0 :   *aDocListener = new ImageListener(this);
     318               0 :   NS_ADDREF(*aDocListener);
     319                 : 
     320               0 :   return NS_OK;
     321                 : }
     322                 : 
     323                 : void
     324               0 : ImageDocument::Destroy()
     325                 : {
     326               0 :   if (mImageContent) {
     327                 :     // Remove our event listener from the image content.
     328               0 :     nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(mImageContent);
     329               0 :     target->RemoveEventListener(NS_LITERAL_STRING("click"), this, false);
     330                 : 
     331                 :     // Break reference cycle with mImageContent, if we have one
     332               0 :     if (mObservingImageLoader) {
     333               0 :       nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mImageContent);
     334               0 :       if (imageLoader) {
     335                 :         // Push a null JSContext on the stack so that code that
     336                 :         // nsImageLoadingContent doesn't think it's being called by JS.  See
     337                 :         // Bug 631241
     338               0 :         nsCxPusher pusher;
     339               0 :         pusher.PushNull();
     340               0 :         imageLoader->RemoveObserver(this);
     341                 :       }
     342                 :     }
     343                 : 
     344               0 :     mImageContent = nsnull;
     345                 :   }
     346                 : 
     347               0 :   MediaDocument::Destroy();
     348               0 : }
     349                 : 
     350                 : void
     351               0 : ImageDocument::SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject)
     352                 : {
     353                 :   // If the script global object is changing, we need to unhook our event
     354                 :   // listeners on the window.
     355               0 :   nsCOMPtr<nsIDOMEventTarget> target;
     356               0 :   if (mScriptGlobalObject &&
     357               0 :       aScriptGlobalObject != mScriptGlobalObject) {
     358               0 :     target = do_QueryInterface(mScriptGlobalObject);
     359               0 :     target->RemoveEventListener(NS_LITERAL_STRING("resize"), this, false);
     360               0 :     target->RemoveEventListener(NS_LITERAL_STRING("keypress"), this,
     361               0 :                                 false);
     362                 :   }
     363                 : 
     364                 :   // Set the script global object on the superclass before doing
     365                 :   // anything that might require it....
     366               0 :   MediaDocument::SetScriptGlobalObject(aScriptGlobalObject);
     367                 : 
     368               0 :   if (aScriptGlobalObject) {
     369               0 :     if (!GetRootElement()) {
     370                 :       // Create synthetic document
     371                 : #ifdef DEBUG
     372                 :       nsresult rv =
     373                 : #endif
     374               0 :         CreateSyntheticDocument();
     375               0 :       NS_ASSERTION(NS_SUCCEEDED(rv), "failed to create synthetic document");
     376                 : 
     377               0 :       target = do_QueryInterface(mImageContent);
     378               0 :       target->AddEventListener(NS_LITERAL_STRING("click"), this, false);
     379                 :     }
     380                 : 
     381               0 :     target = do_QueryInterface(aScriptGlobalObject);
     382               0 :     target->AddEventListener(NS_LITERAL_STRING("resize"), this, false);
     383               0 :     target->AddEventListener(NS_LITERAL_STRING("keypress"), this, false);
     384                 : 
     385               0 :     if (!nsContentUtils::IsChildOfSameType(this)) {
     386               0 :       LinkStylesheet(NS_LITERAL_STRING("resource://gre/res/TopLevelImageDocument.css"));
     387                 :     }
     388                 :   }
     389               0 : }
     390                 : 
     391                 : void
     392               0 : ImageDocument::OnPageShow(bool aPersisted,
     393                 :                           nsIDOMEventTarget* aDispatchStartTarget)
     394                 : {
     395               0 :   if (aPersisted) {
     396                 :     mOriginalZoomLevel =
     397               0 :       Preferences::GetBool(SITE_SPECIFIC_ZOOM, false) ? 1.0 : GetZoomLevel();
     398                 :   }
     399               0 :   MediaDocument::OnPageShow(aPersisted, aDispatchStartTarget);
     400               0 : }
     401                 : 
     402                 : NS_IMETHODIMP
     403               0 : ImageDocument::GetImageResizingEnabled(bool* aImageResizingEnabled)
     404                 : {
     405               0 :   *aImageResizingEnabled = true;
     406               0 :   return NS_OK;
     407                 : }
     408                 : 
     409                 : NS_IMETHODIMP
     410               0 : ImageDocument::GetImageIsOverflowing(bool* aImageIsOverflowing)
     411                 : {
     412               0 :   *aImageIsOverflowing = mImageIsOverflowing;
     413               0 :   return NS_OK;
     414                 : }
     415                 : 
     416                 : NS_IMETHODIMP
     417               0 : ImageDocument::GetImageIsResized(bool* aImageIsResized)
     418                 : {
     419               0 :   *aImageIsResized = mImageIsResized;
     420               0 :   return NS_OK;
     421                 : }
     422                 : 
     423                 : NS_IMETHODIMP
     424               0 : ImageDocument::GetImageRequest(imgIRequest** aImageRequest)
     425                 : {
     426               0 :   nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mImageContent);
     427               0 :   if (imageLoader) {
     428               0 :     return imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
     429               0 :                                    aImageRequest);
     430                 :   }
     431                 : 
     432               0 :   *aImageRequest = nsnull;
     433               0 :   return NS_OK;
     434                 : }
     435                 : 
     436                 : NS_IMETHODIMP
     437               0 : ImageDocument::ShrinkToFit()
     438                 : {
     439               0 :   if (!mImageContent) {
     440               0 :     return NS_OK;
     441                 :   }
     442               0 :   if (GetZoomLevel() != mOriginalZoomLevel && mImageIsResized &&
     443               0 :       !nsContentUtils::IsChildOfSameType(this)) {
     444               0 :     return NS_OK;
     445                 :   }
     446                 : 
     447                 :   // Keep image content alive while changing the attributes.
     448               0 :   nsCOMPtr<nsIContent> imageContent = mImageContent;
     449               0 :   nsCOMPtr<nsIDOMHTMLImageElement> image = do_QueryInterface(mImageContent);
     450               0 :   image->SetWidth(NS_MAX(1, NSToCoordFloor(GetRatio() * mImageWidth)));
     451               0 :   image->SetHeight(NS_MAX(1, NSToCoordFloor(GetRatio() * mImageHeight)));
     452                 :   
     453                 :   // The view might have been scrolled when zooming in, scroll back to the
     454                 :   // origin now that we're showing a shrunk-to-window version.
     455               0 :   (void) ScrollImageTo(0, 0, false);
     456                 : 
     457                 :   imageContent->SetAttr(kNameSpaceID_None, nsGkAtoms::style,
     458               0 :                         NS_LITERAL_STRING("cursor: -moz-zoom-in"), true);
     459                 :   
     460               0 :   mImageIsResized = true;
     461                 :   
     462               0 :   UpdateTitleAndCharset();
     463                 : 
     464               0 :   return NS_OK;
     465                 : }
     466                 : 
     467                 : NS_IMETHODIMP
     468               0 : ImageDocument::RestoreImageTo(PRInt32 aX, PRInt32 aY)
     469                 : {
     470               0 :   return ScrollImageTo(aX, aY, true);
     471                 : }
     472                 : 
     473                 : nsresult
     474               0 : ImageDocument::ScrollImageTo(PRInt32 aX, PRInt32 aY, bool restoreImage)
     475                 : {
     476               0 :   float ratio = GetRatio();
     477                 : 
     478               0 :   if (restoreImage) {
     479               0 :     RestoreImage();
     480               0 :     FlushPendingNotifications(Flush_Layout);
     481                 :   }
     482                 : 
     483               0 :   nsIPresShell *shell = GetShell();
     484               0 :   if (!shell)
     485               0 :     return NS_OK;
     486                 : 
     487               0 :   nsIScrollableFrame* sf = shell->GetRootScrollFrameAsScrollable();
     488               0 :   if (!sf)
     489               0 :     return NS_OK;
     490                 : 
     491               0 :   nsRect portRect = sf->GetScrollPortRect();
     492               0 :   sf->ScrollTo(nsPoint(nsPresContext::CSSPixelsToAppUnits(aX/ratio) - portRect.width/2,
     493               0 :                        nsPresContext::CSSPixelsToAppUnits(aY/ratio) - portRect.height/2),
     494               0 :                nsIScrollableFrame::INSTANT);
     495               0 :   return NS_OK;
     496                 : }
     497                 : 
     498                 : NS_IMETHODIMP
     499               0 : ImageDocument::RestoreImage()
     500                 : {
     501               0 :   if (!mImageContent) {
     502               0 :     return NS_OK;
     503                 :   }
     504                 :   // Keep image content alive while changing the attributes.
     505               0 :   nsCOMPtr<nsIContent> imageContent = mImageContent;
     506               0 :   imageContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::width, true);
     507               0 :   imageContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::height, true);
     508                 :   
     509               0 :   if (mImageIsOverflowing) {
     510                 :     imageContent->SetAttr(kNameSpaceID_None, nsGkAtoms::style,
     511               0 :                           NS_LITERAL_STRING("cursor: -moz-zoom-out"), true);
     512                 :   }
     513                 :   else {
     514               0 :     imageContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::style, true);
     515                 :   }
     516                 :   
     517               0 :   mImageIsResized = false;
     518                 :   
     519               0 :   UpdateTitleAndCharset();
     520                 : 
     521               0 :   return NS_OK;
     522                 : }
     523                 : 
     524                 : NS_IMETHODIMP
     525               0 : ImageDocument::ToggleImageSize()
     526                 : {
     527               0 :   mShouldResize = true;
     528               0 :   if (mImageIsResized) {
     529               0 :     mShouldResize = false;
     530               0 :     ResetZoomLevel();
     531               0 :     RestoreImage();
     532                 :   }
     533               0 :   else if (mImageIsOverflowing) {
     534               0 :     ResetZoomLevel();
     535               0 :     ShrinkToFit();
     536                 :   }
     537                 : 
     538               0 :   return NS_OK;
     539                 : }
     540                 : 
     541                 : NS_IMETHODIMP
     542               0 : ImageDocument::OnStartContainer(imgIRequest* aRequest, imgIContainer* aImage)
     543                 : {
     544               0 :   aImage->GetWidth(&mImageWidth);
     545               0 :   aImage->GetHeight(&mImageHeight);
     546                 :   nsCOMPtr<nsIRunnable> runnable =
     547               0 :     NS_NewRunnableMethod(this, &ImageDocument::DefaultCheckOverflowing);
     548               0 :   nsContentUtils::AddScriptRunner(runnable);
     549               0 :   UpdateTitleAndCharset();
     550                 : 
     551               0 :   return NS_OK;
     552                 : }
     553                 : 
     554                 : NS_IMETHODIMP
     555               0 : ImageDocument::OnStopDecode(imgIRequest *aRequest,
     556                 :                             nsresult aStatus,
     557                 :                             const PRUnichar *aStatusArg)
     558                 : {
     559               0 :   UpdateTitleAndCharset();
     560                 : 
     561               0 :   nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mImageContent);
     562               0 :   if (imageLoader) {
     563               0 :     mObservingImageLoader = false;
     564               0 :     imageLoader->RemoveObserver(this);
     565                 :   }
     566                 : 
     567                 :   // mImageContent can be null if the document is already destroyed
     568               0 :   if (NS_FAILED(aStatus) && mStringBundle && mImageContent) {
     569               0 :     nsCAutoString src;
     570               0 :     mDocumentURI->GetSpec(src);
     571               0 :     NS_ConvertUTF8toUTF16 srcString(src);
     572               0 :     const PRUnichar* formatString[] = { srcString.get() };
     573               0 :     nsXPIDLString errorMsg;
     574               0 :     NS_NAMED_LITERAL_STRING(str, "InvalidImage");
     575               0 :     mStringBundle->FormatStringFromName(str.get(), formatString, 1,
     576               0 :                                         getter_Copies(errorMsg));
     577                 : 
     578               0 :     mImageContent->SetAttr(kNameSpaceID_None, nsGkAtoms::alt, errorMsg, false);
     579                 :   }
     580                 : 
     581               0 :   return NS_OK;
     582                 : }
     583                 : 
     584                 : NS_IMETHODIMP
     585               0 : ImageDocument::HandleEvent(nsIDOMEvent* aEvent)
     586                 : {
     587               0 :   nsAutoString eventType;
     588               0 :   aEvent->GetType(eventType);
     589               0 :   if (eventType.EqualsLiteral("resize")) {
     590               0 :     CheckOverflowing(false);
     591                 :   }
     592               0 :   else if (eventType.EqualsLiteral("click") && mClickResizingEnabled) {
     593               0 :     ResetZoomLevel();
     594               0 :     mShouldResize = true;
     595               0 :     if (mImageIsResized) {
     596               0 :       PRInt32 x = 0, y = 0;
     597               0 :       nsCOMPtr<nsIDOMMouseEvent> event(do_QueryInterface(aEvent));
     598               0 :       if (event) {
     599               0 :         event->GetClientX(&x);
     600               0 :         event->GetClientY(&y);
     601               0 :         PRInt32 left = 0, top = 0;
     602                 :         nsCOMPtr<nsIDOMHTMLElement> htmlElement =
     603               0 :           do_QueryInterface(mImageContent);
     604               0 :         htmlElement->GetOffsetLeft(&left);
     605               0 :         htmlElement->GetOffsetTop(&top);
     606               0 :         x -= left;
     607               0 :         y -= top;
     608                 :       }
     609               0 :       mShouldResize = false;
     610               0 :       RestoreImageTo(x, y);
     611                 :     }
     612               0 :     else if (mImageIsOverflowing) {
     613               0 :       ShrinkToFit();
     614                 :     }
     615                 :   }
     616                 : 
     617               0 :   return NS_OK;
     618                 : }
     619                 : 
     620                 : nsresult
     621               0 : ImageDocument::CreateSyntheticDocument()
     622                 : {
     623                 :   // Synthesize an html document that refers to the image
     624               0 :   nsresult rv = MediaDocument::CreateSyntheticDocument();
     625               0 :   NS_ENSURE_SUCCESS(rv, rv);
     626                 : 
     627                 :   // We must declare the image as a block element. If we stay as
     628                 :   // an inline element, our parent LineBox will be inline too and
     629                 :   // ignore the available height during reflow.
     630                 :   // This is bad during printing, it means tall image frames won't know
     631                 :   // the size of the paper and cannot break into continuations along
     632                 :   // multiple pages.
     633               0 :   Element* head = GetHeadElement();
     634               0 :   NS_ENSURE_TRUE(head, NS_ERROR_FAILURE);
     635                 : 
     636               0 :   nsCOMPtr<nsINodeInfo> nodeInfo;
     637               0 :   if (nsContentUtils::IsChildOfSameType(this)) {
     638                 :     nodeInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::style, nsnull,
     639                 :                                              kNameSpaceID_XHTML,
     640               0 :                                              nsIDOMNode::ELEMENT_NODE);
     641               0 :     NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
     642               0 :     nsRefPtr<nsGenericHTMLElement> styleContent = NS_NewHTMLStyleElement(nodeInfo.forget());
     643               0 :     NS_ENSURE_TRUE(styleContent, NS_ERROR_OUT_OF_MEMORY);
     644                 : 
     645               0 :     styleContent->SetTextContent(NS_LITERAL_STRING("img { display: block; }"));
     646               0 :     head->AppendChildTo(styleContent, false);
     647                 :   }
     648                 : 
     649                 :   // Add the image element
     650               0 :   Element* body = GetBodyElement();
     651               0 :   if (!body) {
     652               0 :     NS_WARNING("no body on image document!");
     653               0 :     return NS_ERROR_FAILURE;
     654                 :   }
     655                 : 
     656                 :   nodeInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::img, nsnull,
     657                 :                                            kNameSpaceID_XHTML,
     658               0 :                                            nsIDOMNode::ELEMENT_NODE);
     659               0 :   NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
     660                 : 
     661               0 :   mImageContent = NS_NewHTMLImageElement(nodeInfo.forget());
     662               0 :   if (!mImageContent) {
     663               0 :     return NS_ERROR_OUT_OF_MEMORY;
     664                 :   }
     665               0 :   nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mImageContent);
     666               0 :   NS_ENSURE_TRUE(imageLoader, NS_ERROR_UNEXPECTED);
     667                 : 
     668               0 :   nsCAutoString src;
     669               0 :   mDocumentURI->GetSpec(src);
     670                 : 
     671                 :   // Push a null JSContext on the stack so that code that runs within
     672                 :   // the below code doesn't think it's being called by JS. See bug
     673                 :   // 604262.
     674               0 :   nsCxPusher pusher;
     675               0 :   pusher.PushNull();
     676                 : 
     677               0 :   NS_ConvertUTF8toUTF16 srcString(src);
     678                 :   // Make sure not to start the image load from here...
     679               0 :   imageLoader->SetLoadingEnabled(false);
     680               0 :   mImageContent->SetAttr(kNameSpaceID_None, nsGkAtoms::src, srcString, false);
     681               0 :   mImageContent->SetAttr(kNameSpaceID_None, nsGkAtoms::alt, srcString, false);
     682                 : 
     683               0 :   body->AppendChildTo(mImageContent, false);
     684               0 :   imageLoader->SetLoadingEnabled(true);
     685                 : 
     686               0 :   return NS_OK;
     687                 : }
     688                 : 
     689                 : nsresult
     690               0 : ImageDocument::CheckOverflowing(bool changeState)
     691                 : {
     692                 :   /* Create a scope so that the style context gets destroyed before we might
     693                 :    * call RebuildStyleData.  Also, holding onto pointers to the
     694                 :    * presentation through style resolution is potentially dangerous.
     695                 :    */
     696                 :   {
     697               0 :     nsIPresShell *shell = GetShell();
     698               0 :     if (!shell) {
     699               0 :       return NS_OK;
     700                 :     }
     701                 : 
     702               0 :     nsPresContext *context = shell->GetPresContext();
     703               0 :     nsRect visibleArea = context->GetVisibleArea();
     704                 : 
     705               0 :     mVisibleWidth = nsPresContext::AppUnitsToIntCSSPixels(visibleArea.width);
     706               0 :     mVisibleHeight = nsPresContext::AppUnitsToIntCSSPixels(visibleArea.height);
     707                 :   }
     708                 : 
     709               0 :   bool imageWasOverflowing = mImageIsOverflowing;
     710                 :   mImageIsOverflowing =
     711               0 :     mImageWidth > mVisibleWidth || mImageHeight > mVisibleHeight;
     712               0 :   bool windowBecameBigEnough = imageWasOverflowing && !mImageIsOverflowing;
     713                 : 
     714               0 :   if (changeState || mShouldResize || mFirstResize ||
     715                 :       windowBecameBigEnough) {
     716               0 :     if (mImageIsOverflowing && (changeState || mShouldResize)) {
     717               0 :       ShrinkToFit();
     718                 :     }
     719               0 :     else if (mImageIsResized || mFirstResize || windowBecameBigEnough) {
     720               0 :       RestoreImage();
     721                 :     }
     722                 :   }
     723               0 :   mFirstResize = false;
     724                 : 
     725               0 :   return NS_OK;
     726                 : }
     727                 : 
     728                 : void 
     729               0 : ImageDocument::UpdateTitleAndCharset()
     730                 : {
     731               0 :   nsCAutoString typeStr;
     732               0 :   nsCOMPtr<imgIRequest> imageRequest;
     733               0 :   nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mImageContent);
     734               0 :   if (imageLoader) {
     735               0 :     imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
     736               0 :                             getter_AddRefs(imageRequest));
     737                 :   }
     738                 :     
     739               0 :   if (imageRequest) {
     740               0 :     nsXPIDLCString mimeType;
     741               0 :     imageRequest->GetMimeType(getter_Copies(mimeType));
     742               0 :     ToUpperCase(mimeType);
     743               0 :     nsXPIDLCString::const_iterator start, end;
     744               0 :     mimeType.BeginReading(start);
     745               0 :     mimeType.EndReading(end);
     746               0 :     nsXPIDLCString::const_iterator iter = end;
     747               0 :     if (FindInReadable(NS_LITERAL_CSTRING("IMAGE/"), start, iter) && 
     748               0 :         iter != end) {
     749                 :       // strip out "X-" if any
     750               0 :       if (*iter == 'X') {
     751               0 :         ++iter;
     752               0 :         if (iter != end && *iter == '-') {
     753               0 :           ++iter;
     754               0 :           if (iter == end) {
     755                 :             // looks like "IMAGE/X-" is the type??  Bail out of here.
     756               0 :             mimeType.BeginReading(iter);
     757                 :           }
     758                 :         } else {
     759               0 :           --iter;
     760                 :         }
     761                 :       }
     762               0 :       typeStr = Substring(iter, end);
     763                 :     } else {
     764               0 :       typeStr = mimeType;
     765                 :     }
     766                 :   }
     767                 : 
     768               0 :   nsXPIDLString status;
     769               0 :   if (mImageIsResized) {
     770               0 :     nsAutoString ratioStr;
     771               0 :     ratioStr.AppendInt(NSToCoordFloor(GetRatio() * 100));
     772                 : 
     773               0 :     const PRUnichar* formatString[1] = { ratioStr.get() };
     774               0 :     mStringBundle->FormatStringFromName(NS_LITERAL_STRING("ScaledImage").get(),
     775                 :                                         formatString, 1,
     776               0 :                                         getter_Copies(status));
     777                 :   }
     778                 : 
     779                 :   static const char* const formatNames[4] = 
     780                 :   {
     781                 :     "ImageTitleWithNeitherDimensionsNorFile",
     782                 :     "ImageTitleWithoutDimensions",
     783                 :     "ImageTitleWithDimensions",
     784                 :     "ImageTitleWithDimensionsAndFile",
     785                 :   };
     786                 : 
     787                 :   MediaDocument::UpdateTitleAndCharset(typeStr, formatNames,
     788               0 :                                        mImageWidth, mImageHeight, status);
     789               0 : }
     790                 : 
     791                 : void
     792               0 : ImageDocument::ResetZoomLevel()
     793                 : {
     794               0 :   nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocumentContainer);
     795               0 :   if (docShell) {
     796               0 :     if (nsContentUtils::IsChildOfSameType(this)) {
     797                 :       return;
     798                 :     }
     799                 : 
     800               0 :     nsCOMPtr<nsIContentViewer> cv;
     801               0 :     docShell->GetContentViewer(getter_AddRefs(cv));
     802               0 :     nsCOMPtr<nsIMarkupDocumentViewer> mdv = do_QueryInterface(cv);
     803               0 :     if (mdv) {
     804               0 :       mdv->SetFullZoom(mOriginalZoomLevel);
     805                 :     }
     806                 :   }
     807                 : }
     808                 : 
     809                 : float
     810               0 : ImageDocument::GetZoomLevel()
     811                 : {
     812               0 :   float zoomLevel = mOriginalZoomLevel;
     813               0 :   nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocumentContainer);
     814               0 :   if (docShell) {
     815               0 :     nsCOMPtr<nsIContentViewer> cv;
     816               0 :     docShell->GetContentViewer(getter_AddRefs(cv));
     817               0 :     nsCOMPtr<nsIMarkupDocumentViewer> mdv = do_QueryInterface(cv);
     818               0 :     if (mdv) {
     819               0 :       mdv->GetFullZoom(&zoomLevel);
     820                 :     }
     821                 :   }
     822               0 :   return zoomLevel;
     823                 : }
     824                 : 
     825                 : } // namespace dom
     826                 : } // namespace mozilla
     827                 : 
     828                 : DOMCI_DATA(ImageDocument, mozilla::dom::ImageDocument)
     829                 : 
     830                 : nsresult
     831               0 : NS_NewImageDocument(nsIDocument** aResult)
     832                 : {
     833               0 :   mozilla::dom::ImageDocument* doc = new mozilla::dom::ImageDocument();
     834               0 :   NS_ADDREF(doc);
     835                 : 
     836               0 :   nsresult rv = doc->Init();
     837               0 :   if (NS_FAILED(rv)) {
     838               0 :     NS_RELEASE(doc);
     839                 :   }
     840                 : 
     841               0 :   *aResult = doc;
     842                 : 
     843               0 :   return rv;
     844            4392 : }

Generated by: LCOV version 1.7