layout/base/nsDocumentViewer.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/base/nsDocumentViewer.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,4412 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=2 sw=2 et tw=80: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +/* container for a document and its presentation */
    1.11 +
    1.12 +#include "nscore.h"
    1.13 +#include "nsCOMPtr.h"
    1.14 +#include "nsCRT.h"
    1.15 +#include "nsString.h"
    1.16 +#include "nsReadableUtils.h"
    1.17 +#include "nsIContent.h"
    1.18 +#include "nsIContentViewerContainer.h"
    1.19 +#include "nsIContentViewer.h"
    1.20 +#include "nsIDocumentViewerPrint.h"
    1.21 +#include "nsIDOMBeforeUnloadEvent.h"
    1.22 +#include "nsIDocument.h"
    1.23 +#include "nsIDOMWindowUtils.h"
    1.24 +#include "nsPresContext.h"
    1.25 +#include "nsIPresShell.h"
    1.26 +#include "nsStyleSet.h"
    1.27 +#include "nsCSSStyleSheet.h"
    1.28 +#include "nsIFrame.h"
    1.29 +#include "nsIWritablePropertyBag2.h"
    1.30 +#include "nsSubDocumentFrame.h"
    1.31 +
    1.32 +#include "nsILinkHandler.h"
    1.33 +#include "nsIDOMDocument.h"
    1.34 +#include "nsISelectionListener.h"
    1.35 +#include "nsISelectionPrivate.h"
    1.36 +#include "nsIDOMHTMLDocument.h"
    1.37 +#include "nsIDOMHTMLElement.h"
    1.38 +#include "nsContentUtils.h"
    1.39 +#include "nsLayoutStylesheetCache.h"
    1.40 +#ifdef ACCESSIBILITY
    1.41 +#include "mozilla/a11y/DocAccessible.h"
    1.42 +#endif
    1.43 +#include "mozilla/BasicEvents.h"
    1.44 +#include "mozilla/Preferences.h"
    1.45 +#include "mozilla/dom/EncodingUtils.h"
    1.46 +#include "mozilla/WeakPtr.h"
    1.47 +
    1.48 +#include "nsViewManager.h"
    1.49 +#include "nsView.h"
    1.50 +
    1.51 +#include "nsIPageSequenceFrame.h"
    1.52 +#include "nsNetUtil.h"
    1.53 +#include "nsIContentViewerEdit.h"
    1.54 +#include "nsIContentViewerFile.h"
    1.55 +#include "mozilla/css/Loader.h"
    1.56 +#include "nsIMarkupDocumentViewer.h"
    1.57 +#include "nsIInterfaceRequestor.h"
    1.58 +#include "nsIInterfaceRequestorUtils.h"
    1.59 +#include "nsDocShell.h"
    1.60 +#include "nsIBaseWindow.h"
    1.61 +#include "nsILayoutHistoryState.h"
    1.62 +#include "nsCharsetSource.h"
    1.63 +#include "nsHTMLReflowState.h"
    1.64 +#include "nsIImageLoadingContent.h"
    1.65 +#include "nsCopySupport.h"
    1.66 +#include "nsIDOMHTMLFrameSetElement.h"
    1.67 +#ifdef MOZ_XUL
    1.68 +#include "nsIXULDocument.h"
    1.69 +#include "nsXULPopupManager.h"
    1.70 +#endif
    1.71 +
    1.72 +#include "nsIClipboardHelper.h"
    1.73 +
    1.74 +#include "nsPIDOMWindow.h"
    1.75 +#include "nsDOMNavigationTiming.h"
    1.76 +#include "nsPIWindowRoot.h"
    1.77 +#include "nsJSEnvironment.h"
    1.78 +#include "nsFocusManager.h"
    1.79 +
    1.80 +#include "nsIScrollableFrame.h"
    1.81 +#include "nsStyleSheetService.h"
    1.82 +#include "nsRenderingContext.h"
    1.83 +#include "nsILoadContext.h"
    1.84 +
    1.85 +#include "nsIPrompt.h"
    1.86 +#include "imgIContainer.h" // image animation mode constants
    1.87 +
    1.88 +//--------------------------
    1.89 +// Printing Include
    1.90 +//---------------------------
    1.91 +#ifdef NS_PRINTING
    1.92 +
    1.93 +#include "nsIWebBrowserPrint.h"
    1.94 +
    1.95 +#include "nsPrintEngine.h"
    1.96 +
    1.97 +// Print Options
    1.98 +#include "nsIPrintSettings.h"
    1.99 +#include "nsIPrintOptions.h"
   1.100 +#include "nsISimpleEnumerator.h"
   1.101 +
   1.102 +#ifdef DEBUG
   1.103 +// PrintOptions is now implemented by PrintSettingsService
   1.104 +static const char sPrintOptionsContractID[] =
   1.105 +  "@mozilla.org/gfx/printsettings-service;1";
   1.106 +#endif // DEBUG
   1.107 +
   1.108 +#include "nsIPluginDocument.h"
   1.109 +
   1.110 +#endif // NS_PRINTING
   1.111 +
   1.112 +//focus
   1.113 +#include "nsIDOMEventTarget.h"
   1.114 +#include "nsIDOMEventListener.h"
   1.115 +#include "nsISelectionController.h"
   1.116 +
   1.117 +#include "mozilla/EventDispatcher.h"
   1.118 +#include "nsISHEntry.h"
   1.119 +#include "nsISHistory.h"
   1.120 +#include "nsISHistoryInternal.h"
   1.121 +#include "nsIWebNavigation.h"
   1.122 +#include "nsXMLHttpRequest.h"
   1.123 +
   1.124 +//paint forcing
   1.125 +#include <stdio.h>
   1.126 +
   1.127 +#include "mozilla/dom/Element.h"
   1.128 +
   1.129 +using namespace mozilla;
   1.130 +using namespace mozilla::dom;
   1.131 +
   1.132 +#define BEFOREUNLOAD_DISABLED_PREFNAME "dom.disable_beforeunload"
   1.133 +
   1.134 +//-----------------------------------------------------
   1.135 +// PR LOGGING
   1.136 +#ifdef MOZ_LOGGING
   1.137 +#define FORCE_PR_LOG /* Allow logging in the release build */
   1.138 +#endif
   1.139 +
   1.140 +#include "prlog.h"
   1.141 +
   1.142 +#ifdef PR_LOGGING
   1.143 +
   1.144 +#ifdef NS_PRINTING
   1.145 +static PRLogModuleInfo *
   1.146 +GetPrintingLog()
   1.147 +{
   1.148 +  static PRLogModuleInfo *sLog;
   1.149 +  if (!sLog)
   1.150 +    sLog = PR_NewLogModule("printing");
   1.151 +  return sLog;
   1.152 +}
   1.153 +#define PR_PL(_p1)  PR_LOG(GetPrintingLog(), PR_LOG_DEBUG, _p1);
   1.154 +#endif // NS_PRINTING
   1.155 +
   1.156 +#define PRT_YESNO(_p) ((_p)?"YES":"NO")
   1.157 +#else
   1.158 +#define PRT_YESNO(_p)
   1.159 +#define PR_PL(_p1)
   1.160 +#endif
   1.161 +//-----------------------------------------------------
   1.162 +
   1.163 +class nsDocumentViewer;
   1.164 +class nsPrintEventDispatcher;
   1.165 +
   1.166 +// a small delegate class used to avoid circular references
   1.167 +
   1.168 +class nsDocViewerSelectionListener : public nsISelectionListener
   1.169 +{
   1.170 +public:
   1.171 +
   1.172 +  // nsISupports interface...
   1.173 +  NS_DECL_ISUPPORTS
   1.174 +
   1.175 +  // nsISelectionListerner interface
   1.176 +  NS_DECL_NSISELECTIONLISTENER
   1.177 +
   1.178 +                       nsDocViewerSelectionListener()
   1.179 +                       : mDocViewer(nullptr)
   1.180 +                       , mGotSelectionState(false)
   1.181 +                       , mSelectionWasCollapsed(false)
   1.182 +                       {
   1.183 +                       }
   1.184 +
   1.185 +  virtual              ~nsDocViewerSelectionListener() {}
   1.186 +
   1.187 +  nsresult             Init(nsDocumentViewer *aDocViewer);
   1.188 +
   1.189 +protected:
   1.190 +
   1.191 +  nsDocumentViewer*  mDocViewer;
   1.192 +  bool                 mGotSelectionState;
   1.193 +  bool                 mSelectionWasCollapsed;
   1.194 +
   1.195 +};
   1.196 +
   1.197 +
   1.198 +/** editor Implementation of the FocusListener interface
   1.199 + */
   1.200 +class nsDocViewerFocusListener : public nsIDOMEventListener
   1.201 +{
   1.202 +public:
   1.203 +  /** default constructor
   1.204 +   */
   1.205 +  nsDocViewerFocusListener();
   1.206 +  /** default destructor
   1.207 +   */
   1.208 +  virtual ~nsDocViewerFocusListener();
   1.209 +
   1.210 +  NS_DECL_ISUPPORTS
   1.211 +  NS_DECL_NSIDOMEVENTLISTENER
   1.212 +
   1.213 +  nsresult             Init(nsDocumentViewer *aDocViewer);
   1.214 +
   1.215 +private:
   1.216 +    nsDocumentViewer*  mDocViewer;
   1.217 +};
   1.218 +
   1.219 +
   1.220 +//-------------------------------------------------------------
   1.221 +class nsDocumentViewer : public nsIContentViewer,
   1.222 +                           public nsIContentViewerEdit,
   1.223 +                           public nsIContentViewerFile,
   1.224 +                           public nsIMarkupDocumentViewer,
   1.225 +                           public nsIDocumentViewerPrint
   1.226 +
   1.227 +#ifdef NS_PRINTING
   1.228 +                           , public nsIWebBrowserPrint
   1.229 +#endif
   1.230 +
   1.231 +{
   1.232 +  friend class nsDocViewerSelectionListener;
   1.233 +  friend class nsPagePrintTimer;
   1.234 +  friend class nsPrintEngine;
   1.235 +
   1.236 +public:
   1.237 +  nsDocumentViewer();
   1.238 +
   1.239 +  NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
   1.240 +
   1.241 +  // nsISupports interface...
   1.242 +  NS_DECL_ISUPPORTS
   1.243 +
   1.244 +  // nsIContentViewer interface...
   1.245 +  NS_DECL_NSICONTENTVIEWER
   1.246 +
   1.247 +  // nsIContentViewerEdit
   1.248 +  NS_DECL_NSICONTENTVIEWEREDIT
   1.249 +
   1.250 +  // nsIContentViewerFile
   1.251 +  NS_DECL_NSICONTENTVIEWERFILE
   1.252 +
   1.253 +  // nsIMarkupDocumentViewer
   1.254 +  NS_DECL_NSIMARKUPDOCUMENTVIEWER
   1.255 +
   1.256 +#ifdef NS_PRINTING
   1.257 +  // nsIWebBrowserPrint
   1.258 +  NS_DECL_NSIWEBBROWSERPRINT
   1.259 +#endif
   1.260 +
   1.261 +  typedef void (*CallChildFunc)(nsIMarkupDocumentViewer* aViewer,
   1.262 +                                void* aClosure);
   1.263 +  void CallChildren(CallChildFunc aFunc, void* aClosure);
   1.264 +
   1.265 +  // nsIDocumentViewerPrint Printing Methods
   1.266 +  NS_DECL_NSIDOCUMENTVIEWERPRINT
   1.267 +
   1.268 +
   1.269 +  static void DispatchBeforePrint(nsIDocument* aTop)
   1.270 +  {
   1.271 +    DispatchEventToWindowTree(aTop, NS_LITERAL_STRING("beforeprint"));
   1.272 +  }
   1.273 +  static void DispatchAfterPrint(nsIDocument* aTop)
   1.274 +  {
   1.275 +    DispatchEventToWindowTree(aTop, NS_LITERAL_STRING("afterprint"));
   1.276 +  }
   1.277 +  static void DispatchEventToWindowTree(nsIDocument* aTop,
   1.278 +                                        const nsAString& aEvent);
   1.279 +
   1.280 +protected:
   1.281 +  virtual ~nsDocumentViewer();
   1.282 +
   1.283 +private:
   1.284 +  /**
   1.285 +   * Creates a view manager, root view, and widget for the root view, setting
   1.286 +   * mViewManager and mWindow.
   1.287 +   * @param aSize the initial size in appunits
   1.288 +   * @param aContainerView the container view to hook our root view up
   1.289 +   * to as a child, or null if this will be the root view manager
   1.290 +   */
   1.291 +  nsresult MakeWindow(const nsSize& aSize, nsView* aContainerView);
   1.292 +
   1.293 +  /**
   1.294 +   * Create our device context
   1.295 +   */
   1.296 +  nsresult CreateDeviceContext(nsView* aContainerView);
   1.297 +
   1.298 +  /**
   1.299 +   * If aDoCreation is true, this creates the device context, creates a
   1.300 +   * prescontext if necessary, and calls MakeWindow.
   1.301 +   *
   1.302 +   * If aForceSetNewDocument is false, then SetNewDocument won't be
   1.303 +   * called if the window's current document is already mDocument.
   1.304 +   */
   1.305 +  nsresult InitInternal(nsIWidget* aParentWidget,
   1.306 +                        nsISupports *aState,
   1.307 +                        const nsIntRect& aBounds,
   1.308 +                        bool aDoCreation,
   1.309 +                        bool aNeedMakeCX = true,
   1.310 +                        bool aForceSetNewDocument = true);
   1.311 +  /**
   1.312 +   * @param aDoInitialReflow set to true if you want to kick off the initial
   1.313 +   * reflow
   1.314 +   */
   1.315 +  nsresult InitPresentationStuff(bool aDoInitialReflow);
   1.316 +
   1.317 +  nsresult GetPopupNode(nsIDOMNode** aNode);
   1.318 +  nsresult GetPopupLinkNode(nsIDOMNode** aNode);
   1.319 +  nsresult GetPopupImageNode(nsIImageLoadingContent** aNode);
   1.320 +
   1.321 +  void PrepareToStartLoad(void);
   1.322 +
   1.323 +  nsresult SyncParentSubDocMap();
   1.324 +
   1.325 +  nsresult GetDocumentSelection(nsISelection **aSelection);
   1.326 +
   1.327 +  void DestroyPresShell();
   1.328 +  void DestroyPresContext();
   1.329 +
   1.330 +#ifdef NS_PRINTING
   1.331 +  // Called when the DocViewer is notified that the state
   1.332 +  // of Printing or PP has changed
   1.333 +  void SetIsPrintingInDocShellTree(nsIDocShellTreeItem* aParentNode, 
   1.334 +                                   bool                 aIsPrintingOrPP, 
   1.335 +                                   bool                 aStartAtTop);
   1.336 +#endif // NS_PRINTING
   1.337 +
   1.338 +  // Whether we should attach to the top level widget. This is true if we
   1.339 +  // are sharing/recycling a single base widget and not creating multiple
   1.340 +  // child widgets.
   1.341 +  bool ShouldAttachToTopLevel();
   1.342 +
   1.343 +protected:
   1.344 +  // These return the current shell/prescontext etc.
   1.345 +  nsIPresShell* GetPresShell();
   1.346 +  nsPresContext* GetPresContext();
   1.347 +  nsViewManager* GetViewManager();
   1.348 +
   1.349 +  void DetachFromTopLevelWidget();
   1.350 +
   1.351 +  // IMPORTANT: The ownership implicit in the following member
   1.352 +  // variables has been explicitly checked and set using nsCOMPtr
   1.353 +  // for owning pointers and raw COM interface pointers for weak
   1.354 +  // (ie, non owning) references. If you add any members to this
   1.355 +  // class, please make the ownership explicit (pinkerton, scc).
   1.356 +
   1.357 +  WeakPtr<nsDocShell> mContainer; // it owns me!
   1.358 +  nsWeakPtr mTopContainerWhilePrinting;
   1.359 +  nsRefPtr<nsDeviceContext> mDeviceContext;  // We create and own this baby
   1.360 +
   1.361 +  // the following six items are explicitly in this order
   1.362 +  // so they will be destroyed in the reverse order (pinkerton, scc)
   1.363 +  nsCOMPtr<nsIDocument>    mDocument;
   1.364 +  nsCOMPtr<nsIWidget>      mWindow;      // may be null
   1.365 +  nsRefPtr<nsViewManager> mViewManager;
   1.366 +  nsRefPtr<nsPresContext>  mPresContext;
   1.367 +  nsCOMPtr<nsIPresShell>   mPresShell;
   1.368 +
   1.369 +  nsCOMPtr<nsISelectionListener> mSelectionListener;
   1.370 +  nsRefPtr<nsDocViewerFocusListener> mFocusListener;
   1.371 +
   1.372 +  nsCOMPtr<nsIContentViewer> mPreviousViewer;
   1.373 +  nsCOMPtr<nsISHEntry> mSHEntry;
   1.374 +
   1.375 +  nsIWidget* mParentWidget; // purposely won't be ref counted.  May be null
   1.376 +  bool mAttachedToParent; // view is attached to the parent widget
   1.377 +
   1.378 +  nsIntRect mBounds;
   1.379 +
   1.380 +  // mTextZoom/mPageZoom record the textzoom/pagezoom of the first (galley)
   1.381 +  // presshell only.
   1.382 +  float mTextZoom;      // Text zoom, defaults to 1.0
   1.383 +  float mPageZoom;
   1.384 +  int mMinFontSize;
   1.385 +
   1.386 +  int16_t mNumURLStarts;
   1.387 +  int16_t mDestroyRefCount;    // a second "refcount" for the document viewer's "destroy"
   1.388 +
   1.389 +  unsigned      mStopped : 1;
   1.390 +  unsigned      mLoaded : 1;
   1.391 +  unsigned      mDeferredWindowClose : 1;
   1.392 +  // document management data
   1.393 +  //   these items are specific to markup documents (html and xml)
   1.394 +  //   may consider splitting these out into a subclass
   1.395 +  unsigned      mIsSticky : 1;
   1.396 +  unsigned      mInPermitUnload : 1;
   1.397 +  unsigned      mInPermitUnloadPrompt: 1;
   1.398 +
   1.399 +#ifdef NS_PRINTING
   1.400 +  unsigned      mClosingWhilePrinting : 1;
   1.401 +
   1.402 +#if NS_PRINT_PREVIEW
   1.403 +  unsigned                         mPrintPreviewZoomed : 1;
   1.404 +
   1.405 +  // These data members support delayed printing when the document is loading
   1.406 +  unsigned                         mPrintIsPending : 1;
   1.407 +  unsigned                         mPrintDocIsFullyLoaded : 1;
   1.408 +  nsCOMPtr<nsIPrintSettings>       mCachedPrintSettings;
   1.409 +  nsCOMPtr<nsIWebProgressListener> mCachedPrintWebProgressListner;
   1.410 +
   1.411 +  nsRefPtr<nsPrintEngine>          mPrintEngine;
   1.412 +  float                            mOriginalPrintPreviewScale;
   1.413 +  float                            mPrintPreviewZoom;
   1.414 +  nsAutoPtr<nsPrintEventDispatcher> mBeforeAndAfterPrint;
   1.415 +#endif // NS_PRINT_PREVIEW
   1.416 +
   1.417 +#ifdef DEBUG
   1.418 +  FILE* mDebugFile;
   1.419 +#endif // DEBUG
   1.420 +#endif // NS_PRINTING
   1.421 +
   1.422 +  /* character set member data */
   1.423 +  int32_t mHintCharsetSource;
   1.424 +  nsCString mHintCharset;
   1.425 +  nsCString mForceCharacterSet;
   1.426 +  
   1.427 +  bool mIsPageMode;
   1.428 +  bool mCallerIsClosingWindow;
   1.429 +  bool mInitializedForPrintPreview;
   1.430 +  bool mHidden;
   1.431 +};
   1.432 +
   1.433 +class nsPrintEventDispatcher
   1.434 +{
   1.435 +public:
   1.436 +  nsPrintEventDispatcher(nsIDocument* aTop) : mTop(aTop)
   1.437 +  {
   1.438 +    nsDocumentViewer::DispatchBeforePrint(mTop);
   1.439 +  }
   1.440 +  ~nsPrintEventDispatcher()
   1.441 +  {
   1.442 +    nsDocumentViewer::DispatchAfterPrint(mTop);
   1.443 +  }
   1.444 +
   1.445 +  nsCOMPtr<nsIDocument> mTop;
   1.446 +};
   1.447 +
   1.448 +class nsDocumentShownDispatcher : public nsRunnable
   1.449 +{
   1.450 +public:
   1.451 +  nsDocumentShownDispatcher(nsCOMPtr<nsIDocument> aDocument)
   1.452 +  : mDocument(aDocument) {}
   1.453 +
   1.454 +  NS_IMETHOD Run() MOZ_OVERRIDE;
   1.455 +
   1.456 +private:
   1.457 +  nsCOMPtr<nsIDocument> mDocument;
   1.458 +};
   1.459 +
   1.460 +
   1.461 +//------------------------------------------------------------------
   1.462 +// nsDocumentViewer
   1.463 +//------------------------------------------------------------------
   1.464 +
   1.465 +//------------------------------------------------------------------
   1.466 +already_AddRefed<nsIContentViewer>
   1.467 +NS_NewContentViewer()
   1.468 +{
   1.469 +  nsRefPtr<nsDocumentViewer> viewer = new nsDocumentViewer();
   1.470 +  return viewer.forget();
   1.471 +}
   1.472 +
   1.473 +void nsDocumentViewer::PrepareToStartLoad()
   1.474 +{
   1.475 +  mStopped          = false;
   1.476 +  mLoaded           = false;
   1.477 +  mAttachedToParent = false;
   1.478 +  mDeferredWindowClose = false;
   1.479 +  mCallerIsClosingWindow = false;
   1.480 +
   1.481 +#ifdef NS_PRINTING
   1.482 +  mPrintIsPending        = false;
   1.483 +  mPrintDocIsFullyLoaded = false;
   1.484 +  mClosingWhilePrinting  = false;
   1.485 +
   1.486 +  // Make sure we have destroyed it and cleared the data member
   1.487 +  if (mPrintEngine) {
   1.488 +    mPrintEngine->Destroy();
   1.489 +    mPrintEngine = nullptr;
   1.490 +#ifdef NS_PRINT_PREVIEW
   1.491 +    SetIsPrintPreview(false);
   1.492 +#endif
   1.493 +  }
   1.494 +
   1.495 +#ifdef DEBUG
   1.496 +  mDebugFile = nullptr;
   1.497 +#endif
   1.498 +
   1.499 +#endif // NS_PRINTING
   1.500 +}
   1.501 +
   1.502 +// Note: operator new zeros our memory, so no need to init things to null.
   1.503 +nsDocumentViewer::nsDocumentViewer()
   1.504 +  : mTextZoom(1.0), mPageZoom(1.0), mMinFontSize(0),
   1.505 +    mIsSticky(true),
   1.506 +#ifdef NS_PRINT_PREVIEW
   1.507 +    mPrintPreviewZoom(1.0),
   1.508 +#endif
   1.509 +    mHintCharsetSource(kCharsetUninitialized),
   1.510 +    mInitializedForPrintPreview(false),
   1.511 +    mHidden(false)
   1.512 +{
   1.513 +  PrepareToStartLoad();
   1.514 +}
   1.515 +
   1.516 +NS_IMPL_ADDREF(nsDocumentViewer)
   1.517 +NS_IMPL_RELEASE(nsDocumentViewer)
   1.518 +
   1.519 +NS_INTERFACE_MAP_BEGIN(nsDocumentViewer)
   1.520 +    NS_INTERFACE_MAP_ENTRY(nsIContentViewer)
   1.521 +    NS_INTERFACE_MAP_ENTRY(nsIMarkupDocumentViewer)
   1.522 +    NS_INTERFACE_MAP_ENTRY(nsIContentViewerFile)
   1.523 +    NS_INTERFACE_MAP_ENTRY(nsIContentViewerEdit)
   1.524 +    NS_INTERFACE_MAP_ENTRY(nsIDocumentViewerPrint)
   1.525 +    NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentViewer)
   1.526 +#ifdef NS_PRINTING
   1.527 +    NS_INTERFACE_MAP_ENTRY(nsIWebBrowserPrint)
   1.528 +#endif
   1.529 +NS_INTERFACE_MAP_END
   1.530 +
   1.531 +nsDocumentViewer::~nsDocumentViewer()
   1.532 +{
   1.533 +  if (mDocument) {
   1.534 +    Close(nullptr);
   1.535 +    mDocument->Destroy();
   1.536 +  }
   1.537 +
   1.538 +  NS_ASSERTION(!mPresShell && !mPresContext,
   1.539 +               "User did not call nsIContentViewer::Destroy");
   1.540 +  if (mPresShell || mPresContext) {
   1.541 +    // Make sure we don't hand out a reference to the content viewer to
   1.542 +    // the SHEntry!
   1.543 +    mSHEntry = nullptr;
   1.544 +
   1.545 +    Destroy();
   1.546 +  }
   1.547 +
   1.548 +  // XXX(?) Revoke pending invalidate events
   1.549 +}
   1.550 +
   1.551 +/*
   1.552 + * This method is called by the Document Loader once a document has
   1.553 + * been created for a particular data stream...  The content viewer
   1.554 + * must cache this document for later use when Init(...) is called.
   1.555 + *
   1.556 + * This method is also called when an out of band document.write() happens.
   1.557 + * In that case, the document passed in is the same as the previous document.
   1.558 + */
   1.559 +/* virtual */ void
   1.560 +nsDocumentViewer::LoadStart(nsIDocument* aDocument)
   1.561 +{
   1.562 +  MOZ_ASSERT(aDocument);
   1.563 +
   1.564 +  if (!mDocument) {
   1.565 +    mDocument = aDocument;
   1.566 +  }
   1.567 +}
   1.568 +
   1.569 +nsresult
   1.570 +nsDocumentViewer::SyncParentSubDocMap()
   1.571 +{
   1.572 +  nsCOMPtr<nsIDocShellTreeItem> item(mContainer);
   1.573 +  nsCOMPtr<nsPIDOMWindow> pwin(do_GetInterface(item));
   1.574 +  nsCOMPtr<nsIContent> content;
   1.575 +
   1.576 +  if (mDocument && pwin) {
   1.577 +    content = do_QueryInterface(pwin->GetFrameElementInternal());
   1.578 +  }
   1.579 +
   1.580 +  if (content) {
   1.581 +    nsCOMPtr<nsIDocShellTreeItem> parent;
   1.582 +    item->GetParent(getter_AddRefs(parent));
   1.583 +
   1.584 +    nsCOMPtr<nsIDOMWindow> parent_win(do_GetInterface(parent));
   1.585 +
   1.586 +    if (parent_win) {
   1.587 +      nsCOMPtr<nsIDOMDocument> dom_doc;
   1.588 +      parent_win->GetDocument(getter_AddRefs(dom_doc));
   1.589 +
   1.590 +      nsCOMPtr<nsIDocument> parent_doc(do_QueryInterface(dom_doc));
   1.591 +
   1.592 +      if (parent_doc) {
   1.593 +        if (mDocument &&
   1.594 +            parent_doc->GetSubDocumentFor(content) != mDocument) {
   1.595 +          mDocument->SuppressEventHandling(nsIDocument::eEvents,
   1.596 +                                           parent_doc->EventHandlingSuppressed());
   1.597 +        }
   1.598 +        return parent_doc->SetSubDocumentFor(content->AsElement(), mDocument);
   1.599 +      }
   1.600 +    }
   1.601 +  }
   1.602 +
   1.603 +  return NS_OK;
   1.604 +}
   1.605 +
   1.606 +NS_IMETHODIMP
   1.607 +nsDocumentViewer::SetContainer(nsIDocShell* aContainer)
   1.608 +{
   1.609 +  mContainer = static_cast<nsDocShell*>(aContainer)->asWeakPtr();
   1.610 +  if (mPresContext) {
   1.611 +    mPresContext->SetContainer(mContainer);
   1.612 +  }
   1.613 +
   1.614 +  // We're loading a new document into the window where this document
   1.615 +  // viewer lives, sync the parent document's frame element -> sub
   1.616 +  // document map
   1.617 +
   1.618 +  return SyncParentSubDocMap();
   1.619 +}
   1.620 +
   1.621 +NS_IMETHODIMP
   1.622 +nsDocumentViewer::GetContainer(nsIDocShell** aResult)
   1.623 +{
   1.624 +   NS_ENSURE_ARG_POINTER(aResult);
   1.625 +
   1.626 +   nsCOMPtr<nsIDocShell> container(mContainer);
   1.627 +   container.swap(*aResult);
   1.628 +   return NS_OK;
   1.629 +}
   1.630 +
   1.631 +NS_IMETHODIMP
   1.632 +nsDocumentViewer::Init(nsIWidget* aParentWidget,
   1.633 +                         const nsIntRect& aBounds)
   1.634 +{
   1.635 +  return InitInternal(aParentWidget, nullptr, aBounds, true);
   1.636 +}
   1.637 +
   1.638 +nsresult
   1.639 +nsDocumentViewer::InitPresentationStuff(bool aDoInitialReflow)
   1.640 +{
   1.641 +  if (GetIsPrintPreview())
   1.642 +    return NS_OK;
   1.643 +
   1.644 +  NS_ASSERTION(!mPresShell,
   1.645 +               "Someone should have destroyed the presshell!");
   1.646 +
   1.647 +  // Create the style set...
   1.648 +  nsStyleSet *styleSet;
   1.649 +  nsresult rv = CreateStyleSet(mDocument, &styleSet);
   1.650 +  NS_ENSURE_SUCCESS(rv, rv);
   1.651 +
   1.652 +  // Now make the shell for the document
   1.653 +  mPresShell = mDocument->CreateShell(mPresContext, mViewManager, styleSet);
   1.654 +  if (!mPresShell) {
   1.655 +    delete styleSet;
   1.656 +    return NS_ERROR_FAILURE;
   1.657 +  }
   1.658 +
   1.659 +  // We're done creating the style set
   1.660 +  styleSet->EndUpdate();
   1.661 +
   1.662 +  if (aDoInitialReflow) {
   1.663 +    // Since Initialize() will create frames for *all* items
   1.664 +    // that are currently in the document tree, we need to flush
   1.665 +    // any pending notifications to prevent the content sink from
   1.666 +    // duplicating layout frames for content it has added to the tree
   1.667 +    // but hasn't notified the document about. (Bug 154018)
   1.668 +    //
   1.669 +    // Note that we are flushing before we add mPresShell as an observer
   1.670 +    // to avoid bogus notifications.
   1.671 +
   1.672 +    mDocument->FlushPendingNotifications(Flush_ContentAndNotify);
   1.673 +  }
   1.674 +
   1.675 +  mPresShell->BeginObservingDocument();
   1.676 +
   1.677 +  // Initialize our view manager
   1.678 +  int32_t p2a = mPresContext->AppUnitsPerDevPixel();
   1.679 +  MOZ_ASSERT(p2a == mPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel());
   1.680 +  nscoord width = p2a * mBounds.width;
   1.681 +  nscoord height = p2a * mBounds.height;
   1.682 +
   1.683 +  mViewManager->SetWindowDimensions(width, height);
   1.684 +  mPresContext->SetTextZoom(mTextZoom);
   1.685 +  mPresContext->SetFullZoom(mPageZoom);
   1.686 +  mPresContext->SetBaseMinFontSize(mMinFontSize);
   1.687 +
   1.688 +  p2a = mPresContext->AppUnitsPerDevPixel();  // zoom may have changed it
   1.689 +  width = p2a * mBounds.width;
   1.690 +  height = p2a * mBounds.height;
   1.691 +  if (aDoInitialReflow) {
   1.692 +    nsCOMPtr<nsIPresShell> shellGrip = mPresShell;
   1.693 +    // Initial reflow
   1.694 +    mPresShell->Initialize(width, height);
   1.695 +  } else {
   1.696 +    // Store the visible area so it's available for other callers of
   1.697 +    // Initialize, like nsContentSink::StartLayout.
   1.698 +    mPresContext->SetVisibleArea(nsRect(0, 0, width, height));
   1.699 +  }
   1.700 +
   1.701 +  // now register ourselves as a selection listener, so that we get
   1.702 +  // called when the selection changes in the window
   1.703 +  if (!mSelectionListener) {
   1.704 +    nsDocViewerSelectionListener *selectionListener =
   1.705 +      new nsDocViewerSelectionListener();
   1.706 +
   1.707 +    selectionListener->Init(this);
   1.708 +
   1.709 +    // mSelectionListener is a owning reference
   1.710 +    mSelectionListener = selectionListener;
   1.711 +  }
   1.712 +
   1.713 +  nsCOMPtr<nsISelection> selection;
   1.714 +  rv = GetDocumentSelection(getter_AddRefs(selection));
   1.715 +  NS_ENSURE_SUCCESS(rv, rv);
   1.716 +
   1.717 +  nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(selection));
   1.718 +  rv = selPrivate->AddSelectionListener(mSelectionListener);
   1.719 +  if (NS_FAILED(rv))
   1.720 +    return rv;
   1.721 +
   1.722 +  // Save old listener so we can unregister it
   1.723 +  nsRefPtr<nsDocViewerFocusListener> oldFocusListener = mFocusListener;
   1.724 +
   1.725 +  // focus listener
   1.726 +  //
   1.727 +  // now register ourselves as a focus listener, so that we get called
   1.728 +  // when the focus changes in the window
   1.729 +  nsDocViewerFocusListener *focusListener = new nsDocViewerFocusListener();
   1.730 +
   1.731 +  focusListener->Init(this);
   1.732 +
   1.733 +  // mFocusListener is a strong reference
   1.734 +  mFocusListener = focusListener;
   1.735 +
   1.736 +  if (mDocument) {
   1.737 +    mDocument->AddEventListener(NS_LITERAL_STRING("focus"),
   1.738 +                                mFocusListener,
   1.739 +                                false, false);
   1.740 +    mDocument->AddEventListener(NS_LITERAL_STRING("blur"),
   1.741 +                                mFocusListener,
   1.742 +                                false, false);
   1.743 +
   1.744 +    if (oldFocusListener) {
   1.745 +      mDocument->RemoveEventListener(NS_LITERAL_STRING("focus"),
   1.746 +                                     oldFocusListener, false);
   1.747 +      mDocument->RemoveEventListener(NS_LITERAL_STRING("blur"),
   1.748 +                                     oldFocusListener, false);
   1.749 +    }
   1.750 +  }
   1.751 +
   1.752 +  if (aDoInitialReflow && mDocument) {
   1.753 +    mDocument->ScrollToRef();
   1.754 +  }
   1.755 +
   1.756 +  return NS_OK;
   1.757 +}
   1.758 +
   1.759 +static nsPresContext*
   1.760 +CreatePresContext(nsIDocument* aDocument,
   1.761 +                  nsPresContext::nsPresContextType aType,
   1.762 +                  nsView* aContainerView)
   1.763 +{
   1.764 +  if (aContainerView)
   1.765 +    return new nsPresContext(aDocument, aType);
   1.766 +  return new nsRootPresContext(aDocument, aType);
   1.767 +}
   1.768 +
   1.769 +//-----------------------------------------------
   1.770 +// This method can be used to initial the "presentation"
   1.771 +// The aDoCreation indicates whether it should create
   1.772 +// all the new objects or just initialize the existing ones
   1.773 +nsresult
   1.774 +nsDocumentViewer::InitInternal(nsIWidget* aParentWidget,
   1.775 +                                 nsISupports *aState,
   1.776 +                                 const nsIntRect& aBounds,
   1.777 +                                 bool aDoCreation,
   1.778 +                                 bool aNeedMakeCX /*= true*/,
   1.779 +                                 bool aForceSetNewDocument /* = true*/)
   1.780 +{
   1.781 +  if (mIsPageMode) {
   1.782 +    // XXXbz should the InitInternal in SetPageMode just pass false
   1.783 +    // here itself?
   1.784 +    aForceSetNewDocument = false;
   1.785 +  }
   1.786 +
   1.787 +  // We don't want any scripts to run here. That can cause flushing,
   1.788 +  // which can cause reentry into initialization of this document viewer,
   1.789 +  // which would be disastrous.
   1.790 +  nsAutoScriptBlocker blockScripts;
   1.791 +
   1.792 +  mParentWidget = aParentWidget; // not ref counted
   1.793 +  mBounds = aBounds;
   1.794 +
   1.795 +  nsresult rv = NS_OK;
   1.796 +  NS_ENSURE_TRUE(mDocument, NS_ERROR_NULL_POINTER);
   1.797 +
   1.798 +  nsView* containerView = FindContainerView();
   1.799 +
   1.800 +  bool makeCX = false;
   1.801 +  if (aDoCreation) {
   1.802 +    nsresult rv = CreateDeviceContext(containerView);
   1.803 +    NS_ENSURE_SUCCESS(rv, rv);
   1.804 +
   1.805 +    // XXXbz this is a nasty hack to do with the fact that we create
   1.806 +    // presentations both in Init() and in Show()...  Ideally we would only do
   1.807 +    // it in one place (Show()) and require that callers call init(), open(),
   1.808 +    // show() in that order or something.
   1.809 +    if (!mPresContext &&
   1.810 +        (aParentWidget || containerView || mDocument->IsBeingUsedAsImage() ||
   1.811 +         (mDocument->GetDisplayDocument() &&
   1.812 +          mDocument->GetDisplayDocument()->GetShell()))) {
   1.813 +      // Create presentation context
   1.814 +      if (mIsPageMode) {
   1.815 +        //Presentation context already created in SetPageMode which is calling this method
   1.816 +      } else {
   1.817 +        mPresContext = CreatePresContext(mDocument,
   1.818 +            nsPresContext::eContext_Galley, containerView);
   1.819 +      }
   1.820 +      NS_ENSURE_TRUE(mPresContext, NS_ERROR_OUT_OF_MEMORY);
   1.821 +
   1.822 +      nsresult rv = mPresContext->Init(mDeviceContext); 
   1.823 +      if (NS_FAILED(rv)) {
   1.824 +        mPresContext = nullptr;
   1.825 +        return rv;
   1.826 +      }
   1.827 +
   1.828 +#if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
   1.829 +      makeCX = !GetIsPrintPreview() && aNeedMakeCX; // needs to be true except when we are already in PP or we are enabling/disabling paginated mode.
   1.830 +#else
   1.831 +      makeCX = true;
   1.832 +#endif
   1.833 +    }
   1.834 +
   1.835 +    if (mPresContext) {
   1.836 +      // Create the ViewManager and Root View...
   1.837 +
   1.838 +      // We must do this before we tell the script global object about
   1.839 +      // this new document since doing that will cause us to re-enter
   1.840 +      // into nsSubDocumentFrame code through reflows caused by
   1.841 +      // FlushPendingNotifications() calls down the road...
   1.842 +
   1.843 +      rv = MakeWindow(nsSize(mPresContext->DevPixelsToAppUnits(aBounds.width),
   1.844 +                             mPresContext->DevPixelsToAppUnits(aBounds.height)),
   1.845 +                      containerView);
   1.846 +      NS_ENSURE_SUCCESS(rv, rv);
   1.847 +      Hide();
   1.848 +
   1.849 +#ifdef NS_PRINT_PREVIEW
   1.850 +      if (mIsPageMode) {
   1.851 +        // I'm leaving this in a broken state for the moment; we should
   1.852 +        // be measuring/scaling with the print device context, not the
   1.853 +        // screen device context, but this is good enough to allow
   1.854 +        // printing reftests to work.
   1.855 +        double pageWidth = 0, pageHeight = 0;
   1.856 +        mPresContext->GetPrintSettings()->GetEffectivePageSize(&pageWidth,
   1.857 +                                                               &pageHeight);
   1.858 +        mPresContext->SetPageSize(
   1.859 +          nsSize(mPresContext->CSSTwipsToAppUnits(NSToIntFloor(pageWidth)),
   1.860 +                 mPresContext->CSSTwipsToAppUnits(NSToIntFloor(pageHeight))));
   1.861 +        mPresContext->SetIsRootPaginatedDocument(true);
   1.862 +        mPresContext->SetPageScale(1.0f);
   1.863 +      }
   1.864 +#endif
   1.865 +    } else {
   1.866 +      // Avoid leaking the old viewer.
   1.867 +      if (mPreviousViewer) {
   1.868 +        mPreviousViewer->Destroy();
   1.869 +        mPreviousViewer = nullptr;
   1.870 +      }
   1.871 +    }
   1.872 +  }
   1.873 +
   1.874 +  nsCOMPtr<nsIInterfaceRequestor> requestor(mContainer);
   1.875 +  if (requestor) {
   1.876 +    if (mPresContext) {
   1.877 +      nsCOMPtr<nsILinkHandler> linkHandler;
   1.878 +      requestor->GetInterface(NS_GET_IID(nsILinkHandler),
   1.879 +                              getter_AddRefs(linkHandler));
   1.880 +
   1.881 +      mPresContext->SetContainer(mContainer);
   1.882 +      mPresContext->SetLinkHandler(linkHandler);
   1.883 +    }
   1.884 +
   1.885 +    // Set script-context-owner in the document
   1.886 +
   1.887 +    nsCOMPtr<nsPIDOMWindow> window;
   1.888 +    requestor->GetInterface(NS_GET_IID(nsPIDOMWindow),
   1.889 +                            getter_AddRefs(window));
   1.890 +
   1.891 +    if (window) {
   1.892 +      nsCOMPtr<nsIDocument> curDoc = window->GetExtantDoc();
   1.893 +      if (aForceSetNewDocument || curDoc != mDocument) {
   1.894 +        window->SetNewDocument(mDocument, aState, false);
   1.895 +        nsJSContext::LoadStart();
   1.896 +      }
   1.897 +    }
   1.898 +  }
   1.899 +
   1.900 +  if (aDoCreation && mPresContext) {
   1.901 +    // The ViewManager and Root View was created above (in
   1.902 +    // MakeWindow())...
   1.903 +
   1.904 +    rv = InitPresentationStuff(!makeCX);
   1.905 +  }
   1.906 +
   1.907 +  return rv;
   1.908 +}
   1.909 +
   1.910 +void nsDocumentViewer::SetNavigationTiming(nsDOMNavigationTiming* timing)
   1.911 +{
   1.912 +  NS_ASSERTION(mDocument, "Must have a document to set navigation timing.");
   1.913 +  if (mDocument) {
   1.914 +    mDocument->SetNavigationTiming(timing);
   1.915 +  }
   1.916 +}
   1.917 +
   1.918 +//
   1.919 +// LoadComplete(aStatus)
   1.920 +//
   1.921 +//   aStatus - The status returned from loading the document.
   1.922 +//
   1.923 +// This method is called by the container when the document has been
   1.924 +// completely loaded.
   1.925 +//
   1.926 +NS_IMETHODIMP
   1.927 +nsDocumentViewer::LoadComplete(nsresult aStatus)
   1.928 +{
   1.929 +  /* We need to protect ourself against auto-destruction in case the
   1.930 +     window is closed while processing the OnLoad event.  See bug
   1.931 +     http://bugzilla.mozilla.org/show_bug.cgi?id=78445 for more
   1.932 +     explanation.
   1.933 +  */
   1.934 +  nsRefPtr<nsDocumentViewer> kungFuDeathGrip(this);
   1.935 +
   1.936 +  // Flush out layout so it's up-to-date by the time onload is called.
   1.937 +  // Note that this could destroy the window, so do this before
   1.938 +  // checking for our mDocument and its window.
   1.939 +  if (mPresShell && !mStopped) {
   1.940 +    // Hold strong ref because this could conceivably run script
   1.941 +    nsCOMPtr<nsIPresShell> shell = mPresShell;
   1.942 +    shell->FlushPendingNotifications(Flush_Layout);
   1.943 +  }
   1.944 +
   1.945 +  nsresult rv = NS_OK;
   1.946 +  NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
   1.947 +
   1.948 +  // First, get the window from the document...
   1.949 +  nsCOMPtr<nsPIDOMWindow> window = mDocument->GetWindow();
   1.950 +
   1.951 +  mLoaded = true;
   1.952 +
   1.953 +  // Now, fire either an OnLoad or OnError event to the document...
   1.954 +  bool restoring = false;
   1.955 +  // XXXbz imagelib kills off the document load for a full-page image with
   1.956 +  // NS_ERROR_PARSED_DATA_CACHED if it's in the cache.  So we want to treat
   1.957 +  // that one as a success code; otherwise whether we fire onload for the image
   1.958 +  // will depend on whether it's cached!
   1.959 +  if(window &&
   1.960 +     (NS_SUCCEEDED(aStatus) || aStatus == NS_ERROR_PARSED_DATA_CACHED)) {
   1.961 +    nsEventStatus status = nsEventStatus_eIgnore;
   1.962 +    WidgetEvent event(true, NS_LOAD);
   1.963 +    event.mFlags.mBubbles = false;
   1.964 +     // XXX Dispatching to |window|, but using |document| as the target.
   1.965 +    event.target = mDocument;
   1.966 +
   1.967 +    // If the document presentation is being restored, we don't want to fire
   1.968 +    // onload to the document content since that would likely confuse scripts
   1.969 +    // on the page.
   1.970 +
   1.971 +    nsIDocShell *docShell = window->GetDocShell();
   1.972 +    NS_ENSURE_TRUE(docShell, NS_ERROR_UNEXPECTED);
   1.973 +
   1.974 +    docShell->GetRestoringDocument(&restoring);
   1.975 +    if (!restoring) {
   1.976 +      NS_ASSERTION(mDocument->IsXUL() || // readyState for XUL is bogus
   1.977 +                   mDocument->GetReadyStateEnum() ==
   1.978 +                     nsIDocument::READYSTATE_INTERACTIVE ||
   1.979 +                   // test_stricttransportsecurity.html has old-style
   1.980 +                   // docshell-generated about:blank docs reach this code!
   1.981 +                   (mDocument->GetReadyStateEnum() ==
   1.982 +                      nsIDocument::READYSTATE_UNINITIALIZED &&
   1.983 +                    NS_IsAboutBlank(mDocument->GetDocumentURI())),
   1.984 +                   "Bad readystate");
   1.985 +      nsCOMPtr<nsIDocument> d = mDocument;
   1.986 +      mDocument->SetReadyStateInternal(nsIDocument::READYSTATE_COMPLETE);
   1.987 +
   1.988 +      nsRefPtr<nsDOMNavigationTiming> timing(d->GetNavigationTiming());
   1.989 +      if (timing) {
   1.990 +        timing->NotifyLoadEventStart();
   1.991 +      }
   1.992 +
   1.993 +      // Dispatch observer notification to notify observers document load is complete.
   1.994 +      nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
   1.995 +      nsIPrincipal *principal = d->NodePrincipal();
   1.996 +      os->NotifyObservers(d,
   1.997 +                          nsContentUtils::IsSystemPrincipal(principal) ?
   1.998 +                          "chrome-document-loaded" :
   1.999 +                          "content-document-loaded",
  1.1000 +                          nullptr);
  1.1001 +
  1.1002 +      EventDispatcher::Dispatch(window, mPresContext, &event, nullptr, &status);
  1.1003 +      if (timing) {
  1.1004 +        timing->NotifyLoadEventEnd();
  1.1005 +      }
  1.1006 +    }
  1.1007 +  } else {
  1.1008 +    // XXX: Should fire error event to the document...
  1.1009 +  }
  1.1010 +
  1.1011 +  // Notify the document that it has been shown (regardless of whether
  1.1012 +  // it was just loaded). Note: mDocument may be null now if the above
  1.1013 +  // firing of onload caused the document to unload.
  1.1014 +  if (mDocument) {
  1.1015 +    // Re-get window, since it might have changed during above firing of onload
  1.1016 +    window = mDocument->GetWindow();
  1.1017 +    if (window) {
  1.1018 +      nsIDocShell *docShell = window->GetDocShell();
  1.1019 +      bool isInUnload;
  1.1020 +      if (docShell && NS_SUCCEEDED(docShell->GetIsInUnload(&isInUnload)) &&
  1.1021 +          !isInUnload) {
  1.1022 +        mDocument->OnPageShow(restoring, nullptr);
  1.1023 +      }
  1.1024 +    }
  1.1025 +  }
  1.1026 +
  1.1027 +  if (!mStopped) {
  1.1028 +    if (mDocument) {
  1.1029 +      mDocument->ScrollToRef();
  1.1030 +    }
  1.1031 +
  1.1032 +    // Now that the document has loaded, we can tell the presshell
  1.1033 +    // to unsuppress painting.
  1.1034 +    if (mPresShell) {
  1.1035 +      nsCOMPtr<nsIPresShell> shellDeathGrip(mPresShell);
  1.1036 +      mPresShell->UnsuppressPainting();
  1.1037 +      // mPresShell could have been removed now, see bug 378682/421432
  1.1038 +      if (mPresShell) {
  1.1039 +        mPresShell->LoadComplete();
  1.1040 +      }
  1.1041 +    }
  1.1042 +  }
  1.1043 +
  1.1044 +  nsJSContext::LoadEnd();
  1.1045 +
  1.1046 +#ifdef NS_PRINTING
  1.1047 +  // Check to see if someone tried to print during the load
  1.1048 +  if (mPrintIsPending) {
  1.1049 +    mPrintIsPending        = false;
  1.1050 +    mPrintDocIsFullyLoaded = true;
  1.1051 +    Print(mCachedPrintSettings, mCachedPrintWebProgressListner);
  1.1052 +    mCachedPrintSettings           = nullptr;
  1.1053 +    mCachedPrintWebProgressListner = nullptr;
  1.1054 +  }
  1.1055 +#endif
  1.1056 +
  1.1057 +  return rv;
  1.1058 +}
  1.1059 +
  1.1060 +NS_IMETHODIMP
  1.1061 +nsDocumentViewer::PermitUnload(bool aCallerClosesWindow,
  1.1062 +                               bool *aPermitUnload)
  1.1063 +{
  1.1064 +  bool shouldPrompt = true;
  1.1065 +  return PermitUnloadInternal(aCallerClosesWindow, &shouldPrompt,
  1.1066 +                              aPermitUnload);
  1.1067 +}
  1.1068 +
  1.1069 +
  1.1070 +nsresult
  1.1071 +nsDocumentViewer::PermitUnloadInternal(bool aCallerClosesWindow,
  1.1072 +                                       bool *aShouldPrompt,
  1.1073 +                                       bool *aPermitUnload)
  1.1074 +{
  1.1075 +  AutoDontWarnAboutSyncXHR disableSyncXHRWarning;
  1.1076 +
  1.1077 +  *aPermitUnload = true;
  1.1078 +
  1.1079 +  if (!mDocument
  1.1080 +   || mInPermitUnload
  1.1081 +   || mCallerIsClosingWindow
  1.1082 +   || mInPermitUnloadPrompt) {
  1.1083 +    return NS_OK;
  1.1084 +  }
  1.1085 +
  1.1086 +  static bool sIsBeforeUnloadDisabled;
  1.1087 +  static bool sBeforeUnloadPrefCached = false;
  1.1088 +
  1.1089 +  if (!sBeforeUnloadPrefCached ) {
  1.1090 +    sBeforeUnloadPrefCached = true;
  1.1091 +    Preferences::AddBoolVarCache(&sIsBeforeUnloadDisabled,
  1.1092 +                                 BEFOREUNLOAD_DISABLED_PREFNAME);
  1.1093 +  }
  1.1094 +
  1.1095 +  // If the user has turned off onbeforeunload warnings, no need to check.
  1.1096 +  if (sIsBeforeUnloadDisabled) {
  1.1097 +    return NS_OK;
  1.1098 +  }
  1.1099 +
  1.1100 +  // First, get the script global object from the document...
  1.1101 +  nsPIDOMWindow *window = mDocument->GetWindow();
  1.1102 +
  1.1103 +  if (!window) {
  1.1104 +    // This is odd, but not fatal
  1.1105 +    NS_WARNING("window not set for document!");
  1.1106 +    return NS_OK;
  1.1107 +  }
  1.1108 +
  1.1109 +  NS_ASSERTION(nsContentUtils::IsSafeToRunScript(), "This is unsafe");
  1.1110 +
  1.1111 +  // Now, fire an BeforeUnload event to the document and see if it's ok
  1.1112 +  // to unload...
  1.1113 +  nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(mDocument);
  1.1114 +  nsCOMPtr<nsIDOMEvent> event;
  1.1115 +  domDoc->CreateEvent(NS_LITERAL_STRING("beforeunloadevent"),
  1.1116 +                      getter_AddRefs(event));
  1.1117 +  nsCOMPtr<nsIDOMBeforeUnloadEvent> beforeUnload = do_QueryInterface(event);
  1.1118 +  NS_ENSURE_STATE(beforeUnload);
  1.1119 +  nsresult rv = event->InitEvent(NS_LITERAL_STRING("beforeunload"),
  1.1120 +                                 false, true);
  1.1121 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1122 +
  1.1123 +  // Dispatching to |window|, but using |document| as the target.
  1.1124 +  event->SetTarget(mDocument);
  1.1125 +  event->SetTrusted(true);
  1.1126 +
  1.1127 +  // In evil cases we might be destroyed while handling the
  1.1128 +  // onbeforeunload event, don't let that happen. (see also bug#331040)
  1.1129 +  nsRefPtr<nsDocumentViewer> kungFuDeathGrip(this);
  1.1130 +
  1.1131 +  {
  1.1132 +    // Never permit popups from the beforeunload handler, no matter
  1.1133 +    // how we get here.
  1.1134 +    nsAutoPopupStatePusher popupStatePusher(openAbused, true);
  1.1135 +
  1.1136 +    // Never permit dialogs from the beforeunload handler
  1.1137 +    nsCOMPtr<nsIDOMWindowUtils> utils = do_GetInterface(window);
  1.1138 +    bool dialogsWereEnabled = false;
  1.1139 +    utils->AreDialogsEnabled(&dialogsWereEnabled);
  1.1140 +    utils->DisableDialogs();
  1.1141 +
  1.1142 +    mInPermitUnload = true;
  1.1143 +    EventDispatcher::DispatchDOMEvent(window, nullptr, event, mPresContext,
  1.1144 +                                      nullptr);
  1.1145 +    mInPermitUnload = false;
  1.1146 +    if (dialogsWereEnabled) {
  1.1147 +      utils->EnableDialogs();
  1.1148 +    }
  1.1149 +  }
  1.1150 +
  1.1151 +  nsCOMPtr<nsIDocShell> docShell(mContainer);
  1.1152 +  nsAutoString text;
  1.1153 +  beforeUnload->GetReturnValue(text);
  1.1154 +  if (*aShouldPrompt && (event->GetInternalNSEvent()->mFlags.mDefaultPrevented ||
  1.1155 +                         !text.IsEmpty())) {
  1.1156 +    // Ask the user if it's ok to unload the current page
  1.1157 +
  1.1158 +    nsCOMPtr<nsIPrompt> prompt = do_GetInterface(docShell);
  1.1159 +
  1.1160 +    if (prompt) {
  1.1161 +      nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt);
  1.1162 +      if (promptBag) {
  1.1163 +        bool isTabModalPromptAllowed;
  1.1164 +        GetIsTabModalPromptAllowed(&isTabModalPromptAllowed);
  1.1165 +        promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"),
  1.1166 +                                     isTabModalPromptAllowed);
  1.1167 +      }
  1.1168 +
  1.1169 +      nsXPIDLString title, message, stayLabel, leaveLabel;
  1.1170 +      rv  = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
  1.1171 +                                               "OnBeforeUnloadTitle",
  1.1172 +                                               title);
  1.1173 +      nsresult tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
  1.1174 +                                               "OnBeforeUnloadMessage",
  1.1175 +                                               message);
  1.1176 +      if (NS_FAILED(tmp)) {
  1.1177 +        rv = tmp;
  1.1178 +      }
  1.1179 +      tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
  1.1180 +                                               "OnBeforeUnloadLeaveButton",
  1.1181 +                                               leaveLabel);
  1.1182 +      if (NS_FAILED(tmp)) {
  1.1183 +        rv = tmp;
  1.1184 +      }
  1.1185 +      tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
  1.1186 +                                               "OnBeforeUnloadStayButton",
  1.1187 +                                               stayLabel);
  1.1188 +      if (NS_FAILED(tmp)) {
  1.1189 +        rv = tmp;
  1.1190 +      }
  1.1191 +
  1.1192 +      if (NS_FAILED(rv) || !title || !message || !stayLabel || !leaveLabel) {
  1.1193 +        NS_ERROR("Failed to get strings from dom.properties!");
  1.1194 +        return NS_OK;
  1.1195 +      }
  1.1196 +
  1.1197 +      // Although the exact value is ignored, we must not pass invalid
  1.1198 +      // bool values through XPConnect.
  1.1199 +      bool dummy = false;
  1.1200 +      int32_t buttonPressed = 0;
  1.1201 +      uint32_t buttonFlags = (nsIPrompt::BUTTON_POS_0_DEFAULT |
  1.1202 +                             (nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_0) |
  1.1203 +                             (nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_1));
  1.1204 +
  1.1205 +      nsAutoSyncOperation sync(mDocument);
  1.1206 +      mInPermitUnloadPrompt = true;
  1.1207 +      rv = prompt->ConfirmEx(title, message, buttonFlags,
  1.1208 +                             leaveLabel, stayLabel, nullptr, nullptr,
  1.1209 +                             &dummy, &buttonPressed);
  1.1210 +      mInPermitUnloadPrompt = false;
  1.1211 +
  1.1212 +      // If the prompt aborted, we tell our consumer that it is not allowed
  1.1213 +      // to unload the page. One reason that prompts abort is that the user
  1.1214 +      // performed some action that caused the page to unload while our prompt
  1.1215 +      // was active. In those cases we don't want our consumer to also unload
  1.1216 +      // the page.
  1.1217 +      //
  1.1218 +      // XXX: Are there other cases where prompts can abort? Is it ok to
  1.1219 +      //      prevent unloading the page in those cases?
  1.1220 +      if (NS_FAILED(rv)) {
  1.1221 +        *aPermitUnload = false;
  1.1222 +        return NS_OK;
  1.1223 +      }
  1.1224 +
  1.1225 +      // Button 0 == leave, button 1 == stay
  1.1226 +      *aPermitUnload = (buttonPressed == 0);
  1.1227 +      // If the user decided to go ahead, make sure not to prompt the user again
  1.1228 +      // by toggling the internal prompting bool to false:
  1.1229 +      if (*aPermitUnload) {
  1.1230 +        *aShouldPrompt = false;
  1.1231 +      }
  1.1232 +    }
  1.1233 +  }
  1.1234 +
  1.1235 +  if (docShell) {
  1.1236 +    int32_t childCount;
  1.1237 +    docShell->GetChildCount(&childCount);
  1.1238 +
  1.1239 +    for (int32_t i = 0; i < childCount && *aPermitUnload; ++i) {
  1.1240 +      nsCOMPtr<nsIDocShellTreeItem> item;
  1.1241 +      docShell->GetChildAt(i, getter_AddRefs(item));
  1.1242 +
  1.1243 +      nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(item));
  1.1244 +
  1.1245 +      if (docShell) {
  1.1246 +        nsCOMPtr<nsIContentViewer> cv;
  1.1247 +        docShell->GetContentViewer(getter_AddRefs(cv));
  1.1248 +
  1.1249 +        if (cv) {
  1.1250 +          cv->PermitUnloadInternal(aCallerClosesWindow, aShouldPrompt,
  1.1251 +                                   aPermitUnload);
  1.1252 +        }
  1.1253 +      }
  1.1254 +    }
  1.1255 +  }
  1.1256 +
  1.1257 +  if (aCallerClosesWindow && *aPermitUnload)
  1.1258 +    mCallerIsClosingWindow = true;
  1.1259 +
  1.1260 +  return NS_OK;
  1.1261 +}
  1.1262 +
  1.1263 +NS_IMETHODIMP
  1.1264 +nsDocumentViewer::GetBeforeUnloadFiring(bool* aInEvent)
  1.1265 +{
  1.1266 +  *aInEvent = mInPermitUnload;
  1.1267 +  return NS_OK;
  1.1268 +}
  1.1269 +
  1.1270 +NS_IMETHODIMP
  1.1271 +nsDocumentViewer::GetInPermitUnload(bool* aInEvent)
  1.1272 +{
  1.1273 +  *aInEvent = mInPermitUnloadPrompt;
  1.1274 +  return NS_OK;
  1.1275 +}
  1.1276 +
  1.1277 +NS_IMETHODIMP
  1.1278 +nsDocumentViewer::ResetCloseWindow()
  1.1279 +{
  1.1280 +  mCallerIsClosingWindow = false;
  1.1281 +
  1.1282 +  nsCOMPtr<nsIDocShell> docShell(mContainer);
  1.1283 +  if (docShell) {
  1.1284 +    int32_t childCount;
  1.1285 +    docShell->GetChildCount(&childCount);
  1.1286 +
  1.1287 +    for (int32_t i = 0; i < childCount; ++i) {
  1.1288 +      nsCOMPtr<nsIDocShellTreeItem> item;
  1.1289 +      docShell->GetChildAt(i, getter_AddRefs(item));
  1.1290 +
  1.1291 +      nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(item));
  1.1292 +
  1.1293 +      if (docShell) {
  1.1294 +        nsCOMPtr<nsIContentViewer> cv;
  1.1295 +        docShell->GetContentViewer(getter_AddRefs(cv));
  1.1296 +
  1.1297 +        if (cv) {
  1.1298 +          cv->ResetCloseWindow();
  1.1299 +        }
  1.1300 +      }
  1.1301 +    }
  1.1302 +  }
  1.1303 +  return NS_OK;
  1.1304 +}
  1.1305 +
  1.1306 +NS_IMETHODIMP
  1.1307 +nsDocumentViewer::PageHide(bool aIsUnload)
  1.1308 +{
  1.1309 +  AutoDontWarnAboutSyncXHR disableSyncXHRWarning;
  1.1310 +
  1.1311 +  mHidden = true;
  1.1312 +
  1.1313 +  if (!mDocument) {
  1.1314 +    return NS_ERROR_NULL_POINTER;
  1.1315 +  }
  1.1316 +
  1.1317 +  mDocument->OnPageHide(!aIsUnload, nullptr);
  1.1318 +
  1.1319 +  // inform the window so that the focus state is reset.
  1.1320 +  NS_ENSURE_STATE(mDocument);
  1.1321 +  nsPIDOMWindow *window = mDocument->GetWindow();
  1.1322 +  if (window)
  1.1323 +    window->PageHidden();
  1.1324 +
  1.1325 +  if (aIsUnload) {
  1.1326 +    // Poke the GC. The window might be collectable garbage now.
  1.1327 +    nsJSContext::PokeGC(JS::gcreason::PAGE_HIDE, NS_GC_DELAY * 2);
  1.1328 +
  1.1329 +    // if Destroy() was called during OnPageHide(), mDocument is nullptr.
  1.1330 +    NS_ENSURE_STATE(mDocument);
  1.1331 +
  1.1332 +    // First, get the window from the document...
  1.1333 +    nsPIDOMWindow *window = mDocument->GetWindow();
  1.1334 +
  1.1335 +    if (!window) {
  1.1336 +      // Fail if no window is available...
  1.1337 +      NS_WARNING("window not set for document!");
  1.1338 +      return NS_ERROR_NULL_POINTER;
  1.1339 +    }
  1.1340 +
  1.1341 +    // Now, fire an Unload event to the document...
  1.1342 +    nsEventStatus status = nsEventStatus_eIgnore;
  1.1343 +    WidgetEvent event(true, NS_PAGE_UNLOAD);
  1.1344 +    event.mFlags.mBubbles = false;
  1.1345 +    // XXX Dispatching to |window|, but using |document| as the target.
  1.1346 +    event.target = mDocument;
  1.1347 +
  1.1348 +    // Never permit popups from the unload handler, no matter how we get
  1.1349 +    // here.
  1.1350 +    nsAutoPopupStatePusher popupStatePusher(openAbused, true);
  1.1351 +
  1.1352 +    EventDispatcher::Dispatch(window, mPresContext, &event, nullptr, &status);
  1.1353 +  }
  1.1354 +
  1.1355 +#ifdef MOZ_XUL
  1.1356 +  // look for open menupopups and close them after the unload event, in case
  1.1357 +  // the unload event listeners open any new popups
  1.1358 +  nsContentUtils::HidePopupsInDocument(mDocument);
  1.1359 +#endif
  1.1360 +
  1.1361 +  return NS_OK;
  1.1362 +}
  1.1363 +
  1.1364 +static void
  1.1365 +AttachContainerRecurse(nsIDocShell* aShell)
  1.1366 +{
  1.1367 +  nsCOMPtr<nsIContentViewer> viewer;
  1.1368 +  aShell->GetContentViewer(getter_AddRefs(viewer));
  1.1369 +  if (viewer) {
  1.1370 +    nsIDocument* doc = viewer->GetDocument();
  1.1371 +    if (doc) {
  1.1372 +      doc->SetContainer(static_cast<nsDocShell*>(aShell));
  1.1373 +    }
  1.1374 +    nsRefPtr<nsPresContext> pc;
  1.1375 +    viewer->GetPresContext(getter_AddRefs(pc));
  1.1376 +    if (pc) {
  1.1377 +      pc->SetContainer(static_cast<nsDocShell*>(aShell));
  1.1378 +      pc->SetLinkHandler(nsCOMPtr<nsILinkHandler>(do_QueryInterface(aShell)));
  1.1379 +    }
  1.1380 +    nsCOMPtr<nsIPresShell> presShell;
  1.1381 +    viewer->GetPresShell(getter_AddRefs(presShell));
  1.1382 +    if (presShell) {
  1.1383 +      presShell->SetForwardingContainer(WeakPtr<nsDocShell>());
  1.1384 +    }
  1.1385 +  }
  1.1386 +
  1.1387 +  // Now recurse through the children
  1.1388 +  int32_t childCount;
  1.1389 +  aShell->GetChildCount(&childCount);
  1.1390 +  for (int32_t i = 0; i < childCount; ++i) {
  1.1391 +    nsCOMPtr<nsIDocShellTreeItem> childItem;
  1.1392 +    aShell->GetChildAt(i, getter_AddRefs(childItem));
  1.1393 +    AttachContainerRecurse(nsCOMPtr<nsIDocShell>(do_QueryInterface(childItem)));
  1.1394 +  }
  1.1395 +}
  1.1396 +
  1.1397 +NS_IMETHODIMP
  1.1398 +nsDocumentViewer::Open(nsISupports *aState, nsISHEntry *aSHEntry)
  1.1399 +{
  1.1400 +  NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);
  1.1401 +
  1.1402 +  if (mDocument)
  1.1403 +    mDocument->SetContainer(mContainer);
  1.1404 +
  1.1405 +  nsresult rv = InitInternal(mParentWidget, aState, mBounds, false);
  1.1406 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1407 +
  1.1408 +  mHidden = false;
  1.1409 +
  1.1410 +  if (mPresShell)
  1.1411 +    mPresShell->SetForwardingContainer(WeakPtr<nsDocShell>());
  1.1412 +
  1.1413 +  // Rehook the child presentations.  The child shells are still in
  1.1414 +  // session history, so get them from there.
  1.1415 +
  1.1416 +  if (aSHEntry) {
  1.1417 +    nsCOMPtr<nsIDocShellTreeItem> item;
  1.1418 +    int32_t itemIndex = 0;
  1.1419 +    while (NS_SUCCEEDED(aSHEntry->ChildShellAt(itemIndex++,
  1.1420 +                                               getter_AddRefs(item))) && item) {
  1.1421 +      AttachContainerRecurse(nsCOMPtr<nsIDocShell>(do_QueryInterface(item)));
  1.1422 +    }
  1.1423 +  }
  1.1424 +  
  1.1425 +  SyncParentSubDocMap();
  1.1426 +
  1.1427 +  if (mFocusListener && mDocument) {
  1.1428 +    mDocument->AddEventListener(NS_LITERAL_STRING("focus"), mFocusListener,
  1.1429 +                                false, false);
  1.1430 +    mDocument->AddEventListener(NS_LITERAL_STRING("blur"), mFocusListener,
  1.1431 +                                false, false);
  1.1432 +  }
  1.1433 +
  1.1434 +  // XXX re-enable image animations once that works correctly
  1.1435 +
  1.1436 +  PrepareToStartLoad();
  1.1437 +
  1.1438 +  // When loading a page from the bfcache with puppet widgets, we do the
  1.1439 +  // widget attachment here (it is otherwise done in MakeWindow, which is
  1.1440 +  // called for non-bfcache pages in the history, but not bfcache pages).
  1.1441 +  // Attachment is necessary, since we get detached when another page
  1.1442 +  // is browsed to. That is, if we are one page A, then when we go to
  1.1443 +  // page B, we detach. So page A's view has no widget. If we then go
  1.1444 +  // back to it, and it is in the bfcache, we will use that view, which
  1.1445 +  // doesn't have a widget. The attach call here will properly attach us.
  1.1446 +  if (nsIWidget::UsePuppetWidgets() && mPresContext &&
  1.1447 +      ShouldAttachToTopLevel()) {
  1.1448 +    // If the old view is already attached to our parent, detach
  1.1449 +    DetachFromTopLevelWidget();
  1.1450 +
  1.1451 +    nsViewManager *vm = GetViewManager();
  1.1452 +    NS_ABORT_IF_FALSE(vm, "no view manager");
  1.1453 +    nsView* v = vm->GetRootView();
  1.1454 +    NS_ABORT_IF_FALSE(v, "no root view");
  1.1455 +    NS_ABORT_IF_FALSE(mParentWidget, "no mParentWidget to set");
  1.1456 +    v->AttachToTopLevelWidget(mParentWidget);
  1.1457 +
  1.1458 +    mAttachedToParent = true;
  1.1459 +  }
  1.1460 +
  1.1461 +  return NS_OK;
  1.1462 +}
  1.1463 +
  1.1464 +NS_IMETHODIMP
  1.1465 +nsDocumentViewer::Close(nsISHEntry *aSHEntry)
  1.1466 +{
  1.1467 +  // All callers are supposed to call close to break circular
  1.1468 +  // references.  If we do this stuff in the destructor, the
  1.1469 +  // destructor might never be called (especially if we're being
  1.1470 +  // used from JS.
  1.1471 +
  1.1472 +  mSHEntry = aSHEntry;
  1.1473 +
  1.1474 +  // Close is also needed to disable scripts during paint suppression,
  1.1475 +  // since we transfer the existing global object to the new document
  1.1476 +  // that is loaded.  In the future, the global object may become a proxy
  1.1477 +  // for an object that can be switched in and out so that we don't need
  1.1478 +  // to disable scripts during paint suppression.
  1.1479 +
  1.1480 +  if (!mDocument)
  1.1481 +    return NS_OK;
  1.1482 +
  1.1483 +#if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
  1.1484 +  // Turn scripting back on
  1.1485 +  // after PrintPreview had turned it off
  1.1486 +  if (GetIsPrintPreview() && mPrintEngine) {
  1.1487 +    mPrintEngine->TurnScriptingOn(true);
  1.1488 +  }
  1.1489 +#endif
  1.1490 +
  1.1491 +#ifdef NS_PRINTING
  1.1492 +  // A Close was called while we were printing
  1.1493 +  // so don't clear the ScriptGlobalObject
  1.1494 +  // or clear the mDocument below
  1.1495 +  if (mPrintEngine && !mClosingWhilePrinting) {
  1.1496 +    mClosingWhilePrinting = true;
  1.1497 +  } else
  1.1498 +#endif
  1.1499 +    {
  1.1500 +      // out of band cleanup of docshell
  1.1501 +      mDocument->SetScriptGlobalObject(nullptr);
  1.1502 +
  1.1503 +      if (!mSHEntry && mDocument)
  1.1504 +        mDocument->RemovedFromDocShell();
  1.1505 +    }
  1.1506 +
  1.1507 +  if (mFocusListener && mDocument) {
  1.1508 +    mDocument->RemoveEventListener(NS_LITERAL_STRING("focus"), mFocusListener,
  1.1509 +                                   false);
  1.1510 +    mDocument->RemoveEventListener(NS_LITERAL_STRING("blur"), mFocusListener,
  1.1511 +                                   false);
  1.1512 +  }
  1.1513 +
  1.1514 +  return NS_OK;
  1.1515 +}
  1.1516 +
  1.1517 +static void
  1.1518 +DetachContainerRecurse(nsIDocShell *aShell)
  1.1519 +{
  1.1520 +  // Unhook this docshell's presentation
  1.1521 +  nsCOMPtr<nsIContentViewer> viewer;
  1.1522 +  aShell->GetContentViewer(getter_AddRefs(viewer));
  1.1523 +  if (viewer) {
  1.1524 +    nsIDocument* doc = viewer->GetDocument();
  1.1525 +    if (doc) {
  1.1526 +      doc->SetContainer(nullptr);
  1.1527 +    }
  1.1528 +    nsRefPtr<nsPresContext> pc;
  1.1529 +    viewer->GetPresContext(getter_AddRefs(pc));
  1.1530 +    if (pc) {
  1.1531 +      pc->Detach();
  1.1532 +    }
  1.1533 +    nsCOMPtr<nsIPresShell> presShell;
  1.1534 +    viewer->GetPresShell(getter_AddRefs(presShell));
  1.1535 +    if (presShell) {
  1.1536 +      auto weakShell = static_cast<nsDocShell*>(aShell)->asWeakPtr();
  1.1537 +      presShell->SetForwardingContainer(weakShell);
  1.1538 +    }
  1.1539 +  }
  1.1540 +
  1.1541 +  // Now recurse through the children
  1.1542 +  int32_t childCount;
  1.1543 +  aShell->GetChildCount(&childCount);
  1.1544 +  for (int32_t i = 0; i < childCount; ++i) {
  1.1545 +    nsCOMPtr<nsIDocShellTreeItem> childItem;
  1.1546 +    aShell->GetChildAt(i, getter_AddRefs(childItem));
  1.1547 +    DetachContainerRecurse(nsCOMPtr<nsIDocShell>(do_QueryInterface(childItem)));
  1.1548 +  }
  1.1549 +}
  1.1550 +
  1.1551 +NS_IMETHODIMP
  1.1552 +nsDocumentViewer::Destroy()
  1.1553 +{
  1.1554 +  NS_ASSERTION(mDocument, "No document in Destroy()!");
  1.1555 +
  1.1556 +#ifdef NS_PRINTING
  1.1557 +  // Here is where we check to see if the document was still being prepared 
  1.1558 +  // for printing when it was asked to be destroy from someone externally
  1.1559 +  // This usually happens if the document is unloaded while the user is in the
  1.1560 +  // Print Dialog
  1.1561 +  //
  1.1562 +  // So we flip the bool to remember that the document is going away
  1.1563 +  // and we can clean up and abort later after returning from the Print Dialog
  1.1564 +  if (mPrintEngine) {
  1.1565 +    if (mPrintEngine->CheckBeforeDestroy()) {
  1.1566 +      return NS_OK;
  1.1567 +    }
  1.1568 +  }
  1.1569 +  mBeforeAndAfterPrint = nullptr;
  1.1570 +#endif
  1.1571 +
  1.1572 +  // Don't let the document get unloaded while we are printing.
  1.1573 +  // this could happen if we hit the back button during printing.
  1.1574 +  // We also keep the viewer from being cached in session history, since
  1.1575 +  // we require all documents there to be sanitized.
  1.1576 +  if (mDestroyRefCount != 0) {
  1.1577 +    --mDestroyRefCount;
  1.1578 +    return NS_OK;
  1.1579 +  }
  1.1580 +
  1.1581 +  // If we were told to put ourselves into session history instead of destroy
  1.1582 +  // the presentation, do that now.
  1.1583 +  if (mSHEntry) {
  1.1584 +    if (mPresShell)
  1.1585 +      mPresShell->Freeze();
  1.1586 +
  1.1587 +    // Make sure the presentation isn't torn down by Hide().
  1.1588 +    mSHEntry->SetSticky(mIsSticky);
  1.1589 +    mIsSticky = true;
  1.1590 +
  1.1591 +    bool savePresentation = mDocument ? mDocument->IsBFCachingAllowed() : true;
  1.1592 +
  1.1593 +    // Remove our root view from the view hierarchy.
  1.1594 +    if (mPresShell) {
  1.1595 +      nsViewManager *vm = mPresShell->GetViewManager();
  1.1596 +      if (vm) {
  1.1597 +        nsView *rootView = vm->GetRootView();
  1.1598 +
  1.1599 +        if (rootView) {
  1.1600 +          nsView *rootViewParent = rootView->GetParent();
  1.1601 +          if (rootViewParent) {
  1.1602 +            nsViewManager *parentVM = rootViewParent->GetViewManager();
  1.1603 +            if (parentVM) {
  1.1604 +              parentVM->RemoveChild(rootView);
  1.1605 +            }
  1.1606 +          }
  1.1607 +        }
  1.1608 +      }
  1.1609 +    }
  1.1610 +
  1.1611 +    Hide();
  1.1612 +
  1.1613 +    // This is after Hide() so that the user doesn't see the inputs clear.
  1.1614 +    if (mDocument) {
  1.1615 +      mDocument->Sanitize();
  1.1616 +    }
  1.1617 +
  1.1618 +    // Reverse ownership. Do this *after* calling sanitize so that sanitize
  1.1619 +    // doesn't cause mutations that make the SHEntry drop the presentation
  1.1620 +
  1.1621 +    // Grab a reference to mSHEntry before calling into things like
  1.1622 +    // SyncPresentationState that might mess with our members.
  1.1623 +    nsCOMPtr<nsISHEntry> shEntry = mSHEntry; // we'll need this below
  1.1624 +    mSHEntry = nullptr;
  1.1625 +
  1.1626 +    if (savePresentation) {
  1.1627 +      shEntry->SetContentViewer(this);
  1.1628 +    }
  1.1629 +
  1.1630 +    // Always sync the presentation state.  That way even if someone screws up
  1.1631 +    // and shEntry has no window state at this point we'll be ok; we just won't
  1.1632 +    // cache ourselves.
  1.1633 +    shEntry->SyncPresentationState();
  1.1634 +
  1.1635 +    // Shut down accessibility for the document before we start to tear it down.
  1.1636 +#ifdef ACCESSIBILITY
  1.1637 +    if (mPresShell) {
  1.1638 +      a11y::DocAccessible* docAcc = mPresShell->GetDocAccessible();
  1.1639 +      if (docAcc) {
  1.1640 +        docAcc->Shutdown();
  1.1641 +      }
  1.1642 +    }
  1.1643 +#endif
  1.1644 +
  1.1645 +    // Break the link from the document/presentation to the docshell, so that
  1.1646 +    // link traversals cannot affect the currently-loaded document.
  1.1647 +    // When the presentation is restored, Open() and InitInternal() will reset
  1.1648 +    // these pointers to their original values.
  1.1649 +
  1.1650 +    if (mDocument) {
  1.1651 +      mDocument->SetContainer(nullptr);
  1.1652 +    }
  1.1653 +    if (mPresContext) {
  1.1654 +      mPresContext->Detach();
  1.1655 +    }
  1.1656 +    if (mPresShell) {
  1.1657 +      mPresShell->SetForwardingContainer(mContainer);
  1.1658 +    }
  1.1659 +
  1.1660 +    // Do the same for our children.  Note that we need to get the child
  1.1661 +    // docshells from the SHEntry now; the docshell will have cleared them.
  1.1662 +    nsCOMPtr<nsIDocShellTreeItem> item;
  1.1663 +    int32_t itemIndex = 0;
  1.1664 +    while (NS_SUCCEEDED(shEntry->ChildShellAt(itemIndex++,
  1.1665 +                                              getter_AddRefs(item))) && item) {
  1.1666 +      DetachContainerRecurse(nsCOMPtr<nsIDocShell>(do_QueryInterface(item)));
  1.1667 +    }
  1.1668 +
  1.1669 +    return NS_OK;
  1.1670 +  }
  1.1671 +
  1.1672 +  // The document was not put in the bfcache
  1.1673 +
  1.1674 +  if (mPresShell) {
  1.1675 +    DestroyPresShell();
  1.1676 +  }
  1.1677 +  if (mDocument) {
  1.1678 +    mDocument->Destroy();
  1.1679 +    mDocument = nullptr;
  1.1680 +  }
  1.1681 +
  1.1682 +  // All callers are supposed to call destroy to break circular
  1.1683 +  // references.  If we do this stuff in the destructor, the
  1.1684 +  // destructor might never be called (especially if we're being
  1.1685 +  // used from JS.
  1.1686 +
  1.1687 +#ifdef NS_PRINTING
  1.1688 +  if (mPrintEngine) {
  1.1689 +#ifdef NS_PRINT_PREVIEW
  1.1690 +    bool doingPrintPreview;
  1.1691 +    mPrintEngine->GetDoingPrintPreview(&doingPrintPreview);
  1.1692 +    if (doingPrintPreview) {
  1.1693 +      mPrintEngine->FinishPrintPreview();
  1.1694 +    }
  1.1695 +#endif
  1.1696 +
  1.1697 +    mPrintEngine->Destroy();
  1.1698 +    mPrintEngine = nullptr;
  1.1699 +  }
  1.1700 +#endif
  1.1701 +
  1.1702 +  // Avoid leaking the old viewer.
  1.1703 +  if (mPreviousViewer) {
  1.1704 +    mPreviousViewer->Destroy();
  1.1705 +    mPreviousViewer = nullptr;
  1.1706 +  }
  1.1707 +
  1.1708 +  mDeviceContext = nullptr;
  1.1709 +
  1.1710 +  if (mPresContext) {
  1.1711 +    DestroyPresContext();
  1.1712 +  }
  1.1713 +
  1.1714 +  mWindow = nullptr;
  1.1715 +  mViewManager = nullptr;
  1.1716 +  mContainer = WeakPtr<nsDocShell>();
  1.1717 +
  1.1718 +  return NS_OK;
  1.1719 +}
  1.1720 +
  1.1721 +NS_IMETHODIMP
  1.1722 +nsDocumentViewer::Stop(void)
  1.1723 +{
  1.1724 +  NS_ASSERTION(mDocument, "Stop called too early or too late");
  1.1725 +  if (mDocument) {
  1.1726 +    mDocument->StopDocumentLoad();
  1.1727 +  }
  1.1728 +
  1.1729 +  if (!mHidden && (mLoaded || mStopped) && mPresContext && !mSHEntry)
  1.1730 +    mPresContext->SetImageAnimationMode(imgIContainer::kDontAnimMode);
  1.1731 +
  1.1732 +  mStopped = true;
  1.1733 +
  1.1734 +  if (!mLoaded && mPresShell) {
  1.1735 +    // Well, we might as well paint what we have so far.
  1.1736 +    nsCOMPtr<nsIPresShell> shellDeathGrip(mPresShell); // bug 378682
  1.1737 +    mPresShell->UnsuppressPainting();
  1.1738 +  }
  1.1739 +
  1.1740 +  return NS_OK;
  1.1741 +}
  1.1742 +
  1.1743 +NS_IMETHODIMP
  1.1744 +nsDocumentViewer::GetDOMDocument(nsIDOMDocument **aResult)
  1.1745 +{
  1.1746 +  NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
  1.1747 +  return CallQueryInterface(mDocument, aResult);
  1.1748 +}
  1.1749 +
  1.1750 +NS_IMETHODIMP_(nsIDocument *)
  1.1751 +nsDocumentViewer::GetDocument()
  1.1752 +{
  1.1753 +  return mDocument;
  1.1754 +}
  1.1755 +
  1.1756 +NS_IMETHODIMP
  1.1757 +nsDocumentViewer::SetDOMDocument(nsIDOMDocument *aDocument)
  1.1758 +{
  1.1759 +  // Assumptions:
  1.1760 +  //
  1.1761 +  // 1) this document viewer has been initialized with a call to Init().
  1.1762 +  // 2) the stylesheets associated with the document have been added
  1.1763 +  // to the document.
  1.1764 +
  1.1765 +  // XXX Right now, this method assumes that the layout of the current
  1.1766 +  // document hasn't started yet.  More cleanup will probably be
  1.1767 +  // necessary to make this method work for the case when layout *has*
  1.1768 +  // occurred for the current document.
  1.1769 +  // That work can happen when and if it is needed.
  1.1770 +
  1.1771 +  if (!aDocument)
  1.1772 +    return NS_ERROR_NULL_POINTER;
  1.1773 +
  1.1774 +  nsCOMPtr<nsIDocument> newDoc = do_QueryInterface(aDocument);
  1.1775 +  NS_ENSURE_TRUE(newDoc, NS_ERROR_UNEXPECTED);
  1.1776 +
  1.1777 +  return SetDocumentInternal(newDoc, false);
  1.1778 +}
  1.1779 +
  1.1780 +NS_IMETHODIMP
  1.1781 +nsDocumentViewer::SetDocumentInternal(nsIDocument* aDocument,
  1.1782 +                                        bool aForceReuseInnerWindow)
  1.1783 +{
  1.1784 +  MOZ_ASSERT(aDocument);
  1.1785 +
  1.1786 +  // Set new container
  1.1787 +  aDocument->SetContainer(mContainer);
  1.1788 +
  1.1789 +  if (mDocument != aDocument) {
  1.1790 +    if (mDocument->IsStaticDocument()) {
  1.1791 +      mDocument->SetScriptGlobalObject(nullptr);
  1.1792 +      mDocument->Destroy();
  1.1793 +    }
  1.1794 +    // Replace the old document with the new one. Do this only when
  1.1795 +    // the new document really is a new document.
  1.1796 +    mDocument = aDocument;
  1.1797 +
  1.1798 +    // Set the script global object on the new document
  1.1799 +    nsCOMPtr<nsPIDOMWindow> window =
  1.1800 +      do_GetInterface(static_cast<nsIDocShell*>(mContainer.get()));
  1.1801 +    if (window) {
  1.1802 +      window->SetNewDocument(aDocument, nullptr, aForceReuseInnerWindow);
  1.1803 +    }
  1.1804 +
  1.1805 +    // Clear the list of old child docshells. Child docshells for the new
  1.1806 +    // document will be constructed as frames are created.
  1.1807 +    if (!aDocument->IsStaticDocument()) {
  1.1808 +      nsCOMPtr<nsIDocShell> node(mContainer);
  1.1809 +      if (node) {
  1.1810 +        int32_t count;
  1.1811 +        node->GetChildCount(&count);
  1.1812 +        for (int32_t i = 0; i < count; ++i) {
  1.1813 +          nsCOMPtr<nsIDocShellTreeItem> child;
  1.1814 +          node->GetChildAt(0, getter_AddRefs(child));
  1.1815 +          node->RemoveChild(child);
  1.1816 +        }
  1.1817 +      }
  1.1818 +    }
  1.1819 +  }
  1.1820 +
  1.1821 +  nsresult rv = SyncParentSubDocMap();
  1.1822 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1823 +
  1.1824 +  // Replace the current pres shell with a new shell for the new document
  1.1825 +
  1.1826 +  if (mPresShell) {
  1.1827 +    DestroyPresShell();
  1.1828 +  }
  1.1829 +
  1.1830 +  if (mPresContext) {
  1.1831 +    DestroyPresContext();
  1.1832 +
  1.1833 +    mWindow = nullptr;
  1.1834 +    InitInternal(mParentWidget, nullptr, mBounds, true, true, false);
  1.1835 +  }
  1.1836 +
  1.1837 +  return rv;
  1.1838 +}
  1.1839 +
  1.1840 +nsIPresShell*
  1.1841 +nsDocumentViewer::GetPresShell()
  1.1842 +{
  1.1843 +  return mPresShell;
  1.1844 +}
  1.1845 +
  1.1846 +nsPresContext*
  1.1847 +nsDocumentViewer::GetPresContext()
  1.1848 +{
  1.1849 +  return mPresContext;
  1.1850 +}
  1.1851 +
  1.1852 +nsViewManager*
  1.1853 +nsDocumentViewer::GetViewManager()
  1.1854 +{
  1.1855 +  return mViewManager;
  1.1856 +}
  1.1857 +
  1.1858 +NS_IMETHODIMP
  1.1859 +nsDocumentViewer::GetPresShell(nsIPresShell** aResult)
  1.1860 +{
  1.1861 +  nsIPresShell* shell = GetPresShell();
  1.1862 +  NS_IF_ADDREF(*aResult = shell);
  1.1863 +  return NS_OK;
  1.1864 +}
  1.1865 +
  1.1866 +NS_IMETHODIMP
  1.1867 +nsDocumentViewer::GetPresContext(nsPresContext** aResult)
  1.1868 +{
  1.1869 +  nsPresContext* pc = GetPresContext();
  1.1870 +  NS_IF_ADDREF(*aResult = pc);
  1.1871 +  return NS_OK;
  1.1872 +}
  1.1873 +
  1.1874 +NS_IMETHODIMP
  1.1875 +nsDocumentViewer::GetBounds(nsIntRect& aResult)
  1.1876 +{
  1.1877 +  NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
  1.1878 +  aResult = mBounds;
  1.1879 +  return NS_OK;
  1.1880 +}
  1.1881 +
  1.1882 +NS_IMETHODIMP
  1.1883 +nsDocumentViewer::GetPreviousViewer(nsIContentViewer** aViewer)
  1.1884 +{
  1.1885 +  *aViewer = mPreviousViewer;
  1.1886 +  NS_IF_ADDREF(*aViewer);
  1.1887 +  return NS_OK;
  1.1888 +}
  1.1889 +
  1.1890 +NS_IMETHODIMP
  1.1891 +nsDocumentViewer::SetPreviousViewer(nsIContentViewer* aViewer)
  1.1892 +{
  1.1893 +  // NOTE:  |Show| sets |mPreviousViewer| to null without calling this
  1.1894 +  // function.
  1.1895 +
  1.1896 +  if (aViewer) {
  1.1897 +    NS_ASSERTION(!mPreviousViewer,
  1.1898 +                 "can't set previous viewer when there already is one");
  1.1899 +
  1.1900 +    // In a multiple chaining situation (which occurs when running a thrashing
  1.1901 +    // test like i-bench or jrgm's tests with no delay), we can build up a
  1.1902 +    // whole chain of viewers.  In order to avoid this, we always set our previous
  1.1903 +    // viewer to the MOST previous viewer in the chain, and then dump the intermediate
  1.1904 +    // link from the chain.  This ensures that at most only 2 documents are alive
  1.1905 +    // and undestroyed at any given time (the one that is showing and the one that
  1.1906 +    // is loading with painting suppressed).
  1.1907 +    // It's very important that if this ever gets changed the code
  1.1908 +    // before the RestorePresentation call in nsDocShell::InternalLoad
  1.1909 +    // be changed accordingly.
  1.1910 +    nsCOMPtr<nsIContentViewer> prevViewer;
  1.1911 +    aViewer->GetPreviousViewer(getter_AddRefs(prevViewer));
  1.1912 +    if (prevViewer) {
  1.1913 +      aViewer->SetPreviousViewer(nullptr);
  1.1914 +      aViewer->Destroy();
  1.1915 +      return SetPreviousViewer(prevViewer);
  1.1916 +    }
  1.1917 +  }
  1.1918 +
  1.1919 +  mPreviousViewer = aViewer;
  1.1920 +  return NS_OK;
  1.1921 +}
  1.1922 +
  1.1923 +NS_IMETHODIMP
  1.1924 +nsDocumentViewer::SetBounds(const nsIntRect& aBounds)
  1.1925 +{
  1.1926 +  NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
  1.1927 +
  1.1928 +  mBounds = aBounds;
  1.1929 +  if (mWindow) {
  1.1930 +    if (!mAttachedToParent) {
  1.1931 +      // Don't have the widget repaint. Layout will generate repaint requests
  1.1932 +      // during reflow.
  1.1933 +      mWindow->Resize(aBounds.x, aBounds.y,
  1.1934 +                      aBounds.width, aBounds.height,
  1.1935 +                      false);
  1.1936 +    }
  1.1937 +  } else if (mPresContext && mViewManager) {
  1.1938 +    int32_t p2a = mPresContext->AppUnitsPerDevPixel();
  1.1939 +    mViewManager->SetWindowDimensions(NSIntPixelsToAppUnits(mBounds.width, p2a),
  1.1940 +                                      NSIntPixelsToAppUnits(mBounds.height, p2a));
  1.1941 +  }
  1.1942 +
  1.1943 +  // If there's a previous viewer, it's the one that's actually showing,
  1.1944 +  // so be sure to resize it as well so it paints over the right area.
  1.1945 +  // This may slow down the performance of the new page load, but resize
  1.1946 +  // during load is also probably a relatively unusual condition
  1.1947 +  // relating to things being hidden while something is loaded.  It so
  1.1948 +  // happens that Firefox does this a good bit with its infobar, and it
  1.1949 +  // looks ugly if we don't do this.
  1.1950 +  if (mPreviousViewer) {
  1.1951 +    nsCOMPtr<nsIContentViewer> previousViewer = mPreviousViewer;
  1.1952 +    previousViewer->SetBounds(aBounds);
  1.1953 +  }
  1.1954 +
  1.1955 +  return NS_OK;
  1.1956 +}
  1.1957 +
  1.1958 +NS_IMETHODIMP
  1.1959 +nsDocumentViewer::Move(int32_t aX, int32_t aY)
  1.1960 +{
  1.1961 +  NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
  1.1962 +  mBounds.MoveTo(aX, aY);
  1.1963 +  if (mWindow) {
  1.1964 +    mWindow->Move(aX, aY);
  1.1965 +  }
  1.1966 +  return NS_OK;
  1.1967 +}
  1.1968 +
  1.1969 +NS_IMETHODIMP
  1.1970 +nsDocumentViewer::Show(void)
  1.1971 +{
  1.1972 +  NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
  1.1973 +
  1.1974 +  // We don't need the previous viewer anymore since we're not
  1.1975 +  // displaying it.
  1.1976 +  if (mPreviousViewer) {
  1.1977 +    // This little dance *may* only be to keep
  1.1978 +    // PresShell::EndObservingDocument happy, but I'm not sure.
  1.1979 +    nsCOMPtr<nsIContentViewer> prevViewer(mPreviousViewer);
  1.1980 +    mPreviousViewer = nullptr;
  1.1981 +    prevViewer->Destroy();
  1.1982 +
  1.1983 +    // Make sure we don't have too many cached ContentViewers
  1.1984 +    nsCOMPtr<nsIDocShellTreeItem> treeItem(mContainer);
  1.1985 +    if (treeItem) {
  1.1986 +      // We need to find the root DocShell since only that object has an
  1.1987 +      // SHistory and we need the SHistory to evict content viewers
  1.1988 +      nsCOMPtr<nsIDocShellTreeItem> root;
  1.1989 +      treeItem->GetSameTypeRootTreeItem(getter_AddRefs(root));
  1.1990 +      nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(root);
  1.1991 +      nsCOMPtr<nsISHistory> history;
  1.1992 +      webNav->GetSessionHistory(getter_AddRefs(history));
  1.1993 +      nsCOMPtr<nsISHistoryInternal> historyInt = do_QueryInterface(history);
  1.1994 +      if (historyInt) {
  1.1995 +        int32_t prevIndex,loadedIndex;
  1.1996 +        nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(treeItem);
  1.1997 +        docShell->GetPreviousTransIndex(&prevIndex);
  1.1998 +        docShell->GetLoadedTransIndex(&loadedIndex);
  1.1999 +#ifdef DEBUG_PAGE_CACHE
  1.2000 +        printf("About to evict content viewers: prev=%d, loaded=%d\n",
  1.2001 +               prevIndex, loadedIndex);
  1.2002 +#endif
  1.2003 +        historyInt->EvictOutOfRangeContentViewers(loadedIndex);
  1.2004 +      }
  1.2005 +    }
  1.2006 +  }
  1.2007 +
  1.2008 +  if (mWindow) {
  1.2009 +    // When attached to a top level xul window, we do not need to call
  1.2010 +    // Show on the widget. Underlying window management code handles
  1.2011 +    // this when the window is initialized.
  1.2012 +    if (!mAttachedToParent) {
  1.2013 +      mWindow->Show(true);
  1.2014 +    }
  1.2015 +  }
  1.2016 +
  1.2017 +  if (mDocument && !mPresShell) {
  1.2018 +    NS_ASSERTION(!mWindow, "Window already created but no presshell?");
  1.2019 +
  1.2020 +    nsCOMPtr<nsIBaseWindow> base_win(mContainer);
  1.2021 +    if (base_win) {
  1.2022 +      base_win->GetParentWidget(&mParentWidget);
  1.2023 +      if (mParentWidget) {
  1.2024 +        mParentWidget->Release(); // GetParentWidget AddRefs, but mParentWidget is weak
  1.2025 +      }
  1.2026 +    }
  1.2027 +
  1.2028 +    nsView* containerView = FindContainerView();
  1.2029 +
  1.2030 +    nsresult rv = CreateDeviceContext(containerView);
  1.2031 +    NS_ENSURE_SUCCESS(rv, rv);
  1.2032 +
  1.2033 +    // Create presentation context
  1.2034 +    NS_ASSERTION(!mPresContext, "Shouldn't have a prescontext if we have no shell!");
  1.2035 +    mPresContext = CreatePresContext(mDocument,
  1.2036 +        nsPresContext::eContext_Galley, containerView);
  1.2037 +    NS_ENSURE_TRUE(mPresContext, NS_ERROR_OUT_OF_MEMORY);
  1.2038 +
  1.2039 +    rv = mPresContext->Init(mDeviceContext);
  1.2040 +    if (NS_FAILED(rv)) {
  1.2041 +      mPresContext = nullptr;
  1.2042 +      return rv;
  1.2043 +    }
  1.2044 +
  1.2045 +    rv = MakeWindow(nsSize(mPresContext->DevPixelsToAppUnits(mBounds.width),
  1.2046 +                           mPresContext->DevPixelsToAppUnits(mBounds.height)),
  1.2047 +                           containerView);
  1.2048 +    if (NS_FAILED(rv))
  1.2049 +      return rv;
  1.2050 +
  1.2051 +    if (mPresContext && base_win) {
  1.2052 +      nsCOMPtr<nsILinkHandler> linkHandler(do_GetInterface(base_win));
  1.2053 +
  1.2054 +      if (linkHandler) {
  1.2055 +        mPresContext->SetLinkHandler(linkHandler);
  1.2056 +      }
  1.2057 +
  1.2058 +      mPresContext->SetContainer(mContainer);
  1.2059 +    }
  1.2060 +
  1.2061 +    if (mPresContext) {
  1.2062 +      Hide();
  1.2063 +
  1.2064 +      rv = InitPresentationStuff(mDocument->MayStartLayout());
  1.2065 +    }
  1.2066 +
  1.2067 +    // If we get here the document load has already started and the
  1.2068 +    // window is shown because some JS on the page caused it to be
  1.2069 +    // shown...
  1.2070 +
  1.2071 +    if (mPresShell) {
  1.2072 +      nsCOMPtr<nsIPresShell> shellDeathGrip(mPresShell); // bug 378682
  1.2073 +      mPresShell->UnsuppressPainting();
  1.2074 +    }
  1.2075 +  }
  1.2076 +
  1.2077 +  // Notify observers that a new page has been shown. This will get run
  1.2078 +  // from the event loop after we actually draw the page.
  1.2079 +  NS_DispatchToMainThread(new nsDocumentShownDispatcher(mDocument));
  1.2080 +
  1.2081 +  return NS_OK;
  1.2082 +}
  1.2083 +
  1.2084 +NS_IMETHODIMP
  1.2085 +nsDocumentViewer::Hide(void)
  1.2086 +{
  1.2087 +  if (!mAttachedToParent && mWindow) {
  1.2088 +    mWindow->Show(false);
  1.2089 +  }
  1.2090 +
  1.2091 +  if (!mPresShell)
  1.2092 +    return NS_OK;
  1.2093 +
  1.2094 +  NS_ASSERTION(mPresContext, "Can't have a presshell and no prescontext!");
  1.2095 +
  1.2096 +  // Avoid leaking the old viewer.
  1.2097 +  if (mPreviousViewer) {
  1.2098 +    mPreviousViewer->Destroy();
  1.2099 +    mPreviousViewer = nullptr;
  1.2100 +  }
  1.2101 +
  1.2102 +  if (mIsSticky) {
  1.2103 +    // This window is sticky, that means that it might be shown again
  1.2104 +    // and we don't want the presshell n' all that to be thrown away
  1.2105 +    // just because the window is hidden.
  1.2106 +
  1.2107 +    return NS_OK;
  1.2108 +  }
  1.2109 +
  1.2110 +  nsCOMPtr<nsIDocShell> docShell(mContainer);
  1.2111 +  if (docShell) {
  1.2112 +    nsCOMPtr<nsILayoutHistoryState> layoutState;
  1.2113 +    mPresShell->CaptureHistoryState(getter_AddRefs(layoutState));
  1.2114 +  }
  1.2115 +
  1.2116 +  DestroyPresShell();
  1.2117 +
  1.2118 +  DestroyPresContext();
  1.2119 +
  1.2120 +  mViewManager   = nullptr;
  1.2121 +  mWindow        = nullptr;
  1.2122 +  mDeviceContext = nullptr;
  1.2123 +  mParentWidget  = nullptr;
  1.2124 +
  1.2125 +  nsCOMPtr<nsIBaseWindow> base_win(mContainer);
  1.2126 +
  1.2127 +  if (base_win && !mAttachedToParent) {
  1.2128 +    base_win->SetParentWidget(nullptr);
  1.2129 +  }
  1.2130 +
  1.2131 +  return NS_OK;
  1.2132 +}
  1.2133 +
  1.2134 +NS_IMETHODIMP
  1.2135 +nsDocumentViewer::GetSticky(bool *aSticky)
  1.2136 +{
  1.2137 +  *aSticky = mIsSticky;
  1.2138 +
  1.2139 +  return NS_OK;
  1.2140 +}
  1.2141 +
  1.2142 +NS_IMETHODIMP
  1.2143 +nsDocumentViewer::SetSticky(bool aSticky)
  1.2144 +{
  1.2145 +  mIsSticky = aSticky;
  1.2146 +
  1.2147 +  return NS_OK;
  1.2148 +}
  1.2149 +
  1.2150 +NS_IMETHODIMP
  1.2151 +nsDocumentViewer::RequestWindowClose(bool* aCanClose)
  1.2152 +{
  1.2153 +#ifdef NS_PRINTING
  1.2154 +  if (mPrintIsPending || (mPrintEngine && mPrintEngine->GetIsPrinting())) {
  1.2155 +    *aCanClose = false;
  1.2156 +    mDeferredWindowClose = true;
  1.2157 +  } else
  1.2158 +#endif
  1.2159 +    *aCanClose = true;
  1.2160 +
  1.2161 +  return NS_OK;
  1.2162 +}
  1.2163 +
  1.2164 +static bool
  1.2165 +AppendAgentSheet(nsIStyleSheet *aSheet, void *aData)
  1.2166 +{
  1.2167 +  nsStyleSet *styleSet = static_cast<nsStyleSet*>(aData);
  1.2168 +  styleSet->AppendStyleSheet(nsStyleSet::eAgentSheet, aSheet);
  1.2169 +  return true;
  1.2170 +}
  1.2171 +
  1.2172 +static bool
  1.2173 +PrependUserSheet(nsIStyleSheet *aSheet, void *aData)
  1.2174 +{
  1.2175 +  nsStyleSet *styleSet = static_cast<nsStyleSet*>(aData);
  1.2176 +  styleSet->PrependStyleSheet(nsStyleSet::eUserSheet, aSheet);
  1.2177 +  return true;
  1.2178 +}
  1.2179 +
  1.2180 +nsresult
  1.2181 +nsDocumentViewer::CreateStyleSet(nsIDocument* aDocument,
  1.2182 +                                   nsStyleSet** aStyleSet)
  1.2183 +{
  1.2184 +  // Make sure this does the same thing as PresShell::AddSheet wrt ordering.
  1.2185 +
  1.2186 +  // this should eventually get expanded to allow for creating
  1.2187 +  // different sets for different media
  1.2188 +  nsStyleSet *styleSet = new nsStyleSet();
  1.2189 +
  1.2190 +  styleSet->BeginUpdate();
  1.2191 +  
  1.2192 +  // The document will fill in the document sheets when we create the presshell
  1.2193 +  
  1.2194 +  // Handle the user sheets.
  1.2195 +  nsCSSStyleSheet* sheet = nullptr;
  1.2196 +  if (nsContentUtils::IsInChromeDocshell(aDocument)) {
  1.2197 +    sheet = nsLayoutStylesheetCache::UserChromeSheet();
  1.2198 +  }
  1.2199 +  else {
  1.2200 +    sheet = nsLayoutStylesheetCache::UserContentSheet();
  1.2201 +  }
  1.2202 +
  1.2203 +  if (sheet)
  1.2204 +    styleSet->AppendStyleSheet(nsStyleSet::eUserSheet, sheet);
  1.2205 +
  1.2206 +  // Append chrome sheets (scrollbars + forms).
  1.2207 +  bool shouldOverride = false;
  1.2208 +  // We don't want a docshell here for external resource docs, so just
  1.2209 +  // look at mContainer.
  1.2210 +  nsCOMPtr<nsIDocShell> ds(mContainer);
  1.2211 +  nsCOMPtr<nsIDOMEventTarget> chromeHandler;
  1.2212 +  nsCOMPtr<nsIURI> uri;
  1.2213 +  nsRefPtr<nsCSSStyleSheet> csssheet;
  1.2214 +
  1.2215 +  if (ds) {
  1.2216 +    ds->GetChromeEventHandler(getter_AddRefs(chromeHandler));
  1.2217 +  }
  1.2218 +  if (chromeHandler) {
  1.2219 +    nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(chromeHandler));
  1.2220 +    nsCOMPtr<nsIContent> content(do_QueryInterface(elt));
  1.2221 +    if (elt && content) {
  1.2222 +      nsCOMPtr<nsIURI> baseURI = content->GetBaseURI();
  1.2223 +
  1.2224 +      nsAutoString sheets;
  1.2225 +      elt->GetAttribute(NS_LITERAL_STRING("usechromesheets"), sheets);
  1.2226 +      if (!sheets.IsEmpty() && baseURI) {
  1.2227 +        nsRefPtr<mozilla::css::Loader> cssLoader = new mozilla::css::Loader();
  1.2228 +
  1.2229 +        char *str = ToNewCString(sheets);
  1.2230 +        char *newStr = str;
  1.2231 +        char *token;
  1.2232 +        while ( (token = nsCRT::strtok(newStr, ", ", &newStr)) ) {
  1.2233 +          NS_NewURI(getter_AddRefs(uri), nsDependentCString(token), nullptr,
  1.2234 +                    baseURI);
  1.2235 +          if (!uri) continue;
  1.2236 +
  1.2237 +          cssLoader->LoadSheetSync(uri, getter_AddRefs(csssheet));
  1.2238 +          if (!csssheet) continue;
  1.2239 +
  1.2240 +          styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, csssheet);
  1.2241 +          shouldOverride = true;
  1.2242 +        }
  1.2243 +        nsMemory::Free(str);
  1.2244 +      }
  1.2245 +    }
  1.2246 +  }
  1.2247 +
  1.2248 +  if (!shouldOverride) {
  1.2249 +    sheet = nsLayoutStylesheetCache::ScrollbarsSheet();
  1.2250 +    if (sheet) {
  1.2251 +      styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet);
  1.2252 +    }
  1.2253 +  }
  1.2254 +
  1.2255 +  sheet = nsLayoutStylesheetCache::NumberControlSheet();
  1.2256 +  if (sheet) {
  1.2257 +    styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet);
  1.2258 +  }
  1.2259 +
  1.2260 +  sheet = nsLayoutStylesheetCache::FormsSheet();
  1.2261 +  if (sheet) {
  1.2262 +    styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet);
  1.2263 +  }
  1.2264 +
  1.2265 +  sheet = nsLayoutStylesheetCache::FullScreenOverrideSheet();
  1.2266 +  if (sheet) {
  1.2267 +    styleSet->PrependStyleSheet(nsStyleSet::eOverrideSheet, sheet);
  1.2268 +  }
  1.2269 +
  1.2270 +  // Make sure to clone the quirk sheet so that it can be usefully
  1.2271 +  // enabled/disabled as needed.
  1.2272 +  nsRefPtr<nsCSSStyleSheet> quirkClone;
  1.2273 +  nsCSSStyleSheet* quirkSheet;
  1.2274 +  if (!nsLayoutStylesheetCache::UASheet() ||
  1.2275 +      !(quirkSheet = nsLayoutStylesheetCache::QuirkSheet()) ||
  1.2276 +      !(quirkClone = quirkSheet->Clone(nullptr, nullptr, nullptr, nullptr)) ||
  1.2277 +      !sheet) {
  1.2278 +    delete styleSet;
  1.2279 +    return NS_ERROR_OUT_OF_MEMORY;
  1.2280 +  }
  1.2281 +  // quirk.css needs to come after the regular UA sheet (or more precisely,
  1.2282 +  // after the html.css and so forth that the UA sheet imports).
  1.2283 +  styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, quirkClone);
  1.2284 +  styleSet->SetQuirkStyleSheet(quirkClone);
  1.2285 +  styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet,
  1.2286 +                              nsLayoutStylesheetCache::UASheet());
  1.2287 +
  1.2288 +  nsStyleSheetService *sheetService = nsStyleSheetService::GetInstance();
  1.2289 +  if (sheetService) {
  1.2290 +    sheetService->AgentStyleSheets()->EnumerateForwards(AppendAgentSheet,
  1.2291 +                                                        styleSet);
  1.2292 +    sheetService->UserStyleSheets()->EnumerateBackwards(PrependUserSheet,
  1.2293 +                                                        styleSet);
  1.2294 +  }
  1.2295 +
  1.2296 +  // Caller will handle calling EndUpdate, per contract.
  1.2297 +  *aStyleSet = styleSet;
  1.2298 +  return NS_OK;
  1.2299 +}
  1.2300 +
  1.2301 +NS_IMETHODIMP
  1.2302 +nsDocumentViewer::ClearHistoryEntry()
  1.2303 +{
  1.2304 +  mSHEntry = nullptr;
  1.2305 +  return NS_OK;
  1.2306 +}
  1.2307 +
  1.2308 +//-------------------------------------------------------
  1.2309 +
  1.2310 +nsresult
  1.2311 +nsDocumentViewer::MakeWindow(const nsSize& aSize, nsView* aContainerView)
  1.2312 +{
  1.2313 +  if (GetIsPrintPreview())
  1.2314 +    return NS_OK;
  1.2315 +
  1.2316 +  bool shouldAttach = ShouldAttachToTopLevel();
  1.2317 +
  1.2318 +  if (shouldAttach) {
  1.2319 +    // If the old view is already attached to our parent, detach
  1.2320 +    DetachFromTopLevelWidget();
  1.2321 +  }
  1.2322 +
  1.2323 +  mViewManager = new nsViewManager();
  1.2324 +
  1.2325 +  nsDeviceContext *dx = mPresContext->DeviceContext();
  1.2326 +
  1.2327 +  nsresult rv = mViewManager->Init(dx);
  1.2328 +  if (NS_FAILED(rv))
  1.2329 +    return rv;
  1.2330 +
  1.2331 +  // The root view is always at 0,0.
  1.2332 +  nsRect tbounds(nsPoint(0, 0), aSize);
  1.2333 +  // Create a view
  1.2334 +  nsView* view = mViewManager->CreateView(tbounds, aContainerView);
  1.2335 +  if (!view)
  1.2336 +    return NS_ERROR_OUT_OF_MEMORY;
  1.2337 +
  1.2338 +  // Create a widget if we were given a parent widget or don't have a
  1.2339 +  // container view that we can hook up to without a widget.
  1.2340 +  // Don't create widgets for ResourceDocs (external resources & svg images),
  1.2341 +  // because when they're displayed, they're painted into *another* document's
  1.2342 +  // widget.
  1.2343 +  if (!mDocument->IsResourceDoc() &&
  1.2344 +      (mParentWidget || !aContainerView)) {
  1.2345 +    // pass in a native widget to be the parent widget ONLY if the view hierarchy will stand alone.
  1.2346 +    // otherwise the view will find its own parent widget and "do the right thing" to
  1.2347 +    // establish a parent/child widget relationship
  1.2348 +    nsWidgetInitData initData;
  1.2349 +    nsWidgetInitData* initDataPtr;
  1.2350 +    if (!mParentWidget) {
  1.2351 +      initDataPtr = &initData;
  1.2352 +      initData.mWindowType = eWindowType_invisible;
  1.2353 +    } else {
  1.2354 +      initDataPtr = nullptr;
  1.2355 +    }
  1.2356 +
  1.2357 +    if (shouldAttach) {
  1.2358 +      // Reuse the top level parent widget.
  1.2359 +      rv = view->AttachToTopLevelWidget(mParentWidget);
  1.2360 +      mAttachedToParent = true;
  1.2361 +    }
  1.2362 +    else if (!aContainerView && mParentWidget) {
  1.2363 +      rv = view->CreateWidgetForParent(mParentWidget, initDataPtr,
  1.2364 +                                       true, false);
  1.2365 +    }
  1.2366 +    else {
  1.2367 +      rv = view->CreateWidget(initDataPtr, true, false);
  1.2368 +    }
  1.2369 +    if (NS_FAILED(rv))
  1.2370 +      return rv;
  1.2371 +  }
  1.2372 +
  1.2373 +  // Setup hierarchical relationship in view manager
  1.2374 +  mViewManager->SetRootView(view);
  1.2375 +
  1.2376 +  mWindow = view->GetWidget();
  1.2377 +
  1.2378 +  // This SetFocus is necessary so the Arrow Key and Page Key events
  1.2379 +  // go to the scrolled view as soon as the Window is created instead of going to
  1.2380 +  // the browser window (this enables keyboard scrolling of the document)
  1.2381 +  // mWindow->SetFocus();
  1.2382 +
  1.2383 +  return rv;
  1.2384 +}
  1.2385 +
  1.2386 +void
  1.2387 +nsDocumentViewer::DetachFromTopLevelWidget()
  1.2388 +{
  1.2389 +  if (mViewManager) {
  1.2390 +    nsView* oldView = mViewManager->GetRootView();
  1.2391 +    if (oldView && oldView->IsAttachedToTopLevel()) {
  1.2392 +      oldView->DetachFromTopLevelWidget();
  1.2393 +    }
  1.2394 +  }
  1.2395 +  mAttachedToParent = false;
  1.2396 +}
  1.2397 +
  1.2398 +nsView*
  1.2399 +nsDocumentViewer::FindContainerView()
  1.2400 +{
  1.2401 +  nsView* containerView = nullptr;
  1.2402 +
  1.2403 +  if (mContainer) {
  1.2404 +    nsCOMPtr<nsIDocShellTreeItem> docShellItem(mContainer);
  1.2405 +    nsCOMPtr<nsPIDOMWindow> pwin(do_GetInterface(docShellItem));
  1.2406 +    if (pwin) {
  1.2407 +      nsCOMPtr<nsIContent> containerElement = do_QueryInterface(pwin->GetFrameElementInternal());
  1.2408 +      if (!containerElement) {
  1.2409 +        return nullptr;
  1.2410 +      }
  1.2411 +      nsCOMPtr<nsIPresShell> parentPresShell;
  1.2412 +      if (docShellItem) {
  1.2413 +        nsCOMPtr<nsIDocShellTreeItem> parentDocShellItem;
  1.2414 +        docShellItem->GetParent(getter_AddRefs(parentDocShellItem));
  1.2415 +        if (parentDocShellItem) {
  1.2416 +          nsCOMPtr<nsIDocShell> parentDocShell = do_QueryInterface(parentDocShellItem);
  1.2417 +          parentPresShell = parentDocShell->GetPresShell();
  1.2418 +        }
  1.2419 +      }
  1.2420 +      if (!parentPresShell) {
  1.2421 +        nsCOMPtr<nsIDocument> parentDoc = containerElement->GetCurrentDoc();
  1.2422 +        if (parentDoc) {
  1.2423 +          parentPresShell = parentDoc->GetShell();
  1.2424 +        }
  1.2425 +      }
  1.2426 +      if (!parentPresShell) {
  1.2427 +        NS_WARNING("Subdocument container has no presshell");
  1.2428 +      } else {
  1.2429 +        nsIFrame* f = parentPresShell->GetRealPrimaryFrameFor(containerElement);
  1.2430 +        if (f) {
  1.2431 +          nsIFrame* subdocFrame = f->GetContentInsertionFrame();
  1.2432 +          // subdocFrame might not be a subdocument frame; the frame
  1.2433 +          // constructor can treat a <frame> as an inline in some XBL
  1.2434 +          // cases. Treat that as display:none, the document is not
  1.2435 +          // displayed.
  1.2436 +          if (subdocFrame->GetType() == nsGkAtoms::subDocumentFrame) {
  1.2437 +            NS_ASSERTION(subdocFrame->GetView(), "Subdoc frames must have views");
  1.2438 +            nsView* innerView =
  1.2439 +              static_cast<nsSubDocumentFrame*>(subdocFrame)->EnsureInnerView();
  1.2440 +            containerView = innerView;
  1.2441 +          } else {
  1.2442 +            NS_WARNING("Subdocument container has non-subdocument frame");
  1.2443 +          }
  1.2444 +        } else {
  1.2445 +          NS_WARNING("Subdocument container has no frame");
  1.2446 +        }
  1.2447 +      }
  1.2448 +    }
  1.2449 +  }
  1.2450 +
  1.2451 +  return containerView;
  1.2452 +}
  1.2453 +
  1.2454 +nsresult
  1.2455 +nsDocumentViewer::CreateDeviceContext(nsView* aContainerView)
  1.2456 +{
  1.2457 +  NS_PRECONDITION(!mPresShell && !mWindow,
  1.2458 +                  "This will screw up our existing presentation");
  1.2459 +  NS_PRECONDITION(mDocument, "Gotta have a document here");
  1.2460 +  
  1.2461 +  nsIDocument* doc = mDocument->GetDisplayDocument();
  1.2462 +  if (doc) {
  1.2463 +    NS_ASSERTION(!aContainerView, "External resource document embedded somewhere?");
  1.2464 +    // We want to use our display document's device context if possible
  1.2465 +    nsIPresShell* shell = doc->GetShell();
  1.2466 +    if (shell) {
  1.2467 +      nsPresContext* ctx = shell->GetPresContext();
  1.2468 +      if (ctx) {
  1.2469 +        mDeviceContext = ctx->DeviceContext();
  1.2470 +        return NS_OK;
  1.2471 +      }
  1.2472 +    }
  1.2473 +  }
  1.2474 +  
  1.2475 +  // Create a device context even if we already have one, since our widget
  1.2476 +  // might have changed.
  1.2477 +  nsIWidget* widget = nullptr;
  1.2478 +  if (aContainerView) {
  1.2479 +    widget = aContainerView->GetNearestWidget(nullptr);
  1.2480 +  }
  1.2481 +  if (!widget) {
  1.2482 +    widget = mParentWidget;
  1.2483 +  }
  1.2484 +  if (widget) {
  1.2485 +    widget = widget->GetTopLevelWidget();
  1.2486 +  }
  1.2487 +
  1.2488 +  mDeviceContext = new nsDeviceContext();
  1.2489 +  mDeviceContext->Init(widget);
  1.2490 +  return NS_OK;
  1.2491 +}
  1.2492 +
  1.2493 +// Return the selection for the document. Note that text fields have their
  1.2494 +// own selection, which cannot be accessed with this method.
  1.2495 +nsresult nsDocumentViewer::GetDocumentSelection(nsISelection **aSelection)
  1.2496 +{
  1.2497 +  NS_ENSURE_ARG_POINTER(aSelection);
  1.2498 +  if (!mPresShell) {
  1.2499 +    return NS_ERROR_NOT_INITIALIZED;
  1.2500 +  }
  1.2501 +
  1.2502 +  nsCOMPtr<nsISelectionController> selcon;
  1.2503 +  selcon = do_QueryInterface(mPresShell);
  1.2504 +  if (selcon)
  1.2505 +    return selcon->GetSelection(nsISelectionController::SELECTION_NORMAL,
  1.2506 +                                aSelection);
  1.2507 +  return NS_ERROR_FAILURE;
  1.2508 +}
  1.2509 +
  1.2510 +/* ========================================================================================
  1.2511 + * nsIContentViewerEdit
  1.2512 + * ======================================================================================== */
  1.2513 +
  1.2514 +NS_IMETHODIMP nsDocumentViewer::ClearSelection()
  1.2515 +{
  1.2516 +  nsresult rv;
  1.2517 +  nsCOMPtr<nsISelection> selection;
  1.2518 +
  1.2519 +  // use nsCopySupport::GetSelectionForCopy() ?
  1.2520 +  rv = GetDocumentSelection(getter_AddRefs(selection));
  1.2521 +  if (NS_FAILED(rv)) return rv;
  1.2522 +
  1.2523 +  return selection->CollapseToStart();
  1.2524 +}
  1.2525 +
  1.2526 +NS_IMETHODIMP nsDocumentViewer::SelectAll()
  1.2527 +{
  1.2528 +  // XXX this is a temporary implementation copied from nsWebShell
  1.2529 +  // for now. I think nsDocument and friends should have some helper
  1.2530 +  // functions to make this easier.
  1.2531 +  nsCOMPtr<nsISelection> selection;
  1.2532 +  nsresult rv;
  1.2533 +
  1.2534 +  // use nsCopySupport::GetSelectionForCopy() ?
  1.2535 +  rv = GetDocumentSelection(getter_AddRefs(selection));
  1.2536 +  if (NS_FAILED(rv)) return rv;
  1.2537 +
  1.2538 +  nsCOMPtr<nsIDOMHTMLDocument> htmldoc = do_QueryInterface(mDocument);
  1.2539 +  nsCOMPtr<nsIDOMNode> bodyNode;
  1.2540 +
  1.2541 +  if (htmldoc)
  1.2542 +  {
  1.2543 +    nsCOMPtr<nsIDOMHTMLElement>bodyElement;
  1.2544 +    rv = htmldoc->GetBody(getter_AddRefs(bodyElement));
  1.2545 +    if (NS_FAILED(rv) || !bodyElement) return rv;
  1.2546 +
  1.2547 +    bodyNode = do_QueryInterface(bodyElement);
  1.2548 +  }
  1.2549 +  else if (mDocument)
  1.2550 +  {
  1.2551 +    bodyNode = do_QueryInterface(mDocument->GetRootElement());
  1.2552 +  }
  1.2553 +  if (!bodyNode) return NS_ERROR_FAILURE;
  1.2554 +
  1.2555 +  rv = selection->RemoveAllRanges();
  1.2556 +  if (NS_FAILED(rv)) return rv;
  1.2557 +
  1.2558 +  rv = selection->SelectAllChildren(bodyNode);
  1.2559 +  return rv;
  1.2560 +}
  1.2561 +
  1.2562 +NS_IMETHODIMP nsDocumentViewer::CopySelection()
  1.2563 +{
  1.2564 +  nsCopySupport::FireClipboardEvent(NS_COPY, nsIClipboard::kGlobalClipboard, mPresShell, nullptr);
  1.2565 +  return NS_OK;
  1.2566 +}
  1.2567 +
  1.2568 +NS_IMETHODIMP nsDocumentViewer::CopyLinkLocation()
  1.2569 +{
  1.2570 +  NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);
  1.2571 +  nsCOMPtr<nsIDOMNode> node;
  1.2572 +  GetPopupLinkNode(getter_AddRefs(node));
  1.2573 +  // make noise if we're not in a link
  1.2574 +  NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
  1.2575 +
  1.2576 +  nsCOMPtr<dom::Element> elm(do_QueryInterface(node));
  1.2577 +  NS_ENSURE_TRUE(elm, NS_ERROR_FAILURE);
  1.2578 +
  1.2579 +  nsAutoString locationText;
  1.2580 +  nsContentUtils::GetLinkLocation(elm, locationText);
  1.2581 +  if (locationText.IsEmpty())
  1.2582 +    return NS_ERROR_FAILURE;
  1.2583 +
  1.2584 +  nsresult rv = NS_OK;
  1.2585 +  nsCOMPtr<nsIClipboardHelper> clipboard(do_GetService("@mozilla.org/widget/clipboardhelper;1", &rv));
  1.2586 +  NS_ENSURE_SUCCESS(rv, rv);
  1.2587 +
  1.2588 +  // copy the href onto the clipboard
  1.2589 +  nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(mDocument);
  1.2590 +  return clipboard->CopyString(locationText, doc);
  1.2591 +}
  1.2592 +
  1.2593 +NS_IMETHODIMP nsDocumentViewer::CopyImage(int32_t aCopyFlags)
  1.2594 +{
  1.2595 +  NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);
  1.2596 +  nsCOMPtr<nsIImageLoadingContent> node;
  1.2597 +  GetPopupImageNode(getter_AddRefs(node));
  1.2598 +  // make noise if we're not in an image
  1.2599 +  NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
  1.2600 +
  1.2601 +  nsCOMPtr<nsILoadContext> loadContext(mContainer);
  1.2602 +  return nsCopySupport::ImageCopy(node, loadContext, aCopyFlags);
  1.2603 +}
  1.2604 +
  1.2605 +
  1.2606 +NS_IMETHODIMP nsDocumentViewer::GetCopyable(bool *aCopyable)
  1.2607 +{
  1.2608 +  NS_ENSURE_ARG_POINTER(aCopyable);
  1.2609 +  *aCopyable = nsCopySupport::CanCopy(mDocument);
  1.2610 +  return NS_OK;
  1.2611 +}
  1.2612 +
  1.2613 +/* AString getContents (in string mimeType, in boolean selectionOnly); */
  1.2614 +NS_IMETHODIMP nsDocumentViewer::GetContents(const char *mimeType, bool selectionOnly, nsAString& aOutValue)
  1.2615 +{
  1.2616 +  aOutValue.Truncate();
  1.2617 +
  1.2618 +  NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);
  1.2619 +  NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_INITIALIZED);
  1.2620 +
  1.2621 +  // Now we have the selection.  Make sure it's nonzero:
  1.2622 +  nsCOMPtr<nsISelection> sel;
  1.2623 +  if (selectionOnly) {
  1.2624 +    nsCopySupport::GetSelectionForCopy(mDocument, getter_AddRefs(sel));
  1.2625 +    NS_ENSURE_TRUE(sel, NS_ERROR_FAILURE);
  1.2626 +  
  1.2627 +    bool isCollapsed;
  1.2628 +    sel->GetIsCollapsed(&isCollapsed);
  1.2629 +    if (isCollapsed)
  1.2630 +      return NS_OK;
  1.2631 +  }
  1.2632 +
  1.2633 +  // call the copy code
  1.2634 +  return nsCopySupport::GetContents(nsDependentCString(mimeType), 0, sel,
  1.2635 +                                    mDocument, aOutValue);
  1.2636 +}
  1.2637 +
  1.2638 +/* readonly attribute boolean canGetContents; */
  1.2639 +NS_IMETHODIMP nsDocumentViewer::GetCanGetContents(bool *aCanGetContents)
  1.2640 +{
  1.2641 +  NS_ENSURE_ARG_POINTER(aCanGetContents);
  1.2642 +  *aCanGetContents = false;
  1.2643 +  NS_ENSURE_STATE(mDocument);
  1.2644 +  *aCanGetContents = nsCopySupport::CanCopy(mDocument);
  1.2645 +  return NS_OK;
  1.2646 +}
  1.2647 +
  1.2648 +
  1.2649 +/* ========================================================================================
  1.2650 + * nsIContentViewerFile
  1.2651 + * ======================================================================================== */
  1.2652 +/** ---------------------------------------------------
  1.2653 + *  See documentation above in the nsIContentViewerfile class definition
  1.2654 + *	@update 01/24/00 dwc
  1.2655 + */
  1.2656 +NS_IMETHODIMP
  1.2657 +nsDocumentViewer::Print(bool              aSilent,
  1.2658 +                          FILE *            aDebugFile,
  1.2659 +                          nsIPrintSettings* aPrintSettings)
  1.2660 +{
  1.2661 +#ifdef NS_PRINTING
  1.2662 +  nsCOMPtr<nsIPrintSettings> printSettings;
  1.2663 +
  1.2664 +#ifdef DEBUG
  1.2665 +  nsresult rv = NS_ERROR_FAILURE;
  1.2666 +
  1.2667 +  mDebugFile = aDebugFile;
  1.2668 +  // if they don't pass in a PrintSettings, then make one
  1.2669 +  // it will have all the default values
  1.2670 +  printSettings = aPrintSettings;
  1.2671 +  nsCOMPtr<nsIPrintOptions> printOptions = do_GetService(sPrintOptionsContractID, &rv);
  1.2672 +  if (NS_SUCCEEDED(rv)) {
  1.2673 +    // if they don't pass in a PrintSettings, then make one
  1.2674 +    if (printSettings == nullptr) {
  1.2675 +      printOptions->CreatePrintSettings(getter_AddRefs(printSettings));
  1.2676 +    }
  1.2677 +    NS_ASSERTION(printSettings, "You can't PrintPreview without a PrintSettings!");
  1.2678 +  }
  1.2679 +  if (printSettings) printSettings->SetPrintSilent(aSilent);
  1.2680 +  if (printSettings) printSettings->SetShowPrintProgress(false);
  1.2681 +#endif
  1.2682 +
  1.2683 +
  1.2684 +  return Print(printSettings, nullptr);
  1.2685 +#else
  1.2686 +  return NS_ERROR_FAILURE;
  1.2687 +#endif
  1.2688 +}
  1.2689 +
  1.2690 +// nsIContentViewerFile interface
  1.2691 +NS_IMETHODIMP
  1.2692 +nsDocumentViewer::GetPrintable(bool *aPrintable)
  1.2693 +{
  1.2694 +  NS_ENSURE_ARG_POINTER(aPrintable);
  1.2695 +
  1.2696 +  *aPrintable = !GetIsPrinting();
  1.2697 +
  1.2698 +  return NS_OK;
  1.2699 +}
  1.2700 +
  1.2701 +//*****************************************************************************
  1.2702 +// nsIMarkupDocumentViewer
  1.2703 +//*****************************************************************************
  1.2704 +
  1.2705 +NS_IMETHODIMP nsDocumentViewer::ScrollToNode(nsIDOMNode* aNode)
  1.2706 +{
  1.2707 +  NS_ENSURE_ARG(aNode);
  1.2708 +  NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
  1.2709 +  nsCOMPtr<nsIPresShell> presShell;
  1.2710 +  NS_ENSURE_SUCCESS(GetPresShell(getter_AddRefs(presShell)), NS_ERROR_FAILURE);
  1.2711 +
  1.2712 +  // Get the nsIContent interface, because that's what we need to
  1.2713 +  // get the primary frame
  1.2714 +
  1.2715 +  nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
  1.2716 +  NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
  1.2717 +
  1.2718 +  // Tell the PresShell to scroll to the primary frame of the content.
  1.2719 +  NS_ENSURE_SUCCESS(
  1.2720 +    presShell->ScrollContentIntoView(content,
  1.2721 +                                     nsIPresShell::ScrollAxis(
  1.2722 +                                       nsIPresShell::SCROLL_TOP,
  1.2723 +                                       nsIPresShell::SCROLL_ALWAYS),
  1.2724 +                                     nsIPresShell::ScrollAxis(),
  1.2725 +                                     nsIPresShell::SCROLL_OVERFLOW_HIDDEN),
  1.2726 +    NS_ERROR_FAILURE);
  1.2727 +  return NS_OK;
  1.2728 +}
  1.2729 +
  1.2730 +void
  1.2731 +nsDocumentViewer::CallChildren(CallChildFunc aFunc, void* aClosure)
  1.2732 +{
  1.2733 +  nsCOMPtr<nsIDocShell> docShell(mContainer);
  1.2734 +  if (docShell)
  1.2735 +  {
  1.2736 +    int32_t i;
  1.2737 +    int32_t n;
  1.2738 +    docShell->GetChildCount(&n);
  1.2739 +    for (i=0; i < n; i++)
  1.2740 +    {
  1.2741 +      nsCOMPtr<nsIDocShellTreeItem> child;
  1.2742 +      docShell->GetChildAt(i, getter_AddRefs(child));
  1.2743 +      nsCOMPtr<nsIDocShell> childAsShell(do_QueryInterface(child));
  1.2744 +      NS_ASSERTION(childAsShell, "null child in docshell");
  1.2745 +      if (childAsShell)
  1.2746 +      {
  1.2747 +        nsCOMPtr<nsIContentViewer> childCV;
  1.2748 +        childAsShell->GetContentViewer(getter_AddRefs(childCV));
  1.2749 +        if (childCV)
  1.2750 +        {
  1.2751 +          nsCOMPtr<nsIMarkupDocumentViewer> markupCV = do_QueryInterface(childCV);
  1.2752 +          if (markupCV) {
  1.2753 +            (*aFunc)(markupCV, aClosure);
  1.2754 +          }
  1.2755 +        }
  1.2756 +      }
  1.2757 +    }
  1.2758 +  }
  1.2759 +}
  1.2760 +
  1.2761 +struct LineBoxInfo
  1.2762 +{
  1.2763 +  nscoord mMaxLineBoxWidth;
  1.2764 +};
  1.2765 +
  1.2766 +static void
  1.2767 +ChangeChildPaintingEnabled(nsIMarkupDocumentViewer* aChild, void* aClosure)
  1.2768 +{
  1.2769 +  bool* enablePainting = (bool*) aClosure;
  1.2770 +  if (*enablePainting) {
  1.2771 +    aChild->ResumePainting();
  1.2772 +  } else {
  1.2773 +    aChild->PausePainting();
  1.2774 +  }
  1.2775 +}
  1.2776 +
  1.2777 +static void
  1.2778 +ChangeChildMaxLineBoxWidth(nsIMarkupDocumentViewer* aChild, void* aClosure)
  1.2779 +{
  1.2780 +  struct LineBoxInfo* lbi = (struct LineBoxInfo*) aClosure;
  1.2781 +  aChild->ChangeMaxLineBoxWidth(lbi->mMaxLineBoxWidth);
  1.2782 +}
  1.2783 +
  1.2784 +struct ZoomInfo
  1.2785 +{
  1.2786 +  float mZoom;
  1.2787 +};
  1.2788 +
  1.2789 +static void
  1.2790 +SetChildTextZoom(nsIMarkupDocumentViewer* aChild, void* aClosure)
  1.2791 +{
  1.2792 +  struct ZoomInfo* ZoomInfo = (struct ZoomInfo*) aClosure;
  1.2793 +  aChild->SetTextZoom(ZoomInfo->mZoom);
  1.2794 +}
  1.2795 +
  1.2796 +static void
  1.2797 +SetChildMinFontSize(nsIMarkupDocumentViewer* aChild, void* aClosure)
  1.2798 +{
  1.2799 +  nsCOMPtr<nsIMarkupDocumentViewer> branch =
  1.2800 +    do_QueryInterface(aChild);
  1.2801 +  branch->SetMinFontSize(NS_PTR_TO_INT32(aClosure));
  1.2802 +}
  1.2803 +
  1.2804 +static void
  1.2805 +SetChildFullZoom(nsIMarkupDocumentViewer* aChild, void* aClosure)
  1.2806 +{
  1.2807 +  struct ZoomInfo* ZoomInfo = (struct ZoomInfo*) aClosure;
  1.2808 +  aChild->SetFullZoom(ZoomInfo->mZoom);
  1.2809 +}
  1.2810 +
  1.2811 +static bool
  1.2812 +SetExtResourceTextZoom(nsIDocument* aDocument, void* aClosure)
  1.2813 +{
  1.2814 +  // Would it be better to enumerate external resource viewers instead?
  1.2815 +  nsIPresShell* shell = aDocument->GetShell();
  1.2816 +  if (shell) {
  1.2817 +    nsPresContext* ctxt = shell->GetPresContext();
  1.2818 +    if (ctxt) {
  1.2819 +      struct ZoomInfo* ZoomInfo = static_cast<struct ZoomInfo*>(aClosure);
  1.2820 +      ctxt->SetTextZoom(ZoomInfo->mZoom);
  1.2821 +    }
  1.2822 +  }
  1.2823 +
  1.2824 +  return true;
  1.2825 +}
  1.2826 +
  1.2827 +static bool
  1.2828 +SetExtResourceMinFontSize(nsIDocument* aDocument, void* aClosure)
  1.2829 +{
  1.2830 +  nsIPresShell* shell = aDocument->GetShell();
  1.2831 +  if (shell) {
  1.2832 +    nsPresContext* ctxt = shell->GetPresContext();
  1.2833 +    if (ctxt) {
  1.2834 +      ctxt->SetBaseMinFontSize(NS_PTR_TO_INT32(aClosure));
  1.2835 +    }
  1.2836 +  }
  1.2837 +
  1.2838 +  return true;
  1.2839 +}
  1.2840 +
  1.2841 +static bool
  1.2842 +SetExtResourceFullZoom(nsIDocument* aDocument, void* aClosure)
  1.2843 +{
  1.2844 +  // Would it be better to enumerate external resource viewers instead?
  1.2845 +  nsIPresShell* shell = aDocument->GetShell();
  1.2846 +  if (shell) {
  1.2847 +    nsPresContext* ctxt = shell->GetPresContext();
  1.2848 +    if (ctxt) {
  1.2849 +      struct ZoomInfo* ZoomInfo = static_cast<struct ZoomInfo*>(aClosure);
  1.2850 +      ctxt->SetFullZoom(ZoomInfo->mZoom);
  1.2851 +    }
  1.2852 +  }
  1.2853 +
  1.2854 +  return true;
  1.2855 +}
  1.2856 +
  1.2857 +NS_IMETHODIMP
  1.2858 +nsDocumentViewer::SetTextZoom(float aTextZoom)
  1.2859 +{
  1.2860 +  // If we don't have a document, then we need to bail.
  1.2861 +  if (!mDocument) {
  1.2862 +    return NS_ERROR_FAILURE;
  1.2863 +  }
  1.2864 +
  1.2865 +  if (GetIsPrintPreview()) {
  1.2866 +    return NS_OK;
  1.2867 +  }
  1.2868 +
  1.2869 +  mTextZoom = aTextZoom;
  1.2870 +
  1.2871 +  // Set the text zoom on all children of mContainer (even if our zoom didn't
  1.2872 +  // change, our children's zoom may be different, though it would be unusual).
  1.2873 +  // Do this first, in case kids are auto-sizing and post reflow commands on
  1.2874 +  // our presshell (which should be subsumed into our own style change reflow).
  1.2875 +  struct ZoomInfo ZoomInfo = { aTextZoom };
  1.2876 +  CallChildren(SetChildTextZoom, &ZoomInfo);
  1.2877 +
  1.2878 +  // Now change our own zoom
  1.2879 +  nsPresContext* pc = GetPresContext();
  1.2880 +  if (pc && aTextZoom != mPresContext->TextZoom()) {
  1.2881 +      pc->SetTextZoom(aTextZoom);
  1.2882 +  }
  1.2883 +
  1.2884 +  // And do the external resources
  1.2885 +  mDocument->EnumerateExternalResources(SetExtResourceTextZoom, &ZoomInfo);
  1.2886 +
  1.2887 +  nsContentUtils::DispatchChromeEvent(mDocument, static_cast<nsIDocument*>(mDocument),
  1.2888 +                                      NS_LITERAL_STRING("TextZoomChange"),
  1.2889 +                                      true, true);
  1.2890 +
  1.2891 +  return NS_OK;
  1.2892 +}
  1.2893 +
  1.2894 +NS_IMETHODIMP
  1.2895 +nsDocumentViewer::GetTextZoom(float* aTextZoom)
  1.2896 +{
  1.2897 +  NS_ENSURE_ARG_POINTER(aTextZoom);
  1.2898 +  nsPresContext* pc = GetPresContext();
  1.2899 +  *aTextZoom = pc ? pc->TextZoom() : 1.0f;
  1.2900 +  return NS_OK;
  1.2901 +}
  1.2902 +
  1.2903 +NS_IMETHODIMP
  1.2904 +nsDocumentViewer::SetMinFontSize(int32_t aMinFontSize)
  1.2905 +{
  1.2906 +  // If we don't have a document, then we need to bail.
  1.2907 +  if (!mDocument) {
  1.2908 +    return NS_ERROR_FAILURE;
  1.2909 +  }
  1.2910 +
  1.2911 +  if (GetIsPrintPreview()) {
  1.2912 +    return NS_OK;
  1.2913 +  }
  1.2914 +
  1.2915 +  mMinFontSize = aMinFontSize;
  1.2916 +
  1.2917 +  // Set the min font on all children of mContainer (even if our min font didn't
  1.2918 +  // change, our children's min font may be different, though it would be unusual).
  1.2919 +  // Do this first, in case kids are auto-sizing and post reflow commands on
  1.2920 +  // our presshell (which should be subsumed into our own style change reflow).
  1.2921 +  CallChildren(SetChildMinFontSize, NS_INT32_TO_PTR(aMinFontSize));
  1.2922 +
  1.2923 +  // Now change our own min font
  1.2924 +  nsPresContext* pc = GetPresContext();
  1.2925 +  if (pc && aMinFontSize != mPresContext->MinFontSize(nullptr)) {
  1.2926 +    pc->SetBaseMinFontSize(aMinFontSize);
  1.2927 +  }
  1.2928 +
  1.2929 +  // And do the external resources
  1.2930 +  mDocument->EnumerateExternalResources(SetExtResourceMinFontSize,
  1.2931 +                                        NS_INT32_TO_PTR(aMinFontSize));
  1.2932 +
  1.2933 +  return NS_OK;
  1.2934 +}
  1.2935 +
  1.2936 +NS_IMETHODIMP
  1.2937 +nsDocumentViewer::GetMinFontSize(int32_t* aMinFontSize)
  1.2938 +{
  1.2939 +  NS_ENSURE_ARG_POINTER(aMinFontSize);
  1.2940 +  nsPresContext* pc = GetPresContext();
  1.2941 +  *aMinFontSize = pc ? pc->BaseMinFontSize() : 0;
  1.2942 +  return NS_OK;
  1.2943 +}
  1.2944 +
  1.2945 +NS_IMETHODIMP
  1.2946 +nsDocumentViewer::SetFullZoom(float aFullZoom)
  1.2947 +{
  1.2948 +#ifdef NS_PRINT_PREVIEW
  1.2949 +  if (GetIsPrintPreview()) {
  1.2950 +    nsPresContext* pc = GetPresContext();
  1.2951 +    NS_ENSURE_TRUE(pc, NS_OK);
  1.2952 +    nsCOMPtr<nsIPresShell> shell = pc->GetPresShell();
  1.2953 +    NS_ENSURE_TRUE(shell, NS_OK);
  1.2954 +
  1.2955 +    if (!mPrintPreviewZoomed) {
  1.2956 +      mOriginalPrintPreviewScale = pc->GetPrintPreviewScale();
  1.2957 +      mPrintPreviewZoomed = true;
  1.2958 +    }
  1.2959 +
  1.2960 +    mPrintPreviewZoom = aFullZoom;
  1.2961 +    pc->SetPrintPreviewScale(aFullZoom * mOriginalPrintPreviewScale);
  1.2962 +    nsIPageSequenceFrame* pf = shell->GetPageSequenceFrame();
  1.2963 +    if (pf) {
  1.2964 +      nsIFrame* f = do_QueryFrame(pf);
  1.2965 +      shell->FrameNeedsReflow(f, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
  1.2966 +    }
  1.2967 +
  1.2968 +    nsIFrame* rootFrame = shell->GetRootFrame();
  1.2969 +    if (rootFrame) {
  1.2970 +      rootFrame->InvalidateFrame();
  1.2971 +    }
  1.2972 +    return NS_OK;
  1.2973 +  }
  1.2974 +#endif
  1.2975 +
  1.2976 +  // If we don't have a document, then we need to bail.
  1.2977 +  if (!mDocument) {
  1.2978 +    return NS_ERROR_FAILURE;
  1.2979 +  }
  1.2980 +
  1.2981 +  mPageZoom = aFullZoom;
  1.2982 +
  1.2983 +  struct ZoomInfo ZoomInfo = { aFullZoom };
  1.2984 +  CallChildren(SetChildFullZoom, &ZoomInfo);
  1.2985 +
  1.2986 +  nsPresContext* pc = GetPresContext();
  1.2987 +  if (pc) {
  1.2988 +    pc->SetFullZoom(aFullZoom);
  1.2989 +  }
  1.2990 +
  1.2991 +  // And do the external resources
  1.2992 +  mDocument->EnumerateExternalResources(SetExtResourceFullZoom, &ZoomInfo);
  1.2993 +
  1.2994 +  nsContentUtils::DispatchChromeEvent(mDocument, static_cast<nsIDocument*>(mDocument),
  1.2995 +                                      NS_LITERAL_STRING("FullZoomChange"),
  1.2996 +                                      true, true);
  1.2997 +
  1.2998 +  return NS_OK;
  1.2999 +}
  1.3000 +
  1.3001 +NS_IMETHODIMP
  1.3002 +nsDocumentViewer::GetFullZoom(float* aFullZoom)
  1.3003 +{
  1.3004 +  NS_ENSURE_ARG_POINTER(aFullZoom);
  1.3005 +#ifdef NS_PRINT_PREVIEW
  1.3006 +  if (GetIsPrintPreview()) {
  1.3007 +    *aFullZoom = mPrintPreviewZoom;
  1.3008 +    return NS_OK;
  1.3009 +  }
  1.3010 +#endif
  1.3011 +  // Check the prescontext first because it might have a temporary
  1.3012 +  // setting for print-preview
  1.3013 +  nsPresContext* pc = GetPresContext();
  1.3014 +  *aFullZoom = pc ? pc->GetFullZoom() : mPageZoom;
  1.3015 +  return NS_OK;
  1.3016 +}
  1.3017 +
  1.3018 +static void
  1.3019 +SetChildAuthorStyleDisabled(nsIMarkupDocumentViewer* aChild, void* aClosure)
  1.3020 +{
  1.3021 +  bool styleDisabled  = *static_cast<bool*>(aClosure);
  1.3022 +  aChild->SetAuthorStyleDisabled(styleDisabled);
  1.3023 +}
  1.3024 +
  1.3025 +
  1.3026 +NS_IMETHODIMP
  1.3027 +nsDocumentViewer::SetAuthorStyleDisabled(bool aStyleDisabled)
  1.3028 +{
  1.3029 +  if (mPresShell) {
  1.3030 +    mPresShell->SetAuthorStyleDisabled(aStyleDisabled);
  1.3031 +  }
  1.3032 +  CallChildren(SetChildAuthorStyleDisabled, &aStyleDisabled);
  1.3033 +  return NS_OK;
  1.3034 +}
  1.3035 +
  1.3036 +NS_IMETHODIMP
  1.3037 +nsDocumentViewer::GetAuthorStyleDisabled(bool* aStyleDisabled)
  1.3038 +{
  1.3039 +  if (mPresShell) {
  1.3040 +    *aStyleDisabled = mPresShell->GetAuthorStyleDisabled();
  1.3041 +  } else {
  1.3042 +    *aStyleDisabled = false;
  1.3043 +  }
  1.3044 +  return NS_OK;
  1.3045 +}
  1.3046 +
  1.3047 +static bool
  1.3048 +ExtResourceEmulateMedium(nsIDocument* aDocument, void* aClosure)
  1.3049 +{
  1.3050 +  nsIPresShell* shell = aDocument->GetShell();
  1.3051 +  if (shell) {
  1.3052 +    nsPresContext* ctxt = shell->GetPresContext();
  1.3053 +    if (ctxt) {
  1.3054 +      const nsAString* mediaType = static_cast<nsAString*>(aClosure);
  1.3055 +      ctxt->EmulateMedium(*mediaType);
  1.3056 +    }
  1.3057 +  }
  1.3058 +
  1.3059 +  return true;
  1.3060 +}
  1.3061 +
  1.3062 +static void
  1.3063 +ChildEmulateMedium(nsIMarkupDocumentViewer* aChild, void* aClosure)
  1.3064 +{
  1.3065 +  const nsAString* mediaType = static_cast<nsAString*>(aClosure);
  1.3066 +  aChild->EmulateMedium(*mediaType);
  1.3067 +}
  1.3068 +
  1.3069 +NS_IMETHODIMP
  1.3070 +nsDocumentViewer::EmulateMedium(const nsAString& aMediaType)
  1.3071 +{
  1.3072 +  if (mPresContext) {
  1.3073 +    mPresContext->EmulateMedium(aMediaType);
  1.3074 +  }
  1.3075 +  CallChildren(ChildEmulateMedium, const_cast<nsAString*>(&aMediaType));
  1.3076 +
  1.3077 +  if (mDocument) {
  1.3078 +    mDocument->EnumerateExternalResources(ExtResourceEmulateMedium,
  1.3079 +                                          const_cast<nsAString*>(&aMediaType));
  1.3080 +  }
  1.3081 +
  1.3082 +  return NS_OK;
  1.3083 +}
  1.3084 +
  1.3085 +static bool
  1.3086 +ExtResourceStopEmulatingMedium(nsIDocument* aDocument, void* aClosure)
  1.3087 +{
  1.3088 +  nsIPresShell* shell = aDocument->GetShell();
  1.3089 +  if (shell) {
  1.3090 +    nsPresContext* ctxt = shell->GetPresContext();
  1.3091 +    if (ctxt) {
  1.3092 +      ctxt->StopEmulatingMedium();
  1.3093 +    }
  1.3094 +  }
  1.3095 +
  1.3096 +  return true;
  1.3097 +}
  1.3098 +
  1.3099 +static void
  1.3100 +ChildStopEmulatingMedium(nsIMarkupDocumentViewer* aChild, void* aClosure)
  1.3101 +{
  1.3102 +  aChild->StopEmulatingMedium();
  1.3103 +}
  1.3104 +
  1.3105 +NS_IMETHODIMP
  1.3106 +nsDocumentViewer::StopEmulatingMedium()
  1.3107 +{
  1.3108 +  if (mPresContext) {
  1.3109 +    mPresContext->StopEmulatingMedium();
  1.3110 +  }
  1.3111 +  CallChildren(ChildStopEmulatingMedium, nullptr);
  1.3112 +
  1.3113 +  if (mDocument) {
  1.3114 +    mDocument->EnumerateExternalResources(ExtResourceStopEmulatingMedium,
  1.3115 +                                          nullptr);
  1.3116 +  }
  1.3117 +
  1.3118 +  return NS_OK;
  1.3119 +}
  1.3120 +
  1.3121 +NS_IMETHODIMP nsDocumentViewer::GetForceCharacterSet(nsACString& aForceCharacterSet)
  1.3122 +{
  1.3123 +  aForceCharacterSet = mForceCharacterSet;
  1.3124 +  return NS_OK;
  1.3125 +}
  1.3126 +
  1.3127 +static void
  1.3128 +SetChildForceCharacterSet(nsIMarkupDocumentViewer* aChild, void* aClosure)
  1.3129 +{
  1.3130 +  const nsACString* charset = static_cast<nsACString*>(aClosure);
  1.3131 +  aChild->SetForceCharacterSet(*charset);
  1.3132 +}
  1.3133 +
  1.3134 +NS_IMETHODIMP
  1.3135 +nsDocumentViewer::SetForceCharacterSet(const nsACString& aForceCharacterSet)
  1.3136 +{
  1.3137 +  mForceCharacterSet = aForceCharacterSet;
  1.3138 +  // now set the force char set on all children of mContainer
  1.3139 +  CallChildren(SetChildForceCharacterSet, (void*) &aForceCharacterSet);
  1.3140 +  return NS_OK;
  1.3141 +}
  1.3142 +
  1.3143 +NS_IMETHODIMP nsDocumentViewer::GetHintCharacterSet(nsACString& aHintCharacterSet)
  1.3144 +{
  1.3145 +
  1.3146 +  if(kCharsetUninitialized == mHintCharsetSource) {
  1.3147 +    aHintCharacterSet.Truncate();
  1.3148 +  } else {
  1.3149 +    aHintCharacterSet = mHintCharset;
  1.3150 +    // this can't possibly be right.  we can't set a value just because somebody got a related value!
  1.3151 +    //mHintCharsetSource = kCharsetUninitialized;
  1.3152 +  }
  1.3153 +  return NS_OK;
  1.3154 +}
  1.3155 +
  1.3156 +NS_IMETHODIMP nsDocumentViewer::GetHintCharacterSetSource(int32_t *aHintCharacterSetSource)
  1.3157 +{
  1.3158 +  NS_ENSURE_ARG_POINTER(aHintCharacterSetSource);
  1.3159 +
  1.3160 +  *aHintCharacterSetSource = mHintCharsetSource;
  1.3161 +  return NS_OK;
  1.3162 +}
  1.3163 +
  1.3164 +static void
  1.3165 +SetChildHintCharacterSetSource(nsIMarkupDocumentViewer* aChild, void* aClosure)
  1.3166 +{
  1.3167 +  aChild->SetHintCharacterSetSource(NS_PTR_TO_INT32(aClosure));
  1.3168 +}
  1.3169 +
  1.3170 +NS_IMETHODIMP
  1.3171 +nsDocumentViewer::SetHintCharacterSetSource(int32_t aHintCharacterSetSource)
  1.3172 +{
  1.3173 +  mHintCharsetSource = aHintCharacterSetSource;
  1.3174 +  // now set the hint char set source on all children of mContainer
  1.3175 +  CallChildren(SetChildHintCharacterSetSource,
  1.3176 +                      NS_INT32_TO_PTR(aHintCharacterSetSource));
  1.3177 +  return NS_OK;
  1.3178 +}
  1.3179 +
  1.3180 +static void
  1.3181 +SetChildHintCharacterSet(nsIMarkupDocumentViewer* aChild, void* aClosure)
  1.3182 +{
  1.3183 +  const nsACString* charset = static_cast<nsACString*>(aClosure);
  1.3184 +  aChild->SetHintCharacterSet(*charset);
  1.3185 +}
  1.3186 +
  1.3187 +NS_IMETHODIMP
  1.3188 +nsDocumentViewer::SetHintCharacterSet(const nsACString& aHintCharacterSet)
  1.3189 +{
  1.3190 +  mHintCharset = aHintCharacterSet;
  1.3191 +  // now set the hint char set on all children of mContainer
  1.3192 +  CallChildren(SetChildHintCharacterSet, (void*) &aHintCharacterSet);
  1.3193 +  return NS_OK;
  1.3194 +}
  1.3195 +
  1.3196 +static void
  1.3197 +AppendChildSubtree(nsIMarkupDocumentViewer* aChild, void* aClosure)
  1.3198 +{
  1.3199 +  nsTArray<nsCOMPtr<nsIMarkupDocumentViewer> >& array =
  1.3200 +    *static_cast<nsTArray<nsCOMPtr<nsIMarkupDocumentViewer> >*>(aClosure);
  1.3201 +  aChild->AppendSubtree(array);
  1.3202 +}
  1.3203 +
  1.3204 +NS_IMETHODIMP nsDocumentViewer::AppendSubtree(nsTArray<nsCOMPtr<nsIMarkupDocumentViewer> >& aArray)
  1.3205 +{
  1.3206 +  aArray.AppendElement(this);
  1.3207 +  CallChildren(AppendChildSubtree, &aArray);
  1.3208 +  return NS_OK;
  1.3209 +}
  1.3210 +
  1.3211 +NS_IMETHODIMP
  1.3212 +nsDocumentViewer::PausePainting()
  1.3213 +{
  1.3214 +  bool enablePaint = false;
  1.3215 +  CallChildren(ChangeChildPaintingEnabled, &enablePaint);
  1.3216 +
  1.3217 +  nsIPresShell* presShell = GetPresShell();
  1.3218 +  if (presShell) {
  1.3219 +    presShell->PausePainting();
  1.3220 +  }
  1.3221 +
  1.3222 +  return NS_OK;
  1.3223 +}
  1.3224 +
  1.3225 +NS_IMETHODIMP
  1.3226 +nsDocumentViewer::ResumePainting()
  1.3227 +{
  1.3228 +  bool enablePaint = true;
  1.3229 +  CallChildren(ChangeChildPaintingEnabled, &enablePaint);
  1.3230 +
  1.3231 +  nsIPresShell* presShell = GetPresShell();
  1.3232 +  if (presShell) {
  1.3233 +    presShell->ResumePainting();
  1.3234 +  }
  1.3235 +
  1.3236 +  return NS_OK;
  1.3237 +}
  1.3238 +
  1.3239 +NS_IMETHODIMP
  1.3240 +nsDocumentViewer::ChangeMaxLineBoxWidth(int32_t aMaxLineBoxWidth)
  1.3241 +{
  1.3242 +  // Change the max line box width for all children.
  1.3243 +  struct LineBoxInfo lbi = { aMaxLineBoxWidth };
  1.3244 +  CallChildren(ChangeChildMaxLineBoxWidth, &lbi);
  1.3245 +
  1.3246 +  // Now, change our max line box width.
  1.3247 +  // Convert to app units, since our input is in CSS pixels.
  1.3248 +  nscoord mlbw = nsPresContext::CSSPixelsToAppUnits(aMaxLineBoxWidth);
  1.3249 +  nsIPresShell* presShell = GetPresShell();
  1.3250 +  if (presShell) {
  1.3251 +    presShell->SetMaxLineBoxWidth(mlbw);
  1.3252 +  }
  1.3253 +
  1.3254 +  return NS_OK;
  1.3255 +}
  1.3256 +
  1.3257 +NS_IMETHODIMP
  1.3258 +nsDocumentViewer::GetContentSize(int32_t* aWidth, int32_t* aHeight)
  1.3259 +{
  1.3260 +   NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
  1.3261 +
  1.3262 +   // Skip doing this on docshell-less documents for now
  1.3263 +   nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(mContainer);
  1.3264 +   NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_NOT_AVAILABLE);
  1.3265 +   
  1.3266 +   nsCOMPtr<nsIDocShellTreeItem> docShellParent;
  1.3267 +   docShellAsItem->GetSameTypeParent(getter_AddRefs(docShellParent));
  1.3268 +
  1.3269 +   // It's only valid to access this from a top frame.  Doesn't work from
  1.3270 +   // sub-frames.
  1.3271 +   NS_ENSURE_TRUE(!docShellParent, NS_ERROR_FAILURE);
  1.3272 +
  1.3273 +   nsCOMPtr<nsIPresShell> presShell;
  1.3274 +   GetPresShell(getter_AddRefs(presShell));
  1.3275 +   NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
  1.3276 +
  1.3277 +   // Flush out all content and style updates. We can't use a resize reflow
  1.3278 +   // because it won't change some sizes that a style change reflow will.
  1.3279 +   mDocument->FlushPendingNotifications(Flush_Layout);
  1.3280 +
  1.3281 +  nsIFrame *root = presShell->GetRootFrame();
  1.3282 +  NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
  1.3283 +
  1.3284 +  nscoord prefWidth;
  1.3285 +  {
  1.3286 +    nsRefPtr<nsRenderingContext> rcx =
  1.3287 +      presShell->CreateReferenceRenderingContext();
  1.3288 +    prefWidth = root->GetPrefWidth(rcx);
  1.3289 +  }
  1.3290 +
  1.3291 +  nsresult rv = presShell->ResizeReflow(prefWidth, NS_UNCONSTRAINEDSIZE);
  1.3292 +  NS_ENSURE_SUCCESS(rv, rv);
  1.3293 +
  1.3294 +   nsRefPtr<nsPresContext> presContext;
  1.3295 +   GetPresContext(getter_AddRefs(presContext));
  1.3296 +   NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
  1.3297 +
  1.3298 +   // so how big is it?
  1.3299 +   nsRect shellArea = presContext->GetVisibleArea();
  1.3300 +   // Protect against bogus returns here
  1.3301 +   NS_ENSURE_TRUE(shellArea.width != NS_UNCONSTRAINEDSIZE &&
  1.3302 +                  shellArea.height != NS_UNCONSTRAINEDSIZE,
  1.3303 +                  NS_ERROR_FAILURE);
  1.3304 +
  1.3305 +   *aWidth = presContext->AppUnitsToDevPixels(shellArea.width);
  1.3306 +   *aHeight = presContext->AppUnitsToDevPixels(shellArea.height);
  1.3307 +
  1.3308 +   return NS_OK;
  1.3309 +}
  1.3310 +
  1.3311 +
  1.3312 +NS_IMPL_ISUPPORTS(nsDocViewerSelectionListener, nsISelectionListener)
  1.3313 +
  1.3314 +nsresult nsDocViewerSelectionListener::Init(nsDocumentViewer *aDocViewer)
  1.3315 +{
  1.3316 +  mDocViewer = aDocViewer;
  1.3317 +  return NS_OK;
  1.3318 +}
  1.3319 +
  1.3320 +/*
  1.3321 + * GetPopupNode, GetPopupLinkNode and GetPopupImageNode are helpers
  1.3322 + * for the cmd_copyLink / cmd_copyImageLocation / cmd_copyImageContents family
  1.3323 + * of commands. The focus controller stores the popup node, these retrieve
  1.3324 + * them and munge appropriately. Note that we have to store the popup node
  1.3325 + * rather than retrieving it from EventStateManager::GetFocusedContent because
  1.3326 + * not all content (images included) can receive focus.
  1.3327 + */
  1.3328 +
  1.3329 +nsresult
  1.3330 +nsDocumentViewer::GetPopupNode(nsIDOMNode** aNode)
  1.3331 +{
  1.3332 +  NS_ENSURE_ARG_POINTER(aNode);
  1.3333 +
  1.3334 +  *aNode = nullptr;
  1.3335 +
  1.3336 +  // get the document
  1.3337 +  nsIDocument* document = GetDocument();
  1.3338 +  NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
  1.3339 +
  1.3340 +  // get the private dom window
  1.3341 +  nsCOMPtr<nsPIDOMWindow> window(document->GetWindow());
  1.3342 +  NS_ENSURE_TRUE(window, NS_ERROR_NOT_AVAILABLE);
  1.3343 +  if (window) {
  1.3344 +    nsCOMPtr<nsPIWindowRoot> root = window->GetTopWindowRoot();
  1.3345 +    NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
  1.3346 +
  1.3347 +    // get the popup node
  1.3348 +    nsCOMPtr<nsIDOMNode> node = root->GetPopupNode();
  1.3349 +#ifdef MOZ_XUL
  1.3350 +    if (!node) {
  1.3351 +      nsPIDOMWindow* rootWindow = root->GetWindow();
  1.3352 +      if (rootWindow) {
  1.3353 +        nsCOMPtr<nsIDocument> rootDoc = rootWindow->GetExtantDoc();
  1.3354 +        if (rootDoc) {
  1.3355 +          nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
  1.3356 +          if (pm) {
  1.3357 +            node = pm->GetLastTriggerPopupNode(rootDoc);
  1.3358 +          }
  1.3359 +        }
  1.3360 +      }
  1.3361 +    }
  1.3362 +#endif
  1.3363 +    node.swap(*aNode);
  1.3364 +  }
  1.3365 +
  1.3366 +  return NS_OK;
  1.3367 +}
  1.3368 +
  1.3369 +// GetPopupLinkNode: return popup link node or fail
  1.3370 +nsresult
  1.3371 +nsDocumentViewer::GetPopupLinkNode(nsIDOMNode** aNode)
  1.3372 +{
  1.3373 +  NS_ENSURE_ARG_POINTER(aNode);
  1.3374 +
  1.3375 +  // you get null unless i say so
  1.3376 +  *aNode = nullptr;
  1.3377 +
  1.3378 +  // find popup node
  1.3379 +  nsCOMPtr<nsIDOMNode> node;
  1.3380 +  nsresult rv = GetPopupNode(getter_AddRefs(node));
  1.3381 +  NS_ENSURE_SUCCESS(rv, rv);
  1.3382 +
  1.3383 +  // find out if we have a link in our ancestry
  1.3384 +  while (node) {
  1.3385 +
  1.3386 +    nsCOMPtr<nsIContent> content(do_QueryInterface(node));
  1.3387 +    if (content) {
  1.3388 +      nsCOMPtr<nsIURI> hrefURI = content->GetHrefURI();
  1.3389 +      if (hrefURI) {
  1.3390 +        *aNode = node;
  1.3391 +        NS_IF_ADDREF(*aNode); // addref
  1.3392 +        return NS_OK;
  1.3393 +      }
  1.3394 +    }
  1.3395 +
  1.3396 +    // get our parent and keep trying...
  1.3397 +    nsCOMPtr<nsIDOMNode> parentNode;
  1.3398 +    node->GetParentNode(getter_AddRefs(parentNode));
  1.3399 +    node = parentNode;
  1.3400 +  }
  1.3401 +
  1.3402 +  // if we have no node, fail
  1.3403 +  return NS_ERROR_FAILURE;
  1.3404 +}
  1.3405 +
  1.3406 +// GetPopupLinkNode: return popup image node or fail
  1.3407 +nsresult
  1.3408 +nsDocumentViewer::GetPopupImageNode(nsIImageLoadingContent** aNode)
  1.3409 +{
  1.3410 +  NS_ENSURE_ARG_POINTER(aNode);
  1.3411 +
  1.3412 +  // you get null unless i say so
  1.3413 +  *aNode = nullptr;
  1.3414 +
  1.3415 +  // find popup node
  1.3416 +  nsCOMPtr<nsIDOMNode> node;
  1.3417 +  nsresult rv = GetPopupNode(getter_AddRefs(node));
  1.3418 +  NS_ENSURE_SUCCESS(rv, rv);
  1.3419 +
  1.3420 +  if (node)
  1.3421 +    CallQueryInterface(node, aNode);
  1.3422 +
  1.3423 +  return NS_OK;
  1.3424 +}
  1.3425 +
  1.3426 +/*
  1.3427 + * XXX dr
  1.3428 + * ------
  1.3429 + * These two functions -- GetInLink and GetInImage -- are kind of annoying
  1.3430 + * in that they only get called from the controller (in
  1.3431 + * nsDOMWindowController::IsCommandEnabled). The actual construction of the
  1.3432 + * context menus in communicator (nsContextMenu.js) has its own, redundant
  1.3433 + * tests. No big deal, but good to keep in mind if we ever clean context
  1.3434 + * menus.
  1.3435 + */
  1.3436 +
  1.3437 +NS_IMETHODIMP nsDocumentViewer::GetInLink(bool* aInLink)
  1.3438 +{
  1.3439 +#ifdef DEBUG_dr
  1.3440 +  printf("dr :: nsDocumentViewer::GetInLink\n");
  1.3441 +#endif
  1.3442 +
  1.3443 +  NS_ENSURE_ARG_POINTER(aInLink);
  1.3444 +
  1.3445 +  // we're not in a link unless i say so
  1.3446 +  *aInLink = false;
  1.3447 +
  1.3448 +  // get the popup link
  1.3449 +  nsCOMPtr<nsIDOMNode> node;
  1.3450 +  nsresult rv = GetPopupLinkNode(getter_AddRefs(node));
  1.3451 +  if (NS_FAILED(rv)) return rv;
  1.3452 +  NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
  1.3453 +
  1.3454 +  // if we made it here, we're in a link
  1.3455 +  *aInLink = true;
  1.3456 +  return NS_OK;
  1.3457 +}
  1.3458 +
  1.3459 +NS_IMETHODIMP nsDocumentViewer::GetInImage(bool* aInImage)
  1.3460 +{
  1.3461 +#ifdef DEBUG_dr
  1.3462 +  printf("dr :: nsDocumentViewer::GetInImage\n");
  1.3463 +#endif
  1.3464 +
  1.3465 +  NS_ENSURE_ARG_POINTER(aInImage);
  1.3466 +
  1.3467 +  // we're not in an image unless i say so
  1.3468 +  *aInImage = false;
  1.3469 +
  1.3470 +  // get the popup image
  1.3471 +  nsCOMPtr<nsIImageLoadingContent> node;
  1.3472 +  nsresult rv = GetPopupImageNode(getter_AddRefs(node));
  1.3473 +  if (NS_FAILED(rv)) return rv;
  1.3474 +  NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
  1.3475 +
  1.3476 +  // if we made it here, we're in an image
  1.3477 +  *aInImage = true;
  1.3478 +  return NS_OK;
  1.3479 +}
  1.3480 +
  1.3481 +NS_IMETHODIMP nsDocViewerSelectionListener::NotifySelectionChanged(nsIDOMDocument *, nsISelection *, int16_t)
  1.3482 +{
  1.3483 +  NS_ASSERTION(mDocViewer, "Should have doc viewer!");
  1.3484 +
  1.3485 +  // get the selection state
  1.3486 +  nsCOMPtr<nsISelection> selection;
  1.3487 +  nsresult rv = mDocViewer->GetDocumentSelection(getter_AddRefs(selection));
  1.3488 +  if (NS_FAILED(rv)) return rv;
  1.3489 +
  1.3490 +  bool selectionCollapsed;
  1.3491 +  selection->GetIsCollapsed(&selectionCollapsed);
  1.3492 +  // we only call UpdateCommands when the selection changes from collapsed
  1.3493 +  // to non-collapsed or vice versa. We might need another update string
  1.3494 +  // for simple selection changes, but that would be expenseive.
  1.3495 +  if (!mGotSelectionState || mSelectionWasCollapsed != selectionCollapsed)
  1.3496 +  {
  1.3497 +    nsIDocument* theDoc = mDocViewer->GetDocument();
  1.3498 +    if (!theDoc) return NS_ERROR_FAILURE;
  1.3499 +
  1.3500 +    nsPIDOMWindow *domWindow = theDoc->GetWindow();
  1.3501 +    if (!domWindow) return NS_ERROR_FAILURE;
  1.3502 +
  1.3503 +    domWindow->UpdateCommands(NS_LITERAL_STRING("select"));
  1.3504 +    mGotSelectionState = true;
  1.3505 +    mSelectionWasCollapsed = selectionCollapsed;
  1.3506 +  }
  1.3507 +
  1.3508 +  return NS_OK;
  1.3509 +}
  1.3510 +
  1.3511 +//nsDocViewerFocusListener
  1.3512 +NS_IMPL_ISUPPORTS(nsDocViewerFocusListener,
  1.3513 +                  nsIDOMEventListener)
  1.3514 +
  1.3515 +nsDocViewerFocusListener::nsDocViewerFocusListener()
  1.3516 +:mDocViewer(nullptr)
  1.3517 +{
  1.3518 +}
  1.3519 +
  1.3520 +nsDocViewerFocusListener::~nsDocViewerFocusListener(){}
  1.3521 +
  1.3522 +nsresult
  1.3523 +nsDocViewerFocusListener::HandleEvent(nsIDOMEvent* aEvent)
  1.3524 +{
  1.3525 +  NS_ENSURE_STATE(mDocViewer);
  1.3526 +
  1.3527 +  nsCOMPtr<nsIPresShell> shell;
  1.3528 +  mDocViewer->GetPresShell(getter_AddRefs(shell));
  1.3529 +  NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE);
  1.3530 +
  1.3531 +  nsCOMPtr<nsISelectionController> selCon = do_QueryInterface(shell);
  1.3532 +  int16_t selectionStatus;
  1.3533 +  selCon->GetDisplaySelection(&selectionStatus);
  1.3534 +
  1.3535 +  nsAutoString eventType;
  1.3536 +  aEvent->GetType(eventType);
  1.3537 +  if (eventType.EqualsLiteral("focus")) {
  1.3538 +    // If selection was disabled, re-enable it.
  1.3539 +    if(selectionStatus == nsISelectionController::SELECTION_DISABLED ||
  1.3540 +       selectionStatus == nsISelectionController::SELECTION_HIDDEN) {
  1.3541 +      selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
  1.3542 +      selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL);
  1.3543 +    }
  1.3544 +  } else {
  1.3545 +    NS_ABORT_IF_FALSE(eventType.EqualsLiteral("blur"),
  1.3546 +                      "Unexpected event type");
  1.3547 +    // If selection was on, disable it.
  1.3548 +    if(selectionStatus == nsISelectionController::SELECTION_ON ||
  1.3549 +       selectionStatus == nsISelectionController::SELECTION_ATTENTION) {
  1.3550 +      selCon->SetDisplaySelection(nsISelectionController::SELECTION_DISABLED);
  1.3551 +      selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL);
  1.3552 +    }
  1.3553 +  }
  1.3554 +
  1.3555 +  return NS_OK;
  1.3556 +}
  1.3557 +
  1.3558 +nsresult
  1.3559 +nsDocViewerFocusListener::Init(nsDocumentViewer *aDocViewer)
  1.3560 +{
  1.3561 +  mDocViewer = aDocViewer;
  1.3562 +  return NS_OK;
  1.3563 +}
  1.3564 +
  1.3565 +/** ---------------------------------------------------
  1.3566 + *  From nsIWebBrowserPrint
  1.3567 + */
  1.3568 +
  1.3569 +#ifdef NS_PRINTING
  1.3570 +
  1.3571 +NS_IMETHODIMP
  1.3572 +nsDocumentViewer::Print(nsIPrintSettings*       aPrintSettings,
  1.3573 +                          nsIWebProgressListener* aWebProgressListener)
  1.3574 +{
  1.3575 +  // Printing XUL documents is not supported.
  1.3576 +  nsCOMPtr<nsIXULDocument> xulDoc(do_QueryInterface(mDocument));
  1.3577 +  if (xulDoc) {
  1.3578 +    return NS_ERROR_FAILURE;
  1.3579 +  }
  1.3580 +
  1.3581 +  if (!mContainer) {
  1.3582 +    PR_PL(("Container was destroyed yet we are still trying to use it!"));
  1.3583 +    return NS_ERROR_FAILURE;
  1.3584 +  }
  1.3585 +
  1.3586 +  nsCOMPtr<nsIDocShell> docShell(mContainer);
  1.3587 +  NS_ENSURE_STATE(docShell);
  1.3588 +
  1.3589 +  // Check to see if this document is still busy
  1.3590 +  // If it is busy and we aren't already "queued" up to print then
  1.3591 +  // Indicate there is a print pending and cache the args for later
  1.3592 +  uint32_t busyFlags = nsIDocShell::BUSY_FLAGS_NONE;
  1.3593 +  if ((NS_FAILED(docShell->GetBusyFlags(&busyFlags)) ||
  1.3594 +       (busyFlags != nsIDocShell::BUSY_FLAGS_NONE && busyFlags & nsIDocShell::BUSY_FLAGS_PAGE_LOADING)) && 
  1.3595 +      !mPrintDocIsFullyLoaded) {
  1.3596 +    if (!mPrintIsPending) {
  1.3597 +      mCachedPrintSettings           = aPrintSettings;
  1.3598 +      mCachedPrintWebProgressListner = aWebProgressListener;
  1.3599 +      mPrintIsPending                = true;
  1.3600 +    }
  1.3601 +    PR_PL(("Printing Stopped - document is still busy!"));
  1.3602 +    return NS_ERROR_GFX_PRINTER_DOC_IS_BUSY;
  1.3603 +  }
  1.3604 +
  1.3605 +  if (!mDocument || !mDeviceContext) {
  1.3606 +    PR_PL(("Can't Print without a document and a device context"));
  1.3607 +    return NS_ERROR_FAILURE;
  1.3608 +  }
  1.3609 +
  1.3610 +  nsresult rv;
  1.3611 +
  1.3612 +  // if we are printing another URL, then exit
  1.3613 +  // the reason we check here is because this method can be called while
  1.3614 +  // another is still in here (the printing dialog is a good example).
  1.3615 +  // the only time we can print more than one job at a time is the regression tests
  1.3616 +  if (GetIsPrinting()) {
  1.3617 +    // Let the user know we are not ready to print.
  1.3618 +    rv = NS_ERROR_NOT_AVAILABLE;
  1.3619 +    nsPrintEngine::ShowPrintErrorDialog(rv);
  1.3620 +    return rv;
  1.3621 +  }
  1.3622 +
  1.3623 +  nsAutoPtr<nsPrintEventDispatcher> beforeAndAfterPrint(
  1.3624 +    new nsPrintEventDispatcher(mDocument));
  1.3625 +  NS_ENSURE_STATE(!GetIsPrinting());
  1.3626 +  // If we are hosting a full-page plugin, tell it to print
  1.3627 +  // first. It shows its own native print UI.
  1.3628 +  nsCOMPtr<nsIPluginDocument> pDoc(do_QueryInterface(mDocument));
  1.3629 +  if (pDoc)
  1.3630 +    return pDoc->Print();
  1.3631 +
  1.3632 +  if (!mPrintEngine) {
  1.3633 +    NS_ENSURE_STATE(mDeviceContext);
  1.3634 +    mPrintEngine = new nsPrintEngine();
  1.3635 +
  1.3636 +    rv = mPrintEngine->Initialize(this, mContainer, mDocument, 
  1.3637 +                                  float(mDeviceContext->AppUnitsPerCSSInch()) /
  1.3638 +                                  float(mDeviceContext->AppUnitsPerDevPixel()) /
  1.3639 +                                  mPageZoom,
  1.3640 +#ifdef DEBUG
  1.3641 +                                  mDebugFile
  1.3642 +#else
  1.3643 +                                  nullptr
  1.3644 +#endif
  1.3645 +                                  );
  1.3646 +    if (NS_FAILED(rv)) {
  1.3647 +      mPrintEngine->Destroy();
  1.3648 +      mPrintEngine = nullptr;
  1.3649 +      return rv;
  1.3650 +    }
  1.3651 +  }
  1.3652 +  if (mPrintEngine->HasPrintCallbackCanvas()) {
  1.3653 +    mBeforeAndAfterPrint = beforeAndAfterPrint;
  1.3654 +  }
  1.3655 +  dom::Element* root = mDocument->GetRootElement();
  1.3656 +  if (root && root->HasAttr(kNameSpaceID_None, nsGkAtoms::mozdisallowselectionprint)) {
  1.3657 +    mPrintEngine->SetDisallowSelectionPrint(true);
  1.3658 +  }
  1.3659 +  if (root && root->HasAttr(kNameSpaceID_None, nsGkAtoms::moznomarginboxes)) {
  1.3660 +    mPrintEngine->SetNoMarginBoxes(true);
  1.3661 +  }
  1.3662 +  rv = mPrintEngine->Print(aPrintSettings, aWebProgressListener);
  1.3663 +  if (NS_FAILED(rv)) {
  1.3664 +    OnDonePrinting();
  1.3665 +  }
  1.3666 +  return rv;
  1.3667 +}
  1.3668 +
  1.3669 +NS_IMETHODIMP
  1.3670 +nsDocumentViewer::PrintPreview(nsIPrintSettings* aPrintSettings, 
  1.3671 +                                 nsIDOMWindow *aChildDOMWin, 
  1.3672 +                                 nsIWebProgressListener* aWebProgressListener)
  1.3673 +{
  1.3674 +#if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
  1.3675 +  NS_WARN_IF_FALSE(IsInitializedForPrintPreview(),
  1.3676 +                   "Using docshell.printPreview is the preferred way for print previewing!");
  1.3677 +
  1.3678 +  NS_ENSURE_ARG_POINTER(aChildDOMWin);
  1.3679 +  nsresult rv = NS_OK;
  1.3680 +
  1.3681 +  if (GetIsPrinting()) {
  1.3682 +    nsPrintEngine::CloseProgressDialog(aWebProgressListener);
  1.3683 +    return NS_ERROR_FAILURE;
  1.3684 +  }
  1.3685 +
  1.3686 +  // Printing XUL documents is not supported.
  1.3687 +  nsCOMPtr<nsIXULDocument> xulDoc(do_QueryInterface(mDocument));
  1.3688 +  if (xulDoc) {
  1.3689 +    nsPrintEngine::CloseProgressDialog(aWebProgressListener);
  1.3690 +    return NS_ERROR_FAILURE;
  1.3691 +  }
  1.3692 +
  1.3693 +  nsCOMPtr<nsIDocShell> docShell(mContainer);
  1.3694 +  if (!docShell || !mDeviceContext) {
  1.3695 +    PR_PL(("Can't Print Preview without device context and docshell"));
  1.3696 +    return NS_ERROR_FAILURE;
  1.3697 +  }
  1.3698 +
  1.3699 +  nsCOMPtr<nsIDOMDocument> domDoc;
  1.3700 +  aChildDOMWin->GetDocument(getter_AddRefs(domDoc));
  1.3701 +  nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
  1.3702 +  NS_ENSURE_STATE(doc);
  1.3703 +
  1.3704 +  nsAutoPtr<nsPrintEventDispatcher> beforeAndAfterPrint(
  1.3705 +    new nsPrintEventDispatcher(doc));
  1.3706 +  NS_ENSURE_STATE(!GetIsPrinting());
  1.3707 +  if (!mPrintEngine) {
  1.3708 +    mPrintEngine = new nsPrintEngine();
  1.3709 +
  1.3710 +    rv = mPrintEngine->Initialize(this, mContainer, doc,
  1.3711 +                                  float(mDeviceContext->AppUnitsPerCSSInch()) /
  1.3712 +                                  float(mDeviceContext->AppUnitsPerDevPixel()) /
  1.3713 +                                  mPageZoom,
  1.3714 +#ifdef DEBUG
  1.3715 +                                  mDebugFile
  1.3716 +#else
  1.3717 +                                  nullptr
  1.3718 +#endif
  1.3719 +                                  );
  1.3720 +    if (NS_FAILED(rv)) {
  1.3721 +      mPrintEngine->Destroy();
  1.3722 +      mPrintEngine = nullptr;
  1.3723 +      return rv;
  1.3724 +    }
  1.3725 +  }
  1.3726 +  if (mPrintEngine->HasPrintCallbackCanvas()) {
  1.3727 +    mBeforeAndAfterPrint = beforeAndAfterPrint;
  1.3728 +  }
  1.3729 +  dom::Element* root = doc->GetRootElement();
  1.3730 +  if (root && root->HasAttr(kNameSpaceID_None, nsGkAtoms::mozdisallowselectionprint)) {
  1.3731 +    PR_PL(("PrintPreview: found mozdisallowselectionprint"));
  1.3732 +    mPrintEngine->SetDisallowSelectionPrint(true);
  1.3733 +  }
  1.3734 +  if (root && root->HasAttr(kNameSpaceID_None, nsGkAtoms::moznomarginboxes)) {
  1.3735 +    PR_PL(("PrintPreview: found moznomarginboxes"));
  1.3736 +    mPrintEngine->SetNoMarginBoxes(true);
  1.3737 +  }
  1.3738 +  rv = mPrintEngine->PrintPreview(aPrintSettings, aChildDOMWin, aWebProgressListener);
  1.3739 +  mPrintPreviewZoomed = false;
  1.3740 +  if (NS_FAILED(rv)) {
  1.3741 +    OnDonePrinting();
  1.3742 +  }
  1.3743 +  return rv;
  1.3744 +#else
  1.3745 +  return NS_ERROR_FAILURE;
  1.3746 +#endif
  1.3747 +}
  1.3748 +
  1.3749 +//----------------------------------------------------------------------
  1.3750 +NS_IMETHODIMP
  1.3751 +nsDocumentViewer::PrintPreviewNavigate(int16_t aType, int32_t aPageNum)
  1.3752 +{
  1.3753 +  if (!GetIsPrintPreview() ||
  1.3754 +      mPrintEngine->GetIsCreatingPrintPreview())
  1.3755 +    return NS_ERROR_FAILURE;
  1.3756 +
  1.3757 +  nsIScrollableFrame* sf =
  1.3758 +    mPrintEngine->GetPrintPreviewPresShell()->GetRootScrollFrameAsScrollable();
  1.3759 +  if (!sf)
  1.3760 +    return NS_OK;
  1.3761 +
  1.3762 +  // Check to see if we can short circut scrolling to the top
  1.3763 +  if (aType == nsIWebBrowserPrint::PRINTPREVIEW_HOME ||
  1.3764 +      (aType == nsIWebBrowserPrint::PRINTPREVIEW_GOTO_PAGENUM && aPageNum == 1)) {
  1.3765 +    sf->ScrollTo(nsPoint(0, 0), nsIScrollableFrame::INSTANT);
  1.3766 +    return NS_OK;
  1.3767 +  }
  1.3768 +
  1.3769 +  // Finds the SimplePageSequencer frame
  1.3770 +  // in PP mPrtPreview->mPrintObject->mSeqFrame is null
  1.3771 +  nsIFrame* seqFrame  = nullptr;
  1.3772 +  int32_t   pageCount = 0;
  1.3773 +  if (NS_FAILED(mPrintEngine->GetSeqFrameAndCountPages(seqFrame, pageCount))) {
  1.3774 +    return NS_ERROR_FAILURE;
  1.3775 +  }
  1.3776 +
  1.3777 +  // Figure where we are currently scrolled to
  1.3778 +  nsPoint pt = sf->GetScrollPosition();
  1.3779 +
  1.3780 +  int32_t    pageNum = 1;
  1.3781 +  nsIFrame * fndPageFrame  = nullptr;
  1.3782 +  nsIFrame * currentPage   = nullptr;
  1.3783 +
  1.3784 +  // If it is "End" then just do a "goto" to the last page
  1.3785 +  if (aType == nsIWebBrowserPrint::PRINTPREVIEW_END) {
  1.3786 +    aType    = nsIWebBrowserPrint::PRINTPREVIEW_GOTO_PAGENUM;
  1.3787 +    aPageNum = pageCount;
  1.3788 +  }
  1.3789 +
  1.3790 +  // Now, locate the current page we are on and
  1.3791 +  // and the page of the page number
  1.3792 +  nsIFrame* pageFrame = seqFrame->GetFirstPrincipalChild();
  1.3793 +  while (pageFrame != nullptr) {
  1.3794 +    nsRect pageRect = pageFrame->GetRect();
  1.3795 +    if (pageRect.Contains(pageRect.x, pt.y)) {
  1.3796 +      currentPage = pageFrame;
  1.3797 +    }
  1.3798 +    if (pageNum == aPageNum) {
  1.3799 +      fndPageFrame = pageFrame;
  1.3800 +      break;
  1.3801 +    }
  1.3802 +    pageNum++;
  1.3803 +    pageFrame = pageFrame->GetNextSibling();
  1.3804 +  }
  1.3805 +
  1.3806 +  if (aType == nsIWebBrowserPrint::PRINTPREVIEW_PREV_PAGE) {
  1.3807 +    if (currentPage) {
  1.3808 +      fndPageFrame = currentPage->GetPrevInFlow();
  1.3809 +      if (!fndPageFrame) {
  1.3810 +        return NS_OK;
  1.3811 +      }
  1.3812 +    } else {
  1.3813 +      return NS_OK;
  1.3814 +    }
  1.3815 +  } else if (aType == nsIWebBrowserPrint::PRINTPREVIEW_NEXT_PAGE) {
  1.3816 +    if (currentPage) {
  1.3817 +      fndPageFrame = currentPage->GetNextInFlow();
  1.3818 +      if (!fndPageFrame) {
  1.3819 +        return NS_OK;
  1.3820 +      }
  1.3821 +    } else {
  1.3822 +      return NS_OK;
  1.3823 +    }
  1.3824 +  } else { // If we get here we are doing "GoTo"
  1.3825 +    if (aPageNum < 0 || aPageNum > pageCount) {
  1.3826 +      return NS_OK;
  1.3827 +    }
  1.3828 +  }
  1.3829 +
  1.3830 +  if (fndPageFrame) {
  1.3831 +    nscoord newYPosn =
  1.3832 +      nscoord(mPrintEngine->GetPrintPreviewScale() * fndPageFrame->GetPosition().y);
  1.3833 +    sf->ScrollTo(nsPoint(pt.x, newYPosn), nsIScrollableFrame::INSTANT);
  1.3834 +  }
  1.3835 +  return NS_OK;
  1.3836 +
  1.3837 +}
  1.3838 +
  1.3839 +/* readonly attribute nsIPrintSettings globalPrintSettings; */
  1.3840 +NS_IMETHODIMP
  1.3841 +nsDocumentViewer::GetGlobalPrintSettings(nsIPrintSettings * *aGlobalPrintSettings)
  1.3842 +{
  1.3843 +  return nsPrintEngine::GetGlobalPrintSettings(aGlobalPrintSettings);
  1.3844 +}
  1.3845 +
  1.3846 +/* readonly attribute boolean doingPrint; */
  1.3847 +// XXX This always returns false for subdocuments
  1.3848 +NS_IMETHODIMP
  1.3849 +nsDocumentViewer::GetDoingPrint(bool *aDoingPrint)
  1.3850 +{
  1.3851 +  NS_ENSURE_ARG_POINTER(aDoingPrint);
  1.3852 +  
  1.3853 +  *aDoingPrint = false;
  1.3854 +  if (mPrintEngine) {
  1.3855 +    // XXX shouldn't this be GetDoingPrint() ?
  1.3856 +    return mPrintEngine->GetDoingPrintPreview(aDoingPrint);
  1.3857 +  } 
  1.3858 +  return NS_OK;
  1.3859 +}
  1.3860 +
  1.3861 +/* readonly attribute boolean doingPrintPreview; */
  1.3862 +// XXX This always returns false for subdocuments
  1.3863 +NS_IMETHODIMP
  1.3864 +nsDocumentViewer::GetDoingPrintPreview(bool *aDoingPrintPreview)
  1.3865 +{
  1.3866 +  NS_ENSURE_ARG_POINTER(aDoingPrintPreview);
  1.3867 +
  1.3868 +  *aDoingPrintPreview = false;
  1.3869 +  if (mPrintEngine) {
  1.3870 +    return mPrintEngine->GetDoingPrintPreview(aDoingPrintPreview);
  1.3871 +  }
  1.3872 +  return NS_OK;
  1.3873 +}
  1.3874 +
  1.3875 +/* readonly attribute nsIPrintSettings currentPrintSettings; */
  1.3876 +NS_IMETHODIMP
  1.3877 +nsDocumentViewer::GetCurrentPrintSettings(nsIPrintSettings * *aCurrentPrintSettings)
  1.3878 +{
  1.3879 +  NS_ENSURE_ARG_POINTER(aCurrentPrintSettings);
  1.3880 +
  1.3881 +  *aCurrentPrintSettings = nullptr;
  1.3882 +  NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
  1.3883 +
  1.3884 +  return mPrintEngine->GetCurrentPrintSettings(aCurrentPrintSettings);
  1.3885 +}
  1.3886 +
  1.3887 +
  1.3888 +/* readonly attribute nsIDOMWindow currentChildDOMWindow; */
  1.3889 +NS_IMETHODIMP 
  1.3890 +nsDocumentViewer::GetCurrentChildDOMWindow(nsIDOMWindow * *aCurrentChildDOMWindow)
  1.3891 +{
  1.3892 +  NS_ENSURE_ARG_POINTER(aCurrentChildDOMWindow);
  1.3893 +  *aCurrentChildDOMWindow = nullptr;
  1.3894 +  return NS_ERROR_NOT_IMPLEMENTED;
  1.3895 +}
  1.3896 +
  1.3897 +/* void cancel (); */
  1.3898 +NS_IMETHODIMP
  1.3899 +nsDocumentViewer::Cancel()
  1.3900 +{
  1.3901 +  NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
  1.3902 +  return mPrintEngine->Cancelled();
  1.3903 +}
  1.3904 +
  1.3905 +/* void exitPrintPreview (); */
  1.3906 +NS_IMETHODIMP
  1.3907 +nsDocumentViewer::ExitPrintPreview()
  1.3908 +{
  1.3909 +  if (GetIsPrinting())
  1.3910 +    return NS_ERROR_FAILURE;
  1.3911 +  NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
  1.3912 +
  1.3913 +  if (GetIsPrintPreview()) {
  1.3914 +    ReturnToGalleyPresentation();
  1.3915 +  }
  1.3916 +  return NS_OK;
  1.3917 +}
  1.3918 +
  1.3919 +//----------------------------------------------------------------------------------
  1.3920 +// Enumerate all the documents for their titles
  1.3921 +NS_IMETHODIMP
  1.3922 +nsDocumentViewer::EnumerateDocumentNames(uint32_t* aCount,
  1.3923 +                                           char16_t*** aResult)
  1.3924 +{
  1.3925 +#ifdef NS_PRINTING
  1.3926 +  NS_ENSURE_ARG(aCount);
  1.3927 +  NS_ENSURE_ARG_POINTER(aResult);
  1.3928 +  NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
  1.3929 +
  1.3930 +  return mPrintEngine->EnumerateDocumentNames(aCount, aResult);
  1.3931 +#else
  1.3932 +  return NS_ERROR_FAILURE;
  1.3933 +#endif
  1.3934 +}
  1.3935 +
  1.3936 +/* readonly attribute boolean isFramesetFrameSelected; */
  1.3937 +NS_IMETHODIMP 
  1.3938 +nsDocumentViewer::GetIsFramesetFrameSelected(bool *aIsFramesetFrameSelected)
  1.3939 +{
  1.3940 +#ifdef NS_PRINTING
  1.3941 +  *aIsFramesetFrameSelected = false;
  1.3942 +  NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
  1.3943 +
  1.3944 +  return mPrintEngine->GetIsFramesetFrameSelected(aIsFramesetFrameSelected);
  1.3945 +#else
  1.3946 +  return NS_ERROR_FAILURE;
  1.3947 +#endif
  1.3948 +}
  1.3949 +
  1.3950 +/* readonly attribute long printPreviewNumPages; */
  1.3951 +NS_IMETHODIMP
  1.3952 +nsDocumentViewer::GetPrintPreviewNumPages(int32_t *aPrintPreviewNumPages)
  1.3953 +{
  1.3954 +#ifdef NS_PRINTING
  1.3955 +  NS_ENSURE_ARG_POINTER(aPrintPreviewNumPages);
  1.3956 +  NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
  1.3957 +
  1.3958 +  return mPrintEngine->GetPrintPreviewNumPages(aPrintPreviewNumPages);
  1.3959 +#else
  1.3960 +  return NS_ERROR_FAILURE;
  1.3961 +#endif
  1.3962 +}
  1.3963 +
  1.3964 +/* readonly attribute boolean isFramesetDocument; */
  1.3965 +NS_IMETHODIMP
  1.3966 +nsDocumentViewer::GetIsFramesetDocument(bool *aIsFramesetDocument)
  1.3967 +{
  1.3968 +#ifdef NS_PRINTING
  1.3969 +  *aIsFramesetDocument = false;
  1.3970 +  NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
  1.3971 +
  1.3972 +  return mPrintEngine->GetIsFramesetDocument(aIsFramesetDocument);
  1.3973 +#else
  1.3974 +  return NS_ERROR_FAILURE;
  1.3975 +#endif
  1.3976 +}
  1.3977 +
  1.3978 +/* readonly attribute boolean isIFrameSelected; */
  1.3979 +NS_IMETHODIMP 
  1.3980 +nsDocumentViewer::GetIsIFrameSelected(bool *aIsIFrameSelected)
  1.3981 +{
  1.3982 +#ifdef NS_PRINTING
  1.3983 +  *aIsIFrameSelected = false;
  1.3984 +  NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
  1.3985 +
  1.3986 +  return mPrintEngine->GetIsIFrameSelected(aIsIFrameSelected);
  1.3987 +#else
  1.3988 +  return NS_ERROR_FAILURE;
  1.3989 +#endif
  1.3990 +}
  1.3991 +
  1.3992 +/* readonly attribute boolean isRangeSelection; */
  1.3993 +NS_IMETHODIMP 
  1.3994 +nsDocumentViewer::GetIsRangeSelection(bool *aIsRangeSelection)
  1.3995 +{
  1.3996 +#ifdef NS_PRINTING
  1.3997 +  *aIsRangeSelection = false;
  1.3998 +  NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
  1.3999 +
  1.4000 +  return mPrintEngine->GetIsRangeSelection(aIsRangeSelection);
  1.4001 +#else
  1.4002 +  return NS_ERROR_FAILURE;
  1.4003 +#endif
  1.4004 +}
  1.4005 +
  1.4006 +//----------------------------------------------------------------------------------
  1.4007 +// Printing/Print Preview Helpers
  1.4008 +//----------------------------------------------------------------------------------
  1.4009 +
  1.4010 +//----------------------------------------------------------------------------------
  1.4011 +// Walks the document tree and tells each DocShell whether Printing/PP is happening
  1.4012 +void 
  1.4013 +nsDocumentViewer::SetIsPrintingInDocShellTree(nsIDocShellTreeItem* aParentNode, 
  1.4014 +                                                bool                 aIsPrintingOrPP, 
  1.4015 +                                                bool                 aStartAtTop)
  1.4016 +{
  1.4017 +  nsCOMPtr<nsIDocShellTreeItem> parentItem(do_QueryInterface(aParentNode));
  1.4018 +
  1.4019 +  // find top of "same parent" tree
  1.4020 +  if (aStartAtTop) {
  1.4021 +    if (aIsPrintingOrPP) {
  1.4022 +      while (parentItem) {
  1.4023 +        nsCOMPtr<nsIDocShellTreeItem> parent;
  1.4024 +        parentItem->GetSameTypeParent(getter_AddRefs(parent));
  1.4025 +        if (!parent) {
  1.4026 +          break;
  1.4027 +        }
  1.4028 +        parentItem = do_QueryInterface(parent);
  1.4029 +      }
  1.4030 +      mTopContainerWhilePrinting = do_GetWeakReference(parentItem);
  1.4031 +    } else {
  1.4032 +      parentItem = do_QueryReferent(mTopContainerWhilePrinting);
  1.4033 +    }
  1.4034 +  }
  1.4035 +
  1.4036 +  // Check to see if the DocShell's ContentViewer is printing/PP
  1.4037 +  nsCOMPtr<nsIContentViewerContainer> viewerContainer(do_QueryInterface(parentItem));
  1.4038 +  if (viewerContainer) {
  1.4039 +    viewerContainer->SetIsPrinting(aIsPrintingOrPP);
  1.4040 +  }
  1.4041 +
  1.4042 +  if (!aParentNode) {
  1.4043 +    return;
  1.4044 +  }
  1.4045 +
  1.4046 +  // Traverse children to see if any of them are printing.
  1.4047 +  int32_t n;
  1.4048 +  aParentNode->GetChildCount(&n);
  1.4049 +  for (int32_t i=0; i < n; i++) {
  1.4050 +    nsCOMPtr<nsIDocShellTreeItem> child;
  1.4051 +    aParentNode->GetChildAt(i, getter_AddRefs(child));
  1.4052 +    NS_ASSERTION(child, "child isn't nsIDocShell");
  1.4053 +    if (child) {
  1.4054 +      SetIsPrintingInDocShellTree(child, aIsPrintingOrPP, false);
  1.4055 +    }
  1.4056 +  }
  1.4057 +
  1.4058 +}
  1.4059 +#endif // NS_PRINTING
  1.4060 +
  1.4061 +bool
  1.4062 +nsDocumentViewer::ShouldAttachToTopLevel()
  1.4063 +{
  1.4064 +  if (!mParentWidget)
  1.4065 +    return false;
  1.4066 +
  1.4067 +  nsCOMPtr<nsIDocShellTreeItem> containerItem(mContainer);
  1.4068 +  if (!containerItem)
  1.4069 +    return false;
  1.4070 +
  1.4071 +  // We always attach when using puppet widgets
  1.4072 +  if (nsIWidget::UsePuppetWidgets())
  1.4073 +    return true;
  1.4074 +
  1.4075 +#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
  1.4076 +  // On windows, in the parent process we also attach, but just to
  1.4077 +  // chrome items
  1.4078 +  nsWindowType winType = mParentWidget->WindowType();
  1.4079 +  if ((winType == eWindowType_toplevel ||
  1.4080 +       winType == eWindowType_dialog ||
  1.4081 +       winType == eWindowType_invisible) &&
  1.4082 +      containerItem->ItemType() == nsIDocShellTreeItem::typeChrome) {
  1.4083 +    return true;
  1.4084 +  }
  1.4085 +#endif
  1.4086 +
  1.4087 +  return false;
  1.4088 +}
  1.4089 +
  1.4090 +bool CollectDocuments(nsIDocument* aDocument, void* aData)
  1.4091 +{
  1.4092 +  if (aDocument) {
  1.4093 +    static_cast<nsCOMArray<nsIDocument>*>(aData)->AppendObject(aDocument);
  1.4094 +    aDocument->EnumerateSubDocuments(CollectDocuments, aData);
  1.4095 +  }
  1.4096 +  return true;
  1.4097 +}
  1.4098 +
  1.4099 +void
  1.4100 +nsDocumentViewer::DispatchEventToWindowTree(nsIDocument* aDoc,
  1.4101 +                                              const nsAString& aEvent)
  1.4102 +{
  1.4103 +  nsCOMArray<nsIDocument> targets;
  1.4104 +  CollectDocuments(aDoc, &targets);
  1.4105 +  for (int32_t i = 0; i < targets.Count(); ++i) {
  1.4106 +    nsIDocument* d = targets[i];
  1.4107 +    nsContentUtils::DispatchTrustedEvent(d, d->GetWindow(),
  1.4108 +                                         aEvent, false, false, nullptr);
  1.4109 +  }
  1.4110 +}
  1.4111 +
  1.4112 +//------------------------------------------------------------
  1.4113 +// XXX this always returns false for subdocuments
  1.4114 +bool
  1.4115 +nsDocumentViewer::GetIsPrinting()
  1.4116 +{
  1.4117 +#ifdef NS_PRINTING
  1.4118 +  if (mPrintEngine) {
  1.4119 +    return mPrintEngine->GetIsPrinting();
  1.4120 +  }
  1.4121 +#endif
  1.4122 +  return false; 
  1.4123 +}
  1.4124 +
  1.4125 +//------------------------------------------------------------
  1.4126 +// Notification from the PrintEngine of the current Printing status
  1.4127 +void
  1.4128 +nsDocumentViewer::SetIsPrinting(bool aIsPrinting)
  1.4129 +{
  1.4130 +#ifdef NS_PRINTING
  1.4131 +  // Set all the docShells in the docshell tree to be printing.
  1.4132 +  // that way if anyone of them tries to "navigate" it can't
  1.4133 +  nsCOMPtr<nsIDocShell> docShell(mContainer);
  1.4134 +  if (docShell || !aIsPrinting) {
  1.4135 +    SetIsPrintingInDocShellTree(docShell, aIsPrinting, true);
  1.4136 +  } else {
  1.4137 +    NS_WARNING("Did you close a window before printing?");
  1.4138 +  }
  1.4139 +
  1.4140 +  if (!aIsPrinting) {
  1.4141 +    mBeforeAndAfterPrint = nullptr;
  1.4142 +  }
  1.4143 +#endif
  1.4144 +}
  1.4145 +
  1.4146 +//------------------------------------------------------------
  1.4147 +// The PrintEngine holds the current value
  1.4148 +// this called from inside the DocViewer.
  1.4149 +// XXX it always returns false for subdocuments
  1.4150 +bool
  1.4151 +nsDocumentViewer::GetIsPrintPreview()
  1.4152 +{
  1.4153 +#ifdef NS_PRINTING
  1.4154 +  if (mPrintEngine) {
  1.4155 +    return mPrintEngine->GetIsPrintPreview();
  1.4156 +  }
  1.4157 +#endif
  1.4158 +  return false; 
  1.4159 +}
  1.4160 +
  1.4161 +//------------------------------------------------------------
  1.4162 +// Notification from the PrintEngine of the current PP status
  1.4163 +void
  1.4164 +nsDocumentViewer::SetIsPrintPreview(bool aIsPrintPreview)
  1.4165 +{
  1.4166 +#ifdef NS_PRINTING
  1.4167 +  // Set all the docShells in the docshell tree to be printing.
  1.4168 +  // that way if anyone of them tries to "navigate" it can't
  1.4169 +  nsCOMPtr<nsIDocShell> docShell(mContainer);
  1.4170 +  if (docShell || !aIsPrintPreview) {
  1.4171 +    SetIsPrintingInDocShellTree(docShell, aIsPrintPreview, true);
  1.4172 +  }
  1.4173 +  if (!aIsPrintPreview) {
  1.4174 +    mBeforeAndAfterPrint = nullptr;
  1.4175 +  }
  1.4176 +#endif
  1.4177 +  if (!aIsPrintPreview) {
  1.4178 +    if (mPresShell) {
  1.4179 +      DestroyPresShell();
  1.4180 +    }
  1.4181 +    mWindow = nullptr;
  1.4182 +    mViewManager = nullptr;
  1.4183 +    mPresContext = nullptr;
  1.4184 +    mPresShell = nullptr;
  1.4185 +  }
  1.4186 +}
  1.4187 +
  1.4188 +//----------------------------------------------------------------------------------
  1.4189 +// nsIDocumentViewerPrint IFace
  1.4190 +//----------------------------------------------------------------------------------
  1.4191 +
  1.4192 +//------------------------------------------------------------
  1.4193 +void
  1.4194 +nsDocumentViewer::IncrementDestroyRefCount()
  1.4195 +{
  1.4196 +  ++mDestroyRefCount;
  1.4197 +}
  1.4198 +
  1.4199 +//------------------------------------------------------------
  1.4200 +
  1.4201 +#if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
  1.4202 +//------------------------------------------------------------
  1.4203 +// Reset ESM focus for all descendent doc shells.
  1.4204 +static void
  1.4205 +ResetFocusState(nsIDocShell* aDocShell)
  1.4206 +{
  1.4207 +  nsIFocusManager* fm = nsFocusManager::GetFocusManager();
  1.4208 +  if (!fm)
  1.4209 +    return;
  1.4210 +
  1.4211 +  nsCOMPtr<nsISimpleEnumerator> docShellEnumerator;
  1.4212 +  aDocShell->GetDocShellEnumerator(nsIDocShellTreeItem::typeContent,
  1.4213 +                                   nsIDocShell::ENUMERATE_FORWARDS,
  1.4214 +                                   getter_AddRefs(docShellEnumerator));
  1.4215 +  
  1.4216 +  nsCOMPtr<nsISupports> currentContainer;
  1.4217 +  bool hasMoreDocShells;
  1.4218 +  while (NS_SUCCEEDED(docShellEnumerator->HasMoreElements(&hasMoreDocShells))
  1.4219 +         && hasMoreDocShells) {
  1.4220 +    docShellEnumerator->GetNext(getter_AddRefs(currentContainer));
  1.4221 +    nsCOMPtr<nsIDOMWindow> win = do_GetInterface(currentContainer);
  1.4222 +    if (win)
  1.4223 +      fm->ClearFocus(win);
  1.4224 +  }
  1.4225 +}
  1.4226 +#endif // NS_PRINTING && NS_PRINT_PREVIEW
  1.4227 +
  1.4228 +void
  1.4229 +nsDocumentViewer::ReturnToGalleyPresentation()
  1.4230 +{
  1.4231 +#if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
  1.4232 +  if (!GetIsPrintPreview()) {
  1.4233 +    NS_ERROR("Wow, we should never get here!");
  1.4234 +    return;
  1.4235 +  }
  1.4236 +
  1.4237 +  SetIsPrintPreview(false);
  1.4238 +
  1.4239 +  mPrintEngine->TurnScriptingOn(true);
  1.4240 +  mPrintEngine->Destroy();
  1.4241 +  mPrintEngine = nullptr;
  1.4242 +
  1.4243 +  nsCOMPtr<nsIDocShell> docShell(mContainer);
  1.4244 +  ResetFocusState(docShell);
  1.4245 +
  1.4246 +  SetTextZoom(mTextZoom);
  1.4247 +  SetFullZoom(mPageZoom);
  1.4248 +  SetMinFontSize(mMinFontSize);
  1.4249 +  Show();
  1.4250 +
  1.4251 +#endif // NS_PRINTING && NS_PRINT_PREVIEW
  1.4252 +}
  1.4253 +
  1.4254 +//------------------------------------------------------------
  1.4255 +// This called ONLY when printing has completed and the DV
  1.4256 +// is being notified that it should get rid of the PrintEngine.
  1.4257 +//
  1.4258 +// BUT, if we are in Print Preview then we want to ignore the 
  1.4259 +// notification (we do not get rid of the PrintEngine)
  1.4260 +// 
  1.4261 +// One small caveat: 
  1.4262 +//   This IS called from two places in this module for cleaning
  1.4263 +//   up when an error occurred during the start up printing 
  1.4264 +//   and print preview
  1.4265 +//
  1.4266 +void
  1.4267 +nsDocumentViewer::OnDonePrinting() 
  1.4268 +{
  1.4269 +#if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
  1.4270 +  if (mPrintEngine) {
  1.4271 +    nsRefPtr<nsPrintEngine> pe = mPrintEngine;
  1.4272 +    if (GetIsPrintPreview()) {
  1.4273 +      pe->DestroyPrintingData();
  1.4274 +    } else {
  1.4275 +      mPrintEngine = nullptr;
  1.4276 +      pe->Destroy();
  1.4277 +    }
  1.4278 +
  1.4279 +    // We are done printing, now cleanup 
  1.4280 +    if (mDeferredWindowClose) {
  1.4281 +      mDeferredWindowClose = false;
  1.4282 +      nsCOMPtr<nsIDOMWindow> win =
  1.4283 +        do_GetInterface(static_cast<nsIDocShell*>(mContainer));
  1.4284 +      if (win)
  1.4285 +        win->Close();
  1.4286 +    } else if (mClosingWhilePrinting) {
  1.4287 +      if (mDocument) {
  1.4288 +        mDocument->SetScriptGlobalObject(nullptr);
  1.4289 +        mDocument->Destroy();
  1.4290 +        mDocument = nullptr;
  1.4291 +      }
  1.4292 +      mClosingWhilePrinting = false;
  1.4293 +    }
  1.4294 +  }
  1.4295 +#endif // NS_PRINTING && NS_PRINT_PREVIEW
  1.4296 +}
  1.4297 +
  1.4298 +NS_IMETHODIMP nsDocumentViewer::SetPageMode(bool aPageMode, nsIPrintSettings* aPrintSettings)
  1.4299 +{
  1.4300 +  // XXX Page mode is only partially working; it's currently used for
  1.4301 +  // reftests that require a paginated context
  1.4302 +  mIsPageMode = aPageMode;
  1.4303 +
  1.4304 +  if (mPresShell) {
  1.4305 +    DestroyPresShell();
  1.4306 +  }
  1.4307 +
  1.4308 +  if (mPresContext) {
  1.4309 +    DestroyPresContext();
  1.4310 +  }
  1.4311 +
  1.4312 +  mViewManager  = nullptr;
  1.4313 +  mWindow       = nullptr;
  1.4314 +
  1.4315 +  NS_ENSURE_STATE(mDocument);
  1.4316 +  if (aPageMode)
  1.4317 +  {    
  1.4318 +    mPresContext = CreatePresContext(mDocument,
  1.4319 +        nsPresContext::eContext_PageLayout, FindContainerView());
  1.4320 +    NS_ENSURE_TRUE(mPresContext, NS_ERROR_OUT_OF_MEMORY);
  1.4321 +    mPresContext->SetPaginatedScrolling(true);
  1.4322 +    mPresContext->SetPrintSettings(aPrintSettings);
  1.4323 +    nsresult rv = mPresContext->Init(mDeviceContext);
  1.4324 +    NS_ENSURE_SUCCESS(rv, rv);
  1.4325 +  }
  1.4326 +  InitInternal(mParentWidget, nullptr, mBounds, true, false);
  1.4327 +
  1.4328 +  Show();
  1.4329 +  return NS_OK;
  1.4330 +}
  1.4331 +
  1.4332 +NS_IMETHODIMP
  1.4333 +nsDocumentViewer::GetHistoryEntry(nsISHEntry **aHistoryEntry)
  1.4334 +{
  1.4335 +  NS_IF_ADDREF(*aHistoryEntry = mSHEntry);
  1.4336 +  return NS_OK;
  1.4337 +}
  1.4338 +
  1.4339 +NS_IMETHODIMP
  1.4340 +nsDocumentViewer::GetIsTabModalPromptAllowed(bool *aAllowed)
  1.4341 +{
  1.4342 +  *aAllowed = !mHidden;
  1.4343 +  return NS_OK;
  1.4344 +}
  1.4345 +
  1.4346 +NS_IMETHODIMP
  1.4347 +nsDocumentViewer::GetIsHidden(bool *aHidden)
  1.4348 +{
  1.4349 +  *aHidden = mHidden;
  1.4350 +  return NS_OK;
  1.4351 +}
  1.4352 +
  1.4353 +void
  1.4354 +nsDocumentViewer::DestroyPresShell()
  1.4355 +{
  1.4356 +  // Break circular reference (or something)
  1.4357 +  mPresShell->EndObservingDocument();
  1.4358 +
  1.4359 +  nsCOMPtr<nsISelection> selection;
  1.4360 +  GetDocumentSelection(getter_AddRefs(selection));
  1.4361 +  nsCOMPtr<nsISelectionPrivate> selPrivate = do_QueryInterface(selection);
  1.4362 +  if (selPrivate && mSelectionListener)
  1.4363 +    selPrivate->RemoveSelectionListener(mSelectionListener);
  1.4364 +
  1.4365 +  nsAutoScriptBlocker scriptBlocker;
  1.4366 +  mPresShell->Destroy();
  1.4367 +  mPresShell = nullptr;
  1.4368 +}
  1.4369 +
  1.4370 +void
  1.4371 +nsDocumentViewer::DestroyPresContext()
  1.4372 +{
  1.4373 +  mPresContext->Detach();
  1.4374 +  mPresContext = nullptr;
  1.4375 +}
  1.4376 +
  1.4377 +bool
  1.4378 +nsDocumentViewer::IsInitializedForPrintPreview()
  1.4379 +{
  1.4380 +  return mInitializedForPrintPreview;
  1.4381 +}
  1.4382 +
  1.4383 +void
  1.4384 +nsDocumentViewer::InitializeForPrintPreview()
  1.4385 +{
  1.4386 +  mInitializedForPrintPreview = true;
  1.4387 +}
  1.4388 +
  1.4389 +void
  1.4390 +nsDocumentViewer::SetPrintPreviewPresentation(nsViewManager* aViewManager,
  1.4391 +                                                nsPresContext* aPresContext,
  1.4392 +                                                nsIPresShell* aPresShell)
  1.4393 +{
  1.4394 +  if (mPresShell) {
  1.4395 +    DestroyPresShell();
  1.4396 +  }
  1.4397 +
  1.4398 +  mWindow = nullptr;
  1.4399 +  mViewManager = aViewManager;
  1.4400 +  mPresContext = aPresContext;
  1.4401 +  mPresShell = aPresShell;
  1.4402 +}
  1.4403 +
  1.4404 +// Fires the "document-shown" event so that interested parties are aware of it.
  1.4405 +NS_IMETHODIMP
  1.4406 +nsDocumentShownDispatcher::Run()
  1.4407 +{
  1.4408 +  nsCOMPtr<nsIObserverService> observerService =
  1.4409 +    mozilla::services::GetObserverService();
  1.4410 +  if (observerService) {
  1.4411 +    observerService->NotifyObservers(mDocument, "document-shown", nullptr);
  1.4412 +  }
  1.4413 +  return NS_OK;
  1.4414 +}
  1.4415 +

mercurial