layout/base/nsDocumentViewer.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=2 sw=2 et 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/. */
     7 /* container for a document and its presentation */
     9 #include "nscore.h"
    10 #include "nsCOMPtr.h"
    11 #include "nsCRT.h"
    12 #include "nsString.h"
    13 #include "nsReadableUtils.h"
    14 #include "nsIContent.h"
    15 #include "nsIContentViewerContainer.h"
    16 #include "nsIContentViewer.h"
    17 #include "nsIDocumentViewerPrint.h"
    18 #include "nsIDOMBeforeUnloadEvent.h"
    19 #include "nsIDocument.h"
    20 #include "nsIDOMWindowUtils.h"
    21 #include "nsPresContext.h"
    22 #include "nsIPresShell.h"
    23 #include "nsStyleSet.h"
    24 #include "nsCSSStyleSheet.h"
    25 #include "nsIFrame.h"
    26 #include "nsIWritablePropertyBag2.h"
    27 #include "nsSubDocumentFrame.h"
    29 #include "nsILinkHandler.h"
    30 #include "nsIDOMDocument.h"
    31 #include "nsISelectionListener.h"
    32 #include "nsISelectionPrivate.h"
    33 #include "nsIDOMHTMLDocument.h"
    34 #include "nsIDOMHTMLElement.h"
    35 #include "nsContentUtils.h"
    36 #include "nsLayoutStylesheetCache.h"
    37 #ifdef ACCESSIBILITY
    38 #include "mozilla/a11y/DocAccessible.h"
    39 #endif
    40 #include "mozilla/BasicEvents.h"
    41 #include "mozilla/Preferences.h"
    42 #include "mozilla/dom/EncodingUtils.h"
    43 #include "mozilla/WeakPtr.h"
    45 #include "nsViewManager.h"
    46 #include "nsView.h"
    48 #include "nsIPageSequenceFrame.h"
    49 #include "nsNetUtil.h"
    50 #include "nsIContentViewerEdit.h"
    51 #include "nsIContentViewerFile.h"
    52 #include "mozilla/css/Loader.h"
    53 #include "nsIMarkupDocumentViewer.h"
    54 #include "nsIInterfaceRequestor.h"
    55 #include "nsIInterfaceRequestorUtils.h"
    56 #include "nsDocShell.h"
    57 #include "nsIBaseWindow.h"
    58 #include "nsILayoutHistoryState.h"
    59 #include "nsCharsetSource.h"
    60 #include "nsHTMLReflowState.h"
    61 #include "nsIImageLoadingContent.h"
    62 #include "nsCopySupport.h"
    63 #include "nsIDOMHTMLFrameSetElement.h"
    64 #ifdef MOZ_XUL
    65 #include "nsIXULDocument.h"
    66 #include "nsXULPopupManager.h"
    67 #endif
    69 #include "nsIClipboardHelper.h"
    71 #include "nsPIDOMWindow.h"
    72 #include "nsDOMNavigationTiming.h"
    73 #include "nsPIWindowRoot.h"
    74 #include "nsJSEnvironment.h"
    75 #include "nsFocusManager.h"
    77 #include "nsIScrollableFrame.h"
    78 #include "nsStyleSheetService.h"
    79 #include "nsRenderingContext.h"
    80 #include "nsILoadContext.h"
    82 #include "nsIPrompt.h"
    83 #include "imgIContainer.h" // image animation mode constants
    85 //--------------------------
    86 // Printing Include
    87 //---------------------------
    88 #ifdef NS_PRINTING
    90 #include "nsIWebBrowserPrint.h"
    92 #include "nsPrintEngine.h"
    94 // Print Options
    95 #include "nsIPrintSettings.h"
    96 #include "nsIPrintOptions.h"
    97 #include "nsISimpleEnumerator.h"
    99 #ifdef DEBUG
   100 // PrintOptions is now implemented by PrintSettingsService
   101 static const char sPrintOptionsContractID[] =
   102   "@mozilla.org/gfx/printsettings-service;1";
   103 #endif // DEBUG
   105 #include "nsIPluginDocument.h"
   107 #endif // NS_PRINTING
   109 //focus
   110 #include "nsIDOMEventTarget.h"
   111 #include "nsIDOMEventListener.h"
   112 #include "nsISelectionController.h"
   114 #include "mozilla/EventDispatcher.h"
   115 #include "nsISHEntry.h"
   116 #include "nsISHistory.h"
   117 #include "nsISHistoryInternal.h"
   118 #include "nsIWebNavigation.h"
   119 #include "nsXMLHttpRequest.h"
   121 //paint forcing
   122 #include <stdio.h>
   124 #include "mozilla/dom/Element.h"
   126 using namespace mozilla;
   127 using namespace mozilla::dom;
   129 #define BEFOREUNLOAD_DISABLED_PREFNAME "dom.disable_beforeunload"
   131 //-----------------------------------------------------
   132 // PR LOGGING
   133 #ifdef MOZ_LOGGING
   134 #define FORCE_PR_LOG /* Allow logging in the release build */
   135 #endif
   137 #include "prlog.h"
   139 #ifdef PR_LOGGING
   141 #ifdef NS_PRINTING
   142 static PRLogModuleInfo *
   143 GetPrintingLog()
   144 {
   145   static PRLogModuleInfo *sLog;
   146   if (!sLog)
   147     sLog = PR_NewLogModule("printing");
   148   return sLog;
   149 }
   150 #define PR_PL(_p1)  PR_LOG(GetPrintingLog(), PR_LOG_DEBUG, _p1);
   151 #endif // NS_PRINTING
   153 #define PRT_YESNO(_p) ((_p)?"YES":"NO")
   154 #else
   155 #define PRT_YESNO(_p)
   156 #define PR_PL(_p1)
   157 #endif
   158 //-----------------------------------------------------
   160 class nsDocumentViewer;
   161 class nsPrintEventDispatcher;
   163 // a small delegate class used to avoid circular references
   165 class nsDocViewerSelectionListener : public nsISelectionListener
   166 {
   167 public:
   169   // nsISupports interface...
   170   NS_DECL_ISUPPORTS
   172   // nsISelectionListerner interface
   173   NS_DECL_NSISELECTIONLISTENER
   175                        nsDocViewerSelectionListener()
   176                        : mDocViewer(nullptr)
   177                        , mGotSelectionState(false)
   178                        , mSelectionWasCollapsed(false)
   179                        {
   180                        }
   182   virtual              ~nsDocViewerSelectionListener() {}
   184   nsresult             Init(nsDocumentViewer *aDocViewer);
   186 protected:
   188   nsDocumentViewer*  mDocViewer;
   189   bool                 mGotSelectionState;
   190   bool                 mSelectionWasCollapsed;
   192 };
   195 /** editor Implementation of the FocusListener interface
   196  */
   197 class nsDocViewerFocusListener : public nsIDOMEventListener
   198 {
   199 public:
   200   /** default constructor
   201    */
   202   nsDocViewerFocusListener();
   203   /** default destructor
   204    */
   205   virtual ~nsDocViewerFocusListener();
   207   NS_DECL_ISUPPORTS
   208   NS_DECL_NSIDOMEVENTLISTENER
   210   nsresult             Init(nsDocumentViewer *aDocViewer);
   212 private:
   213     nsDocumentViewer*  mDocViewer;
   214 };
   217 //-------------------------------------------------------------
   218 class nsDocumentViewer : public nsIContentViewer,
   219                            public nsIContentViewerEdit,
   220                            public nsIContentViewerFile,
   221                            public nsIMarkupDocumentViewer,
   222                            public nsIDocumentViewerPrint
   224 #ifdef NS_PRINTING
   225                            , public nsIWebBrowserPrint
   226 #endif
   228 {
   229   friend class nsDocViewerSelectionListener;
   230   friend class nsPagePrintTimer;
   231   friend class nsPrintEngine;
   233 public:
   234   nsDocumentViewer();
   236   NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
   238   // nsISupports interface...
   239   NS_DECL_ISUPPORTS
   241   // nsIContentViewer interface...
   242   NS_DECL_NSICONTENTVIEWER
   244   // nsIContentViewerEdit
   245   NS_DECL_NSICONTENTVIEWEREDIT
   247   // nsIContentViewerFile
   248   NS_DECL_NSICONTENTVIEWERFILE
   250   // nsIMarkupDocumentViewer
   251   NS_DECL_NSIMARKUPDOCUMENTVIEWER
   253 #ifdef NS_PRINTING
   254   // nsIWebBrowserPrint
   255   NS_DECL_NSIWEBBROWSERPRINT
   256 #endif
   258   typedef void (*CallChildFunc)(nsIMarkupDocumentViewer* aViewer,
   259                                 void* aClosure);
   260   void CallChildren(CallChildFunc aFunc, void* aClosure);
   262   // nsIDocumentViewerPrint Printing Methods
   263   NS_DECL_NSIDOCUMENTVIEWERPRINT
   266   static void DispatchBeforePrint(nsIDocument* aTop)
   267   {
   268     DispatchEventToWindowTree(aTop, NS_LITERAL_STRING("beforeprint"));
   269   }
   270   static void DispatchAfterPrint(nsIDocument* aTop)
   271   {
   272     DispatchEventToWindowTree(aTop, NS_LITERAL_STRING("afterprint"));
   273   }
   274   static void DispatchEventToWindowTree(nsIDocument* aTop,
   275                                         const nsAString& aEvent);
   277 protected:
   278   virtual ~nsDocumentViewer();
   280 private:
   281   /**
   282    * Creates a view manager, root view, and widget for the root view, setting
   283    * mViewManager and mWindow.
   284    * @param aSize the initial size in appunits
   285    * @param aContainerView the container view to hook our root view up
   286    * to as a child, or null if this will be the root view manager
   287    */
   288   nsresult MakeWindow(const nsSize& aSize, nsView* aContainerView);
   290   /**
   291    * Create our device context
   292    */
   293   nsresult CreateDeviceContext(nsView* aContainerView);
   295   /**
   296    * If aDoCreation is true, this creates the device context, creates a
   297    * prescontext if necessary, and calls MakeWindow.
   298    *
   299    * If aForceSetNewDocument is false, then SetNewDocument won't be
   300    * called if the window's current document is already mDocument.
   301    */
   302   nsresult InitInternal(nsIWidget* aParentWidget,
   303                         nsISupports *aState,
   304                         const nsIntRect& aBounds,
   305                         bool aDoCreation,
   306                         bool aNeedMakeCX = true,
   307                         bool aForceSetNewDocument = true);
   308   /**
   309    * @param aDoInitialReflow set to true if you want to kick off the initial
   310    * reflow
   311    */
   312   nsresult InitPresentationStuff(bool aDoInitialReflow);
   314   nsresult GetPopupNode(nsIDOMNode** aNode);
   315   nsresult GetPopupLinkNode(nsIDOMNode** aNode);
   316   nsresult GetPopupImageNode(nsIImageLoadingContent** aNode);
   318   void PrepareToStartLoad(void);
   320   nsresult SyncParentSubDocMap();
   322   nsresult GetDocumentSelection(nsISelection **aSelection);
   324   void DestroyPresShell();
   325   void DestroyPresContext();
   327 #ifdef NS_PRINTING
   328   // Called when the DocViewer is notified that the state
   329   // of Printing or PP has changed
   330   void SetIsPrintingInDocShellTree(nsIDocShellTreeItem* aParentNode, 
   331                                    bool                 aIsPrintingOrPP, 
   332                                    bool                 aStartAtTop);
   333 #endif // NS_PRINTING
   335   // Whether we should attach to the top level widget. This is true if we
   336   // are sharing/recycling a single base widget and not creating multiple
   337   // child widgets.
   338   bool ShouldAttachToTopLevel();
   340 protected:
   341   // These return the current shell/prescontext etc.
   342   nsIPresShell* GetPresShell();
   343   nsPresContext* GetPresContext();
   344   nsViewManager* GetViewManager();
   346   void DetachFromTopLevelWidget();
   348   // IMPORTANT: The ownership implicit in the following member
   349   // variables has been explicitly checked and set using nsCOMPtr
   350   // for owning pointers and raw COM interface pointers for weak
   351   // (ie, non owning) references. If you add any members to this
   352   // class, please make the ownership explicit (pinkerton, scc).
   354   WeakPtr<nsDocShell> mContainer; // it owns me!
   355   nsWeakPtr mTopContainerWhilePrinting;
   356   nsRefPtr<nsDeviceContext> mDeviceContext;  // We create and own this baby
   358   // the following six items are explicitly in this order
   359   // so they will be destroyed in the reverse order (pinkerton, scc)
   360   nsCOMPtr<nsIDocument>    mDocument;
   361   nsCOMPtr<nsIWidget>      mWindow;      // may be null
   362   nsRefPtr<nsViewManager> mViewManager;
   363   nsRefPtr<nsPresContext>  mPresContext;
   364   nsCOMPtr<nsIPresShell>   mPresShell;
   366   nsCOMPtr<nsISelectionListener> mSelectionListener;
   367   nsRefPtr<nsDocViewerFocusListener> mFocusListener;
   369   nsCOMPtr<nsIContentViewer> mPreviousViewer;
   370   nsCOMPtr<nsISHEntry> mSHEntry;
   372   nsIWidget* mParentWidget; // purposely won't be ref counted.  May be null
   373   bool mAttachedToParent; // view is attached to the parent widget
   375   nsIntRect mBounds;
   377   // mTextZoom/mPageZoom record the textzoom/pagezoom of the first (galley)
   378   // presshell only.
   379   float mTextZoom;      // Text zoom, defaults to 1.0
   380   float mPageZoom;
   381   int mMinFontSize;
   383   int16_t mNumURLStarts;
   384   int16_t mDestroyRefCount;    // a second "refcount" for the document viewer's "destroy"
   386   unsigned      mStopped : 1;
   387   unsigned      mLoaded : 1;
   388   unsigned      mDeferredWindowClose : 1;
   389   // document management data
   390   //   these items are specific to markup documents (html and xml)
   391   //   may consider splitting these out into a subclass
   392   unsigned      mIsSticky : 1;
   393   unsigned      mInPermitUnload : 1;
   394   unsigned      mInPermitUnloadPrompt: 1;
   396 #ifdef NS_PRINTING
   397   unsigned      mClosingWhilePrinting : 1;
   399 #if NS_PRINT_PREVIEW
   400   unsigned                         mPrintPreviewZoomed : 1;
   402   // These data members support delayed printing when the document is loading
   403   unsigned                         mPrintIsPending : 1;
   404   unsigned                         mPrintDocIsFullyLoaded : 1;
   405   nsCOMPtr<nsIPrintSettings>       mCachedPrintSettings;
   406   nsCOMPtr<nsIWebProgressListener> mCachedPrintWebProgressListner;
   408   nsRefPtr<nsPrintEngine>          mPrintEngine;
   409   float                            mOriginalPrintPreviewScale;
   410   float                            mPrintPreviewZoom;
   411   nsAutoPtr<nsPrintEventDispatcher> mBeforeAndAfterPrint;
   412 #endif // NS_PRINT_PREVIEW
   414 #ifdef DEBUG
   415   FILE* mDebugFile;
   416 #endif // DEBUG
   417 #endif // NS_PRINTING
   419   /* character set member data */
   420   int32_t mHintCharsetSource;
   421   nsCString mHintCharset;
   422   nsCString mForceCharacterSet;
   424   bool mIsPageMode;
   425   bool mCallerIsClosingWindow;
   426   bool mInitializedForPrintPreview;
   427   bool mHidden;
   428 };
   430 class nsPrintEventDispatcher
   431 {
   432 public:
   433   nsPrintEventDispatcher(nsIDocument* aTop) : mTop(aTop)
   434   {
   435     nsDocumentViewer::DispatchBeforePrint(mTop);
   436   }
   437   ~nsPrintEventDispatcher()
   438   {
   439     nsDocumentViewer::DispatchAfterPrint(mTop);
   440   }
   442   nsCOMPtr<nsIDocument> mTop;
   443 };
   445 class nsDocumentShownDispatcher : public nsRunnable
   446 {
   447 public:
   448   nsDocumentShownDispatcher(nsCOMPtr<nsIDocument> aDocument)
   449   : mDocument(aDocument) {}
   451   NS_IMETHOD Run() MOZ_OVERRIDE;
   453 private:
   454   nsCOMPtr<nsIDocument> mDocument;
   455 };
   458 //------------------------------------------------------------------
   459 // nsDocumentViewer
   460 //------------------------------------------------------------------
   462 //------------------------------------------------------------------
   463 already_AddRefed<nsIContentViewer>
   464 NS_NewContentViewer()
   465 {
   466   nsRefPtr<nsDocumentViewer> viewer = new nsDocumentViewer();
   467   return viewer.forget();
   468 }
   470 void nsDocumentViewer::PrepareToStartLoad()
   471 {
   472   mStopped          = false;
   473   mLoaded           = false;
   474   mAttachedToParent = false;
   475   mDeferredWindowClose = false;
   476   mCallerIsClosingWindow = false;
   478 #ifdef NS_PRINTING
   479   mPrintIsPending        = false;
   480   mPrintDocIsFullyLoaded = false;
   481   mClosingWhilePrinting  = false;
   483   // Make sure we have destroyed it and cleared the data member
   484   if (mPrintEngine) {
   485     mPrintEngine->Destroy();
   486     mPrintEngine = nullptr;
   487 #ifdef NS_PRINT_PREVIEW
   488     SetIsPrintPreview(false);
   489 #endif
   490   }
   492 #ifdef DEBUG
   493   mDebugFile = nullptr;
   494 #endif
   496 #endif // NS_PRINTING
   497 }
   499 // Note: operator new zeros our memory, so no need to init things to null.
   500 nsDocumentViewer::nsDocumentViewer()
   501   : mTextZoom(1.0), mPageZoom(1.0), mMinFontSize(0),
   502     mIsSticky(true),
   503 #ifdef NS_PRINT_PREVIEW
   504     mPrintPreviewZoom(1.0),
   505 #endif
   506     mHintCharsetSource(kCharsetUninitialized),
   507     mInitializedForPrintPreview(false),
   508     mHidden(false)
   509 {
   510   PrepareToStartLoad();
   511 }
   513 NS_IMPL_ADDREF(nsDocumentViewer)
   514 NS_IMPL_RELEASE(nsDocumentViewer)
   516 NS_INTERFACE_MAP_BEGIN(nsDocumentViewer)
   517     NS_INTERFACE_MAP_ENTRY(nsIContentViewer)
   518     NS_INTERFACE_MAP_ENTRY(nsIMarkupDocumentViewer)
   519     NS_INTERFACE_MAP_ENTRY(nsIContentViewerFile)
   520     NS_INTERFACE_MAP_ENTRY(nsIContentViewerEdit)
   521     NS_INTERFACE_MAP_ENTRY(nsIDocumentViewerPrint)
   522     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentViewer)
   523 #ifdef NS_PRINTING
   524     NS_INTERFACE_MAP_ENTRY(nsIWebBrowserPrint)
   525 #endif
   526 NS_INTERFACE_MAP_END
   528 nsDocumentViewer::~nsDocumentViewer()
   529 {
   530   if (mDocument) {
   531     Close(nullptr);
   532     mDocument->Destroy();
   533   }
   535   NS_ASSERTION(!mPresShell && !mPresContext,
   536                "User did not call nsIContentViewer::Destroy");
   537   if (mPresShell || mPresContext) {
   538     // Make sure we don't hand out a reference to the content viewer to
   539     // the SHEntry!
   540     mSHEntry = nullptr;
   542     Destroy();
   543   }
   545   // XXX(?) Revoke pending invalidate events
   546 }
   548 /*
   549  * This method is called by the Document Loader once a document has
   550  * been created for a particular data stream...  The content viewer
   551  * must cache this document for later use when Init(...) is called.
   552  *
   553  * This method is also called when an out of band document.write() happens.
   554  * In that case, the document passed in is the same as the previous document.
   555  */
   556 /* virtual */ void
   557 nsDocumentViewer::LoadStart(nsIDocument* aDocument)
   558 {
   559   MOZ_ASSERT(aDocument);
   561   if (!mDocument) {
   562     mDocument = aDocument;
   563   }
   564 }
   566 nsresult
   567 nsDocumentViewer::SyncParentSubDocMap()
   568 {
   569   nsCOMPtr<nsIDocShellTreeItem> item(mContainer);
   570   nsCOMPtr<nsPIDOMWindow> pwin(do_GetInterface(item));
   571   nsCOMPtr<nsIContent> content;
   573   if (mDocument && pwin) {
   574     content = do_QueryInterface(pwin->GetFrameElementInternal());
   575   }
   577   if (content) {
   578     nsCOMPtr<nsIDocShellTreeItem> parent;
   579     item->GetParent(getter_AddRefs(parent));
   581     nsCOMPtr<nsIDOMWindow> parent_win(do_GetInterface(parent));
   583     if (parent_win) {
   584       nsCOMPtr<nsIDOMDocument> dom_doc;
   585       parent_win->GetDocument(getter_AddRefs(dom_doc));
   587       nsCOMPtr<nsIDocument> parent_doc(do_QueryInterface(dom_doc));
   589       if (parent_doc) {
   590         if (mDocument &&
   591             parent_doc->GetSubDocumentFor(content) != mDocument) {
   592           mDocument->SuppressEventHandling(nsIDocument::eEvents,
   593                                            parent_doc->EventHandlingSuppressed());
   594         }
   595         return parent_doc->SetSubDocumentFor(content->AsElement(), mDocument);
   596       }
   597     }
   598   }
   600   return NS_OK;
   601 }
   603 NS_IMETHODIMP
   604 nsDocumentViewer::SetContainer(nsIDocShell* aContainer)
   605 {
   606   mContainer = static_cast<nsDocShell*>(aContainer)->asWeakPtr();
   607   if (mPresContext) {
   608     mPresContext->SetContainer(mContainer);
   609   }
   611   // We're loading a new document into the window where this document
   612   // viewer lives, sync the parent document's frame element -> sub
   613   // document map
   615   return SyncParentSubDocMap();
   616 }
   618 NS_IMETHODIMP
   619 nsDocumentViewer::GetContainer(nsIDocShell** aResult)
   620 {
   621    NS_ENSURE_ARG_POINTER(aResult);
   623    nsCOMPtr<nsIDocShell> container(mContainer);
   624    container.swap(*aResult);
   625    return NS_OK;
   626 }
   628 NS_IMETHODIMP
   629 nsDocumentViewer::Init(nsIWidget* aParentWidget,
   630                          const nsIntRect& aBounds)
   631 {
   632   return InitInternal(aParentWidget, nullptr, aBounds, true);
   633 }
   635 nsresult
   636 nsDocumentViewer::InitPresentationStuff(bool aDoInitialReflow)
   637 {
   638   if (GetIsPrintPreview())
   639     return NS_OK;
   641   NS_ASSERTION(!mPresShell,
   642                "Someone should have destroyed the presshell!");
   644   // Create the style set...
   645   nsStyleSet *styleSet;
   646   nsresult rv = CreateStyleSet(mDocument, &styleSet);
   647   NS_ENSURE_SUCCESS(rv, rv);
   649   // Now make the shell for the document
   650   mPresShell = mDocument->CreateShell(mPresContext, mViewManager, styleSet);
   651   if (!mPresShell) {
   652     delete styleSet;
   653     return NS_ERROR_FAILURE;
   654   }
   656   // We're done creating the style set
   657   styleSet->EndUpdate();
   659   if (aDoInitialReflow) {
   660     // Since Initialize() will create frames for *all* items
   661     // that are currently in the document tree, we need to flush
   662     // any pending notifications to prevent the content sink from
   663     // duplicating layout frames for content it has added to the tree
   664     // but hasn't notified the document about. (Bug 154018)
   665     //
   666     // Note that we are flushing before we add mPresShell as an observer
   667     // to avoid bogus notifications.
   669     mDocument->FlushPendingNotifications(Flush_ContentAndNotify);
   670   }
   672   mPresShell->BeginObservingDocument();
   674   // Initialize our view manager
   675   int32_t p2a = mPresContext->AppUnitsPerDevPixel();
   676   MOZ_ASSERT(p2a == mPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel());
   677   nscoord width = p2a * mBounds.width;
   678   nscoord height = p2a * mBounds.height;
   680   mViewManager->SetWindowDimensions(width, height);
   681   mPresContext->SetTextZoom(mTextZoom);
   682   mPresContext->SetFullZoom(mPageZoom);
   683   mPresContext->SetBaseMinFontSize(mMinFontSize);
   685   p2a = mPresContext->AppUnitsPerDevPixel();  // zoom may have changed it
   686   width = p2a * mBounds.width;
   687   height = p2a * mBounds.height;
   688   if (aDoInitialReflow) {
   689     nsCOMPtr<nsIPresShell> shellGrip = mPresShell;
   690     // Initial reflow
   691     mPresShell->Initialize(width, height);
   692   } else {
   693     // Store the visible area so it's available for other callers of
   694     // Initialize, like nsContentSink::StartLayout.
   695     mPresContext->SetVisibleArea(nsRect(0, 0, width, height));
   696   }
   698   // now register ourselves as a selection listener, so that we get
   699   // called when the selection changes in the window
   700   if (!mSelectionListener) {
   701     nsDocViewerSelectionListener *selectionListener =
   702       new nsDocViewerSelectionListener();
   704     selectionListener->Init(this);
   706     // mSelectionListener is a owning reference
   707     mSelectionListener = selectionListener;
   708   }
   710   nsCOMPtr<nsISelection> selection;
   711   rv = GetDocumentSelection(getter_AddRefs(selection));
   712   NS_ENSURE_SUCCESS(rv, rv);
   714   nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(selection));
   715   rv = selPrivate->AddSelectionListener(mSelectionListener);
   716   if (NS_FAILED(rv))
   717     return rv;
   719   // Save old listener so we can unregister it
   720   nsRefPtr<nsDocViewerFocusListener> oldFocusListener = mFocusListener;
   722   // focus listener
   723   //
   724   // now register ourselves as a focus listener, so that we get called
   725   // when the focus changes in the window
   726   nsDocViewerFocusListener *focusListener = new nsDocViewerFocusListener();
   728   focusListener->Init(this);
   730   // mFocusListener is a strong reference
   731   mFocusListener = focusListener;
   733   if (mDocument) {
   734     mDocument->AddEventListener(NS_LITERAL_STRING("focus"),
   735                                 mFocusListener,
   736                                 false, false);
   737     mDocument->AddEventListener(NS_LITERAL_STRING("blur"),
   738                                 mFocusListener,
   739                                 false, false);
   741     if (oldFocusListener) {
   742       mDocument->RemoveEventListener(NS_LITERAL_STRING("focus"),
   743                                      oldFocusListener, false);
   744       mDocument->RemoveEventListener(NS_LITERAL_STRING("blur"),
   745                                      oldFocusListener, false);
   746     }
   747   }
   749   if (aDoInitialReflow && mDocument) {
   750     mDocument->ScrollToRef();
   751   }
   753   return NS_OK;
   754 }
   756 static nsPresContext*
   757 CreatePresContext(nsIDocument* aDocument,
   758                   nsPresContext::nsPresContextType aType,
   759                   nsView* aContainerView)
   760 {
   761   if (aContainerView)
   762     return new nsPresContext(aDocument, aType);
   763   return new nsRootPresContext(aDocument, aType);
   764 }
   766 //-----------------------------------------------
   767 // This method can be used to initial the "presentation"
   768 // The aDoCreation indicates whether it should create
   769 // all the new objects or just initialize the existing ones
   770 nsresult
   771 nsDocumentViewer::InitInternal(nsIWidget* aParentWidget,
   772                                  nsISupports *aState,
   773                                  const nsIntRect& aBounds,
   774                                  bool aDoCreation,
   775                                  bool aNeedMakeCX /*= true*/,
   776                                  bool aForceSetNewDocument /* = true*/)
   777 {
   778   if (mIsPageMode) {
   779     // XXXbz should the InitInternal in SetPageMode just pass false
   780     // here itself?
   781     aForceSetNewDocument = false;
   782   }
   784   // We don't want any scripts to run here. That can cause flushing,
   785   // which can cause reentry into initialization of this document viewer,
   786   // which would be disastrous.
   787   nsAutoScriptBlocker blockScripts;
   789   mParentWidget = aParentWidget; // not ref counted
   790   mBounds = aBounds;
   792   nsresult rv = NS_OK;
   793   NS_ENSURE_TRUE(mDocument, NS_ERROR_NULL_POINTER);
   795   nsView* containerView = FindContainerView();
   797   bool makeCX = false;
   798   if (aDoCreation) {
   799     nsresult rv = CreateDeviceContext(containerView);
   800     NS_ENSURE_SUCCESS(rv, rv);
   802     // XXXbz this is a nasty hack to do with the fact that we create
   803     // presentations both in Init() and in Show()...  Ideally we would only do
   804     // it in one place (Show()) and require that callers call init(), open(),
   805     // show() in that order or something.
   806     if (!mPresContext &&
   807         (aParentWidget || containerView || mDocument->IsBeingUsedAsImage() ||
   808          (mDocument->GetDisplayDocument() &&
   809           mDocument->GetDisplayDocument()->GetShell()))) {
   810       // Create presentation context
   811       if (mIsPageMode) {
   812         //Presentation context already created in SetPageMode which is calling this method
   813       } else {
   814         mPresContext = CreatePresContext(mDocument,
   815             nsPresContext::eContext_Galley, containerView);
   816       }
   817       NS_ENSURE_TRUE(mPresContext, NS_ERROR_OUT_OF_MEMORY);
   819       nsresult rv = mPresContext->Init(mDeviceContext); 
   820       if (NS_FAILED(rv)) {
   821         mPresContext = nullptr;
   822         return rv;
   823       }
   825 #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
   826       makeCX = !GetIsPrintPreview() && aNeedMakeCX; // needs to be true except when we are already in PP or we are enabling/disabling paginated mode.
   827 #else
   828       makeCX = true;
   829 #endif
   830     }
   832     if (mPresContext) {
   833       // Create the ViewManager and Root View...
   835       // We must do this before we tell the script global object about
   836       // this new document since doing that will cause us to re-enter
   837       // into nsSubDocumentFrame code through reflows caused by
   838       // FlushPendingNotifications() calls down the road...
   840       rv = MakeWindow(nsSize(mPresContext->DevPixelsToAppUnits(aBounds.width),
   841                              mPresContext->DevPixelsToAppUnits(aBounds.height)),
   842                       containerView);
   843       NS_ENSURE_SUCCESS(rv, rv);
   844       Hide();
   846 #ifdef NS_PRINT_PREVIEW
   847       if (mIsPageMode) {
   848         // I'm leaving this in a broken state for the moment; we should
   849         // be measuring/scaling with the print device context, not the
   850         // screen device context, but this is good enough to allow
   851         // printing reftests to work.
   852         double pageWidth = 0, pageHeight = 0;
   853         mPresContext->GetPrintSettings()->GetEffectivePageSize(&pageWidth,
   854                                                                &pageHeight);
   855         mPresContext->SetPageSize(
   856           nsSize(mPresContext->CSSTwipsToAppUnits(NSToIntFloor(pageWidth)),
   857                  mPresContext->CSSTwipsToAppUnits(NSToIntFloor(pageHeight))));
   858         mPresContext->SetIsRootPaginatedDocument(true);
   859         mPresContext->SetPageScale(1.0f);
   860       }
   861 #endif
   862     } else {
   863       // Avoid leaking the old viewer.
   864       if (mPreviousViewer) {
   865         mPreviousViewer->Destroy();
   866         mPreviousViewer = nullptr;
   867       }
   868     }
   869   }
   871   nsCOMPtr<nsIInterfaceRequestor> requestor(mContainer);
   872   if (requestor) {
   873     if (mPresContext) {
   874       nsCOMPtr<nsILinkHandler> linkHandler;
   875       requestor->GetInterface(NS_GET_IID(nsILinkHandler),
   876                               getter_AddRefs(linkHandler));
   878       mPresContext->SetContainer(mContainer);
   879       mPresContext->SetLinkHandler(linkHandler);
   880     }
   882     // Set script-context-owner in the document
   884     nsCOMPtr<nsPIDOMWindow> window;
   885     requestor->GetInterface(NS_GET_IID(nsPIDOMWindow),
   886                             getter_AddRefs(window));
   888     if (window) {
   889       nsCOMPtr<nsIDocument> curDoc = window->GetExtantDoc();
   890       if (aForceSetNewDocument || curDoc != mDocument) {
   891         window->SetNewDocument(mDocument, aState, false);
   892         nsJSContext::LoadStart();
   893       }
   894     }
   895   }
   897   if (aDoCreation && mPresContext) {
   898     // The ViewManager and Root View was created above (in
   899     // MakeWindow())...
   901     rv = InitPresentationStuff(!makeCX);
   902   }
   904   return rv;
   905 }
   907 void nsDocumentViewer::SetNavigationTiming(nsDOMNavigationTiming* timing)
   908 {
   909   NS_ASSERTION(mDocument, "Must have a document to set navigation timing.");
   910   if (mDocument) {
   911     mDocument->SetNavigationTiming(timing);
   912   }
   913 }
   915 //
   916 // LoadComplete(aStatus)
   917 //
   918 //   aStatus - The status returned from loading the document.
   919 //
   920 // This method is called by the container when the document has been
   921 // completely loaded.
   922 //
   923 NS_IMETHODIMP
   924 nsDocumentViewer::LoadComplete(nsresult aStatus)
   925 {
   926   /* We need to protect ourself against auto-destruction in case the
   927      window is closed while processing the OnLoad event.  See bug
   928      http://bugzilla.mozilla.org/show_bug.cgi?id=78445 for more
   929      explanation.
   930   */
   931   nsRefPtr<nsDocumentViewer> kungFuDeathGrip(this);
   933   // Flush out layout so it's up-to-date by the time onload is called.
   934   // Note that this could destroy the window, so do this before
   935   // checking for our mDocument and its window.
   936   if (mPresShell && !mStopped) {
   937     // Hold strong ref because this could conceivably run script
   938     nsCOMPtr<nsIPresShell> shell = mPresShell;
   939     shell->FlushPendingNotifications(Flush_Layout);
   940   }
   942   nsresult rv = NS_OK;
   943   NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
   945   // First, get the window from the document...
   946   nsCOMPtr<nsPIDOMWindow> window = mDocument->GetWindow();
   948   mLoaded = true;
   950   // Now, fire either an OnLoad or OnError event to the document...
   951   bool restoring = false;
   952   // XXXbz imagelib kills off the document load for a full-page image with
   953   // NS_ERROR_PARSED_DATA_CACHED if it's in the cache.  So we want to treat
   954   // that one as a success code; otherwise whether we fire onload for the image
   955   // will depend on whether it's cached!
   956   if(window &&
   957      (NS_SUCCEEDED(aStatus) || aStatus == NS_ERROR_PARSED_DATA_CACHED)) {
   958     nsEventStatus status = nsEventStatus_eIgnore;
   959     WidgetEvent event(true, NS_LOAD);
   960     event.mFlags.mBubbles = false;
   961      // XXX Dispatching to |window|, but using |document| as the target.
   962     event.target = mDocument;
   964     // If the document presentation is being restored, we don't want to fire
   965     // onload to the document content since that would likely confuse scripts
   966     // on the page.
   968     nsIDocShell *docShell = window->GetDocShell();
   969     NS_ENSURE_TRUE(docShell, NS_ERROR_UNEXPECTED);
   971     docShell->GetRestoringDocument(&restoring);
   972     if (!restoring) {
   973       NS_ASSERTION(mDocument->IsXUL() || // readyState for XUL is bogus
   974                    mDocument->GetReadyStateEnum() ==
   975                      nsIDocument::READYSTATE_INTERACTIVE ||
   976                    // test_stricttransportsecurity.html has old-style
   977                    // docshell-generated about:blank docs reach this code!
   978                    (mDocument->GetReadyStateEnum() ==
   979                       nsIDocument::READYSTATE_UNINITIALIZED &&
   980                     NS_IsAboutBlank(mDocument->GetDocumentURI())),
   981                    "Bad readystate");
   982       nsCOMPtr<nsIDocument> d = mDocument;
   983       mDocument->SetReadyStateInternal(nsIDocument::READYSTATE_COMPLETE);
   985       nsRefPtr<nsDOMNavigationTiming> timing(d->GetNavigationTiming());
   986       if (timing) {
   987         timing->NotifyLoadEventStart();
   988       }
   990       // Dispatch observer notification to notify observers document load is complete.
   991       nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
   992       nsIPrincipal *principal = d->NodePrincipal();
   993       os->NotifyObservers(d,
   994                           nsContentUtils::IsSystemPrincipal(principal) ?
   995                           "chrome-document-loaded" :
   996                           "content-document-loaded",
   997                           nullptr);
   999       EventDispatcher::Dispatch(window, mPresContext, &event, nullptr, &status);
  1000       if (timing) {
  1001         timing->NotifyLoadEventEnd();
  1004   } else {
  1005     // XXX: Should fire error event to the document...
  1008   // Notify the document that it has been shown (regardless of whether
  1009   // it was just loaded). Note: mDocument may be null now if the above
  1010   // firing of onload caused the document to unload.
  1011   if (mDocument) {
  1012     // Re-get window, since it might have changed during above firing of onload
  1013     window = mDocument->GetWindow();
  1014     if (window) {
  1015       nsIDocShell *docShell = window->GetDocShell();
  1016       bool isInUnload;
  1017       if (docShell && NS_SUCCEEDED(docShell->GetIsInUnload(&isInUnload)) &&
  1018           !isInUnload) {
  1019         mDocument->OnPageShow(restoring, nullptr);
  1024   if (!mStopped) {
  1025     if (mDocument) {
  1026       mDocument->ScrollToRef();
  1029     // Now that the document has loaded, we can tell the presshell
  1030     // to unsuppress painting.
  1031     if (mPresShell) {
  1032       nsCOMPtr<nsIPresShell> shellDeathGrip(mPresShell);
  1033       mPresShell->UnsuppressPainting();
  1034       // mPresShell could have been removed now, see bug 378682/421432
  1035       if (mPresShell) {
  1036         mPresShell->LoadComplete();
  1041   nsJSContext::LoadEnd();
  1043 #ifdef NS_PRINTING
  1044   // Check to see if someone tried to print during the load
  1045   if (mPrintIsPending) {
  1046     mPrintIsPending        = false;
  1047     mPrintDocIsFullyLoaded = true;
  1048     Print(mCachedPrintSettings, mCachedPrintWebProgressListner);
  1049     mCachedPrintSettings           = nullptr;
  1050     mCachedPrintWebProgressListner = nullptr;
  1052 #endif
  1054   return rv;
  1057 NS_IMETHODIMP
  1058 nsDocumentViewer::PermitUnload(bool aCallerClosesWindow,
  1059                                bool *aPermitUnload)
  1061   bool shouldPrompt = true;
  1062   return PermitUnloadInternal(aCallerClosesWindow, &shouldPrompt,
  1063                               aPermitUnload);
  1067 nsresult
  1068 nsDocumentViewer::PermitUnloadInternal(bool aCallerClosesWindow,
  1069                                        bool *aShouldPrompt,
  1070                                        bool *aPermitUnload)
  1072   AutoDontWarnAboutSyncXHR disableSyncXHRWarning;
  1074   *aPermitUnload = true;
  1076   if (!mDocument
  1077    || mInPermitUnload
  1078    || mCallerIsClosingWindow
  1079    || mInPermitUnloadPrompt) {
  1080     return NS_OK;
  1083   static bool sIsBeforeUnloadDisabled;
  1084   static bool sBeforeUnloadPrefCached = false;
  1086   if (!sBeforeUnloadPrefCached ) {
  1087     sBeforeUnloadPrefCached = true;
  1088     Preferences::AddBoolVarCache(&sIsBeforeUnloadDisabled,
  1089                                  BEFOREUNLOAD_DISABLED_PREFNAME);
  1092   // If the user has turned off onbeforeunload warnings, no need to check.
  1093   if (sIsBeforeUnloadDisabled) {
  1094     return NS_OK;
  1097   // First, get the script global object from the document...
  1098   nsPIDOMWindow *window = mDocument->GetWindow();
  1100   if (!window) {
  1101     // This is odd, but not fatal
  1102     NS_WARNING("window not set for document!");
  1103     return NS_OK;
  1106   NS_ASSERTION(nsContentUtils::IsSafeToRunScript(), "This is unsafe");
  1108   // Now, fire an BeforeUnload event to the document and see if it's ok
  1109   // to unload...
  1110   nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(mDocument);
  1111   nsCOMPtr<nsIDOMEvent> event;
  1112   domDoc->CreateEvent(NS_LITERAL_STRING("beforeunloadevent"),
  1113                       getter_AddRefs(event));
  1114   nsCOMPtr<nsIDOMBeforeUnloadEvent> beforeUnload = do_QueryInterface(event);
  1115   NS_ENSURE_STATE(beforeUnload);
  1116   nsresult rv = event->InitEvent(NS_LITERAL_STRING("beforeunload"),
  1117                                  false, true);
  1118   NS_ENSURE_SUCCESS(rv, rv);
  1120   // Dispatching to |window|, but using |document| as the target.
  1121   event->SetTarget(mDocument);
  1122   event->SetTrusted(true);
  1124   // In evil cases we might be destroyed while handling the
  1125   // onbeforeunload event, don't let that happen. (see also bug#331040)
  1126   nsRefPtr<nsDocumentViewer> kungFuDeathGrip(this);
  1129     // Never permit popups from the beforeunload handler, no matter
  1130     // how we get here.
  1131     nsAutoPopupStatePusher popupStatePusher(openAbused, true);
  1133     // Never permit dialogs from the beforeunload handler
  1134     nsCOMPtr<nsIDOMWindowUtils> utils = do_GetInterface(window);
  1135     bool dialogsWereEnabled = false;
  1136     utils->AreDialogsEnabled(&dialogsWereEnabled);
  1137     utils->DisableDialogs();
  1139     mInPermitUnload = true;
  1140     EventDispatcher::DispatchDOMEvent(window, nullptr, event, mPresContext,
  1141                                       nullptr);
  1142     mInPermitUnload = false;
  1143     if (dialogsWereEnabled) {
  1144       utils->EnableDialogs();
  1148   nsCOMPtr<nsIDocShell> docShell(mContainer);
  1149   nsAutoString text;
  1150   beforeUnload->GetReturnValue(text);
  1151   if (*aShouldPrompt && (event->GetInternalNSEvent()->mFlags.mDefaultPrevented ||
  1152                          !text.IsEmpty())) {
  1153     // Ask the user if it's ok to unload the current page
  1155     nsCOMPtr<nsIPrompt> prompt = do_GetInterface(docShell);
  1157     if (prompt) {
  1158       nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt);
  1159       if (promptBag) {
  1160         bool isTabModalPromptAllowed;
  1161         GetIsTabModalPromptAllowed(&isTabModalPromptAllowed);
  1162         promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"),
  1163                                      isTabModalPromptAllowed);
  1166       nsXPIDLString title, message, stayLabel, leaveLabel;
  1167       rv  = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
  1168                                                "OnBeforeUnloadTitle",
  1169                                                title);
  1170       nsresult tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
  1171                                                "OnBeforeUnloadMessage",
  1172                                                message);
  1173       if (NS_FAILED(tmp)) {
  1174         rv = tmp;
  1176       tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
  1177                                                "OnBeforeUnloadLeaveButton",
  1178                                                leaveLabel);
  1179       if (NS_FAILED(tmp)) {
  1180         rv = tmp;
  1182       tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
  1183                                                "OnBeforeUnloadStayButton",
  1184                                                stayLabel);
  1185       if (NS_FAILED(tmp)) {
  1186         rv = tmp;
  1189       if (NS_FAILED(rv) || !title || !message || !stayLabel || !leaveLabel) {
  1190         NS_ERROR("Failed to get strings from dom.properties!");
  1191         return NS_OK;
  1194       // Although the exact value is ignored, we must not pass invalid
  1195       // bool values through XPConnect.
  1196       bool dummy = false;
  1197       int32_t buttonPressed = 0;
  1198       uint32_t buttonFlags = (nsIPrompt::BUTTON_POS_0_DEFAULT |
  1199                              (nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_0) |
  1200                              (nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_1));
  1202       nsAutoSyncOperation sync(mDocument);
  1203       mInPermitUnloadPrompt = true;
  1204       rv = prompt->ConfirmEx(title, message, buttonFlags,
  1205                              leaveLabel, stayLabel, nullptr, nullptr,
  1206                              &dummy, &buttonPressed);
  1207       mInPermitUnloadPrompt = false;
  1209       // If the prompt aborted, we tell our consumer that it is not allowed
  1210       // to unload the page. One reason that prompts abort is that the user
  1211       // performed some action that caused the page to unload while our prompt
  1212       // was active. In those cases we don't want our consumer to also unload
  1213       // the page.
  1214       //
  1215       // XXX: Are there other cases where prompts can abort? Is it ok to
  1216       //      prevent unloading the page in those cases?
  1217       if (NS_FAILED(rv)) {
  1218         *aPermitUnload = false;
  1219         return NS_OK;
  1222       // Button 0 == leave, button 1 == stay
  1223       *aPermitUnload = (buttonPressed == 0);
  1224       // If the user decided to go ahead, make sure not to prompt the user again
  1225       // by toggling the internal prompting bool to false:
  1226       if (*aPermitUnload) {
  1227         *aShouldPrompt = false;
  1232   if (docShell) {
  1233     int32_t childCount;
  1234     docShell->GetChildCount(&childCount);
  1236     for (int32_t i = 0; i < childCount && *aPermitUnload; ++i) {
  1237       nsCOMPtr<nsIDocShellTreeItem> item;
  1238       docShell->GetChildAt(i, getter_AddRefs(item));
  1240       nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(item));
  1242       if (docShell) {
  1243         nsCOMPtr<nsIContentViewer> cv;
  1244         docShell->GetContentViewer(getter_AddRefs(cv));
  1246         if (cv) {
  1247           cv->PermitUnloadInternal(aCallerClosesWindow, aShouldPrompt,
  1248                                    aPermitUnload);
  1254   if (aCallerClosesWindow && *aPermitUnload)
  1255     mCallerIsClosingWindow = true;
  1257   return NS_OK;
  1260 NS_IMETHODIMP
  1261 nsDocumentViewer::GetBeforeUnloadFiring(bool* aInEvent)
  1263   *aInEvent = mInPermitUnload;
  1264   return NS_OK;
  1267 NS_IMETHODIMP
  1268 nsDocumentViewer::GetInPermitUnload(bool* aInEvent)
  1270   *aInEvent = mInPermitUnloadPrompt;
  1271   return NS_OK;
  1274 NS_IMETHODIMP
  1275 nsDocumentViewer::ResetCloseWindow()
  1277   mCallerIsClosingWindow = false;
  1279   nsCOMPtr<nsIDocShell> docShell(mContainer);
  1280   if (docShell) {
  1281     int32_t childCount;
  1282     docShell->GetChildCount(&childCount);
  1284     for (int32_t i = 0; i < childCount; ++i) {
  1285       nsCOMPtr<nsIDocShellTreeItem> item;
  1286       docShell->GetChildAt(i, getter_AddRefs(item));
  1288       nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(item));
  1290       if (docShell) {
  1291         nsCOMPtr<nsIContentViewer> cv;
  1292         docShell->GetContentViewer(getter_AddRefs(cv));
  1294         if (cv) {
  1295           cv->ResetCloseWindow();
  1300   return NS_OK;
  1303 NS_IMETHODIMP
  1304 nsDocumentViewer::PageHide(bool aIsUnload)
  1306   AutoDontWarnAboutSyncXHR disableSyncXHRWarning;
  1308   mHidden = true;
  1310   if (!mDocument) {
  1311     return NS_ERROR_NULL_POINTER;
  1314   mDocument->OnPageHide(!aIsUnload, nullptr);
  1316   // inform the window so that the focus state is reset.
  1317   NS_ENSURE_STATE(mDocument);
  1318   nsPIDOMWindow *window = mDocument->GetWindow();
  1319   if (window)
  1320     window->PageHidden();
  1322   if (aIsUnload) {
  1323     // Poke the GC. The window might be collectable garbage now.
  1324     nsJSContext::PokeGC(JS::gcreason::PAGE_HIDE, NS_GC_DELAY * 2);
  1326     // if Destroy() was called during OnPageHide(), mDocument is nullptr.
  1327     NS_ENSURE_STATE(mDocument);
  1329     // First, get the window from the document...
  1330     nsPIDOMWindow *window = mDocument->GetWindow();
  1332     if (!window) {
  1333       // Fail if no window is available...
  1334       NS_WARNING("window not set for document!");
  1335       return NS_ERROR_NULL_POINTER;
  1338     // Now, fire an Unload event to the document...
  1339     nsEventStatus status = nsEventStatus_eIgnore;
  1340     WidgetEvent event(true, NS_PAGE_UNLOAD);
  1341     event.mFlags.mBubbles = false;
  1342     // XXX Dispatching to |window|, but using |document| as the target.
  1343     event.target = mDocument;
  1345     // Never permit popups from the unload handler, no matter how we get
  1346     // here.
  1347     nsAutoPopupStatePusher popupStatePusher(openAbused, true);
  1349     EventDispatcher::Dispatch(window, mPresContext, &event, nullptr, &status);
  1352 #ifdef MOZ_XUL
  1353   // look for open menupopups and close them after the unload event, in case
  1354   // the unload event listeners open any new popups
  1355   nsContentUtils::HidePopupsInDocument(mDocument);
  1356 #endif
  1358   return NS_OK;
  1361 static void
  1362 AttachContainerRecurse(nsIDocShell* aShell)
  1364   nsCOMPtr<nsIContentViewer> viewer;
  1365   aShell->GetContentViewer(getter_AddRefs(viewer));
  1366   if (viewer) {
  1367     nsIDocument* doc = viewer->GetDocument();
  1368     if (doc) {
  1369       doc->SetContainer(static_cast<nsDocShell*>(aShell));
  1371     nsRefPtr<nsPresContext> pc;
  1372     viewer->GetPresContext(getter_AddRefs(pc));
  1373     if (pc) {
  1374       pc->SetContainer(static_cast<nsDocShell*>(aShell));
  1375       pc->SetLinkHandler(nsCOMPtr<nsILinkHandler>(do_QueryInterface(aShell)));
  1377     nsCOMPtr<nsIPresShell> presShell;
  1378     viewer->GetPresShell(getter_AddRefs(presShell));
  1379     if (presShell) {
  1380       presShell->SetForwardingContainer(WeakPtr<nsDocShell>());
  1384   // Now recurse through the children
  1385   int32_t childCount;
  1386   aShell->GetChildCount(&childCount);
  1387   for (int32_t i = 0; i < childCount; ++i) {
  1388     nsCOMPtr<nsIDocShellTreeItem> childItem;
  1389     aShell->GetChildAt(i, getter_AddRefs(childItem));
  1390     AttachContainerRecurse(nsCOMPtr<nsIDocShell>(do_QueryInterface(childItem)));
  1394 NS_IMETHODIMP
  1395 nsDocumentViewer::Open(nsISupports *aState, nsISHEntry *aSHEntry)
  1397   NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);
  1399   if (mDocument)
  1400     mDocument->SetContainer(mContainer);
  1402   nsresult rv = InitInternal(mParentWidget, aState, mBounds, false);
  1403   NS_ENSURE_SUCCESS(rv, rv);
  1405   mHidden = false;
  1407   if (mPresShell)
  1408     mPresShell->SetForwardingContainer(WeakPtr<nsDocShell>());
  1410   // Rehook the child presentations.  The child shells are still in
  1411   // session history, so get them from there.
  1413   if (aSHEntry) {
  1414     nsCOMPtr<nsIDocShellTreeItem> item;
  1415     int32_t itemIndex = 0;
  1416     while (NS_SUCCEEDED(aSHEntry->ChildShellAt(itemIndex++,
  1417                                                getter_AddRefs(item))) && item) {
  1418       AttachContainerRecurse(nsCOMPtr<nsIDocShell>(do_QueryInterface(item)));
  1422   SyncParentSubDocMap();
  1424   if (mFocusListener && mDocument) {
  1425     mDocument->AddEventListener(NS_LITERAL_STRING("focus"), mFocusListener,
  1426                                 false, false);
  1427     mDocument->AddEventListener(NS_LITERAL_STRING("blur"), mFocusListener,
  1428                                 false, false);
  1431   // XXX re-enable image animations once that works correctly
  1433   PrepareToStartLoad();
  1435   // When loading a page from the bfcache with puppet widgets, we do the
  1436   // widget attachment here (it is otherwise done in MakeWindow, which is
  1437   // called for non-bfcache pages in the history, but not bfcache pages).
  1438   // Attachment is necessary, since we get detached when another page
  1439   // is browsed to. That is, if we are one page A, then when we go to
  1440   // page B, we detach. So page A's view has no widget. If we then go
  1441   // back to it, and it is in the bfcache, we will use that view, which
  1442   // doesn't have a widget. The attach call here will properly attach us.
  1443   if (nsIWidget::UsePuppetWidgets() && mPresContext &&
  1444       ShouldAttachToTopLevel()) {
  1445     // If the old view is already attached to our parent, detach
  1446     DetachFromTopLevelWidget();
  1448     nsViewManager *vm = GetViewManager();
  1449     NS_ABORT_IF_FALSE(vm, "no view manager");
  1450     nsView* v = vm->GetRootView();
  1451     NS_ABORT_IF_FALSE(v, "no root view");
  1452     NS_ABORT_IF_FALSE(mParentWidget, "no mParentWidget to set");
  1453     v->AttachToTopLevelWidget(mParentWidget);
  1455     mAttachedToParent = true;
  1458   return NS_OK;
  1461 NS_IMETHODIMP
  1462 nsDocumentViewer::Close(nsISHEntry *aSHEntry)
  1464   // All callers are supposed to call close to break circular
  1465   // references.  If we do this stuff in the destructor, the
  1466   // destructor might never be called (especially if we're being
  1467   // used from JS.
  1469   mSHEntry = aSHEntry;
  1471   // Close is also needed to disable scripts during paint suppression,
  1472   // since we transfer the existing global object to the new document
  1473   // that is loaded.  In the future, the global object may become a proxy
  1474   // for an object that can be switched in and out so that we don't need
  1475   // to disable scripts during paint suppression.
  1477   if (!mDocument)
  1478     return NS_OK;
  1480 #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
  1481   // Turn scripting back on
  1482   // after PrintPreview had turned it off
  1483   if (GetIsPrintPreview() && mPrintEngine) {
  1484     mPrintEngine->TurnScriptingOn(true);
  1486 #endif
  1488 #ifdef NS_PRINTING
  1489   // A Close was called while we were printing
  1490   // so don't clear the ScriptGlobalObject
  1491   // or clear the mDocument below
  1492   if (mPrintEngine && !mClosingWhilePrinting) {
  1493     mClosingWhilePrinting = true;
  1494   } else
  1495 #endif
  1497       // out of band cleanup of docshell
  1498       mDocument->SetScriptGlobalObject(nullptr);
  1500       if (!mSHEntry && mDocument)
  1501         mDocument->RemovedFromDocShell();
  1504   if (mFocusListener && mDocument) {
  1505     mDocument->RemoveEventListener(NS_LITERAL_STRING("focus"), mFocusListener,
  1506                                    false);
  1507     mDocument->RemoveEventListener(NS_LITERAL_STRING("blur"), mFocusListener,
  1508                                    false);
  1511   return NS_OK;
  1514 static void
  1515 DetachContainerRecurse(nsIDocShell *aShell)
  1517   // Unhook this docshell's presentation
  1518   nsCOMPtr<nsIContentViewer> viewer;
  1519   aShell->GetContentViewer(getter_AddRefs(viewer));
  1520   if (viewer) {
  1521     nsIDocument* doc = viewer->GetDocument();
  1522     if (doc) {
  1523       doc->SetContainer(nullptr);
  1525     nsRefPtr<nsPresContext> pc;
  1526     viewer->GetPresContext(getter_AddRefs(pc));
  1527     if (pc) {
  1528       pc->Detach();
  1530     nsCOMPtr<nsIPresShell> presShell;
  1531     viewer->GetPresShell(getter_AddRefs(presShell));
  1532     if (presShell) {
  1533       auto weakShell = static_cast<nsDocShell*>(aShell)->asWeakPtr();
  1534       presShell->SetForwardingContainer(weakShell);
  1538   // Now recurse through the children
  1539   int32_t childCount;
  1540   aShell->GetChildCount(&childCount);
  1541   for (int32_t i = 0; i < childCount; ++i) {
  1542     nsCOMPtr<nsIDocShellTreeItem> childItem;
  1543     aShell->GetChildAt(i, getter_AddRefs(childItem));
  1544     DetachContainerRecurse(nsCOMPtr<nsIDocShell>(do_QueryInterface(childItem)));
  1548 NS_IMETHODIMP
  1549 nsDocumentViewer::Destroy()
  1551   NS_ASSERTION(mDocument, "No document in Destroy()!");
  1553 #ifdef NS_PRINTING
  1554   // Here is where we check to see if the document was still being prepared 
  1555   // for printing when it was asked to be destroy from someone externally
  1556   // This usually happens if the document is unloaded while the user is in the
  1557   // Print Dialog
  1558   //
  1559   // So we flip the bool to remember that the document is going away
  1560   // and we can clean up and abort later after returning from the Print Dialog
  1561   if (mPrintEngine) {
  1562     if (mPrintEngine->CheckBeforeDestroy()) {
  1563       return NS_OK;
  1566   mBeforeAndAfterPrint = nullptr;
  1567 #endif
  1569   // Don't let the document get unloaded while we are printing.
  1570   // this could happen if we hit the back button during printing.
  1571   // We also keep the viewer from being cached in session history, since
  1572   // we require all documents there to be sanitized.
  1573   if (mDestroyRefCount != 0) {
  1574     --mDestroyRefCount;
  1575     return NS_OK;
  1578   // If we were told to put ourselves into session history instead of destroy
  1579   // the presentation, do that now.
  1580   if (mSHEntry) {
  1581     if (mPresShell)
  1582       mPresShell->Freeze();
  1584     // Make sure the presentation isn't torn down by Hide().
  1585     mSHEntry->SetSticky(mIsSticky);
  1586     mIsSticky = true;
  1588     bool savePresentation = mDocument ? mDocument->IsBFCachingAllowed() : true;
  1590     // Remove our root view from the view hierarchy.
  1591     if (mPresShell) {
  1592       nsViewManager *vm = mPresShell->GetViewManager();
  1593       if (vm) {
  1594         nsView *rootView = vm->GetRootView();
  1596         if (rootView) {
  1597           nsView *rootViewParent = rootView->GetParent();
  1598           if (rootViewParent) {
  1599             nsViewManager *parentVM = rootViewParent->GetViewManager();
  1600             if (parentVM) {
  1601               parentVM->RemoveChild(rootView);
  1608     Hide();
  1610     // This is after Hide() so that the user doesn't see the inputs clear.
  1611     if (mDocument) {
  1612       mDocument->Sanitize();
  1615     // Reverse ownership. Do this *after* calling sanitize so that sanitize
  1616     // doesn't cause mutations that make the SHEntry drop the presentation
  1618     // Grab a reference to mSHEntry before calling into things like
  1619     // SyncPresentationState that might mess with our members.
  1620     nsCOMPtr<nsISHEntry> shEntry = mSHEntry; // we'll need this below
  1621     mSHEntry = nullptr;
  1623     if (savePresentation) {
  1624       shEntry->SetContentViewer(this);
  1627     // Always sync the presentation state.  That way even if someone screws up
  1628     // and shEntry has no window state at this point we'll be ok; we just won't
  1629     // cache ourselves.
  1630     shEntry->SyncPresentationState();
  1632     // Shut down accessibility for the document before we start to tear it down.
  1633 #ifdef ACCESSIBILITY
  1634     if (mPresShell) {
  1635       a11y::DocAccessible* docAcc = mPresShell->GetDocAccessible();
  1636       if (docAcc) {
  1637         docAcc->Shutdown();
  1640 #endif
  1642     // Break the link from the document/presentation to the docshell, so that
  1643     // link traversals cannot affect the currently-loaded document.
  1644     // When the presentation is restored, Open() and InitInternal() will reset
  1645     // these pointers to their original values.
  1647     if (mDocument) {
  1648       mDocument->SetContainer(nullptr);
  1650     if (mPresContext) {
  1651       mPresContext->Detach();
  1653     if (mPresShell) {
  1654       mPresShell->SetForwardingContainer(mContainer);
  1657     // Do the same for our children.  Note that we need to get the child
  1658     // docshells from the SHEntry now; the docshell will have cleared them.
  1659     nsCOMPtr<nsIDocShellTreeItem> item;
  1660     int32_t itemIndex = 0;
  1661     while (NS_SUCCEEDED(shEntry->ChildShellAt(itemIndex++,
  1662                                               getter_AddRefs(item))) && item) {
  1663       DetachContainerRecurse(nsCOMPtr<nsIDocShell>(do_QueryInterface(item)));
  1666     return NS_OK;
  1669   // The document was not put in the bfcache
  1671   if (mPresShell) {
  1672     DestroyPresShell();
  1674   if (mDocument) {
  1675     mDocument->Destroy();
  1676     mDocument = nullptr;
  1679   // All callers are supposed to call destroy to break circular
  1680   // references.  If we do this stuff in the destructor, the
  1681   // destructor might never be called (especially if we're being
  1682   // used from JS.
  1684 #ifdef NS_PRINTING
  1685   if (mPrintEngine) {
  1686 #ifdef NS_PRINT_PREVIEW
  1687     bool doingPrintPreview;
  1688     mPrintEngine->GetDoingPrintPreview(&doingPrintPreview);
  1689     if (doingPrintPreview) {
  1690       mPrintEngine->FinishPrintPreview();
  1692 #endif
  1694     mPrintEngine->Destroy();
  1695     mPrintEngine = nullptr;
  1697 #endif
  1699   // Avoid leaking the old viewer.
  1700   if (mPreviousViewer) {
  1701     mPreviousViewer->Destroy();
  1702     mPreviousViewer = nullptr;
  1705   mDeviceContext = nullptr;
  1707   if (mPresContext) {
  1708     DestroyPresContext();
  1711   mWindow = nullptr;
  1712   mViewManager = nullptr;
  1713   mContainer = WeakPtr<nsDocShell>();
  1715   return NS_OK;
  1718 NS_IMETHODIMP
  1719 nsDocumentViewer::Stop(void)
  1721   NS_ASSERTION(mDocument, "Stop called too early or too late");
  1722   if (mDocument) {
  1723     mDocument->StopDocumentLoad();
  1726   if (!mHidden && (mLoaded || mStopped) && mPresContext && !mSHEntry)
  1727     mPresContext->SetImageAnimationMode(imgIContainer::kDontAnimMode);
  1729   mStopped = true;
  1731   if (!mLoaded && mPresShell) {
  1732     // Well, we might as well paint what we have so far.
  1733     nsCOMPtr<nsIPresShell> shellDeathGrip(mPresShell); // bug 378682
  1734     mPresShell->UnsuppressPainting();
  1737   return NS_OK;
  1740 NS_IMETHODIMP
  1741 nsDocumentViewer::GetDOMDocument(nsIDOMDocument **aResult)
  1743   NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
  1744   return CallQueryInterface(mDocument, aResult);
  1747 NS_IMETHODIMP_(nsIDocument *)
  1748 nsDocumentViewer::GetDocument()
  1750   return mDocument;
  1753 NS_IMETHODIMP
  1754 nsDocumentViewer::SetDOMDocument(nsIDOMDocument *aDocument)
  1756   // Assumptions:
  1757   //
  1758   // 1) this document viewer has been initialized with a call to Init().
  1759   // 2) the stylesheets associated with the document have been added
  1760   // to the document.
  1762   // XXX Right now, this method assumes that the layout of the current
  1763   // document hasn't started yet.  More cleanup will probably be
  1764   // necessary to make this method work for the case when layout *has*
  1765   // occurred for the current document.
  1766   // That work can happen when and if it is needed.
  1768   if (!aDocument)
  1769     return NS_ERROR_NULL_POINTER;
  1771   nsCOMPtr<nsIDocument> newDoc = do_QueryInterface(aDocument);
  1772   NS_ENSURE_TRUE(newDoc, NS_ERROR_UNEXPECTED);
  1774   return SetDocumentInternal(newDoc, false);
  1777 NS_IMETHODIMP
  1778 nsDocumentViewer::SetDocumentInternal(nsIDocument* aDocument,
  1779                                         bool aForceReuseInnerWindow)
  1781   MOZ_ASSERT(aDocument);
  1783   // Set new container
  1784   aDocument->SetContainer(mContainer);
  1786   if (mDocument != aDocument) {
  1787     if (mDocument->IsStaticDocument()) {
  1788       mDocument->SetScriptGlobalObject(nullptr);
  1789       mDocument->Destroy();
  1791     // Replace the old document with the new one. Do this only when
  1792     // the new document really is a new document.
  1793     mDocument = aDocument;
  1795     // Set the script global object on the new document
  1796     nsCOMPtr<nsPIDOMWindow> window =
  1797       do_GetInterface(static_cast<nsIDocShell*>(mContainer.get()));
  1798     if (window) {
  1799       window->SetNewDocument(aDocument, nullptr, aForceReuseInnerWindow);
  1802     // Clear the list of old child docshells. Child docshells for the new
  1803     // document will be constructed as frames are created.
  1804     if (!aDocument->IsStaticDocument()) {
  1805       nsCOMPtr<nsIDocShell> node(mContainer);
  1806       if (node) {
  1807         int32_t count;
  1808         node->GetChildCount(&count);
  1809         for (int32_t i = 0; i < count; ++i) {
  1810           nsCOMPtr<nsIDocShellTreeItem> child;
  1811           node->GetChildAt(0, getter_AddRefs(child));
  1812           node->RemoveChild(child);
  1818   nsresult rv = SyncParentSubDocMap();
  1819   NS_ENSURE_SUCCESS(rv, rv);
  1821   // Replace the current pres shell with a new shell for the new document
  1823   if (mPresShell) {
  1824     DestroyPresShell();
  1827   if (mPresContext) {
  1828     DestroyPresContext();
  1830     mWindow = nullptr;
  1831     InitInternal(mParentWidget, nullptr, mBounds, true, true, false);
  1834   return rv;
  1837 nsIPresShell*
  1838 nsDocumentViewer::GetPresShell()
  1840   return mPresShell;
  1843 nsPresContext*
  1844 nsDocumentViewer::GetPresContext()
  1846   return mPresContext;
  1849 nsViewManager*
  1850 nsDocumentViewer::GetViewManager()
  1852   return mViewManager;
  1855 NS_IMETHODIMP
  1856 nsDocumentViewer::GetPresShell(nsIPresShell** aResult)
  1858   nsIPresShell* shell = GetPresShell();
  1859   NS_IF_ADDREF(*aResult = shell);
  1860   return NS_OK;
  1863 NS_IMETHODIMP
  1864 nsDocumentViewer::GetPresContext(nsPresContext** aResult)
  1866   nsPresContext* pc = GetPresContext();
  1867   NS_IF_ADDREF(*aResult = pc);
  1868   return NS_OK;
  1871 NS_IMETHODIMP
  1872 nsDocumentViewer::GetBounds(nsIntRect& aResult)
  1874   NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
  1875   aResult = mBounds;
  1876   return NS_OK;
  1879 NS_IMETHODIMP
  1880 nsDocumentViewer::GetPreviousViewer(nsIContentViewer** aViewer)
  1882   *aViewer = mPreviousViewer;
  1883   NS_IF_ADDREF(*aViewer);
  1884   return NS_OK;
  1887 NS_IMETHODIMP
  1888 nsDocumentViewer::SetPreviousViewer(nsIContentViewer* aViewer)
  1890   // NOTE:  |Show| sets |mPreviousViewer| to null without calling this
  1891   // function.
  1893   if (aViewer) {
  1894     NS_ASSERTION(!mPreviousViewer,
  1895                  "can't set previous viewer when there already is one");
  1897     // In a multiple chaining situation (which occurs when running a thrashing
  1898     // test like i-bench or jrgm's tests with no delay), we can build up a
  1899     // whole chain of viewers.  In order to avoid this, we always set our previous
  1900     // viewer to the MOST previous viewer in the chain, and then dump the intermediate
  1901     // link from the chain.  This ensures that at most only 2 documents are alive
  1902     // and undestroyed at any given time (the one that is showing and the one that
  1903     // is loading with painting suppressed).
  1904     // It's very important that if this ever gets changed the code
  1905     // before the RestorePresentation call in nsDocShell::InternalLoad
  1906     // be changed accordingly.
  1907     nsCOMPtr<nsIContentViewer> prevViewer;
  1908     aViewer->GetPreviousViewer(getter_AddRefs(prevViewer));
  1909     if (prevViewer) {
  1910       aViewer->SetPreviousViewer(nullptr);
  1911       aViewer->Destroy();
  1912       return SetPreviousViewer(prevViewer);
  1916   mPreviousViewer = aViewer;
  1917   return NS_OK;
  1920 NS_IMETHODIMP
  1921 nsDocumentViewer::SetBounds(const nsIntRect& aBounds)
  1923   NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
  1925   mBounds = aBounds;
  1926   if (mWindow) {
  1927     if (!mAttachedToParent) {
  1928       // Don't have the widget repaint. Layout will generate repaint requests
  1929       // during reflow.
  1930       mWindow->Resize(aBounds.x, aBounds.y,
  1931                       aBounds.width, aBounds.height,
  1932                       false);
  1934   } else if (mPresContext && mViewManager) {
  1935     int32_t p2a = mPresContext->AppUnitsPerDevPixel();
  1936     mViewManager->SetWindowDimensions(NSIntPixelsToAppUnits(mBounds.width, p2a),
  1937                                       NSIntPixelsToAppUnits(mBounds.height, p2a));
  1940   // If there's a previous viewer, it's the one that's actually showing,
  1941   // so be sure to resize it as well so it paints over the right area.
  1942   // This may slow down the performance of the new page load, but resize
  1943   // during load is also probably a relatively unusual condition
  1944   // relating to things being hidden while something is loaded.  It so
  1945   // happens that Firefox does this a good bit with its infobar, and it
  1946   // looks ugly if we don't do this.
  1947   if (mPreviousViewer) {
  1948     nsCOMPtr<nsIContentViewer> previousViewer = mPreviousViewer;
  1949     previousViewer->SetBounds(aBounds);
  1952   return NS_OK;
  1955 NS_IMETHODIMP
  1956 nsDocumentViewer::Move(int32_t aX, int32_t aY)
  1958   NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
  1959   mBounds.MoveTo(aX, aY);
  1960   if (mWindow) {
  1961     mWindow->Move(aX, aY);
  1963   return NS_OK;
  1966 NS_IMETHODIMP
  1967 nsDocumentViewer::Show(void)
  1969   NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
  1971   // We don't need the previous viewer anymore since we're not
  1972   // displaying it.
  1973   if (mPreviousViewer) {
  1974     // This little dance *may* only be to keep
  1975     // PresShell::EndObservingDocument happy, but I'm not sure.
  1976     nsCOMPtr<nsIContentViewer> prevViewer(mPreviousViewer);
  1977     mPreviousViewer = nullptr;
  1978     prevViewer->Destroy();
  1980     // Make sure we don't have too many cached ContentViewers
  1981     nsCOMPtr<nsIDocShellTreeItem> treeItem(mContainer);
  1982     if (treeItem) {
  1983       // We need to find the root DocShell since only that object has an
  1984       // SHistory and we need the SHistory to evict content viewers
  1985       nsCOMPtr<nsIDocShellTreeItem> root;
  1986       treeItem->GetSameTypeRootTreeItem(getter_AddRefs(root));
  1987       nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(root);
  1988       nsCOMPtr<nsISHistory> history;
  1989       webNav->GetSessionHistory(getter_AddRefs(history));
  1990       nsCOMPtr<nsISHistoryInternal> historyInt = do_QueryInterface(history);
  1991       if (historyInt) {
  1992         int32_t prevIndex,loadedIndex;
  1993         nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(treeItem);
  1994         docShell->GetPreviousTransIndex(&prevIndex);
  1995         docShell->GetLoadedTransIndex(&loadedIndex);
  1996 #ifdef DEBUG_PAGE_CACHE
  1997         printf("About to evict content viewers: prev=%d, loaded=%d\n",
  1998                prevIndex, loadedIndex);
  1999 #endif
  2000         historyInt->EvictOutOfRangeContentViewers(loadedIndex);
  2005   if (mWindow) {
  2006     // When attached to a top level xul window, we do not need to call
  2007     // Show on the widget. Underlying window management code handles
  2008     // this when the window is initialized.
  2009     if (!mAttachedToParent) {
  2010       mWindow->Show(true);
  2014   if (mDocument && !mPresShell) {
  2015     NS_ASSERTION(!mWindow, "Window already created but no presshell?");
  2017     nsCOMPtr<nsIBaseWindow> base_win(mContainer);
  2018     if (base_win) {
  2019       base_win->GetParentWidget(&mParentWidget);
  2020       if (mParentWidget) {
  2021         mParentWidget->Release(); // GetParentWidget AddRefs, but mParentWidget is weak
  2025     nsView* containerView = FindContainerView();
  2027     nsresult rv = CreateDeviceContext(containerView);
  2028     NS_ENSURE_SUCCESS(rv, rv);
  2030     // Create presentation context
  2031     NS_ASSERTION(!mPresContext, "Shouldn't have a prescontext if we have no shell!");
  2032     mPresContext = CreatePresContext(mDocument,
  2033         nsPresContext::eContext_Galley, containerView);
  2034     NS_ENSURE_TRUE(mPresContext, NS_ERROR_OUT_OF_MEMORY);
  2036     rv = mPresContext->Init(mDeviceContext);
  2037     if (NS_FAILED(rv)) {
  2038       mPresContext = nullptr;
  2039       return rv;
  2042     rv = MakeWindow(nsSize(mPresContext->DevPixelsToAppUnits(mBounds.width),
  2043                            mPresContext->DevPixelsToAppUnits(mBounds.height)),
  2044                            containerView);
  2045     if (NS_FAILED(rv))
  2046       return rv;
  2048     if (mPresContext && base_win) {
  2049       nsCOMPtr<nsILinkHandler> linkHandler(do_GetInterface(base_win));
  2051       if (linkHandler) {
  2052         mPresContext->SetLinkHandler(linkHandler);
  2055       mPresContext->SetContainer(mContainer);
  2058     if (mPresContext) {
  2059       Hide();
  2061       rv = InitPresentationStuff(mDocument->MayStartLayout());
  2064     // If we get here the document load has already started and the
  2065     // window is shown because some JS on the page caused it to be
  2066     // shown...
  2068     if (mPresShell) {
  2069       nsCOMPtr<nsIPresShell> shellDeathGrip(mPresShell); // bug 378682
  2070       mPresShell->UnsuppressPainting();
  2074   // Notify observers that a new page has been shown. This will get run
  2075   // from the event loop after we actually draw the page.
  2076   NS_DispatchToMainThread(new nsDocumentShownDispatcher(mDocument));
  2078   return NS_OK;
  2081 NS_IMETHODIMP
  2082 nsDocumentViewer::Hide(void)
  2084   if (!mAttachedToParent && mWindow) {
  2085     mWindow->Show(false);
  2088   if (!mPresShell)
  2089     return NS_OK;
  2091   NS_ASSERTION(mPresContext, "Can't have a presshell and no prescontext!");
  2093   // Avoid leaking the old viewer.
  2094   if (mPreviousViewer) {
  2095     mPreviousViewer->Destroy();
  2096     mPreviousViewer = nullptr;
  2099   if (mIsSticky) {
  2100     // This window is sticky, that means that it might be shown again
  2101     // and we don't want the presshell n' all that to be thrown away
  2102     // just because the window is hidden.
  2104     return NS_OK;
  2107   nsCOMPtr<nsIDocShell> docShell(mContainer);
  2108   if (docShell) {
  2109     nsCOMPtr<nsILayoutHistoryState> layoutState;
  2110     mPresShell->CaptureHistoryState(getter_AddRefs(layoutState));
  2113   DestroyPresShell();
  2115   DestroyPresContext();
  2117   mViewManager   = nullptr;
  2118   mWindow        = nullptr;
  2119   mDeviceContext = nullptr;
  2120   mParentWidget  = nullptr;
  2122   nsCOMPtr<nsIBaseWindow> base_win(mContainer);
  2124   if (base_win && !mAttachedToParent) {
  2125     base_win->SetParentWidget(nullptr);
  2128   return NS_OK;
  2131 NS_IMETHODIMP
  2132 nsDocumentViewer::GetSticky(bool *aSticky)
  2134   *aSticky = mIsSticky;
  2136   return NS_OK;
  2139 NS_IMETHODIMP
  2140 nsDocumentViewer::SetSticky(bool aSticky)
  2142   mIsSticky = aSticky;
  2144   return NS_OK;
  2147 NS_IMETHODIMP
  2148 nsDocumentViewer::RequestWindowClose(bool* aCanClose)
  2150 #ifdef NS_PRINTING
  2151   if (mPrintIsPending || (mPrintEngine && mPrintEngine->GetIsPrinting())) {
  2152     *aCanClose = false;
  2153     mDeferredWindowClose = true;
  2154   } else
  2155 #endif
  2156     *aCanClose = true;
  2158   return NS_OK;
  2161 static bool
  2162 AppendAgentSheet(nsIStyleSheet *aSheet, void *aData)
  2164   nsStyleSet *styleSet = static_cast<nsStyleSet*>(aData);
  2165   styleSet->AppendStyleSheet(nsStyleSet::eAgentSheet, aSheet);
  2166   return true;
  2169 static bool
  2170 PrependUserSheet(nsIStyleSheet *aSheet, void *aData)
  2172   nsStyleSet *styleSet = static_cast<nsStyleSet*>(aData);
  2173   styleSet->PrependStyleSheet(nsStyleSet::eUserSheet, aSheet);
  2174   return true;
  2177 nsresult
  2178 nsDocumentViewer::CreateStyleSet(nsIDocument* aDocument,
  2179                                    nsStyleSet** aStyleSet)
  2181   // Make sure this does the same thing as PresShell::AddSheet wrt ordering.
  2183   // this should eventually get expanded to allow for creating
  2184   // different sets for different media
  2185   nsStyleSet *styleSet = new nsStyleSet();
  2187   styleSet->BeginUpdate();
  2189   // The document will fill in the document sheets when we create the presshell
  2191   // Handle the user sheets.
  2192   nsCSSStyleSheet* sheet = nullptr;
  2193   if (nsContentUtils::IsInChromeDocshell(aDocument)) {
  2194     sheet = nsLayoutStylesheetCache::UserChromeSheet();
  2196   else {
  2197     sheet = nsLayoutStylesheetCache::UserContentSheet();
  2200   if (sheet)
  2201     styleSet->AppendStyleSheet(nsStyleSet::eUserSheet, sheet);
  2203   // Append chrome sheets (scrollbars + forms).
  2204   bool shouldOverride = false;
  2205   // We don't want a docshell here for external resource docs, so just
  2206   // look at mContainer.
  2207   nsCOMPtr<nsIDocShell> ds(mContainer);
  2208   nsCOMPtr<nsIDOMEventTarget> chromeHandler;
  2209   nsCOMPtr<nsIURI> uri;
  2210   nsRefPtr<nsCSSStyleSheet> csssheet;
  2212   if (ds) {
  2213     ds->GetChromeEventHandler(getter_AddRefs(chromeHandler));
  2215   if (chromeHandler) {
  2216     nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(chromeHandler));
  2217     nsCOMPtr<nsIContent> content(do_QueryInterface(elt));
  2218     if (elt && content) {
  2219       nsCOMPtr<nsIURI> baseURI = content->GetBaseURI();
  2221       nsAutoString sheets;
  2222       elt->GetAttribute(NS_LITERAL_STRING("usechromesheets"), sheets);
  2223       if (!sheets.IsEmpty() && baseURI) {
  2224         nsRefPtr<mozilla::css::Loader> cssLoader = new mozilla::css::Loader();
  2226         char *str = ToNewCString(sheets);
  2227         char *newStr = str;
  2228         char *token;
  2229         while ( (token = nsCRT::strtok(newStr, ", ", &newStr)) ) {
  2230           NS_NewURI(getter_AddRefs(uri), nsDependentCString(token), nullptr,
  2231                     baseURI);
  2232           if (!uri) continue;
  2234           cssLoader->LoadSheetSync(uri, getter_AddRefs(csssheet));
  2235           if (!csssheet) continue;
  2237           styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, csssheet);
  2238           shouldOverride = true;
  2240         nsMemory::Free(str);
  2245   if (!shouldOverride) {
  2246     sheet = nsLayoutStylesheetCache::ScrollbarsSheet();
  2247     if (sheet) {
  2248       styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet);
  2252   sheet = nsLayoutStylesheetCache::NumberControlSheet();
  2253   if (sheet) {
  2254     styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet);
  2257   sheet = nsLayoutStylesheetCache::FormsSheet();
  2258   if (sheet) {
  2259     styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet);
  2262   sheet = nsLayoutStylesheetCache::FullScreenOverrideSheet();
  2263   if (sheet) {
  2264     styleSet->PrependStyleSheet(nsStyleSet::eOverrideSheet, sheet);
  2267   // Make sure to clone the quirk sheet so that it can be usefully
  2268   // enabled/disabled as needed.
  2269   nsRefPtr<nsCSSStyleSheet> quirkClone;
  2270   nsCSSStyleSheet* quirkSheet;
  2271   if (!nsLayoutStylesheetCache::UASheet() ||
  2272       !(quirkSheet = nsLayoutStylesheetCache::QuirkSheet()) ||
  2273       !(quirkClone = quirkSheet->Clone(nullptr, nullptr, nullptr, nullptr)) ||
  2274       !sheet) {
  2275     delete styleSet;
  2276     return NS_ERROR_OUT_OF_MEMORY;
  2278   // quirk.css needs to come after the regular UA sheet (or more precisely,
  2279   // after the html.css and so forth that the UA sheet imports).
  2280   styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, quirkClone);
  2281   styleSet->SetQuirkStyleSheet(quirkClone);
  2282   styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet,
  2283                               nsLayoutStylesheetCache::UASheet());
  2285   nsStyleSheetService *sheetService = nsStyleSheetService::GetInstance();
  2286   if (sheetService) {
  2287     sheetService->AgentStyleSheets()->EnumerateForwards(AppendAgentSheet,
  2288                                                         styleSet);
  2289     sheetService->UserStyleSheets()->EnumerateBackwards(PrependUserSheet,
  2290                                                         styleSet);
  2293   // Caller will handle calling EndUpdate, per contract.
  2294   *aStyleSet = styleSet;
  2295   return NS_OK;
  2298 NS_IMETHODIMP
  2299 nsDocumentViewer::ClearHistoryEntry()
  2301   mSHEntry = nullptr;
  2302   return NS_OK;
  2305 //-------------------------------------------------------
  2307 nsresult
  2308 nsDocumentViewer::MakeWindow(const nsSize& aSize, nsView* aContainerView)
  2310   if (GetIsPrintPreview())
  2311     return NS_OK;
  2313   bool shouldAttach = ShouldAttachToTopLevel();
  2315   if (shouldAttach) {
  2316     // If the old view is already attached to our parent, detach
  2317     DetachFromTopLevelWidget();
  2320   mViewManager = new nsViewManager();
  2322   nsDeviceContext *dx = mPresContext->DeviceContext();
  2324   nsresult rv = mViewManager->Init(dx);
  2325   if (NS_FAILED(rv))
  2326     return rv;
  2328   // The root view is always at 0,0.
  2329   nsRect tbounds(nsPoint(0, 0), aSize);
  2330   // Create a view
  2331   nsView* view = mViewManager->CreateView(tbounds, aContainerView);
  2332   if (!view)
  2333     return NS_ERROR_OUT_OF_MEMORY;
  2335   // Create a widget if we were given a parent widget or don't have a
  2336   // container view that we can hook up to without a widget.
  2337   // Don't create widgets for ResourceDocs (external resources & svg images),
  2338   // because when they're displayed, they're painted into *another* document's
  2339   // widget.
  2340   if (!mDocument->IsResourceDoc() &&
  2341       (mParentWidget || !aContainerView)) {
  2342     // pass in a native widget to be the parent widget ONLY if the view hierarchy will stand alone.
  2343     // otherwise the view will find its own parent widget and "do the right thing" to
  2344     // establish a parent/child widget relationship
  2345     nsWidgetInitData initData;
  2346     nsWidgetInitData* initDataPtr;
  2347     if (!mParentWidget) {
  2348       initDataPtr = &initData;
  2349       initData.mWindowType = eWindowType_invisible;
  2350     } else {
  2351       initDataPtr = nullptr;
  2354     if (shouldAttach) {
  2355       // Reuse the top level parent widget.
  2356       rv = view->AttachToTopLevelWidget(mParentWidget);
  2357       mAttachedToParent = true;
  2359     else if (!aContainerView && mParentWidget) {
  2360       rv = view->CreateWidgetForParent(mParentWidget, initDataPtr,
  2361                                        true, false);
  2363     else {
  2364       rv = view->CreateWidget(initDataPtr, true, false);
  2366     if (NS_FAILED(rv))
  2367       return rv;
  2370   // Setup hierarchical relationship in view manager
  2371   mViewManager->SetRootView(view);
  2373   mWindow = view->GetWidget();
  2375   // This SetFocus is necessary so the Arrow Key and Page Key events
  2376   // go to the scrolled view as soon as the Window is created instead of going to
  2377   // the browser window (this enables keyboard scrolling of the document)
  2378   // mWindow->SetFocus();
  2380   return rv;
  2383 void
  2384 nsDocumentViewer::DetachFromTopLevelWidget()
  2386   if (mViewManager) {
  2387     nsView* oldView = mViewManager->GetRootView();
  2388     if (oldView && oldView->IsAttachedToTopLevel()) {
  2389       oldView->DetachFromTopLevelWidget();
  2392   mAttachedToParent = false;
  2395 nsView*
  2396 nsDocumentViewer::FindContainerView()
  2398   nsView* containerView = nullptr;
  2400   if (mContainer) {
  2401     nsCOMPtr<nsIDocShellTreeItem> docShellItem(mContainer);
  2402     nsCOMPtr<nsPIDOMWindow> pwin(do_GetInterface(docShellItem));
  2403     if (pwin) {
  2404       nsCOMPtr<nsIContent> containerElement = do_QueryInterface(pwin->GetFrameElementInternal());
  2405       if (!containerElement) {
  2406         return nullptr;
  2408       nsCOMPtr<nsIPresShell> parentPresShell;
  2409       if (docShellItem) {
  2410         nsCOMPtr<nsIDocShellTreeItem> parentDocShellItem;
  2411         docShellItem->GetParent(getter_AddRefs(parentDocShellItem));
  2412         if (parentDocShellItem) {
  2413           nsCOMPtr<nsIDocShell> parentDocShell = do_QueryInterface(parentDocShellItem);
  2414           parentPresShell = parentDocShell->GetPresShell();
  2417       if (!parentPresShell) {
  2418         nsCOMPtr<nsIDocument> parentDoc = containerElement->GetCurrentDoc();
  2419         if (parentDoc) {
  2420           parentPresShell = parentDoc->GetShell();
  2423       if (!parentPresShell) {
  2424         NS_WARNING("Subdocument container has no presshell");
  2425       } else {
  2426         nsIFrame* f = parentPresShell->GetRealPrimaryFrameFor(containerElement);
  2427         if (f) {
  2428           nsIFrame* subdocFrame = f->GetContentInsertionFrame();
  2429           // subdocFrame might not be a subdocument frame; the frame
  2430           // constructor can treat a <frame> as an inline in some XBL
  2431           // cases. Treat that as display:none, the document is not
  2432           // displayed.
  2433           if (subdocFrame->GetType() == nsGkAtoms::subDocumentFrame) {
  2434             NS_ASSERTION(subdocFrame->GetView(), "Subdoc frames must have views");
  2435             nsView* innerView =
  2436               static_cast<nsSubDocumentFrame*>(subdocFrame)->EnsureInnerView();
  2437             containerView = innerView;
  2438           } else {
  2439             NS_WARNING("Subdocument container has non-subdocument frame");
  2441         } else {
  2442           NS_WARNING("Subdocument container has no frame");
  2448   return containerView;
  2451 nsresult
  2452 nsDocumentViewer::CreateDeviceContext(nsView* aContainerView)
  2454   NS_PRECONDITION(!mPresShell && !mWindow,
  2455                   "This will screw up our existing presentation");
  2456   NS_PRECONDITION(mDocument, "Gotta have a document here");
  2458   nsIDocument* doc = mDocument->GetDisplayDocument();
  2459   if (doc) {
  2460     NS_ASSERTION(!aContainerView, "External resource document embedded somewhere?");
  2461     // We want to use our display document's device context if possible
  2462     nsIPresShell* shell = doc->GetShell();
  2463     if (shell) {
  2464       nsPresContext* ctx = shell->GetPresContext();
  2465       if (ctx) {
  2466         mDeviceContext = ctx->DeviceContext();
  2467         return NS_OK;
  2472   // Create a device context even if we already have one, since our widget
  2473   // might have changed.
  2474   nsIWidget* widget = nullptr;
  2475   if (aContainerView) {
  2476     widget = aContainerView->GetNearestWidget(nullptr);
  2478   if (!widget) {
  2479     widget = mParentWidget;
  2481   if (widget) {
  2482     widget = widget->GetTopLevelWidget();
  2485   mDeviceContext = new nsDeviceContext();
  2486   mDeviceContext->Init(widget);
  2487   return NS_OK;
  2490 // Return the selection for the document. Note that text fields have their
  2491 // own selection, which cannot be accessed with this method.
  2492 nsresult nsDocumentViewer::GetDocumentSelection(nsISelection **aSelection)
  2494   NS_ENSURE_ARG_POINTER(aSelection);
  2495   if (!mPresShell) {
  2496     return NS_ERROR_NOT_INITIALIZED;
  2499   nsCOMPtr<nsISelectionController> selcon;
  2500   selcon = do_QueryInterface(mPresShell);
  2501   if (selcon)
  2502     return selcon->GetSelection(nsISelectionController::SELECTION_NORMAL,
  2503                                 aSelection);
  2504   return NS_ERROR_FAILURE;
  2507 /* ========================================================================================
  2508  * nsIContentViewerEdit
  2509  * ======================================================================================== */
  2511 NS_IMETHODIMP nsDocumentViewer::ClearSelection()
  2513   nsresult rv;
  2514   nsCOMPtr<nsISelection> selection;
  2516   // use nsCopySupport::GetSelectionForCopy() ?
  2517   rv = GetDocumentSelection(getter_AddRefs(selection));
  2518   if (NS_FAILED(rv)) return rv;
  2520   return selection->CollapseToStart();
  2523 NS_IMETHODIMP nsDocumentViewer::SelectAll()
  2525   // XXX this is a temporary implementation copied from nsWebShell
  2526   // for now. I think nsDocument and friends should have some helper
  2527   // functions to make this easier.
  2528   nsCOMPtr<nsISelection> selection;
  2529   nsresult rv;
  2531   // use nsCopySupport::GetSelectionForCopy() ?
  2532   rv = GetDocumentSelection(getter_AddRefs(selection));
  2533   if (NS_FAILED(rv)) return rv;
  2535   nsCOMPtr<nsIDOMHTMLDocument> htmldoc = do_QueryInterface(mDocument);
  2536   nsCOMPtr<nsIDOMNode> bodyNode;
  2538   if (htmldoc)
  2540     nsCOMPtr<nsIDOMHTMLElement>bodyElement;
  2541     rv = htmldoc->GetBody(getter_AddRefs(bodyElement));
  2542     if (NS_FAILED(rv) || !bodyElement) return rv;
  2544     bodyNode = do_QueryInterface(bodyElement);
  2546   else if (mDocument)
  2548     bodyNode = do_QueryInterface(mDocument->GetRootElement());
  2550   if (!bodyNode) return NS_ERROR_FAILURE;
  2552   rv = selection->RemoveAllRanges();
  2553   if (NS_FAILED(rv)) return rv;
  2555   rv = selection->SelectAllChildren(bodyNode);
  2556   return rv;
  2559 NS_IMETHODIMP nsDocumentViewer::CopySelection()
  2561   nsCopySupport::FireClipboardEvent(NS_COPY, nsIClipboard::kGlobalClipboard, mPresShell, nullptr);
  2562   return NS_OK;
  2565 NS_IMETHODIMP nsDocumentViewer::CopyLinkLocation()
  2567   NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);
  2568   nsCOMPtr<nsIDOMNode> node;
  2569   GetPopupLinkNode(getter_AddRefs(node));
  2570   // make noise if we're not in a link
  2571   NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
  2573   nsCOMPtr<dom::Element> elm(do_QueryInterface(node));
  2574   NS_ENSURE_TRUE(elm, NS_ERROR_FAILURE);
  2576   nsAutoString locationText;
  2577   nsContentUtils::GetLinkLocation(elm, locationText);
  2578   if (locationText.IsEmpty())
  2579     return NS_ERROR_FAILURE;
  2581   nsresult rv = NS_OK;
  2582   nsCOMPtr<nsIClipboardHelper> clipboard(do_GetService("@mozilla.org/widget/clipboardhelper;1", &rv));
  2583   NS_ENSURE_SUCCESS(rv, rv);
  2585   // copy the href onto the clipboard
  2586   nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(mDocument);
  2587   return clipboard->CopyString(locationText, doc);
  2590 NS_IMETHODIMP nsDocumentViewer::CopyImage(int32_t aCopyFlags)
  2592   NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);
  2593   nsCOMPtr<nsIImageLoadingContent> node;
  2594   GetPopupImageNode(getter_AddRefs(node));
  2595   // make noise if we're not in an image
  2596   NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
  2598   nsCOMPtr<nsILoadContext> loadContext(mContainer);
  2599   return nsCopySupport::ImageCopy(node, loadContext, aCopyFlags);
  2603 NS_IMETHODIMP nsDocumentViewer::GetCopyable(bool *aCopyable)
  2605   NS_ENSURE_ARG_POINTER(aCopyable);
  2606   *aCopyable = nsCopySupport::CanCopy(mDocument);
  2607   return NS_OK;
  2610 /* AString getContents (in string mimeType, in boolean selectionOnly); */
  2611 NS_IMETHODIMP nsDocumentViewer::GetContents(const char *mimeType, bool selectionOnly, nsAString& aOutValue)
  2613   aOutValue.Truncate();
  2615   NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);
  2616   NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_INITIALIZED);
  2618   // Now we have the selection.  Make sure it's nonzero:
  2619   nsCOMPtr<nsISelection> sel;
  2620   if (selectionOnly) {
  2621     nsCopySupport::GetSelectionForCopy(mDocument, getter_AddRefs(sel));
  2622     NS_ENSURE_TRUE(sel, NS_ERROR_FAILURE);
  2624     bool isCollapsed;
  2625     sel->GetIsCollapsed(&isCollapsed);
  2626     if (isCollapsed)
  2627       return NS_OK;
  2630   // call the copy code
  2631   return nsCopySupport::GetContents(nsDependentCString(mimeType), 0, sel,
  2632                                     mDocument, aOutValue);
  2635 /* readonly attribute boolean canGetContents; */
  2636 NS_IMETHODIMP nsDocumentViewer::GetCanGetContents(bool *aCanGetContents)
  2638   NS_ENSURE_ARG_POINTER(aCanGetContents);
  2639   *aCanGetContents = false;
  2640   NS_ENSURE_STATE(mDocument);
  2641   *aCanGetContents = nsCopySupport::CanCopy(mDocument);
  2642   return NS_OK;
  2646 /* ========================================================================================
  2647  * nsIContentViewerFile
  2648  * ======================================================================================== */
  2649 /** ---------------------------------------------------
  2650  *  See documentation above in the nsIContentViewerfile class definition
  2651  *	@update 01/24/00 dwc
  2652  */
  2653 NS_IMETHODIMP
  2654 nsDocumentViewer::Print(bool              aSilent,
  2655                           FILE *            aDebugFile,
  2656                           nsIPrintSettings* aPrintSettings)
  2658 #ifdef NS_PRINTING
  2659   nsCOMPtr<nsIPrintSettings> printSettings;
  2661 #ifdef DEBUG
  2662   nsresult rv = NS_ERROR_FAILURE;
  2664   mDebugFile = aDebugFile;
  2665   // if they don't pass in a PrintSettings, then make one
  2666   // it will have all the default values
  2667   printSettings = aPrintSettings;
  2668   nsCOMPtr<nsIPrintOptions> printOptions = do_GetService(sPrintOptionsContractID, &rv);
  2669   if (NS_SUCCEEDED(rv)) {
  2670     // if they don't pass in a PrintSettings, then make one
  2671     if (printSettings == nullptr) {
  2672       printOptions->CreatePrintSettings(getter_AddRefs(printSettings));
  2674     NS_ASSERTION(printSettings, "You can't PrintPreview without a PrintSettings!");
  2676   if (printSettings) printSettings->SetPrintSilent(aSilent);
  2677   if (printSettings) printSettings->SetShowPrintProgress(false);
  2678 #endif
  2681   return Print(printSettings, nullptr);
  2682 #else
  2683   return NS_ERROR_FAILURE;
  2684 #endif
  2687 // nsIContentViewerFile interface
  2688 NS_IMETHODIMP
  2689 nsDocumentViewer::GetPrintable(bool *aPrintable)
  2691   NS_ENSURE_ARG_POINTER(aPrintable);
  2693   *aPrintable = !GetIsPrinting();
  2695   return NS_OK;
  2698 //*****************************************************************************
  2699 // nsIMarkupDocumentViewer
  2700 //*****************************************************************************
  2702 NS_IMETHODIMP nsDocumentViewer::ScrollToNode(nsIDOMNode* aNode)
  2704   NS_ENSURE_ARG(aNode);
  2705   NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
  2706   nsCOMPtr<nsIPresShell> presShell;
  2707   NS_ENSURE_SUCCESS(GetPresShell(getter_AddRefs(presShell)), NS_ERROR_FAILURE);
  2709   // Get the nsIContent interface, because that's what we need to
  2710   // get the primary frame
  2712   nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
  2713   NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
  2715   // Tell the PresShell to scroll to the primary frame of the content.
  2716   NS_ENSURE_SUCCESS(
  2717     presShell->ScrollContentIntoView(content,
  2718                                      nsIPresShell::ScrollAxis(
  2719                                        nsIPresShell::SCROLL_TOP,
  2720                                        nsIPresShell::SCROLL_ALWAYS),
  2721                                      nsIPresShell::ScrollAxis(),
  2722                                      nsIPresShell::SCROLL_OVERFLOW_HIDDEN),
  2723     NS_ERROR_FAILURE);
  2724   return NS_OK;
  2727 void
  2728 nsDocumentViewer::CallChildren(CallChildFunc aFunc, void* aClosure)
  2730   nsCOMPtr<nsIDocShell> docShell(mContainer);
  2731   if (docShell)
  2733     int32_t i;
  2734     int32_t n;
  2735     docShell->GetChildCount(&n);
  2736     for (i=0; i < n; i++)
  2738       nsCOMPtr<nsIDocShellTreeItem> child;
  2739       docShell->GetChildAt(i, getter_AddRefs(child));
  2740       nsCOMPtr<nsIDocShell> childAsShell(do_QueryInterface(child));
  2741       NS_ASSERTION(childAsShell, "null child in docshell");
  2742       if (childAsShell)
  2744         nsCOMPtr<nsIContentViewer> childCV;
  2745         childAsShell->GetContentViewer(getter_AddRefs(childCV));
  2746         if (childCV)
  2748           nsCOMPtr<nsIMarkupDocumentViewer> markupCV = do_QueryInterface(childCV);
  2749           if (markupCV) {
  2750             (*aFunc)(markupCV, aClosure);
  2758 struct LineBoxInfo
  2760   nscoord mMaxLineBoxWidth;
  2761 };
  2763 static void
  2764 ChangeChildPaintingEnabled(nsIMarkupDocumentViewer* aChild, void* aClosure)
  2766   bool* enablePainting = (bool*) aClosure;
  2767   if (*enablePainting) {
  2768     aChild->ResumePainting();
  2769   } else {
  2770     aChild->PausePainting();
  2774 static void
  2775 ChangeChildMaxLineBoxWidth(nsIMarkupDocumentViewer* aChild, void* aClosure)
  2777   struct LineBoxInfo* lbi = (struct LineBoxInfo*) aClosure;
  2778   aChild->ChangeMaxLineBoxWidth(lbi->mMaxLineBoxWidth);
  2781 struct ZoomInfo
  2783   float mZoom;
  2784 };
  2786 static void
  2787 SetChildTextZoom(nsIMarkupDocumentViewer* aChild, void* aClosure)
  2789   struct ZoomInfo* ZoomInfo = (struct ZoomInfo*) aClosure;
  2790   aChild->SetTextZoom(ZoomInfo->mZoom);
  2793 static void
  2794 SetChildMinFontSize(nsIMarkupDocumentViewer* aChild, void* aClosure)
  2796   nsCOMPtr<nsIMarkupDocumentViewer> branch =
  2797     do_QueryInterface(aChild);
  2798   branch->SetMinFontSize(NS_PTR_TO_INT32(aClosure));
  2801 static void
  2802 SetChildFullZoom(nsIMarkupDocumentViewer* aChild, void* aClosure)
  2804   struct ZoomInfo* ZoomInfo = (struct ZoomInfo*) aClosure;
  2805   aChild->SetFullZoom(ZoomInfo->mZoom);
  2808 static bool
  2809 SetExtResourceTextZoom(nsIDocument* aDocument, void* aClosure)
  2811   // Would it be better to enumerate external resource viewers instead?
  2812   nsIPresShell* shell = aDocument->GetShell();
  2813   if (shell) {
  2814     nsPresContext* ctxt = shell->GetPresContext();
  2815     if (ctxt) {
  2816       struct ZoomInfo* ZoomInfo = static_cast<struct ZoomInfo*>(aClosure);
  2817       ctxt->SetTextZoom(ZoomInfo->mZoom);
  2821   return true;
  2824 static bool
  2825 SetExtResourceMinFontSize(nsIDocument* aDocument, void* aClosure)
  2827   nsIPresShell* shell = aDocument->GetShell();
  2828   if (shell) {
  2829     nsPresContext* ctxt = shell->GetPresContext();
  2830     if (ctxt) {
  2831       ctxt->SetBaseMinFontSize(NS_PTR_TO_INT32(aClosure));
  2835   return true;
  2838 static bool
  2839 SetExtResourceFullZoom(nsIDocument* aDocument, void* aClosure)
  2841   // Would it be better to enumerate external resource viewers instead?
  2842   nsIPresShell* shell = aDocument->GetShell();
  2843   if (shell) {
  2844     nsPresContext* ctxt = shell->GetPresContext();
  2845     if (ctxt) {
  2846       struct ZoomInfo* ZoomInfo = static_cast<struct ZoomInfo*>(aClosure);
  2847       ctxt->SetFullZoom(ZoomInfo->mZoom);
  2851   return true;
  2854 NS_IMETHODIMP
  2855 nsDocumentViewer::SetTextZoom(float aTextZoom)
  2857   // If we don't have a document, then we need to bail.
  2858   if (!mDocument) {
  2859     return NS_ERROR_FAILURE;
  2862   if (GetIsPrintPreview()) {
  2863     return NS_OK;
  2866   mTextZoom = aTextZoom;
  2868   // Set the text zoom on all children of mContainer (even if our zoom didn't
  2869   // change, our children's zoom may be different, though it would be unusual).
  2870   // Do this first, in case kids are auto-sizing and post reflow commands on
  2871   // our presshell (which should be subsumed into our own style change reflow).
  2872   struct ZoomInfo ZoomInfo = { aTextZoom };
  2873   CallChildren(SetChildTextZoom, &ZoomInfo);
  2875   // Now change our own zoom
  2876   nsPresContext* pc = GetPresContext();
  2877   if (pc && aTextZoom != mPresContext->TextZoom()) {
  2878       pc->SetTextZoom(aTextZoom);
  2881   // And do the external resources
  2882   mDocument->EnumerateExternalResources(SetExtResourceTextZoom, &ZoomInfo);
  2884   nsContentUtils::DispatchChromeEvent(mDocument, static_cast<nsIDocument*>(mDocument),
  2885                                       NS_LITERAL_STRING("TextZoomChange"),
  2886                                       true, true);
  2888   return NS_OK;
  2891 NS_IMETHODIMP
  2892 nsDocumentViewer::GetTextZoom(float* aTextZoom)
  2894   NS_ENSURE_ARG_POINTER(aTextZoom);
  2895   nsPresContext* pc = GetPresContext();
  2896   *aTextZoom = pc ? pc->TextZoom() : 1.0f;
  2897   return NS_OK;
  2900 NS_IMETHODIMP
  2901 nsDocumentViewer::SetMinFontSize(int32_t aMinFontSize)
  2903   // If we don't have a document, then we need to bail.
  2904   if (!mDocument) {
  2905     return NS_ERROR_FAILURE;
  2908   if (GetIsPrintPreview()) {
  2909     return NS_OK;
  2912   mMinFontSize = aMinFontSize;
  2914   // Set the min font on all children of mContainer (even if our min font didn't
  2915   // change, our children's min font may be different, though it would be unusual).
  2916   // Do this first, in case kids are auto-sizing and post reflow commands on
  2917   // our presshell (which should be subsumed into our own style change reflow).
  2918   CallChildren(SetChildMinFontSize, NS_INT32_TO_PTR(aMinFontSize));
  2920   // Now change our own min font
  2921   nsPresContext* pc = GetPresContext();
  2922   if (pc && aMinFontSize != mPresContext->MinFontSize(nullptr)) {
  2923     pc->SetBaseMinFontSize(aMinFontSize);
  2926   // And do the external resources
  2927   mDocument->EnumerateExternalResources(SetExtResourceMinFontSize,
  2928                                         NS_INT32_TO_PTR(aMinFontSize));
  2930   return NS_OK;
  2933 NS_IMETHODIMP
  2934 nsDocumentViewer::GetMinFontSize(int32_t* aMinFontSize)
  2936   NS_ENSURE_ARG_POINTER(aMinFontSize);
  2937   nsPresContext* pc = GetPresContext();
  2938   *aMinFontSize = pc ? pc->BaseMinFontSize() : 0;
  2939   return NS_OK;
  2942 NS_IMETHODIMP
  2943 nsDocumentViewer::SetFullZoom(float aFullZoom)
  2945 #ifdef NS_PRINT_PREVIEW
  2946   if (GetIsPrintPreview()) {
  2947     nsPresContext* pc = GetPresContext();
  2948     NS_ENSURE_TRUE(pc, NS_OK);
  2949     nsCOMPtr<nsIPresShell> shell = pc->GetPresShell();
  2950     NS_ENSURE_TRUE(shell, NS_OK);
  2952     if (!mPrintPreviewZoomed) {
  2953       mOriginalPrintPreviewScale = pc->GetPrintPreviewScale();
  2954       mPrintPreviewZoomed = true;
  2957     mPrintPreviewZoom = aFullZoom;
  2958     pc->SetPrintPreviewScale(aFullZoom * mOriginalPrintPreviewScale);
  2959     nsIPageSequenceFrame* pf = shell->GetPageSequenceFrame();
  2960     if (pf) {
  2961       nsIFrame* f = do_QueryFrame(pf);
  2962       shell->FrameNeedsReflow(f, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
  2965     nsIFrame* rootFrame = shell->GetRootFrame();
  2966     if (rootFrame) {
  2967       rootFrame->InvalidateFrame();
  2969     return NS_OK;
  2971 #endif
  2973   // If we don't have a document, then we need to bail.
  2974   if (!mDocument) {
  2975     return NS_ERROR_FAILURE;
  2978   mPageZoom = aFullZoom;
  2980   struct ZoomInfo ZoomInfo = { aFullZoom };
  2981   CallChildren(SetChildFullZoom, &ZoomInfo);
  2983   nsPresContext* pc = GetPresContext();
  2984   if (pc) {
  2985     pc->SetFullZoom(aFullZoom);
  2988   // And do the external resources
  2989   mDocument->EnumerateExternalResources(SetExtResourceFullZoom, &ZoomInfo);
  2991   nsContentUtils::DispatchChromeEvent(mDocument, static_cast<nsIDocument*>(mDocument),
  2992                                       NS_LITERAL_STRING("FullZoomChange"),
  2993                                       true, true);
  2995   return NS_OK;
  2998 NS_IMETHODIMP
  2999 nsDocumentViewer::GetFullZoom(float* aFullZoom)
  3001   NS_ENSURE_ARG_POINTER(aFullZoom);
  3002 #ifdef NS_PRINT_PREVIEW
  3003   if (GetIsPrintPreview()) {
  3004     *aFullZoom = mPrintPreviewZoom;
  3005     return NS_OK;
  3007 #endif
  3008   // Check the prescontext first because it might have a temporary
  3009   // setting for print-preview
  3010   nsPresContext* pc = GetPresContext();
  3011   *aFullZoom = pc ? pc->GetFullZoom() : mPageZoom;
  3012   return NS_OK;
  3015 static void
  3016 SetChildAuthorStyleDisabled(nsIMarkupDocumentViewer* aChild, void* aClosure)
  3018   bool styleDisabled  = *static_cast<bool*>(aClosure);
  3019   aChild->SetAuthorStyleDisabled(styleDisabled);
  3023 NS_IMETHODIMP
  3024 nsDocumentViewer::SetAuthorStyleDisabled(bool aStyleDisabled)
  3026   if (mPresShell) {
  3027     mPresShell->SetAuthorStyleDisabled(aStyleDisabled);
  3029   CallChildren(SetChildAuthorStyleDisabled, &aStyleDisabled);
  3030   return NS_OK;
  3033 NS_IMETHODIMP
  3034 nsDocumentViewer::GetAuthorStyleDisabled(bool* aStyleDisabled)
  3036   if (mPresShell) {
  3037     *aStyleDisabled = mPresShell->GetAuthorStyleDisabled();
  3038   } else {
  3039     *aStyleDisabled = false;
  3041   return NS_OK;
  3044 static bool
  3045 ExtResourceEmulateMedium(nsIDocument* aDocument, void* aClosure)
  3047   nsIPresShell* shell = aDocument->GetShell();
  3048   if (shell) {
  3049     nsPresContext* ctxt = shell->GetPresContext();
  3050     if (ctxt) {
  3051       const nsAString* mediaType = static_cast<nsAString*>(aClosure);
  3052       ctxt->EmulateMedium(*mediaType);
  3056   return true;
  3059 static void
  3060 ChildEmulateMedium(nsIMarkupDocumentViewer* aChild, void* aClosure)
  3062   const nsAString* mediaType = static_cast<nsAString*>(aClosure);
  3063   aChild->EmulateMedium(*mediaType);
  3066 NS_IMETHODIMP
  3067 nsDocumentViewer::EmulateMedium(const nsAString& aMediaType)
  3069   if (mPresContext) {
  3070     mPresContext->EmulateMedium(aMediaType);
  3072   CallChildren(ChildEmulateMedium, const_cast<nsAString*>(&aMediaType));
  3074   if (mDocument) {
  3075     mDocument->EnumerateExternalResources(ExtResourceEmulateMedium,
  3076                                           const_cast<nsAString*>(&aMediaType));
  3079   return NS_OK;
  3082 static bool
  3083 ExtResourceStopEmulatingMedium(nsIDocument* aDocument, void* aClosure)
  3085   nsIPresShell* shell = aDocument->GetShell();
  3086   if (shell) {
  3087     nsPresContext* ctxt = shell->GetPresContext();
  3088     if (ctxt) {
  3089       ctxt->StopEmulatingMedium();
  3093   return true;
  3096 static void
  3097 ChildStopEmulatingMedium(nsIMarkupDocumentViewer* aChild, void* aClosure)
  3099   aChild->StopEmulatingMedium();
  3102 NS_IMETHODIMP
  3103 nsDocumentViewer::StopEmulatingMedium()
  3105   if (mPresContext) {
  3106     mPresContext->StopEmulatingMedium();
  3108   CallChildren(ChildStopEmulatingMedium, nullptr);
  3110   if (mDocument) {
  3111     mDocument->EnumerateExternalResources(ExtResourceStopEmulatingMedium,
  3112                                           nullptr);
  3115   return NS_OK;
  3118 NS_IMETHODIMP nsDocumentViewer::GetForceCharacterSet(nsACString& aForceCharacterSet)
  3120   aForceCharacterSet = mForceCharacterSet;
  3121   return NS_OK;
  3124 static void
  3125 SetChildForceCharacterSet(nsIMarkupDocumentViewer* aChild, void* aClosure)
  3127   const nsACString* charset = static_cast<nsACString*>(aClosure);
  3128   aChild->SetForceCharacterSet(*charset);
  3131 NS_IMETHODIMP
  3132 nsDocumentViewer::SetForceCharacterSet(const nsACString& aForceCharacterSet)
  3134   mForceCharacterSet = aForceCharacterSet;
  3135   // now set the force char set on all children of mContainer
  3136   CallChildren(SetChildForceCharacterSet, (void*) &aForceCharacterSet);
  3137   return NS_OK;
  3140 NS_IMETHODIMP nsDocumentViewer::GetHintCharacterSet(nsACString& aHintCharacterSet)
  3143   if(kCharsetUninitialized == mHintCharsetSource) {
  3144     aHintCharacterSet.Truncate();
  3145   } else {
  3146     aHintCharacterSet = mHintCharset;
  3147     // this can't possibly be right.  we can't set a value just because somebody got a related value!
  3148     //mHintCharsetSource = kCharsetUninitialized;
  3150   return NS_OK;
  3153 NS_IMETHODIMP nsDocumentViewer::GetHintCharacterSetSource(int32_t *aHintCharacterSetSource)
  3155   NS_ENSURE_ARG_POINTER(aHintCharacterSetSource);
  3157   *aHintCharacterSetSource = mHintCharsetSource;
  3158   return NS_OK;
  3161 static void
  3162 SetChildHintCharacterSetSource(nsIMarkupDocumentViewer* aChild, void* aClosure)
  3164   aChild->SetHintCharacterSetSource(NS_PTR_TO_INT32(aClosure));
  3167 NS_IMETHODIMP
  3168 nsDocumentViewer::SetHintCharacterSetSource(int32_t aHintCharacterSetSource)
  3170   mHintCharsetSource = aHintCharacterSetSource;
  3171   // now set the hint char set source on all children of mContainer
  3172   CallChildren(SetChildHintCharacterSetSource,
  3173                       NS_INT32_TO_PTR(aHintCharacterSetSource));
  3174   return NS_OK;
  3177 static void
  3178 SetChildHintCharacterSet(nsIMarkupDocumentViewer* aChild, void* aClosure)
  3180   const nsACString* charset = static_cast<nsACString*>(aClosure);
  3181   aChild->SetHintCharacterSet(*charset);
  3184 NS_IMETHODIMP
  3185 nsDocumentViewer::SetHintCharacterSet(const nsACString& aHintCharacterSet)
  3187   mHintCharset = aHintCharacterSet;
  3188   // now set the hint char set on all children of mContainer
  3189   CallChildren(SetChildHintCharacterSet, (void*) &aHintCharacterSet);
  3190   return NS_OK;
  3193 static void
  3194 AppendChildSubtree(nsIMarkupDocumentViewer* aChild, void* aClosure)
  3196   nsTArray<nsCOMPtr<nsIMarkupDocumentViewer> >& array =
  3197     *static_cast<nsTArray<nsCOMPtr<nsIMarkupDocumentViewer> >*>(aClosure);
  3198   aChild->AppendSubtree(array);
  3201 NS_IMETHODIMP nsDocumentViewer::AppendSubtree(nsTArray<nsCOMPtr<nsIMarkupDocumentViewer> >& aArray)
  3203   aArray.AppendElement(this);
  3204   CallChildren(AppendChildSubtree, &aArray);
  3205   return NS_OK;
  3208 NS_IMETHODIMP
  3209 nsDocumentViewer::PausePainting()
  3211   bool enablePaint = false;
  3212   CallChildren(ChangeChildPaintingEnabled, &enablePaint);
  3214   nsIPresShell* presShell = GetPresShell();
  3215   if (presShell) {
  3216     presShell->PausePainting();
  3219   return NS_OK;
  3222 NS_IMETHODIMP
  3223 nsDocumentViewer::ResumePainting()
  3225   bool enablePaint = true;
  3226   CallChildren(ChangeChildPaintingEnabled, &enablePaint);
  3228   nsIPresShell* presShell = GetPresShell();
  3229   if (presShell) {
  3230     presShell->ResumePainting();
  3233   return NS_OK;
  3236 NS_IMETHODIMP
  3237 nsDocumentViewer::ChangeMaxLineBoxWidth(int32_t aMaxLineBoxWidth)
  3239   // Change the max line box width for all children.
  3240   struct LineBoxInfo lbi = { aMaxLineBoxWidth };
  3241   CallChildren(ChangeChildMaxLineBoxWidth, &lbi);
  3243   // Now, change our max line box width.
  3244   // Convert to app units, since our input is in CSS pixels.
  3245   nscoord mlbw = nsPresContext::CSSPixelsToAppUnits(aMaxLineBoxWidth);
  3246   nsIPresShell* presShell = GetPresShell();
  3247   if (presShell) {
  3248     presShell->SetMaxLineBoxWidth(mlbw);
  3251   return NS_OK;
  3254 NS_IMETHODIMP
  3255 nsDocumentViewer::GetContentSize(int32_t* aWidth, int32_t* aHeight)
  3257    NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
  3259    // Skip doing this on docshell-less documents for now
  3260    nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(mContainer);
  3261    NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_NOT_AVAILABLE);
  3263    nsCOMPtr<nsIDocShellTreeItem> docShellParent;
  3264    docShellAsItem->GetSameTypeParent(getter_AddRefs(docShellParent));
  3266    // It's only valid to access this from a top frame.  Doesn't work from
  3267    // sub-frames.
  3268    NS_ENSURE_TRUE(!docShellParent, NS_ERROR_FAILURE);
  3270    nsCOMPtr<nsIPresShell> presShell;
  3271    GetPresShell(getter_AddRefs(presShell));
  3272    NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
  3274    // Flush out all content and style updates. We can't use a resize reflow
  3275    // because it won't change some sizes that a style change reflow will.
  3276    mDocument->FlushPendingNotifications(Flush_Layout);
  3278   nsIFrame *root = presShell->GetRootFrame();
  3279   NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
  3281   nscoord prefWidth;
  3283     nsRefPtr<nsRenderingContext> rcx =
  3284       presShell->CreateReferenceRenderingContext();
  3285     prefWidth = root->GetPrefWidth(rcx);
  3288   nsresult rv = presShell->ResizeReflow(prefWidth, NS_UNCONSTRAINEDSIZE);
  3289   NS_ENSURE_SUCCESS(rv, rv);
  3291    nsRefPtr<nsPresContext> presContext;
  3292    GetPresContext(getter_AddRefs(presContext));
  3293    NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
  3295    // so how big is it?
  3296    nsRect shellArea = presContext->GetVisibleArea();
  3297    // Protect against bogus returns here
  3298    NS_ENSURE_TRUE(shellArea.width != NS_UNCONSTRAINEDSIZE &&
  3299                   shellArea.height != NS_UNCONSTRAINEDSIZE,
  3300                   NS_ERROR_FAILURE);
  3302    *aWidth = presContext->AppUnitsToDevPixels(shellArea.width);
  3303    *aHeight = presContext->AppUnitsToDevPixels(shellArea.height);
  3305    return NS_OK;
  3309 NS_IMPL_ISUPPORTS(nsDocViewerSelectionListener, nsISelectionListener)
  3311 nsresult nsDocViewerSelectionListener::Init(nsDocumentViewer *aDocViewer)
  3313   mDocViewer = aDocViewer;
  3314   return NS_OK;
  3317 /*
  3318  * GetPopupNode, GetPopupLinkNode and GetPopupImageNode are helpers
  3319  * for the cmd_copyLink / cmd_copyImageLocation / cmd_copyImageContents family
  3320  * of commands. The focus controller stores the popup node, these retrieve
  3321  * them and munge appropriately. Note that we have to store the popup node
  3322  * rather than retrieving it from EventStateManager::GetFocusedContent because
  3323  * not all content (images included) can receive focus.
  3324  */
  3326 nsresult
  3327 nsDocumentViewer::GetPopupNode(nsIDOMNode** aNode)
  3329   NS_ENSURE_ARG_POINTER(aNode);
  3331   *aNode = nullptr;
  3333   // get the document
  3334   nsIDocument* document = GetDocument();
  3335   NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
  3337   // get the private dom window
  3338   nsCOMPtr<nsPIDOMWindow> window(document->GetWindow());
  3339   NS_ENSURE_TRUE(window, NS_ERROR_NOT_AVAILABLE);
  3340   if (window) {
  3341     nsCOMPtr<nsPIWindowRoot> root = window->GetTopWindowRoot();
  3342     NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
  3344     // get the popup node
  3345     nsCOMPtr<nsIDOMNode> node = root->GetPopupNode();
  3346 #ifdef MOZ_XUL
  3347     if (!node) {
  3348       nsPIDOMWindow* rootWindow = root->GetWindow();
  3349       if (rootWindow) {
  3350         nsCOMPtr<nsIDocument> rootDoc = rootWindow->GetExtantDoc();
  3351         if (rootDoc) {
  3352           nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
  3353           if (pm) {
  3354             node = pm->GetLastTriggerPopupNode(rootDoc);
  3359 #endif
  3360     node.swap(*aNode);
  3363   return NS_OK;
  3366 // GetPopupLinkNode: return popup link node or fail
  3367 nsresult
  3368 nsDocumentViewer::GetPopupLinkNode(nsIDOMNode** aNode)
  3370   NS_ENSURE_ARG_POINTER(aNode);
  3372   // you get null unless i say so
  3373   *aNode = nullptr;
  3375   // find popup node
  3376   nsCOMPtr<nsIDOMNode> node;
  3377   nsresult rv = GetPopupNode(getter_AddRefs(node));
  3378   NS_ENSURE_SUCCESS(rv, rv);
  3380   // find out if we have a link in our ancestry
  3381   while (node) {
  3383     nsCOMPtr<nsIContent> content(do_QueryInterface(node));
  3384     if (content) {
  3385       nsCOMPtr<nsIURI> hrefURI = content->GetHrefURI();
  3386       if (hrefURI) {
  3387         *aNode = node;
  3388         NS_IF_ADDREF(*aNode); // addref
  3389         return NS_OK;
  3393     // get our parent and keep trying...
  3394     nsCOMPtr<nsIDOMNode> parentNode;
  3395     node->GetParentNode(getter_AddRefs(parentNode));
  3396     node = parentNode;
  3399   // if we have no node, fail
  3400   return NS_ERROR_FAILURE;
  3403 // GetPopupLinkNode: return popup image node or fail
  3404 nsresult
  3405 nsDocumentViewer::GetPopupImageNode(nsIImageLoadingContent** aNode)
  3407   NS_ENSURE_ARG_POINTER(aNode);
  3409   // you get null unless i say so
  3410   *aNode = nullptr;
  3412   // find popup node
  3413   nsCOMPtr<nsIDOMNode> node;
  3414   nsresult rv = GetPopupNode(getter_AddRefs(node));
  3415   NS_ENSURE_SUCCESS(rv, rv);
  3417   if (node)
  3418     CallQueryInterface(node, aNode);
  3420   return NS_OK;
  3423 /*
  3424  * XXX dr
  3425  * ------
  3426  * These two functions -- GetInLink and GetInImage -- are kind of annoying
  3427  * in that they only get called from the controller (in
  3428  * nsDOMWindowController::IsCommandEnabled). The actual construction of the
  3429  * context menus in communicator (nsContextMenu.js) has its own, redundant
  3430  * tests. No big deal, but good to keep in mind if we ever clean context
  3431  * menus.
  3432  */
  3434 NS_IMETHODIMP nsDocumentViewer::GetInLink(bool* aInLink)
  3436 #ifdef DEBUG_dr
  3437   printf("dr :: nsDocumentViewer::GetInLink\n");
  3438 #endif
  3440   NS_ENSURE_ARG_POINTER(aInLink);
  3442   // we're not in a link unless i say so
  3443   *aInLink = false;
  3445   // get the popup link
  3446   nsCOMPtr<nsIDOMNode> node;
  3447   nsresult rv = GetPopupLinkNode(getter_AddRefs(node));
  3448   if (NS_FAILED(rv)) return rv;
  3449   NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
  3451   // if we made it here, we're in a link
  3452   *aInLink = true;
  3453   return NS_OK;
  3456 NS_IMETHODIMP nsDocumentViewer::GetInImage(bool* aInImage)
  3458 #ifdef DEBUG_dr
  3459   printf("dr :: nsDocumentViewer::GetInImage\n");
  3460 #endif
  3462   NS_ENSURE_ARG_POINTER(aInImage);
  3464   // we're not in an image unless i say so
  3465   *aInImage = false;
  3467   // get the popup image
  3468   nsCOMPtr<nsIImageLoadingContent> node;
  3469   nsresult rv = GetPopupImageNode(getter_AddRefs(node));
  3470   if (NS_FAILED(rv)) return rv;
  3471   NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
  3473   // if we made it here, we're in an image
  3474   *aInImage = true;
  3475   return NS_OK;
  3478 NS_IMETHODIMP nsDocViewerSelectionListener::NotifySelectionChanged(nsIDOMDocument *, nsISelection *, int16_t)
  3480   NS_ASSERTION(mDocViewer, "Should have doc viewer!");
  3482   // get the selection state
  3483   nsCOMPtr<nsISelection> selection;
  3484   nsresult rv = mDocViewer->GetDocumentSelection(getter_AddRefs(selection));
  3485   if (NS_FAILED(rv)) return rv;
  3487   bool selectionCollapsed;
  3488   selection->GetIsCollapsed(&selectionCollapsed);
  3489   // we only call UpdateCommands when the selection changes from collapsed
  3490   // to non-collapsed or vice versa. We might need another update string
  3491   // for simple selection changes, but that would be expenseive.
  3492   if (!mGotSelectionState || mSelectionWasCollapsed != selectionCollapsed)
  3494     nsIDocument* theDoc = mDocViewer->GetDocument();
  3495     if (!theDoc) return NS_ERROR_FAILURE;
  3497     nsPIDOMWindow *domWindow = theDoc->GetWindow();
  3498     if (!domWindow) return NS_ERROR_FAILURE;
  3500     domWindow->UpdateCommands(NS_LITERAL_STRING("select"));
  3501     mGotSelectionState = true;
  3502     mSelectionWasCollapsed = selectionCollapsed;
  3505   return NS_OK;
  3508 //nsDocViewerFocusListener
  3509 NS_IMPL_ISUPPORTS(nsDocViewerFocusListener,
  3510                   nsIDOMEventListener)
  3512 nsDocViewerFocusListener::nsDocViewerFocusListener()
  3513 :mDocViewer(nullptr)
  3517 nsDocViewerFocusListener::~nsDocViewerFocusListener(){}
  3519 nsresult
  3520 nsDocViewerFocusListener::HandleEvent(nsIDOMEvent* aEvent)
  3522   NS_ENSURE_STATE(mDocViewer);
  3524   nsCOMPtr<nsIPresShell> shell;
  3525   mDocViewer->GetPresShell(getter_AddRefs(shell));
  3526   NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE);
  3528   nsCOMPtr<nsISelectionController> selCon = do_QueryInterface(shell);
  3529   int16_t selectionStatus;
  3530   selCon->GetDisplaySelection(&selectionStatus);
  3532   nsAutoString eventType;
  3533   aEvent->GetType(eventType);
  3534   if (eventType.EqualsLiteral("focus")) {
  3535     // If selection was disabled, re-enable it.
  3536     if(selectionStatus == nsISelectionController::SELECTION_DISABLED ||
  3537        selectionStatus == nsISelectionController::SELECTION_HIDDEN) {
  3538       selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
  3539       selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL);
  3541   } else {
  3542     NS_ABORT_IF_FALSE(eventType.EqualsLiteral("blur"),
  3543                       "Unexpected event type");
  3544     // If selection was on, disable it.
  3545     if(selectionStatus == nsISelectionController::SELECTION_ON ||
  3546        selectionStatus == nsISelectionController::SELECTION_ATTENTION) {
  3547       selCon->SetDisplaySelection(nsISelectionController::SELECTION_DISABLED);
  3548       selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL);
  3552   return NS_OK;
  3555 nsresult
  3556 nsDocViewerFocusListener::Init(nsDocumentViewer *aDocViewer)
  3558   mDocViewer = aDocViewer;
  3559   return NS_OK;
  3562 /** ---------------------------------------------------
  3563  *  From nsIWebBrowserPrint
  3564  */
  3566 #ifdef NS_PRINTING
  3568 NS_IMETHODIMP
  3569 nsDocumentViewer::Print(nsIPrintSettings*       aPrintSettings,
  3570                           nsIWebProgressListener* aWebProgressListener)
  3572   // Printing XUL documents is not supported.
  3573   nsCOMPtr<nsIXULDocument> xulDoc(do_QueryInterface(mDocument));
  3574   if (xulDoc) {
  3575     return NS_ERROR_FAILURE;
  3578   if (!mContainer) {
  3579     PR_PL(("Container was destroyed yet we are still trying to use it!"));
  3580     return NS_ERROR_FAILURE;
  3583   nsCOMPtr<nsIDocShell> docShell(mContainer);
  3584   NS_ENSURE_STATE(docShell);
  3586   // Check to see if this document is still busy
  3587   // If it is busy and we aren't already "queued" up to print then
  3588   // Indicate there is a print pending and cache the args for later
  3589   uint32_t busyFlags = nsIDocShell::BUSY_FLAGS_NONE;
  3590   if ((NS_FAILED(docShell->GetBusyFlags(&busyFlags)) ||
  3591        (busyFlags != nsIDocShell::BUSY_FLAGS_NONE && busyFlags & nsIDocShell::BUSY_FLAGS_PAGE_LOADING)) && 
  3592       !mPrintDocIsFullyLoaded) {
  3593     if (!mPrintIsPending) {
  3594       mCachedPrintSettings           = aPrintSettings;
  3595       mCachedPrintWebProgressListner = aWebProgressListener;
  3596       mPrintIsPending                = true;
  3598     PR_PL(("Printing Stopped - document is still busy!"));
  3599     return NS_ERROR_GFX_PRINTER_DOC_IS_BUSY;
  3602   if (!mDocument || !mDeviceContext) {
  3603     PR_PL(("Can't Print without a document and a device context"));
  3604     return NS_ERROR_FAILURE;
  3607   nsresult rv;
  3609   // if we are printing another URL, then exit
  3610   // the reason we check here is because this method can be called while
  3611   // another is still in here (the printing dialog is a good example).
  3612   // the only time we can print more than one job at a time is the regression tests
  3613   if (GetIsPrinting()) {
  3614     // Let the user know we are not ready to print.
  3615     rv = NS_ERROR_NOT_AVAILABLE;
  3616     nsPrintEngine::ShowPrintErrorDialog(rv);
  3617     return rv;
  3620   nsAutoPtr<nsPrintEventDispatcher> beforeAndAfterPrint(
  3621     new nsPrintEventDispatcher(mDocument));
  3622   NS_ENSURE_STATE(!GetIsPrinting());
  3623   // If we are hosting a full-page plugin, tell it to print
  3624   // first. It shows its own native print UI.
  3625   nsCOMPtr<nsIPluginDocument> pDoc(do_QueryInterface(mDocument));
  3626   if (pDoc)
  3627     return pDoc->Print();
  3629   if (!mPrintEngine) {
  3630     NS_ENSURE_STATE(mDeviceContext);
  3631     mPrintEngine = new nsPrintEngine();
  3633     rv = mPrintEngine->Initialize(this, mContainer, mDocument, 
  3634                                   float(mDeviceContext->AppUnitsPerCSSInch()) /
  3635                                   float(mDeviceContext->AppUnitsPerDevPixel()) /
  3636                                   mPageZoom,
  3637 #ifdef DEBUG
  3638                                   mDebugFile
  3639 #else
  3640                                   nullptr
  3641 #endif
  3642                                   );
  3643     if (NS_FAILED(rv)) {
  3644       mPrintEngine->Destroy();
  3645       mPrintEngine = nullptr;
  3646       return rv;
  3649   if (mPrintEngine->HasPrintCallbackCanvas()) {
  3650     mBeforeAndAfterPrint = beforeAndAfterPrint;
  3652   dom::Element* root = mDocument->GetRootElement();
  3653   if (root && root->HasAttr(kNameSpaceID_None, nsGkAtoms::mozdisallowselectionprint)) {
  3654     mPrintEngine->SetDisallowSelectionPrint(true);
  3656   if (root && root->HasAttr(kNameSpaceID_None, nsGkAtoms::moznomarginboxes)) {
  3657     mPrintEngine->SetNoMarginBoxes(true);
  3659   rv = mPrintEngine->Print(aPrintSettings, aWebProgressListener);
  3660   if (NS_FAILED(rv)) {
  3661     OnDonePrinting();
  3663   return rv;
  3666 NS_IMETHODIMP
  3667 nsDocumentViewer::PrintPreview(nsIPrintSettings* aPrintSettings, 
  3668                                  nsIDOMWindow *aChildDOMWin, 
  3669                                  nsIWebProgressListener* aWebProgressListener)
  3671 #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
  3672   NS_WARN_IF_FALSE(IsInitializedForPrintPreview(),
  3673                    "Using docshell.printPreview is the preferred way for print previewing!");
  3675   NS_ENSURE_ARG_POINTER(aChildDOMWin);
  3676   nsresult rv = NS_OK;
  3678   if (GetIsPrinting()) {
  3679     nsPrintEngine::CloseProgressDialog(aWebProgressListener);
  3680     return NS_ERROR_FAILURE;
  3683   // Printing XUL documents is not supported.
  3684   nsCOMPtr<nsIXULDocument> xulDoc(do_QueryInterface(mDocument));
  3685   if (xulDoc) {
  3686     nsPrintEngine::CloseProgressDialog(aWebProgressListener);
  3687     return NS_ERROR_FAILURE;
  3690   nsCOMPtr<nsIDocShell> docShell(mContainer);
  3691   if (!docShell || !mDeviceContext) {
  3692     PR_PL(("Can't Print Preview without device context and docshell"));
  3693     return NS_ERROR_FAILURE;
  3696   nsCOMPtr<nsIDOMDocument> domDoc;
  3697   aChildDOMWin->GetDocument(getter_AddRefs(domDoc));
  3698   nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
  3699   NS_ENSURE_STATE(doc);
  3701   nsAutoPtr<nsPrintEventDispatcher> beforeAndAfterPrint(
  3702     new nsPrintEventDispatcher(doc));
  3703   NS_ENSURE_STATE(!GetIsPrinting());
  3704   if (!mPrintEngine) {
  3705     mPrintEngine = new nsPrintEngine();
  3707     rv = mPrintEngine->Initialize(this, mContainer, doc,
  3708                                   float(mDeviceContext->AppUnitsPerCSSInch()) /
  3709                                   float(mDeviceContext->AppUnitsPerDevPixel()) /
  3710                                   mPageZoom,
  3711 #ifdef DEBUG
  3712                                   mDebugFile
  3713 #else
  3714                                   nullptr
  3715 #endif
  3716                                   );
  3717     if (NS_FAILED(rv)) {
  3718       mPrintEngine->Destroy();
  3719       mPrintEngine = nullptr;
  3720       return rv;
  3723   if (mPrintEngine->HasPrintCallbackCanvas()) {
  3724     mBeforeAndAfterPrint = beforeAndAfterPrint;
  3726   dom::Element* root = doc->GetRootElement();
  3727   if (root && root->HasAttr(kNameSpaceID_None, nsGkAtoms::mozdisallowselectionprint)) {
  3728     PR_PL(("PrintPreview: found mozdisallowselectionprint"));
  3729     mPrintEngine->SetDisallowSelectionPrint(true);
  3731   if (root && root->HasAttr(kNameSpaceID_None, nsGkAtoms::moznomarginboxes)) {
  3732     PR_PL(("PrintPreview: found moznomarginboxes"));
  3733     mPrintEngine->SetNoMarginBoxes(true);
  3735   rv = mPrintEngine->PrintPreview(aPrintSettings, aChildDOMWin, aWebProgressListener);
  3736   mPrintPreviewZoomed = false;
  3737   if (NS_FAILED(rv)) {
  3738     OnDonePrinting();
  3740   return rv;
  3741 #else
  3742   return NS_ERROR_FAILURE;
  3743 #endif
  3746 //----------------------------------------------------------------------
  3747 NS_IMETHODIMP
  3748 nsDocumentViewer::PrintPreviewNavigate(int16_t aType, int32_t aPageNum)
  3750   if (!GetIsPrintPreview() ||
  3751       mPrintEngine->GetIsCreatingPrintPreview())
  3752     return NS_ERROR_FAILURE;
  3754   nsIScrollableFrame* sf =
  3755     mPrintEngine->GetPrintPreviewPresShell()->GetRootScrollFrameAsScrollable();
  3756   if (!sf)
  3757     return NS_OK;
  3759   // Check to see if we can short circut scrolling to the top
  3760   if (aType == nsIWebBrowserPrint::PRINTPREVIEW_HOME ||
  3761       (aType == nsIWebBrowserPrint::PRINTPREVIEW_GOTO_PAGENUM && aPageNum == 1)) {
  3762     sf->ScrollTo(nsPoint(0, 0), nsIScrollableFrame::INSTANT);
  3763     return NS_OK;
  3766   // Finds the SimplePageSequencer frame
  3767   // in PP mPrtPreview->mPrintObject->mSeqFrame is null
  3768   nsIFrame* seqFrame  = nullptr;
  3769   int32_t   pageCount = 0;
  3770   if (NS_FAILED(mPrintEngine->GetSeqFrameAndCountPages(seqFrame, pageCount))) {
  3771     return NS_ERROR_FAILURE;
  3774   // Figure where we are currently scrolled to
  3775   nsPoint pt = sf->GetScrollPosition();
  3777   int32_t    pageNum = 1;
  3778   nsIFrame * fndPageFrame  = nullptr;
  3779   nsIFrame * currentPage   = nullptr;
  3781   // If it is "End" then just do a "goto" to the last page
  3782   if (aType == nsIWebBrowserPrint::PRINTPREVIEW_END) {
  3783     aType    = nsIWebBrowserPrint::PRINTPREVIEW_GOTO_PAGENUM;
  3784     aPageNum = pageCount;
  3787   // Now, locate the current page we are on and
  3788   // and the page of the page number
  3789   nsIFrame* pageFrame = seqFrame->GetFirstPrincipalChild();
  3790   while (pageFrame != nullptr) {
  3791     nsRect pageRect = pageFrame->GetRect();
  3792     if (pageRect.Contains(pageRect.x, pt.y)) {
  3793       currentPage = pageFrame;
  3795     if (pageNum == aPageNum) {
  3796       fndPageFrame = pageFrame;
  3797       break;
  3799     pageNum++;
  3800     pageFrame = pageFrame->GetNextSibling();
  3803   if (aType == nsIWebBrowserPrint::PRINTPREVIEW_PREV_PAGE) {
  3804     if (currentPage) {
  3805       fndPageFrame = currentPage->GetPrevInFlow();
  3806       if (!fndPageFrame) {
  3807         return NS_OK;
  3809     } else {
  3810       return NS_OK;
  3812   } else if (aType == nsIWebBrowserPrint::PRINTPREVIEW_NEXT_PAGE) {
  3813     if (currentPage) {
  3814       fndPageFrame = currentPage->GetNextInFlow();
  3815       if (!fndPageFrame) {
  3816         return NS_OK;
  3818     } else {
  3819       return NS_OK;
  3821   } else { // If we get here we are doing "GoTo"
  3822     if (aPageNum < 0 || aPageNum > pageCount) {
  3823       return NS_OK;
  3827   if (fndPageFrame) {
  3828     nscoord newYPosn =
  3829       nscoord(mPrintEngine->GetPrintPreviewScale() * fndPageFrame->GetPosition().y);
  3830     sf->ScrollTo(nsPoint(pt.x, newYPosn), nsIScrollableFrame::INSTANT);
  3832   return NS_OK;
  3836 /* readonly attribute nsIPrintSettings globalPrintSettings; */
  3837 NS_IMETHODIMP
  3838 nsDocumentViewer::GetGlobalPrintSettings(nsIPrintSettings * *aGlobalPrintSettings)
  3840   return nsPrintEngine::GetGlobalPrintSettings(aGlobalPrintSettings);
  3843 /* readonly attribute boolean doingPrint; */
  3844 // XXX This always returns false for subdocuments
  3845 NS_IMETHODIMP
  3846 nsDocumentViewer::GetDoingPrint(bool *aDoingPrint)
  3848   NS_ENSURE_ARG_POINTER(aDoingPrint);
  3850   *aDoingPrint = false;
  3851   if (mPrintEngine) {
  3852     // XXX shouldn't this be GetDoingPrint() ?
  3853     return mPrintEngine->GetDoingPrintPreview(aDoingPrint);
  3855   return NS_OK;
  3858 /* readonly attribute boolean doingPrintPreview; */
  3859 // XXX This always returns false for subdocuments
  3860 NS_IMETHODIMP
  3861 nsDocumentViewer::GetDoingPrintPreview(bool *aDoingPrintPreview)
  3863   NS_ENSURE_ARG_POINTER(aDoingPrintPreview);
  3865   *aDoingPrintPreview = false;
  3866   if (mPrintEngine) {
  3867     return mPrintEngine->GetDoingPrintPreview(aDoingPrintPreview);
  3869   return NS_OK;
  3872 /* readonly attribute nsIPrintSettings currentPrintSettings; */
  3873 NS_IMETHODIMP
  3874 nsDocumentViewer::GetCurrentPrintSettings(nsIPrintSettings * *aCurrentPrintSettings)
  3876   NS_ENSURE_ARG_POINTER(aCurrentPrintSettings);
  3878   *aCurrentPrintSettings = nullptr;
  3879   NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
  3881   return mPrintEngine->GetCurrentPrintSettings(aCurrentPrintSettings);
  3885 /* readonly attribute nsIDOMWindow currentChildDOMWindow; */
  3886 NS_IMETHODIMP 
  3887 nsDocumentViewer::GetCurrentChildDOMWindow(nsIDOMWindow * *aCurrentChildDOMWindow)
  3889   NS_ENSURE_ARG_POINTER(aCurrentChildDOMWindow);
  3890   *aCurrentChildDOMWindow = nullptr;
  3891   return NS_ERROR_NOT_IMPLEMENTED;
  3894 /* void cancel (); */
  3895 NS_IMETHODIMP
  3896 nsDocumentViewer::Cancel()
  3898   NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
  3899   return mPrintEngine->Cancelled();
  3902 /* void exitPrintPreview (); */
  3903 NS_IMETHODIMP
  3904 nsDocumentViewer::ExitPrintPreview()
  3906   if (GetIsPrinting())
  3907     return NS_ERROR_FAILURE;
  3908   NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
  3910   if (GetIsPrintPreview()) {
  3911     ReturnToGalleyPresentation();
  3913   return NS_OK;
  3916 //----------------------------------------------------------------------------------
  3917 // Enumerate all the documents for their titles
  3918 NS_IMETHODIMP
  3919 nsDocumentViewer::EnumerateDocumentNames(uint32_t* aCount,
  3920                                            char16_t*** aResult)
  3922 #ifdef NS_PRINTING
  3923   NS_ENSURE_ARG(aCount);
  3924   NS_ENSURE_ARG_POINTER(aResult);
  3925   NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
  3927   return mPrintEngine->EnumerateDocumentNames(aCount, aResult);
  3928 #else
  3929   return NS_ERROR_FAILURE;
  3930 #endif
  3933 /* readonly attribute boolean isFramesetFrameSelected; */
  3934 NS_IMETHODIMP 
  3935 nsDocumentViewer::GetIsFramesetFrameSelected(bool *aIsFramesetFrameSelected)
  3937 #ifdef NS_PRINTING
  3938   *aIsFramesetFrameSelected = false;
  3939   NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
  3941   return mPrintEngine->GetIsFramesetFrameSelected(aIsFramesetFrameSelected);
  3942 #else
  3943   return NS_ERROR_FAILURE;
  3944 #endif
  3947 /* readonly attribute long printPreviewNumPages; */
  3948 NS_IMETHODIMP
  3949 nsDocumentViewer::GetPrintPreviewNumPages(int32_t *aPrintPreviewNumPages)
  3951 #ifdef NS_PRINTING
  3952   NS_ENSURE_ARG_POINTER(aPrintPreviewNumPages);
  3953   NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
  3955   return mPrintEngine->GetPrintPreviewNumPages(aPrintPreviewNumPages);
  3956 #else
  3957   return NS_ERROR_FAILURE;
  3958 #endif
  3961 /* readonly attribute boolean isFramesetDocument; */
  3962 NS_IMETHODIMP
  3963 nsDocumentViewer::GetIsFramesetDocument(bool *aIsFramesetDocument)
  3965 #ifdef NS_PRINTING
  3966   *aIsFramesetDocument = false;
  3967   NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
  3969   return mPrintEngine->GetIsFramesetDocument(aIsFramesetDocument);
  3970 #else
  3971   return NS_ERROR_FAILURE;
  3972 #endif
  3975 /* readonly attribute boolean isIFrameSelected; */
  3976 NS_IMETHODIMP 
  3977 nsDocumentViewer::GetIsIFrameSelected(bool *aIsIFrameSelected)
  3979 #ifdef NS_PRINTING
  3980   *aIsIFrameSelected = false;
  3981   NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
  3983   return mPrintEngine->GetIsIFrameSelected(aIsIFrameSelected);
  3984 #else
  3985   return NS_ERROR_FAILURE;
  3986 #endif
  3989 /* readonly attribute boolean isRangeSelection; */
  3990 NS_IMETHODIMP 
  3991 nsDocumentViewer::GetIsRangeSelection(bool *aIsRangeSelection)
  3993 #ifdef NS_PRINTING
  3994   *aIsRangeSelection = false;
  3995   NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
  3997   return mPrintEngine->GetIsRangeSelection(aIsRangeSelection);
  3998 #else
  3999   return NS_ERROR_FAILURE;
  4000 #endif
  4003 //----------------------------------------------------------------------------------
  4004 // Printing/Print Preview Helpers
  4005 //----------------------------------------------------------------------------------
  4007 //----------------------------------------------------------------------------------
  4008 // Walks the document tree and tells each DocShell whether Printing/PP is happening
  4009 void 
  4010 nsDocumentViewer::SetIsPrintingInDocShellTree(nsIDocShellTreeItem* aParentNode, 
  4011                                                 bool                 aIsPrintingOrPP, 
  4012                                                 bool                 aStartAtTop)
  4014   nsCOMPtr<nsIDocShellTreeItem> parentItem(do_QueryInterface(aParentNode));
  4016   // find top of "same parent" tree
  4017   if (aStartAtTop) {
  4018     if (aIsPrintingOrPP) {
  4019       while (parentItem) {
  4020         nsCOMPtr<nsIDocShellTreeItem> parent;
  4021         parentItem->GetSameTypeParent(getter_AddRefs(parent));
  4022         if (!parent) {
  4023           break;
  4025         parentItem = do_QueryInterface(parent);
  4027       mTopContainerWhilePrinting = do_GetWeakReference(parentItem);
  4028     } else {
  4029       parentItem = do_QueryReferent(mTopContainerWhilePrinting);
  4033   // Check to see if the DocShell's ContentViewer is printing/PP
  4034   nsCOMPtr<nsIContentViewerContainer> viewerContainer(do_QueryInterface(parentItem));
  4035   if (viewerContainer) {
  4036     viewerContainer->SetIsPrinting(aIsPrintingOrPP);
  4039   if (!aParentNode) {
  4040     return;
  4043   // Traverse children to see if any of them are printing.
  4044   int32_t n;
  4045   aParentNode->GetChildCount(&n);
  4046   for (int32_t i=0; i < n; i++) {
  4047     nsCOMPtr<nsIDocShellTreeItem> child;
  4048     aParentNode->GetChildAt(i, getter_AddRefs(child));
  4049     NS_ASSERTION(child, "child isn't nsIDocShell");
  4050     if (child) {
  4051       SetIsPrintingInDocShellTree(child, aIsPrintingOrPP, false);
  4056 #endif // NS_PRINTING
  4058 bool
  4059 nsDocumentViewer::ShouldAttachToTopLevel()
  4061   if (!mParentWidget)
  4062     return false;
  4064   nsCOMPtr<nsIDocShellTreeItem> containerItem(mContainer);
  4065   if (!containerItem)
  4066     return false;
  4068   // We always attach when using puppet widgets
  4069   if (nsIWidget::UsePuppetWidgets())
  4070     return true;
  4072 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
  4073   // On windows, in the parent process we also attach, but just to
  4074   // chrome items
  4075   nsWindowType winType = mParentWidget->WindowType();
  4076   if ((winType == eWindowType_toplevel ||
  4077        winType == eWindowType_dialog ||
  4078        winType == eWindowType_invisible) &&
  4079       containerItem->ItemType() == nsIDocShellTreeItem::typeChrome) {
  4080     return true;
  4082 #endif
  4084   return false;
  4087 bool CollectDocuments(nsIDocument* aDocument, void* aData)
  4089   if (aDocument) {
  4090     static_cast<nsCOMArray<nsIDocument>*>(aData)->AppendObject(aDocument);
  4091     aDocument->EnumerateSubDocuments(CollectDocuments, aData);
  4093   return true;
  4096 void
  4097 nsDocumentViewer::DispatchEventToWindowTree(nsIDocument* aDoc,
  4098                                               const nsAString& aEvent)
  4100   nsCOMArray<nsIDocument> targets;
  4101   CollectDocuments(aDoc, &targets);
  4102   for (int32_t i = 0; i < targets.Count(); ++i) {
  4103     nsIDocument* d = targets[i];
  4104     nsContentUtils::DispatchTrustedEvent(d, d->GetWindow(),
  4105                                          aEvent, false, false, nullptr);
  4109 //------------------------------------------------------------
  4110 // XXX this always returns false for subdocuments
  4111 bool
  4112 nsDocumentViewer::GetIsPrinting()
  4114 #ifdef NS_PRINTING
  4115   if (mPrintEngine) {
  4116     return mPrintEngine->GetIsPrinting();
  4118 #endif
  4119   return false; 
  4122 //------------------------------------------------------------
  4123 // Notification from the PrintEngine of the current Printing status
  4124 void
  4125 nsDocumentViewer::SetIsPrinting(bool aIsPrinting)
  4127 #ifdef NS_PRINTING
  4128   // Set all the docShells in the docshell tree to be printing.
  4129   // that way if anyone of them tries to "navigate" it can't
  4130   nsCOMPtr<nsIDocShell> docShell(mContainer);
  4131   if (docShell || !aIsPrinting) {
  4132     SetIsPrintingInDocShellTree(docShell, aIsPrinting, true);
  4133   } else {
  4134     NS_WARNING("Did you close a window before printing?");
  4137   if (!aIsPrinting) {
  4138     mBeforeAndAfterPrint = nullptr;
  4140 #endif
  4143 //------------------------------------------------------------
  4144 // The PrintEngine holds the current value
  4145 // this called from inside the DocViewer.
  4146 // XXX it always returns false for subdocuments
  4147 bool
  4148 nsDocumentViewer::GetIsPrintPreview()
  4150 #ifdef NS_PRINTING
  4151   if (mPrintEngine) {
  4152     return mPrintEngine->GetIsPrintPreview();
  4154 #endif
  4155   return false; 
  4158 //------------------------------------------------------------
  4159 // Notification from the PrintEngine of the current PP status
  4160 void
  4161 nsDocumentViewer::SetIsPrintPreview(bool aIsPrintPreview)
  4163 #ifdef NS_PRINTING
  4164   // Set all the docShells in the docshell tree to be printing.
  4165   // that way if anyone of them tries to "navigate" it can't
  4166   nsCOMPtr<nsIDocShell> docShell(mContainer);
  4167   if (docShell || !aIsPrintPreview) {
  4168     SetIsPrintingInDocShellTree(docShell, aIsPrintPreview, true);
  4170   if (!aIsPrintPreview) {
  4171     mBeforeAndAfterPrint = nullptr;
  4173 #endif
  4174   if (!aIsPrintPreview) {
  4175     if (mPresShell) {
  4176       DestroyPresShell();
  4178     mWindow = nullptr;
  4179     mViewManager = nullptr;
  4180     mPresContext = nullptr;
  4181     mPresShell = nullptr;
  4185 //----------------------------------------------------------------------------------
  4186 // nsIDocumentViewerPrint IFace
  4187 //----------------------------------------------------------------------------------
  4189 //------------------------------------------------------------
  4190 void
  4191 nsDocumentViewer::IncrementDestroyRefCount()
  4193   ++mDestroyRefCount;
  4196 //------------------------------------------------------------
  4198 #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
  4199 //------------------------------------------------------------
  4200 // Reset ESM focus for all descendent doc shells.
  4201 static void
  4202 ResetFocusState(nsIDocShell* aDocShell)
  4204   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
  4205   if (!fm)
  4206     return;
  4208   nsCOMPtr<nsISimpleEnumerator> docShellEnumerator;
  4209   aDocShell->GetDocShellEnumerator(nsIDocShellTreeItem::typeContent,
  4210                                    nsIDocShell::ENUMERATE_FORWARDS,
  4211                                    getter_AddRefs(docShellEnumerator));
  4213   nsCOMPtr<nsISupports> currentContainer;
  4214   bool hasMoreDocShells;
  4215   while (NS_SUCCEEDED(docShellEnumerator->HasMoreElements(&hasMoreDocShells))
  4216          && hasMoreDocShells) {
  4217     docShellEnumerator->GetNext(getter_AddRefs(currentContainer));
  4218     nsCOMPtr<nsIDOMWindow> win = do_GetInterface(currentContainer);
  4219     if (win)
  4220       fm->ClearFocus(win);
  4223 #endif // NS_PRINTING && NS_PRINT_PREVIEW
  4225 void
  4226 nsDocumentViewer::ReturnToGalleyPresentation()
  4228 #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
  4229   if (!GetIsPrintPreview()) {
  4230     NS_ERROR("Wow, we should never get here!");
  4231     return;
  4234   SetIsPrintPreview(false);
  4236   mPrintEngine->TurnScriptingOn(true);
  4237   mPrintEngine->Destroy();
  4238   mPrintEngine = nullptr;
  4240   nsCOMPtr<nsIDocShell> docShell(mContainer);
  4241   ResetFocusState(docShell);
  4243   SetTextZoom(mTextZoom);
  4244   SetFullZoom(mPageZoom);
  4245   SetMinFontSize(mMinFontSize);
  4246   Show();
  4248 #endif // NS_PRINTING && NS_PRINT_PREVIEW
  4251 //------------------------------------------------------------
  4252 // This called ONLY when printing has completed and the DV
  4253 // is being notified that it should get rid of the PrintEngine.
  4254 //
  4255 // BUT, if we are in Print Preview then we want to ignore the 
  4256 // notification (we do not get rid of the PrintEngine)
  4257 // 
  4258 // One small caveat: 
  4259 //   This IS called from two places in this module for cleaning
  4260 //   up when an error occurred during the start up printing 
  4261 //   and print preview
  4262 //
  4263 void
  4264 nsDocumentViewer::OnDonePrinting() 
  4266 #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
  4267   if (mPrintEngine) {
  4268     nsRefPtr<nsPrintEngine> pe = mPrintEngine;
  4269     if (GetIsPrintPreview()) {
  4270       pe->DestroyPrintingData();
  4271     } else {
  4272       mPrintEngine = nullptr;
  4273       pe->Destroy();
  4276     // We are done printing, now cleanup 
  4277     if (mDeferredWindowClose) {
  4278       mDeferredWindowClose = false;
  4279       nsCOMPtr<nsIDOMWindow> win =
  4280         do_GetInterface(static_cast<nsIDocShell*>(mContainer));
  4281       if (win)
  4282         win->Close();
  4283     } else if (mClosingWhilePrinting) {
  4284       if (mDocument) {
  4285         mDocument->SetScriptGlobalObject(nullptr);
  4286         mDocument->Destroy();
  4287         mDocument = nullptr;
  4289       mClosingWhilePrinting = false;
  4292 #endif // NS_PRINTING && NS_PRINT_PREVIEW
  4295 NS_IMETHODIMP nsDocumentViewer::SetPageMode(bool aPageMode, nsIPrintSettings* aPrintSettings)
  4297   // XXX Page mode is only partially working; it's currently used for
  4298   // reftests that require a paginated context
  4299   mIsPageMode = aPageMode;
  4301   if (mPresShell) {
  4302     DestroyPresShell();
  4305   if (mPresContext) {
  4306     DestroyPresContext();
  4309   mViewManager  = nullptr;
  4310   mWindow       = nullptr;
  4312   NS_ENSURE_STATE(mDocument);
  4313   if (aPageMode)
  4315     mPresContext = CreatePresContext(mDocument,
  4316         nsPresContext::eContext_PageLayout, FindContainerView());
  4317     NS_ENSURE_TRUE(mPresContext, NS_ERROR_OUT_OF_MEMORY);
  4318     mPresContext->SetPaginatedScrolling(true);
  4319     mPresContext->SetPrintSettings(aPrintSettings);
  4320     nsresult rv = mPresContext->Init(mDeviceContext);
  4321     NS_ENSURE_SUCCESS(rv, rv);
  4323   InitInternal(mParentWidget, nullptr, mBounds, true, false);
  4325   Show();
  4326   return NS_OK;
  4329 NS_IMETHODIMP
  4330 nsDocumentViewer::GetHistoryEntry(nsISHEntry **aHistoryEntry)
  4332   NS_IF_ADDREF(*aHistoryEntry = mSHEntry);
  4333   return NS_OK;
  4336 NS_IMETHODIMP
  4337 nsDocumentViewer::GetIsTabModalPromptAllowed(bool *aAllowed)
  4339   *aAllowed = !mHidden;
  4340   return NS_OK;
  4343 NS_IMETHODIMP
  4344 nsDocumentViewer::GetIsHidden(bool *aHidden)
  4346   *aHidden = mHidden;
  4347   return NS_OK;
  4350 void
  4351 nsDocumentViewer::DestroyPresShell()
  4353   // Break circular reference (or something)
  4354   mPresShell->EndObservingDocument();
  4356   nsCOMPtr<nsISelection> selection;
  4357   GetDocumentSelection(getter_AddRefs(selection));
  4358   nsCOMPtr<nsISelectionPrivate> selPrivate = do_QueryInterface(selection);
  4359   if (selPrivate && mSelectionListener)
  4360     selPrivate->RemoveSelectionListener(mSelectionListener);
  4362   nsAutoScriptBlocker scriptBlocker;
  4363   mPresShell->Destroy();
  4364   mPresShell = nullptr;
  4367 void
  4368 nsDocumentViewer::DestroyPresContext()
  4370   mPresContext->Detach();
  4371   mPresContext = nullptr;
  4374 bool
  4375 nsDocumentViewer::IsInitializedForPrintPreview()
  4377   return mInitializedForPrintPreview;
  4380 void
  4381 nsDocumentViewer::InitializeForPrintPreview()
  4383   mInitializedForPrintPreview = true;
  4386 void
  4387 nsDocumentViewer::SetPrintPreviewPresentation(nsViewManager* aViewManager,
  4388                                                 nsPresContext* aPresContext,
  4389                                                 nsIPresShell* aPresShell)
  4391   if (mPresShell) {
  4392     DestroyPresShell();
  4395   mWindow = nullptr;
  4396   mViewManager = aViewManager;
  4397   mPresContext = aPresContext;
  4398   mPresShell = aPresShell;
  4401 // Fires the "document-shown" event so that interested parties are aware of it.
  4402 NS_IMETHODIMP
  4403 nsDocumentShownDispatcher::Run()
  4405   nsCOMPtr<nsIObserverService> observerService =
  4406     mozilla::services::GetObserverService();
  4407   if (observerService) {
  4408     observerService->NotifyObservers(mDocument, "document-shown", nullptr);
  4410   return NS_OK;

mercurial