forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			4120 lines
		
	
	
	
		
			120 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			4120 lines
		
	
	
	
		
			120 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=2 sw=2 et tw=80: */
 | |
| /* ***** BEGIN LICENSE BLOCK *****
 | |
|  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 | |
|  *
 | |
|  * The contents of this file are subject to the Mozilla Public License Version
 | |
|  * 1.1 (the "License"); you may not use this file except in compliance with
 | |
|  * the License. You may obtain a copy of the License at
 | |
|  * http://www.mozilla.org/MPL/
 | |
|  *
 | |
|  * Software distributed under the License is distributed on an "AS IS" basis,
 | |
|  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 | |
|  * for the specific language governing rights and limitations under the
 | |
|  * License.
 | |
|  *
 | |
|  * The Original Code is Mozilla Communicator client code.
 | |
|  *
 | |
|  * The Initial Developer of the Original Code is
 | |
|  * Netscape Communications Corporation.
 | |
|  * Portions created by the Initial Developer are Copyright (C) 1998
 | |
|  * the Initial Developer. All Rights Reserved.
 | |
|  *
 | |
|  * Contributor(s):
 | |
|  *   Dan Rosen <dr@netscape.com>
 | |
|  *   Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
 | |
|  *   Mats Palmgren <mats.palmgren@bredband.net>
 | |
|  *
 | |
|  * Alternatively, the contents of this file may be used under the terms of
 | |
|  * either of the GNU General Public License Version 2 or later (the "GPL"),
 | |
|  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 | |
|  * in which case the provisions of the GPL or the LGPL are applicable instead
 | |
|  * of those above. If you wish to allow use of your version of this file only
 | |
|  * under the terms of either the GPL or the LGPL, and not to allow others to
 | |
|  * use your version of this file under the terms of the MPL, indicate your
 | |
|  * decision by deleting the provisions above and replace them with the notice
 | |
|  * and other provisions required by the GPL or the LGPL. If you do not delete
 | |
|  * the provisions above, a recipient may use your version of this file under
 | |
|  * the terms of any one of the MPL, the GPL or the LGPL.
 | |
|  *
 | |
|  * ***** END LICENSE BLOCK ***** */
 | |
| 
 | |
| /* container for a document and its presentation */
 | |
| 
 | |
| #include "nscore.h"
 | |
| #include "nsCOMPtr.h"
 | |
| #include "nsCRT.h"
 | |
| #include "nsString.h"
 | |
| #include "nsReadableUtils.h"
 | |
| #include "nsISupports.h"
 | |
| #include "nsIContent.h"
 | |
| #include "nsIContentViewerContainer.h"
 | |
| #include "nsIDocumentViewer.h"
 | |
| #include "nsIDocumentViewerPrint.h"
 | |
| 
 | |
| #include "nsIDocument.h"
 | |
| #include "nsPresContext.h"
 | |
| #include "nsIPresShell.h"
 | |
| #include "nsIEventStateManager.h"
 | |
| #include "nsStyleSet.h"
 | |
| #include "nsIStyleSheet.h"
 | |
| #include "nsICSSStyleSheet.h"
 | |
| #include "nsIFrame.h"
 | |
| 
 | |
| #include "nsILinkHandler.h"
 | |
| #include "nsIDOMDocument.h"
 | |
| #include "nsISelectionListener.h"
 | |
| #include "nsISelectionPrivate.h"
 | |
| #include "nsIDOMHTMLDocument.h"
 | |
| #include "nsIDOMNSHTMLDocument.h"
 | |
| #include "nsIDOMHTMLCollection.h"
 | |
| #include "nsIDOMHTMLElement.h"
 | |
| #include "nsIDOMRange.h"
 | |
| #include "nsContentCID.h"
 | |
| #include "nsLayoutCID.h"
 | |
| #include "nsContentUtils.h"
 | |
| #include "nsLayoutStylesheetCache.h"
 | |
| 
 | |
| #include "nsViewsCID.h"
 | |
| #include "nsWidgetsCID.h"
 | |
| #include "nsIDeviceContext.h"
 | |
| #include "nsIDeviceContextSpec.h"
 | |
| #include "nsIViewManager.h"
 | |
| #include "nsIView.h"
 | |
| 
 | |
| #include "nsIPageSequenceFrame.h"
 | |
| #include "nsIURL.h"
 | |
| #include "nsNetUtil.h"
 | |
| #include "nsIContentViewerEdit.h"
 | |
| #include "nsIContentViewerFile.h"
 | |
| #include "nsICSSLoader.h"
 | |
| #include "nsIMarkupDocumentViewer.h"
 | |
| #include "nsIInterfaceRequestor.h"
 | |
| #include "nsIInterfaceRequestorUtils.h"
 | |
| #include "nsIDocShellTreeItem.h"
 | |
| #include "nsIDocShellTreeNode.h"
 | |
| #include "nsIDocShellTreeOwner.h"
 | |
| #include "nsIDocShell.h"
 | |
| #include "nsIBaseWindow.h"
 | |
| #include "nsIFrameDebug.h"
 | |
| #include "nsILayoutHistoryState.h"
 | |
| #include "nsIParser.h"
 | |
| #include "nsGUIEvent.h"
 | |
| #include "nsHTMLReflowState.h"
 | |
| #include "nsIDOMHTMLAnchorElement.h"
 | |
| #include "nsIDOMHTMLAreaElement.h"
 | |
| #include "nsIDOMHTMLLinkElement.h"
 | |
| #include "nsIImageLoadingContent.h"
 | |
| #include "nsCopySupport.h"
 | |
| #include "nsIDOMHTMLFrameSetElement.h"
 | |
| #ifdef MOZ_XUL
 | |
| #include "nsIXULDocument.h"
 | |
| #include "nsXULPopupManager.h"
 | |
| #endif
 | |
| #include "nsPrintfCString.h"
 | |
| 
 | |
| #include "nsIClipboardHelper.h"
 | |
| 
 | |
| #include "nsPIDOMWindow.h"
 | |
| #include "nsJSEnvironment.h"
 | |
| #include "nsIFocusController.h"
 | |
| #include "nsIMenuParent.h"
 | |
| 
 | |
| #include "nsIScrollableView.h"
 | |
| #include "nsIHTMLDocument.h"
 | |
| #include "nsITimelineService.h"
 | |
| #include "nsGfxCIID.h"
 | |
| #include "nsStyleSheetService.h"
 | |
| 
 | |
| #include "nsIPrompt.h"
 | |
| #include "imgIContainer.h" // image animation mode constants
 | |
| 
 | |
| //--------------------------
 | |
| // Printing Include
 | |
| //---------------------------
 | |
| #ifdef NS_PRINTING
 | |
| 
 | |
| #include "nsIWebBrowserPrint.h"
 | |
| 
 | |
| #include "nsPrintEngine.h"
 | |
| 
 | |
| // Print Options
 | |
| #include "nsIPrintSettings.h"
 | |
| #include "nsIPrintSettingsService.h"
 | |
| #include "nsIPrintOptions.h"
 | |
| #include "nsIServiceManager.h"
 | |
| #include "nsISimpleEnumerator.h"
 | |
| #include "nsXPCOM.h"
 | |
| #include "nsISupportsPrimitives.h"
 | |
| 
 | |
| // PrintOptions is now implemented by PrintSettingsService
 | |
| static const char sPrintOptionsContractID[]         = "@mozilla.org/gfx/printsettings-service;1";
 | |
| 
 | |
| // Printing Events
 | |
| #include "nsPrintPreviewListener.h"
 | |
| 
 | |
| #include "nsIDOMHTMLFrameElement.h"
 | |
| #include "nsIDOMHTMLIFrameElement.h"
 | |
| #include "nsIDOMHTMLObjectElement.h"
 | |
| #include "nsIPluginDocument.h"
 | |
| 
 | |
| // Print Progress
 | |
| #include "nsIPrintProgress.h"
 | |
| #include "nsIPrintProgressParams.h"
 | |
| 
 | |
| // Print error dialog
 | |
| #include "nsIWindowWatcher.h"
 | |
| 
 | |
| // Printing 
 | |
| #include "nsPrintEngine.h"
 | |
| #include "nsPagePrintTimer.h"
 | |
| 
 | |
| #endif // NS_PRINTING
 | |
| 
 | |
| // FrameSet
 | |
| #include "nsIDocument.h"
 | |
| 
 | |
| //focus
 | |
| #include "nsIDOMEventTarget.h"
 | |
| #include "nsIDOMFocusListener.h"
 | |
| #include "nsISelectionController.h"
 | |
| 
 | |
| #include "nsBidiUtils.h"
 | |
| #include "nsISHEntry.h"
 | |
| #include "nsISHistory.h"
 | |
| #include "nsISHistoryInternal.h"
 | |
| #include "nsIWebNavigation.h"
 | |
| #include "nsWeakPtr.h"
 | |
| #include "nsEventDispatcher.h"
 | |
| #include "nsPresShellIterator.h"
 | |
| 
 | |
| //paint forcing
 | |
| #include "prenv.h"
 | |
| #include <stdio.h>
 | |
| 
 | |
| //switch to page layout
 | |
| #include "nsGfxCIID.h"
 | |
| 
 | |
| #ifdef NS_DEBUG
 | |
| 
 | |
| #undef NOISY_VIEWER
 | |
| #else
 | |
| #undef NOISY_VIEWER
 | |
| #endif
 | |
| 
 | |
| //-----------------------------------------------------
 | |
| // PR LOGGING
 | |
| #ifdef MOZ_LOGGING
 | |
| #define FORCE_PR_LOG /* Allow logging in the release build */
 | |
| #endif
 | |
| 
 | |
| #include "prlog.h"
 | |
| 
 | |
| #ifdef PR_LOGGING
 | |
| 
 | |
| static PRLogModuleInfo * kPrintingLogMod = PR_NewLogModule("printing");
 | |
| #define PR_PL(_p1)  PR_LOG(kPrintingLogMod, PR_LOG_DEBUG, _p1);
 | |
| 
 | |
| #define PRT_YESNO(_p) ((_p)?"YES":"NO")
 | |
| #else
 | |
| #define PRT_YESNO(_p)
 | |
| #define PR_PL(_p1)
 | |
| #endif
 | |
| //-----------------------------------------------------
 | |
| 
 | |
| class DocumentViewerImpl;
 | |
| 
 | |
| // a small delegate class used to avoid circular references
 | |
| 
 | |
| #ifdef XP_MAC
 | |
| #pragma mark ** nsDocViewerSelectionListener **
 | |
| #endif
 | |
| 
 | |
| class nsDocViewerSelectionListener : public nsISelectionListener
 | |
| {
 | |
| public:
 | |
| 
 | |
|   // nsISupports interface...
 | |
|   NS_DECL_ISUPPORTS
 | |
| 
 | |
|   // nsISelectionListerner interface
 | |
|   NS_DECL_NSISELECTIONLISTENER
 | |
| 
 | |
|                        nsDocViewerSelectionListener()
 | |
|                        : mDocViewer(NULL)
 | |
|                        , mGotSelectionState(PR_FALSE)
 | |
|                        , mSelectionWasCollapsed(PR_FALSE)
 | |
|                        {
 | |
|                        }
 | |
| 
 | |
|   virtual              ~nsDocViewerSelectionListener() {}
 | |
| 
 | |
|   nsresult             Init(DocumentViewerImpl *aDocViewer);
 | |
| 
 | |
| protected:
 | |
| 
 | |
|   DocumentViewerImpl*  mDocViewer;
 | |
|   PRPackedBool         mGotSelectionState;
 | |
|   PRPackedBool         mSelectionWasCollapsed;
 | |
| 
 | |
| };
 | |
| 
 | |
| 
 | |
| /** editor Implementation of the FocusListener interface
 | |
|  */
 | |
| class nsDocViewerFocusListener : public nsIDOMFocusListener
 | |
| {
 | |
| public:
 | |
|   /** default constructor
 | |
|    */
 | |
|   nsDocViewerFocusListener();
 | |
|   /** default destructor
 | |
|    */
 | |
|   virtual ~nsDocViewerFocusListener();
 | |
| 
 | |
| 
 | |
| /*interfaces for addref and release and queryinterface*/
 | |
|   NS_DECL_ISUPPORTS
 | |
| 
 | |
| /*BEGIN implementations of focus event handler interface*/
 | |
|   NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
 | |
|   NS_IMETHOD Focus(nsIDOMEvent* aEvent);
 | |
|   NS_IMETHOD Blur(nsIDOMEvent* aEvent);
 | |
| /*END implementations of focus event handler interface*/
 | |
|   nsresult             Init(DocumentViewerImpl *aDocViewer);
 | |
| 
 | |
| private:
 | |
|     DocumentViewerImpl*  mDocViewer;
 | |
| };
 | |
| 
 | |
| 
 | |
| 
 | |
| #ifdef XP_MAC
 | |
| #pragma mark ** DocumentViewerImpl **
 | |
| #endif
 | |
| 
 | |
| //-------------------------------------------------------------
 | |
| class DocumentViewerImpl : public nsIDocumentViewer,
 | |
|                            public nsIContentViewerEdit,
 | |
|                            public nsIContentViewerFile,
 | |
|                            public nsIMarkupDocumentViewer,
 | |
|                            public nsIDocumentViewerPrint
 | |
| 
 | |
| #ifdef NS_PRINTING
 | |
|                            , public nsIWebBrowserPrint
 | |
| #endif
 | |
| 
 | |
| {
 | |
|   friend class nsDocViewerSelectionListener;
 | |
|   friend class nsPagePrintTimer;
 | |
|   friend class nsPrintEngine;
 | |
| 
 | |
| public:
 | |
|   DocumentViewerImpl();
 | |
| 
 | |
|   NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
 | |
| 
 | |
|   // nsISupports interface...
 | |
|   NS_DECL_ISUPPORTS
 | |
| 
 | |
|   // nsIContentViewer interface...
 | |
|   NS_DECL_NSICONTENTVIEWER
 | |
| 
 | |
|   // nsIDocumentViewer interface...
 | |
|   NS_IMETHOD SetUAStyleSheet(nsIStyleSheet* aUAStyleSheet);
 | |
|   NS_IMETHOD GetDocument(nsIDocument** aResult);
 | |
|   NS_IMETHOD GetPresShell(nsIPresShell** aResult);
 | |
|   NS_IMETHOD GetPresContext(nsPresContext** aResult);
 | |
| 
 | |
|   // nsIContentViewerEdit
 | |
|   NS_DECL_NSICONTENTVIEWEREDIT
 | |
| 
 | |
|   // nsIContentViewerFile
 | |
|   NS_DECL_NSICONTENTVIEWERFILE
 | |
| 
 | |
|   // nsIMarkupDocumentViewer
 | |
|   NS_DECL_NSIMARKUPDOCUMENTVIEWER
 | |
| 
 | |
| #ifdef NS_PRINTING
 | |
|   // nsIWebBrowserPrint
 | |
|   NS_DECL_NSIWEBBROWSERPRINT
 | |
| #endif
 | |
| 
 | |
|   typedef void (*CallChildFunc)(nsIMarkupDocumentViewer* aViewer,
 | |
|                                 void* aClosure);
 | |
|   void CallChildren(CallChildFunc aFunc, void* aClosure);
 | |
| 
 | |
|   // nsIDocumentViewerPrint Printing Methods
 | |
|   NS_DECL_NSIDOCUMENTVIEWERPRINT
 | |
| 
 | |
| protected:
 | |
|   virtual ~DocumentViewerImpl();
 | |
| 
 | |
| private:
 | |
|   /**
 | |
|    * Creates a view manager, root view, and widget for the root view, setting
 | |
|    * mViewManager and mWindow.
 | |
|    * @param aSize the initial size in appunits
 | |
|    */
 | |
|   nsresult MakeWindow(const nsSize& aSize);
 | |
|   nsresult InitInternal(nsIWidget* aParentWidget,
 | |
|                         nsISupports *aState,
 | |
|                         nsIDeviceContext* aDeviceContext,
 | |
|                         const nsRect& aBounds,
 | |
|                         PRBool aDoCreation,
 | |
|                         PRBool aInPrintPreview,
 | |
|                         PRBool aNeedMakeCX = PR_TRUE);
 | |
|   /**
 | |
|    * @param aDoInitialReflow set to true if you want to kick off the initial
 | |
|    * reflow
 | |
|    * @param aReenableRefresh set to true if you want this to reenable refresh
 | |
|    * before returning; otherwise this will return with refresh disabled
 | |
|    * in the view manager
 | |
|    */
 | |
|   nsresult InitPresentationStuff(PRBool aDoInitialReflow, PRBool aReenableRefresh);
 | |
| 
 | |
|   nsresult GetPopupNode(nsIDOMNode** aNode);
 | |
|   nsresult GetPopupLinkNode(nsIDOMNode** aNode);
 | |
|   nsresult GetPopupImageNode(nsIImageLoadingContent** aNode);
 | |
| 
 | |
|   void DumpContentToPPM(const char* aFileName);
 | |
| 
 | |
|   void PrepareToStartLoad(void);
 | |
| 
 | |
|   nsresult SyncParentSubDocMap();
 | |
| 
 | |
|   nsresult GetDocumentSelection(nsISelection **aSelection);
 | |
| 
 | |
|   nsresult GetClipboardEventTarget(nsIDOMNode **aEventTarget);
 | |
|   nsresult FireClipboardEvent(PRUint32 msg, PRBool* aPreventDefault);
 | |
| 
 | |
| #ifdef NS_PRINTING
 | |
|   // Called when the DocViewer is notified that the state
 | |
|   // of Printing or PP has changed
 | |
|   void SetIsPrintingInDocShellTree(nsIDocShellTreeNode* aParentNode, 
 | |
|                                    PRBool               aIsPrintingOrPP, 
 | |
|                                    PRBool               aStartAtTop);
 | |
| #endif // NS_PRINTING
 | |
| 
 | |
| protected:
 | |
|   // These return the current shell/prescontext etc.
 | |
|   nsIPresShell* GetPresShell();
 | |
|   nsPresContext* GetPresContext();
 | |
|   nsIViewManager* GetViewManager();
 | |
| 
 | |
|   // IMPORTANT: The ownership implicit in the following member
 | |
|   // variables has been explicitly checked and set using nsCOMPtr
 | |
|   // for owning pointers and raw COM interface pointers for weak
 | |
|   // (ie, non owning) references. If you add any members to this
 | |
|   // class, please make the ownership explicit (pinkerton, scc).
 | |
| 
 | |
|   nsWeakPtr mContainer; // it owns me!
 | |
|   nsCOMPtr<nsIDeviceContext> mDeviceContext;   // ??? can't hurt, but...
 | |
| 
 | |
|   // the following six items are explicitly in this order
 | |
|   // so they will be destroyed in the reverse order (pinkerton, scc)
 | |
|   nsCOMPtr<nsIDocument>    mDocument;
 | |
|   nsCOMPtr<nsIWidget>      mWindow;      // ??? should we really own it?
 | |
|   nsCOMPtr<nsIViewManager> mViewManager;
 | |
|   nsCOMPtr<nsPresContext> mPresContext;
 | |
|   nsCOMPtr<nsIPresShell>   mPresShell;
 | |
| 
 | |
|   nsCOMPtr<nsIStyleSheet>  mUAStyleSheet;
 | |
| 
 | |
|   nsCOMPtr<nsISelectionListener> mSelectionListener;
 | |
|   nsCOMPtr<nsIDOMFocusListener> mFocusListener;
 | |
| 
 | |
|   nsCOMPtr<nsIContentViewer> mPreviousViewer;
 | |
|   nsCOMPtr<nsISHEntry> mSHEntry;
 | |
| 
 | |
|   nsIWidget* mParentWidget;          // purposely won't be ref counted
 | |
| 
 | |
|   // mTextZoom/mPageZoom record the textzoom/pagezoom of the first (galley)
 | |
|   // presshell only.
 | |
|   float mTextZoom;      // Text zoom, defaults to 1.0
 | |
|   float mPageZoom;
 | |
| 
 | |
|   PRInt16 mNumURLStarts;
 | |
|   PRInt16 mDestroyRefCount;    // a second "refcount" for the document viewer's "destroy"
 | |
| 
 | |
|   unsigned      mEnableRendering : 1;
 | |
|   unsigned      mStopped : 1;
 | |
|   unsigned      mLoaded : 1;
 | |
|   unsigned      mDeferredWindowClose : 1;
 | |
|   // document management data
 | |
|   //   these items are specific to markup documents (html and xml)
 | |
|   //   may consider splitting these out into a subclass
 | |
|   unsigned      mIsSticky : 1;
 | |
|   unsigned      mInPermitUnload : 1;
 | |
| 
 | |
| #ifdef NS_PRINTING
 | |
|   unsigned      mClosingWhilePrinting : 1;
 | |
| 
 | |
| #if NS_PRINT_PREVIEW
 | |
|   // These data members support delayed printing when the document is loading
 | |
|   unsigned                         mPrintIsPending : 1;
 | |
|   unsigned                         mPrintDocIsFullyLoaded : 1;
 | |
|   nsCOMPtr<nsIPrintSettings>       mCachedPrintSettings;
 | |
|   nsCOMPtr<nsIWebProgressListener> mCachedPrintWebProgressListner;
 | |
| 
 | |
|   nsCOMPtr<nsPrintEngine>          mPrintEngine;
 | |
| #endif // NS_PRINT_PREVIEW
 | |
| 
 | |
| #ifdef NS_DEBUG
 | |
|   FILE* mDebugFile;
 | |
| #endif // NS_DEBUG
 | |
| #endif // NS_PRINTING
 | |
| 
 | |
|   /* character set member data */
 | |
|   PRInt32 mHintCharsetSource;
 | |
|   nsCString mHintCharset;
 | |
|   nsCString mDefaultCharacterSet;
 | |
|   nsCString mForceCharacterSet;
 | |
|   nsCString mPrevDocCharacterSet;
 | |
|   
 | |
|   PRPackedBool mIsPageMode;
 | |
| 
 | |
| };
 | |
| 
 | |
| //------------------------------------------------------------------
 | |
| // DocumentViewerImpl
 | |
| //------------------------------------------------------------------
 | |
| // Class IDs
 | |
| static NS_DEFINE_CID(kViewManagerCID,       NS_VIEW_MANAGER_CID);
 | |
| static NS_DEFINE_CID(kWidgetCID,            NS_CHILD_CID);
 | |
| 
 | |
| //------------------------------------------------------------------
 | |
| nsresult
 | |
| NS_NewDocumentViewer(nsIDocumentViewer** aResult)
 | |
| {
 | |
|   *aResult = new DocumentViewerImpl();
 | |
|   if (!*aResult) {
 | |
|     return NS_ERROR_OUT_OF_MEMORY;
 | |
|   }
 | |
| 
 | |
|   NS_ADDREF(*aResult);
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| void DocumentViewerImpl::PrepareToStartLoad()
 | |
| {
 | |
|   mEnableRendering  = PR_TRUE;
 | |
|   mStopped          = PR_FALSE;
 | |
|   mLoaded           = PR_FALSE;
 | |
|   mDeferredWindowClose = PR_FALSE;
 | |
| 
 | |
| #ifdef NS_PRINTING
 | |
|   mPrintIsPending        = PR_FALSE;
 | |
|   mPrintDocIsFullyLoaded = PR_FALSE;
 | |
|   mClosingWhilePrinting  = PR_FALSE;
 | |
| 
 | |
|   // Make sure we have destroyed it and cleared the data member
 | |
|   if (mPrintEngine) {
 | |
|     mPrintEngine->Destroy();
 | |
|     mPrintEngine = nsnull;
 | |
|   }
 | |
| 
 | |
| #ifdef NS_PRINT_PREVIEW
 | |
|   SetIsPrintPreview(PR_FALSE);
 | |
| #endif
 | |
| 
 | |
| #ifdef NS_DEBUG
 | |
|   mDebugFile = nsnull;
 | |
| #endif
 | |
| 
 | |
| #endif // NS_PRINTING
 | |
| }
 | |
| 
 | |
| // Note: operator new zeros our memory, so no need to init things to null.
 | |
| DocumentViewerImpl::DocumentViewerImpl()
 | |
|   : mTextZoom(1.0), mPageZoom(1.0),
 | |
|     mIsSticky(PR_TRUE),
 | |
|     mHintCharsetSource(kCharsetUninitialized)
 | |
| {
 | |
|   PrepareToStartLoad();
 | |
| }
 | |
| 
 | |
| NS_IMPL_ADDREF(DocumentViewerImpl)
 | |
| NS_IMPL_RELEASE(DocumentViewerImpl)
 | |
| 
 | |
| NS_INTERFACE_MAP_BEGIN(DocumentViewerImpl)
 | |
|     NS_INTERFACE_MAP_ENTRY(nsIContentViewer)
 | |
|     NS_INTERFACE_MAP_ENTRY(nsIDocumentViewer)
 | |
|     NS_INTERFACE_MAP_ENTRY(nsIMarkupDocumentViewer)
 | |
|     NS_INTERFACE_MAP_ENTRY(nsIContentViewerFile)
 | |
|     NS_INTERFACE_MAP_ENTRY(nsIContentViewerEdit)
 | |
|     NS_INTERFACE_MAP_ENTRY(nsIDocumentViewerPrint)
 | |
|     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentViewer)
 | |
| #ifdef NS_PRINTING
 | |
|     NS_INTERFACE_MAP_ENTRY(nsIWebBrowserPrint)
 | |
| #endif
 | |
| NS_INTERFACE_MAP_END
 | |
| 
 | |
| DocumentViewerImpl::~DocumentViewerImpl()
 | |
| {
 | |
|   if (mDocument) {
 | |
|     Close(nsnull);
 | |
|     mDocument->Destroy();
 | |
|   }
 | |
| 
 | |
|   NS_ASSERTION(!mPresShell && !mPresContext,
 | |
|                "User did not call nsIContentViewer::Destroy");
 | |
|   if (mPresShell || mPresContext) {
 | |
|     // Make sure we don't hand out a reference to the content viewer to
 | |
|     // the SHEntry!
 | |
|     mSHEntry = nsnull;
 | |
| 
 | |
|     Destroy();
 | |
|   }
 | |
| 
 | |
|   // XXX(?) Revoke pending invalidate events
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * This method is called by the Document Loader once a document has
 | |
|  * been created for a particular data stream...  The content viewer
 | |
|  * must cache this document for later use when Init(...) is called.
 | |
|  *
 | |
|  * This method is also called when an out of band document.write() happens.
 | |
|  * In that case, the document passed in is the same as the previous document.
 | |
|  */
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::LoadStart(nsISupports *aDoc)
 | |
| {
 | |
| #ifdef NOISY_VIEWER
 | |
|   printf("DocumentViewerImpl::LoadStart\n");
 | |
| #endif
 | |
| 
 | |
|   nsresult rv = NS_OK;
 | |
|   if (!mDocument) {
 | |
|     mDocument = do_QueryInterface(aDoc, &rv);
 | |
|   }
 | |
|   else if (mDocument == aDoc) {
 | |
|     // Reset the document viewer's state back to what it was
 | |
|     // when the document load started.
 | |
|     PrepareToStartLoad();
 | |
|   }
 | |
| 
 | |
|   return rv;
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| DocumentViewerImpl::SyncParentSubDocMap()
 | |
| {
 | |
|   nsCOMPtr<nsIDocShellTreeItem> item(do_QueryReferent(mContainer));
 | |
|   nsCOMPtr<nsPIDOMWindow> pwin(do_GetInterface(item));
 | |
|   nsCOMPtr<nsIContent> content;
 | |
| 
 | |
|   if (mDocument && pwin) {
 | |
|     content = do_QueryInterface(pwin->GetFrameElementInternal());
 | |
|   }
 | |
| 
 | |
|   if (content) {
 | |
|     nsCOMPtr<nsIDocShellTreeItem> parent;
 | |
|     item->GetParent(getter_AddRefs(parent));
 | |
| 
 | |
|     nsCOMPtr<nsIDOMWindow> parent_win(do_GetInterface(parent));
 | |
| 
 | |
|     if (parent_win) {
 | |
|       nsCOMPtr<nsIDOMDocument> dom_doc;
 | |
|       parent_win->GetDocument(getter_AddRefs(dom_doc));
 | |
| 
 | |
|       nsCOMPtr<nsIDocument> parent_doc(do_QueryInterface(dom_doc));
 | |
| 
 | |
|       if (parent_doc) {
 | |
|         return parent_doc->SetSubDocumentFor(content, mDocument);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::SetContainer(nsISupports* aContainer)
 | |
| {
 | |
|   mContainer = do_GetWeakReference(aContainer);
 | |
|   if (mPresContext) {
 | |
|     mPresContext->SetContainer(aContainer);
 | |
|   }
 | |
| 
 | |
|   // We're loading a new document into the window where this document
 | |
|   // viewer lives, sync the parent document's frame element -> sub
 | |
|   // document map
 | |
| 
 | |
|   return SyncParentSubDocMap();
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::GetContainer(nsISupports** aResult)
 | |
| {
 | |
|    NS_ENSURE_ARG_POINTER(aResult);
 | |
| 
 | |
|    *aResult = nsnull;
 | |
|    nsCOMPtr<nsISupports> container = do_QueryReferent(mContainer);
 | |
|    container.swap(*aResult);
 | |
|    return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::Init(nsIWidget* aParentWidget,
 | |
|                          nsIDeviceContext* aDeviceContext,
 | |
|                          const nsRect& aBounds)
 | |
| {
 | |
|   return InitInternal(aParentWidget, nsnull, aDeviceContext, aBounds, PR_TRUE, PR_FALSE);
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| DocumentViewerImpl::InitPresentationStuff(PRBool aDoInitialReflow, PRBool aReenableRefresh)
 | |
| {
 | |
|   // Create the style set...
 | |
|   nsStyleSet *styleSet;
 | |
|   nsresult rv = CreateStyleSet(mDocument, &styleSet);
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   // Now make the shell for the document
 | |
|   rv = mDocument->CreateShell(mPresContext, mViewManager, styleSet,
 | |
|                               getter_AddRefs(mPresShell));
 | |
|   if (NS_FAILED(rv)) {
 | |
|     delete styleSet;
 | |
|     return rv;
 | |
|   }
 | |
| 
 | |
|   // We're done creating the style set
 | |
|   styleSet->EndUpdate();
 | |
| 
 | |
|   if (aDoInitialReflow) {
 | |
|     // Since InitialReflow() will create frames for *all* items
 | |
|     // that are currently in the document tree, we need to flush
 | |
|     // any pending notifications to prevent the content sink from
 | |
|     // duplicating layout frames for content it has added to the tree
 | |
|     // but hasn't notified the document about. (Bug 154018)
 | |
|     //
 | |
|     // Note that we are flushing before we add mPresShell as an observer
 | |
|     // to avoid bogus notifications.
 | |
| 
 | |
|     mDocument->FlushPendingNotifications(Flush_ContentAndNotify);
 | |
|   }
 | |
| 
 | |
|   mPresShell->BeginObservingDocument();
 | |
| 
 | |
|   // Initialize our view manager
 | |
|   nsRect bounds;
 | |
|   mWindow->GetBounds(bounds);
 | |
| 
 | |
|   nscoord width = mPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel() * bounds.width;
 | |
|   nscoord height = mPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel() * bounds.height;
 | |
| 
 | |
|   mViewManager->DisableRefresh();
 | |
|   mViewManager->SetWindowDimensions(width, height);
 | |
|   mPresContext->SetTextZoom(mTextZoom);
 | |
|   mPresContext->SetFullZoom(mPageZoom);
 | |
| 
 | |
|   // Setup default view manager background color
 | |
| 
 | |
|   // This may be overridden by the docshell with the background color
 | |
|   // for the last document loaded into the docshell
 | |
|   mViewManager->SetDefaultBackgroundColor(mPresContext->DefaultBackgroundColor());
 | |
| 
 | |
|   if (aDoInitialReflow) {
 | |
|     nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(mDocument);
 | |
|     if (htmlDoc) {
 | |
|       nsCOMPtr<nsIDOMHTMLFrameSetElement> frameset =
 | |
|         do_QueryInterface(mDocument->GetRootContent());
 | |
|       htmlDoc->SetIsFrameset(frameset != nsnull);
 | |
|     }
 | |
| 
 | |
|     nsCOMPtr<nsIPresShell> shellGrip = mPresShell;
 | |
|     // Initial reflow
 | |
|     mPresShell->InitialReflow(width, height);
 | |
|   } else {
 | |
|     // Store the visible area so it's available for other callers of
 | |
|     // InitialReflow, like nsContentSink::StartLayout.
 | |
|     mPresContext->SetVisibleArea(nsRect(0, 0, width, height));
 | |
|   }
 | |
| 
 | |
|   // Now trigger a refresh
 | |
|   if (aReenableRefresh && mEnableRendering && mViewManager) {
 | |
|     mViewManager->EnableRefresh(NS_VMREFRESH_IMMEDIATE);
 | |
|   }
 | |
| 
 | |
|   // now register ourselves as a selection listener, so that we get
 | |
|   // called when the selection changes in the window
 | |
|   nsDocViewerSelectionListener *selectionListener =
 | |
|     new nsDocViewerSelectionListener();
 | |
|   NS_ENSURE_TRUE(selectionListener, NS_ERROR_OUT_OF_MEMORY);
 | |
| 
 | |
|   selectionListener->Init(this);
 | |
| 
 | |
|   // mSelectionListener is a owning reference
 | |
|   mSelectionListener = selectionListener;
 | |
| 
 | |
|   nsCOMPtr<nsISelection> selection;
 | |
|   rv = GetDocumentSelection(getter_AddRefs(selection));
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(selection));
 | |
|   rv = selPrivate->AddSelectionListener(mSelectionListener);
 | |
|   if (NS_FAILED(rv))
 | |
|     return rv;
 | |
| 
 | |
|   // Save old listener so we can unregister it
 | |
|   nsCOMPtr<nsIDOMFocusListener> oldFocusListener = mFocusListener;
 | |
| 
 | |
|   // focus listener
 | |
|   //
 | |
|   // now register ourselves as a focus listener, so that we get called
 | |
|   // when the focus changes in the window
 | |
|   nsDocViewerFocusListener *focusListener;
 | |
|   NS_NEWXPCOM(focusListener, nsDocViewerFocusListener);
 | |
|   NS_ENSURE_TRUE(focusListener, NS_ERROR_OUT_OF_MEMORY);
 | |
| 
 | |
|   focusListener->Init(this);
 | |
| 
 | |
|   // mFocusListener is a strong reference
 | |
|   mFocusListener = focusListener;
 | |
| 
 | |
|   if (mDocument) {
 | |
|     rv = mDocument->AddEventListenerByIID(mFocusListener,
 | |
|                                           NS_GET_IID(nsIDOMFocusListener));
 | |
|     NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register focus listener");
 | |
|     if (oldFocusListener) {
 | |
|       rv = mDocument->RemoveEventListenerByIID(oldFocusListener,
 | |
|                                                NS_GET_IID(nsIDOMFocusListener));
 | |
|       NS_ASSERTION(NS_SUCCEEDED(rv), "failed to remove focus listener");
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| //-----------------------------------------------
 | |
| // This method can be used to initial the "presentation"
 | |
| // The aDoCreation indicates whether it should create
 | |
| // all the new objects or just initialize the existing ones
 | |
| nsresult
 | |
| DocumentViewerImpl::InitInternal(nsIWidget* aParentWidget,
 | |
|                                  nsISupports *aState,
 | |
|                                  nsIDeviceContext* aDeviceContext,
 | |
|                                  const nsRect& aBounds,
 | |
|                                  PRBool aDoCreation,
 | |
|                                  PRBool aInPrintPreview,
 | |
|                                  PRBool aNeedMakeCX /*= PR_TRUE*/)
 | |
| {
 | |
|   mParentWidget = aParentWidget; // not ref counted
 | |
| 
 | |
|   nsresult rv = NS_OK;
 | |
|   NS_ENSURE_TRUE(mDocument, NS_ERROR_NULL_POINTER);
 | |
| 
 | |
|   mDeviceContext = aDeviceContext;
 | |
| 
 | |
|   PRBool makeCX = PR_FALSE;
 | |
|   if (aDoCreation) {
 | |
|     if (aParentWidget && !mPresContext) {
 | |
|       // Create presentation context
 | |
|       if (mIsPageMode) {
 | |
|         //Presentation context already created in SetPageMode which is calling this method
 | |
|       }
 | |
|       else
 | |
|         mPresContext =
 | |
|             new nsPresContext(mDocument, nsPresContext::eContext_Galley);
 | |
|       NS_ENSURE_TRUE(mPresContext, NS_ERROR_OUT_OF_MEMORY);
 | |
| 
 | |
|       nsresult rv = mPresContext->Init(aDeviceContext); 
 | |
|       if (NS_FAILED(rv)) {
 | |
|         mPresContext = nsnull;
 | |
|         return rv;
 | |
|       }
 | |
| 
 | |
| #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
 | |
|       makeCX = !GetIsPrintPreview() && aNeedMakeCX; // needs to be true except when we are already in PP or we are enabling/disabling paginated mode.
 | |
| #else
 | |
|       makeCX = PR_TRUE;
 | |
| #endif
 | |
|     }
 | |
| 
 | |
|     if (mPresContext) {
 | |
|       // Create the ViewManager and Root View...
 | |
| 
 | |
|       // We must do this before we tell the script global object about
 | |
|       // this new document since doing that will cause us to re-enter
 | |
|       // into nsSubDocumentFrame code through reflows caused by
 | |
|       // FlushPendingNotifications() calls down the road...
 | |
| 
 | |
|       rv = MakeWindow(nsSize(mPresContext->DevPixelsToAppUnits(aBounds.width),
 | |
|                              mPresContext->DevPixelsToAppUnits(aBounds.height)));
 | |
|       NS_ENSURE_SUCCESS(rv, rv);
 | |
|       Hide();
 | |
| 
 | |
| #ifdef NS_PRINT_PREVIEW
 | |
|       if (mIsPageMode) {
 | |
|         // I'm leaving this in a broken state for the moment; we should
 | |
|         // be measuring/scaling with the print device context, not the
 | |
|         // screen device context, but this is good enough to allow
 | |
|         // printing reftests to work.
 | |
| #if 0
 | |
|         nsCOMPtr<nsIDeviceContextSpec> devspec =
 | |
|           do_CreateInstance("@mozilla.org/gfx/devicecontextspec;1", &rv);
 | |
|         NS_ENSURE_SUCCESS(rv, rv);
 | |
|         // mWindow has been initialized by preceding call to MakeWindow
 | |
|         rv = devspec->Init(mWindow, mPresContext->GetPrintSettings(), PR_FALSE);
 | |
|         NS_ENSURE_SUCCESS(rv, rv);
 | |
|         nsCOMPtr<nsIDeviceContext> devctx =
 | |
|           do_CreateInstance("@mozilla.org/gfx/devicecontext;1", &rv);
 | |
|         NS_ENSURE_SUCCESS(rv, rv);
 | |
|         rv = devctx->InitForPrinting(devspec);
 | |
|         NS_ENSURE_SUCCESS(rv, rv);
 | |
|         // XXX I'm breaking this code; I'm not sure I really want to mess with
 | |
|         // the document viewer at the moment to get the right device context
 | |
|         // (this won't break anyone, since page layout mode was never really
 | |
|         // usable)
 | |
| #endif
 | |
|         double pageWidth = 0, pageHeight = 0;
 | |
|         mPresContext->GetPrintSettings()->GetEffectivePageSize(&pageWidth,
 | |
|                                                                &pageHeight);
 | |
|         mPresContext->SetPageSize(
 | |
|           nsSize(mPresContext->TwipsToAppUnits(NSToIntFloor(pageWidth)),
 | |
|                  mPresContext->TwipsToAppUnits(NSToIntFloor(pageHeight))));
 | |
|         mPresContext->SetIsRootPaginatedDocument(PR_TRUE);
 | |
|         mPresContext->SetPageScale(1.0f);
 | |
|       }
 | |
| #endif
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsIInterfaceRequestor> requestor(do_QueryReferent(mContainer));
 | |
|   if (requestor) {
 | |
|     if (mPresContext) {
 | |
|       nsCOMPtr<nsILinkHandler> linkHandler;
 | |
|       requestor->GetInterface(NS_GET_IID(nsILinkHandler),
 | |
|                               getter_AddRefs(linkHandler));
 | |
| 
 | |
|       mPresContext->SetContainer(requestor);
 | |
|       mPresContext->SetLinkHandler(linkHandler);
 | |
|     }
 | |
| 
 | |
|     if (!aInPrintPreview) {
 | |
|       // Set script-context-owner in the document
 | |
| 
 | |
|       nsCOMPtr<nsPIDOMWindow> window;
 | |
|       requestor->GetInterface(NS_GET_IID(nsPIDOMWindow),
 | |
|                               getter_AddRefs(window));
 | |
| 
 | |
|       if (window) {
 | |
|         window->SetNewDocument(mDocument, aState, PR_TRUE);
 | |
| 
 | |
|         nsJSContext::LoadStart();
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (aDoCreation && mPresContext) {
 | |
|     // The ViewManager and Root View was created above (in
 | |
|     // MakeWindow())...
 | |
| 
 | |
|     rv = InitPresentationStuff(!makeCX, !makeCX);
 | |
|   }
 | |
| 
 | |
|   return rv;
 | |
| }
 | |
| 
 | |
| //
 | |
| // LoadComplete(aStatus)
 | |
| //
 | |
| //   aStatus - The status returned from loading the document.
 | |
| //
 | |
| // This method is called by the container when the document has been
 | |
| // completely loaded.
 | |
| //
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::LoadComplete(nsresult aStatus)
 | |
| {
 | |
|   /* We need to protect ourself against auto-destruction in case the
 | |
|      window is closed while processing the OnLoad event.  See bug
 | |
|      http://bugzilla.mozilla.org/show_bug.cgi?id=78445 for more
 | |
|      explanation.
 | |
|   */
 | |
|   nsCOMPtr<nsIDocumentViewer> kungFuDeathGrip(this);
 | |
| 
 | |
|   // Flush out layout so it's up-to-date by the time onload is called.
 | |
|   // Note that this could destroy the window, so do this before
 | |
|   // checking for our mDocument and its window.
 | |
|   if (mPresShell && !mStopped) {
 | |
|     // Hold strong ref because this could conceivably run script
 | |
|     nsCOMPtr<nsIPresShell> shell = mPresShell;
 | |
|     shell->FlushPendingNotifications(Flush_Layout);
 | |
|   }
 | |
|   
 | |
|   nsresult rv = NS_OK;
 | |
|   NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
 | |
| 
 | |
|   // First, get the window from the document...
 | |
|   nsPIDOMWindow *window = mDocument->GetWindow();
 | |
| 
 | |
|   // Fail if no window is available...
 | |
|   NS_ENSURE_TRUE(window, NS_ERROR_NULL_POINTER);
 | |
| 
 | |
|   mLoaded = PR_TRUE;
 | |
| 
 | |
|   // Now, fire either an OnLoad or OnError event to the document...
 | |
|   PRBool restoring = PR_FALSE;
 | |
|   if(NS_SUCCEEDED(aStatus)) {
 | |
|     nsEventStatus status = nsEventStatus_eIgnore;
 | |
|     nsEvent event(PR_TRUE, NS_LOAD);
 | |
|     event.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
 | |
|      // XXX Dispatching to |window|, but using |document| as the target.
 | |
|     event.target = mDocument;
 | |
| 
 | |
|     // If the document presentation is being restored, we don't want to fire
 | |
|     // onload to the document content since that would likely confuse scripts
 | |
|     // on the page.
 | |
| 
 | |
|     nsIDocShell *docShell = window->GetDocShell();
 | |
|     NS_ENSURE_TRUE(docShell, NS_ERROR_UNEXPECTED);
 | |
| 
 | |
|     docShell->GetRestoringDocument(&restoring);
 | |
|     if (!restoring) {
 | |
|       nsEventDispatcher::Dispatch(window, mPresContext, &event, nsnull,
 | |
|                                   &status);
 | |
| #ifdef MOZ_TIMELINE
 | |
|       // if navigator.xul's load is complete, the main nav window is visible
 | |
|       // mark that point.
 | |
| 
 | |
|       //printf("DEBUG: getting uri from document (%p)\n", mDocument.get());
 | |
| 
 | |
|       nsIURI *uri = mDocument ? mDocument->GetDocumentURI() : nsnull;
 | |
| 
 | |
|       if (uri) {
 | |
|         //printf("DEBUG: getting spec for uri (%p)\n", uri.get());
 | |
|         nsCAutoString spec;
 | |
|         uri->GetSpec(spec);
 | |
|         if (spec.EqualsLiteral("chrome://navigator/content/navigator.xul") ||
 | |
|             spec.EqualsLiteral("chrome://browser/content/browser.xul")) {
 | |
|           NS_TIMELINE_MARK("Navigator Window visible now");
 | |
|         }
 | |
|       }
 | |
| #endif /* MOZ_TIMELINE */
 | |
|     }
 | |
|   } else {
 | |
|     // XXX: Should fire error event to the document...
 | |
|   }
 | |
| 
 | |
|   // Notify the document that it has been shown (regardless of whether
 | |
|   // it was just loaded). Note: mDocument may be null now if the above
 | |
|   // firing of onload caused the document to unload.
 | |
|   if (mDocument)
 | |
|     mDocument->OnPageShow(restoring);
 | |
| 
 | |
|   // Now that the document has loaded, we can tell the presshell
 | |
|   // to unsuppress painting.
 | |
|   if (mPresShell && !mStopped) {
 | |
|     nsCOMPtr<nsIPresShell> shellDeathGrip(mPresShell); // bug 378682
 | |
|     mPresShell->UnsuppressPainting();
 | |
|   }
 | |
| 
 | |
|   nsJSContext::LoadEnd();
 | |
| 
 | |
| #ifdef NS_PRINTING
 | |
|   // Check to see if someone tried to print during the load
 | |
|   if (mPrintIsPending) {
 | |
|     mPrintIsPending        = PR_FALSE;
 | |
|     mPrintDocIsFullyLoaded = PR_TRUE;
 | |
|     Print(mCachedPrintSettings, mCachedPrintWebProgressListner);
 | |
|     mCachedPrintSettings           = nsnull;
 | |
|     mCachedPrintWebProgressListner = nsnull;
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|   return rv;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::PermitUnload(PRBool *aPermitUnload)
 | |
| {
 | |
|   *aPermitUnload = PR_TRUE;
 | |
| 
 | |
|   if (!mDocument || mInPermitUnload) {
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   // First, get the script global object from the document...
 | |
|   nsPIDOMWindow *window = mDocument->GetWindow();
 | |
| 
 | |
|   if (!window) {
 | |
|     // This is odd, but not fatal
 | |
|     NS_WARNING("window not set for document!");
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   // Now, fire an BeforeUnload event to the document and see if it's ok
 | |
|   // to unload...
 | |
|   nsEventStatus status = nsEventStatus_eIgnore;
 | |
|   nsBeforePageUnloadEvent event(PR_TRUE, NS_BEFORE_PAGE_UNLOAD);
 | |
|   event.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
 | |
|   // XXX Dispatching to |window|, but using |document| as the target.
 | |
|   event.target = mDocument;
 | |
|   nsresult rv = NS_OK;
 | |
| 
 | |
|   // In evil cases we might be destroyed while handling the
 | |
|   // onbeforeunload event, don't let that happen. (see also bug#331040)
 | |
|   nsRefPtr<DocumentViewerImpl> kungFuDeathGrip(this);
 | |
| 
 | |
|   {
 | |
|     // Never permit popups from the beforeunload handler, no matter
 | |
|     // how we get here.
 | |
|     nsAutoPopupStatePusher popupStatePusher(openAbused, PR_TRUE);
 | |
| 
 | |
|     mInPermitUnload = PR_TRUE;
 | |
|     nsEventDispatcher::Dispatch(window, mPresContext, &event, nsnull, &status);
 | |
|     mInPermitUnload = PR_FALSE;
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsIDocShellTreeNode> docShellNode(do_QueryReferent(mContainer));
 | |
| 
 | |
|   if (NS_SUCCEEDED(rv) && (event.flags & NS_EVENT_FLAG_NO_DEFAULT ||
 | |
|                            !event.text.IsEmpty())) {
 | |
|     // Ask the user if it's ok to unload the current page
 | |
| 
 | |
|     nsCOMPtr<nsIPrompt> prompt = do_GetInterface(docShellNode);
 | |
| 
 | |
|     if (prompt) {
 | |
|       nsXPIDLString preMsg, postMsg;
 | |
|       rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
 | |
|                                               "OnBeforeUnloadPreMessage",
 | |
|                                               preMsg);
 | |
|       rv |= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
 | |
|                                                "OnBeforeUnloadPostMessage",
 | |
|                                                postMsg);
 | |
| 
 | |
|       // GetStringFromName can succeed, yet give NULL strings back.
 | |
|       if (NS_FAILED(rv) || preMsg.IsEmpty() || postMsg.IsEmpty()) {
 | |
|         NS_ERROR("Failed to get strings from dom.properties!");
 | |
|         return NS_OK;
 | |
|       }
 | |
| 
 | |
|       // Limit the length of the text the page can inject into this
 | |
|       // dialogue to 1024 characters.
 | |
|       PRInt32 len = PR_MIN(event.text.Length(), 1024);
 | |
| 
 | |
|       nsAutoString msg;
 | |
|       if (len == 0) {
 | |
|         msg = preMsg + NS_LITERAL_STRING("\n\n") + postMsg;
 | |
|       } else {
 | |
|         msg = preMsg + NS_LITERAL_STRING("\n\n") +
 | |
|               StringHead(event.text, len) +
 | |
|               NS_LITERAL_STRING("\n\n") + postMsg;
 | |
|       } 
 | |
| 
 | |
|       // This doesn't pass a title, which makes the title be
 | |
|       // "Confirm", is that ok, or do we want a localizable title for
 | |
|       // this dialogue?
 | |
|       if (NS_FAILED(prompt->Confirm(nsnull, msg.get(), aPermitUnload))) {
 | |
|         *aPermitUnload = PR_TRUE;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (docShellNode) {
 | |
|     PRInt32 childCount;
 | |
|     docShellNode->GetChildCount(&childCount);
 | |
| 
 | |
|     for (PRInt32 i = 0; i < childCount && *aPermitUnload; ++i) {
 | |
|       nsCOMPtr<nsIDocShellTreeItem> item;
 | |
|       docShellNode->GetChildAt(i, getter_AddRefs(item));
 | |
| 
 | |
|       nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(item));
 | |
| 
 | |
|       if (docShell) {
 | |
|         nsCOMPtr<nsIContentViewer> cv;
 | |
|       docShell->GetContentViewer(getter_AddRefs(cv));
 | |
| 
 | |
|       if (cv) {
 | |
|         cv->PermitUnload(aPermitUnload);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::PageHide(PRBool aIsUnload)
 | |
| {
 | |
|   mEnableRendering = PR_FALSE;
 | |
| 
 | |
|   if (!mDocument) {
 | |
|     return NS_ERROR_NULL_POINTER;
 | |
|   }
 | |
| 
 | |
|   mDocument->OnPageHide(!aIsUnload);
 | |
|   if (aIsUnload) {
 | |
|     // if Destroy() was called during OnPageHide(), mDocument is nsnull.
 | |
|     NS_ENSURE_STATE(mDocument);
 | |
| 
 | |
|     // First, get the window from the document...
 | |
|     nsPIDOMWindow *window = mDocument->GetWindow();
 | |
| 
 | |
|     if (!window) {
 | |
|       // Fail if no window is available...
 | |
|       NS_ERROR("window not set for document!");
 | |
|       return NS_ERROR_NULL_POINTER;
 | |
|     }
 | |
| 
 | |
|     // Now, fire an Unload event to the document...
 | |
|     nsEventStatus status = nsEventStatus_eIgnore;
 | |
|     nsEvent event(PR_TRUE, NS_PAGE_UNLOAD);
 | |
|     event.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
 | |
|     // XXX Dispatching to |window|, but using |document| as the target.
 | |
|     event.target = mDocument;
 | |
| 
 | |
|     // Never permit popups from the unload handler, no matter how we get
 | |
|     // here.
 | |
|     nsAutoPopupStatePusher popupStatePusher(openAbused, PR_TRUE);
 | |
| 
 | |
|     nsEventDispatcher::Dispatch(window, mPresContext, &event, nsnull, &status);
 | |
|   }
 | |
| 
 | |
| #ifdef MOZ_XUL
 | |
|   // look for open menupopups and close them after the unload event, in case
 | |
|   // the unload event listeners open any new popups
 | |
|   nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
 | |
|   if (pm && mDocument)
 | |
|     pm->HidePopupsInDocument(mDocument);
 | |
| #endif
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| static void
 | |
| AttachContainerRecurse(nsIDocShell* aShell)
 | |
| {
 | |
|   nsCOMPtr<nsIContentViewer> viewer;
 | |
|   aShell->GetContentViewer(getter_AddRefs(viewer));
 | |
|   nsCOMPtr<nsIDocumentViewer> docViewer = do_QueryInterface(viewer);
 | |
|   if (docViewer) {
 | |
|     nsCOMPtr<nsIDocument> doc;
 | |
|     docViewer->GetDocument(getter_AddRefs(doc));
 | |
|     if (doc) {
 | |
|       doc->SetContainer(aShell);
 | |
|     }
 | |
|     nsCOMPtr<nsPresContext> pc;
 | |
|     docViewer->GetPresContext(getter_AddRefs(pc));
 | |
|     if (pc) {
 | |
|       pc->SetContainer(aShell);
 | |
|       pc->SetLinkHandler(nsCOMPtr<nsILinkHandler>(do_QueryInterface(aShell)));
 | |
|     }
 | |
|     nsCOMPtr<nsIPresShell> presShell;
 | |
|     docViewer->GetPresShell(getter_AddRefs(presShell));
 | |
|     if (presShell) {
 | |
|       presShell->SetForwardingContainer(nsnull);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // Now recurse through the children
 | |
|   nsCOMPtr<nsIDocShellTreeNode> node = do_QueryInterface(aShell);
 | |
|   NS_ASSERTION(node, "docshells must implement nsIDocShellTreeNode");
 | |
| 
 | |
|   PRInt32 childCount;
 | |
|   node->GetChildCount(&childCount);
 | |
|   for (PRInt32 i = 0; i < childCount; ++i) {
 | |
|     nsCOMPtr<nsIDocShellTreeItem> childItem;
 | |
|     node->GetChildAt(i, getter_AddRefs(childItem));
 | |
|     AttachContainerRecurse(nsCOMPtr<nsIDocShell>(do_QueryInterface(childItem)));
 | |
|   }
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::Open(nsISupports *aState, nsISHEntry *aSHEntry)
 | |
| {
 | |
|   NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);
 | |
| 
 | |
|   // Our container might have gone away while we were closed.
 | |
|   // If this is the case, we must fail to open so we don't crash.
 | |
|   nsCOMPtr<nsISupports> container = do_QueryReferent(mContainer);
 | |
|   if (!container)
 | |
|     return NS_ERROR_NOT_AVAILABLE;
 | |
| 
 | |
|   nsRect bounds;
 | |
|   mWindow->GetBounds(bounds);
 | |
| 
 | |
|   nsresult rv = InitInternal(mParentWidget, aState, mDeviceContext, bounds,
 | |
|                              PR_FALSE, PR_FALSE);
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   if (mDocument)
 | |
|     mDocument->SetContainer(nsCOMPtr<nsISupports>(do_QueryReferent(mContainer)));
 | |
| 
 | |
|   if (mPresShell)
 | |
|     mPresShell->SetForwardingContainer(nsnull);
 | |
| 
 | |
|   // Rehook the child presentations.  The child shells are still in
 | |
|   // session history, so get them from there.
 | |
| 
 | |
|   nsCOMPtr<nsIDocShellTreeItem> item;
 | |
|   PRInt32 itemIndex = 0;
 | |
|   while (NS_SUCCEEDED(aSHEntry->ChildShellAt(itemIndex++,
 | |
|                                              getter_AddRefs(item))) && item) {
 | |
|     AttachContainerRecurse(nsCOMPtr<nsIDocShell>(do_QueryInterface(item)));
 | |
|   }
 | |
|   
 | |
|   SyncParentSubDocMap();
 | |
| 
 | |
|   if (mFocusListener && mDocument) {
 | |
|     mDocument->AddEventListenerByIID(mFocusListener,
 | |
|                                      NS_GET_IID(nsIDOMFocusListener));
 | |
|   }
 | |
| 
 | |
|   // XXX re-enable image animations once that works correctly
 | |
| 
 | |
|   PrepareToStartLoad();
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::Close(nsISHEntry *aSHEntry)
 | |
| {
 | |
|   // All callers are supposed to call close to break circular
 | |
|   // references.  If we do this stuff in the destructor, the
 | |
|   // destructor might never be called (especially if we're being
 | |
|   // used from JS.
 | |
| 
 | |
|   mSHEntry = aSHEntry;
 | |
| 
 | |
|   // Close is also needed to disable scripts during paint suppression,
 | |
|   // since we transfer the existing global object to the new document
 | |
|   // that is loaded.  In the future, the global object may become a proxy
 | |
|   // for an object that can be switched in and out so that we don't need
 | |
|   // to disable scripts during paint suppression.
 | |
| 
 | |
|   if (!mDocument)
 | |
|     return NS_OK;
 | |
| 
 | |
| #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
 | |
|   // Turn scripting back on
 | |
|   // after PrintPreview had turned it off
 | |
|   if (GetIsPrintPreview() && mPrintEngine) {
 | |
|     mPrintEngine->TurnScriptingOn(PR_TRUE);
 | |
|   }
 | |
| #endif
 | |
| 
 | |
| #ifdef NS_PRINTING
 | |
|   // A Close was called while we were printing
 | |
|   // so don't clear the ScriptGlobalObject
 | |
|   // or clear the mDocument below
 | |
|   // Also, do an extra addref to keep the viewer from going away.
 | |
|   if (mPrintEngine && !mClosingWhilePrinting) {
 | |
|     mClosingWhilePrinting = PR_TRUE;
 | |
|     NS_ADDREF_THIS();
 | |
|   } else
 | |
| #endif
 | |
|     {
 | |
|       // out of band cleanup of webshell
 | |
|       mDocument->SetScriptGlobalObject(nsnull);
 | |
| 
 | |
|       if (!mSHEntry)
 | |
|         mDocument->Destroy();
 | |
|     }
 | |
| 
 | |
|   if (mFocusListener && mDocument) {
 | |
|     mDocument->RemoveEventListenerByIID(mFocusListener,
 | |
|                                         NS_GET_IID(nsIDOMFocusListener));
 | |
|   }
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| static void
 | |
| DetachContainerRecurse(nsIDocShell *aShell)
 | |
| {
 | |
|   // Unhook this docshell's presentation
 | |
|   nsCOMPtr<nsIContentViewer> viewer;
 | |
|   aShell->GetContentViewer(getter_AddRefs(viewer));
 | |
|   nsCOMPtr<nsIDocumentViewer> docViewer = do_QueryInterface(viewer);
 | |
|   if (docViewer) {
 | |
|     nsCOMPtr<nsIDocument> doc;
 | |
|     docViewer->GetDocument(getter_AddRefs(doc));
 | |
|     if (doc) {
 | |
|       doc->SetContainer(nsnull);
 | |
|     }
 | |
|     nsCOMPtr<nsPresContext> pc;
 | |
|     docViewer->GetPresContext(getter_AddRefs(pc));
 | |
|     if (pc) {
 | |
|       pc->SetContainer(nsnull);
 | |
|       pc->SetLinkHandler(nsnull);
 | |
|     }
 | |
|     nsCOMPtr<nsIPresShell> presShell;
 | |
|     docViewer->GetPresShell(getter_AddRefs(presShell));
 | |
|     if (presShell) {
 | |
|       presShell->SetForwardingContainer(nsWeakPtr(do_GetWeakReference(aShell)));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // Now recurse through the children
 | |
|   nsCOMPtr<nsIDocShellTreeNode> node = do_QueryInterface(aShell);
 | |
|   NS_ASSERTION(node, "docshells must implement nsIDocShellTreeNode");
 | |
| 
 | |
|   PRInt32 childCount;
 | |
|   node->GetChildCount(&childCount);
 | |
|   for (PRInt32 i = 0; i < childCount; ++i) {
 | |
|     nsCOMPtr<nsIDocShellTreeItem> childItem;
 | |
|     node->GetChildAt(i, getter_AddRefs(childItem));
 | |
|     DetachContainerRecurse(nsCOMPtr<nsIDocShell>(do_QueryInterface(childItem)));
 | |
|   }
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::Destroy()
 | |
| {
 | |
|   NS_ASSERTION(mDocument, "No document in Destroy()!");
 | |
| 
 | |
| #ifdef NS_PRINTING
 | |
|   // Here is where we check to see if the docment was still being prepared 
 | |
|   // for printing when it was asked to be destroy from someone externally
 | |
|   // This usually happens if the document is unloaded while the user is in the Print Dialog
 | |
|   //
 | |
|   // So we flip the bool to remember that the document is going away
 | |
|   // and we can clean up and abort later after returning from the Print Dialog
 | |
|   if (mPrintEngine) {
 | |
|     if (mPrintEngine->CheckBeforeDestroy()) {
 | |
|       return NS_OK;
 | |
|     }
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|   // Don't let the document get unloaded while we are printing.
 | |
|   // this could happen if we hit the back button during printing.
 | |
|   // We also keep the viewer from being cached in session history, since
 | |
|   // we require all documents there to be sanitized.
 | |
|   if (mDestroyRefCount != 0) {
 | |
|     --mDestroyRefCount;
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   // If we were told to put ourselves into session history instead of destroy
 | |
|   // the presentation, do that now.
 | |
|   if (mSHEntry) {
 | |
|     if (mPresShell)
 | |
|       mPresShell->Freeze();
 | |
| 
 | |
|     // Make sure the presentation isn't torn down by Hide().
 | |
|     mSHEntry->SetSticky(mIsSticky);
 | |
|     mIsSticky = PR_TRUE;
 | |
| 
 | |
|     PRBool savePresentation = PR_TRUE;
 | |
| 
 | |
|     // Remove our root view from the view hierarchy.
 | |
|     if (mPresShell) {
 | |
|       nsIViewManager *vm = mPresShell->GetViewManager();
 | |
|       if (vm) {
 | |
|         nsIView *rootView = nsnull;
 | |
|         vm->GetRootView(rootView);
 | |
| 
 | |
|         if (rootView) {
 | |
|           nsIView *rootViewParent = rootView->GetParent();
 | |
|           if (rootViewParent) {
 | |
|             nsIViewManager *parentVM = rootViewParent->GetViewManager();
 | |
|             if (parentVM) {
 | |
|               parentVM->RemoveChild(rootView);
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
| #ifdef NS_PRINTING
 | |
|   if (mPrintEngine) {
 | |
|     // This code was moved earlier to fix a crash when a document was
 | |
|     // destroyed while it was in print preview mode, see bug 396024
 | |
| #ifdef NS_PRINT_PREVIEW
 | |
|     PRBool doingPrintPreview;
 | |
|     mPrintEngine->GetDoingPrintPreview(&doingPrintPreview);
 | |
|     if (doingPrintPreview) {
 | |
|       mPrintEngine->FinishPrintPreview();
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|     mPrintEngine->Destroy();
 | |
|     mPrintEngine = nsnull;
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|     Hide();
 | |
| 
 | |
|     // This is after Hide() so that the user doesn't see the inputs clear.
 | |
|     if (mDocument) {
 | |
|       nsresult rv = mDocument->Sanitize();
 | |
|       if (NS_FAILED(rv)) {
 | |
|         // If we failed to sanitize, don't save presentation.
 | |
|         savePresentation = PR_FALSE;
 | |
|       }
 | |
|     }
 | |
| 
 | |
| 
 | |
|     // Reverse ownership. Do this *after* calling sanitize so that sanitize
 | |
|     // doesn't cause mutations that make the SHEntry drop the presentation
 | |
|     if (savePresentation) {
 | |
|       mSHEntry->SetContentViewer(this);
 | |
|     }
 | |
|     else {
 | |
|       mSHEntry->SyncPresentationState();
 | |
|     }
 | |
|     nsCOMPtr<nsISHEntry> shEntry = mSHEntry; // we'll need this below
 | |
|     mSHEntry = nsnull;
 | |
| 
 | |
|     // Break the link from the document/presentation to the docshell, so that
 | |
|     // link traversals cannot affect the currently-loaded document.
 | |
|     // When the presentation is restored, Open() and InitInternal() will reset
 | |
|     // these pointers to their original values.
 | |
| 
 | |
|     if (mDocument)
 | |
|       mDocument->SetContainer(nsnull);
 | |
|     if (mPresContext) {
 | |
|       mPresContext->SetLinkHandler(nsnull);
 | |
|       mPresContext->SetContainer(nsnull);
 | |
|     }
 | |
|     if (mPresShell)
 | |
|       mPresShell->SetForwardingContainer(mContainer);
 | |
| 
 | |
|     // Do the same for our children.  Note that we need to get the child
 | |
|     // docshells from the SHEntry now; the docshell will have cleared them.
 | |
|     nsCOMPtr<nsIDocShellTreeItem> item;
 | |
|     PRInt32 itemIndex = 0;
 | |
|     while (NS_SUCCEEDED(shEntry->ChildShellAt(itemIndex++,
 | |
|                                               getter_AddRefs(item))) && item) {
 | |
|       DetachContainerRecurse(nsCOMPtr<nsIDocShell>(do_QueryInterface(item)));
 | |
|     }
 | |
| 
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   if (mDocument) {
 | |
|     mDocument->Destroy();
 | |
|     mDocument = nsnull;
 | |
|   }
 | |
| 
 | |
|   // All callers are supposed to call destroy to break circular
 | |
|   // references.  If we do this stuff in the destructor, the
 | |
|   // destructor might never be called (especially if we're being
 | |
|   // used from JS.
 | |
| 
 | |
|   // Avoid leaking the old viewer.
 | |
|   if (mPreviousViewer) {
 | |
|     mPreviousViewer->Destroy();
 | |
|     mPreviousViewer = nsnull;
 | |
|   }
 | |
| 
 | |
|   if (mDeviceContext) {
 | |
|     mDeviceContext->FlushFontCache();
 | |
|     mDeviceContext = nsnull;
 | |
|   }
 | |
| 
 | |
|   if (mPresShell) {
 | |
|     // Break circular reference (or something)
 | |
|     mPresShell->EndObservingDocument();
 | |
| 
 | |
|     nsCOMPtr<nsISelection> selection;
 | |
|     GetDocumentSelection(getter_AddRefs(selection));
 | |
| 
 | |
|     nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(selection));
 | |
| 
 | |
|     if (selPrivate && mSelectionListener)
 | |
|       selPrivate->RemoveSelectionListener(mSelectionListener);
 | |
| 
 | |
|     mPresShell->Destroy();
 | |
|     mPresShell = nsnull;
 | |
|   }
 | |
| 
 | |
|   if (mPresContext) {
 | |
|     mPresContext->SetContainer(nsnull);
 | |
|     mPresContext->SetLinkHandler(nsnull);
 | |
|     mPresContext = nsnull;
 | |
|   }
 | |
| 
 | |
|   mContainer = nsnull;
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::Stop(void)
 | |
| {
 | |
|   NS_ASSERTION(mDocument, "Stop called too early or too late");
 | |
|   if (mDocument) {
 | |
|     mDocument->StopDocumentLoad();
 | |
|   }
 | |
| 
 | |
|   if (mEnableRendering && (mLoaded || mStopped) && mPresContext && !mSHEntry)
 | |
|     mPresContext->SetImageAnimationMode(imgIContainer::kDontAnimMode);
 | |
| 
 | |
|   mStopped = PR_TRUE;
 | |
| 
 | |
|   if (!mLoaded && mPresShell) {
 | |
|     // Well, we might as well paint what we have so far.
 | |
|     nsCOMPtr<nsIPresShell> shellDeathGrip(mPresShell); // bug 378682
 | |
|     mPresShell->UnsuppressPainting();
 | |
|   }
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::GetDOMDocument(nsIDOMDocument **aResult)
 | |
| {
 | |
|   NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
 | |
|   return CallQueryInterface(mDocument, aResult);
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::SetDOMDocument(nsIDOMDocument *aDocument)
 | |
| {
 | |
|   // Assumptions:
 | |
|   //
 | |
|   // 1) this document viewer has been initialized with a call to Init().
 | |
|   // 2) the stylesheets associated with the document have been added
 | |
|   // to the document.
 | |
| 
 | |
|   // XXX Right now, this method assumes that the layout of the current
 | |
|   // document hasn't started yet.  More cleanup will probably be
 | |
|   // necessary to make this method work for the case when layout *has*
 | |
|   // occurred for the current document.
 | |
|   // That work can happen when and if it is needed.
 | |
| 
 | |
|   nsresult rv;
 | |
|   if (!aDocument)
 | |
|     return NS_ERROR_NULL_POINTER;
 | |
| 
 | |
|   nsCOMPtr<nsIDocument> newDoc = do_QueryInterface(aDocument, &rv);
 | |
|   if (NS_FAILED(rv)) return rv;
 | |
| 
 | |
|   // Set new container
 | |
|   nsCOMPtr<nsISupports> container = do_QueryReferent(mContainer);
 | |
|   newDoc->SetContainer(container);
 | |
| 
 | |
|   if (mDocument != newDoc) {
 | |
|     // Replace the old document with the new one. Do this only when
 | |
|     // the new document really is a new document.
 | |
|     mDocument = newDoc;
 | |
| 
 | |
|     // Set the script global object on the new document
 | |
|     nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(container);
 | |
|     if (window) {
 | |
|       window->SetNewDocument(newDoc, nsnull, PR_TRUE);
 | |
|     }
 | |
| 
 | |
|     // Clear the list of old child docshells. CChild docshells for the new
 | |
|     // document will be constructed as frames are created.
 | |
|     nsCOMPtr<nsIDocShellTreeNode> node = do_QueryInterface(container);
 | |
|     if (node) {
 | |
|       PRInt32 count;
 | |
|       node->GetChildCount(&count);
 | |
|       for (PRInt32 i = 0; i < count; ++i) {
 | |
|         nsCOMPtr<nsIDocShellTreeItem> child;
 | |
|         node->GetChildAt(0, getter_AddRefs(child));
 | |
|         node->RemoveChild(child);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   rv = SyncParentSubDocMap();
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   // Replace the current pres shell with a new shell for the new document
 | |
| 
 | |
|   nsCOMPtr<nsILinkHandler> linkHandler;
 | |
|   if (mPresShell) {
 | |
|     nsSize currentSize(0, 0);
 | |
| 
 | |
|     if (mViewManager) {
 | |
|       mViewManager->GetWindowDimensions(¤tSize.width, ¤tSize.height);
 | |
|     }
 | |
| 
 | |
|     if (mPresContext) {
 | |
|       // Save the linkhandler (nsPresShell::Destroy removes it from
 | |
|       // mPresContext).
 | |
|       linkHandler = mPresContext->GetLinkHandler();
 | |
|     }
 | |
| 
 | |
|     mPresShell->EndObservingDocument();
 | |
|     mPresShell->Destroy();
 | |
| 
 | |
|     mPresShell = nsnull;
 | |
| 
 | |
|     // This destroys the root view because it was associated with the root frame,
 | |
|     // which has been torn down. Recreate the viewmanager and root view.
 | |
|     MakeWindow(currentSize);
 | |
|   }
 | |
| 
 | |
|   // And if we're already given a prescontext...
 | |
|   if (mPresContext) {
 | |
|     // If we had a linkHandler and it got removed, put it back.
 | |
|     if (linkHandler) {
 | |
|       mPresContext->SetLinkHandler(linkHandler);
 | |
|     }
 | |
| 
 | |
|     rv = InitPresentationStuff(PR_FALSE, PR_TRUE);
 | |
|   }
 | |
| 
 | |
|   return rv;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::SetUAStyleSheet(nsIStyleSheet* aUAStyleSheet)
 | |
| {
 | |
|   NS_ASSERTION(aUAStyleSheet, "unexpected null pointer");
 | |
|   nsCOMPtr<nsICSSStyleSheet> sheet(do_QueryInterface(aUAStyleSheet));
 | |
|   if (sheet) {
 | |
|     nsCOMPtr<nsICSSStyleSheet> newSheet;
 | |
|     sheet->Clone(nsnull, nsnull, nsnull, nsnull, getter_AddRefs(newSheet));
 | |
|     mUAStyleSheet = newSheet;
 | |
|   }
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::GetDocument(nsIDocument** aResult)
 | |
| {
 | |
|   NS_IF_ADDREF(*aResult = mDocument);
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| nsIPresShell*
 | |
| DocumentViewerImpl::GetPresShell()
 | |
| {
 | |
|   if (!GetIsPrintPreview()) {
 | |
|     return mPresShell;
 | |
|   }
 | |
|   NS_ENSURE_TRUE(mDocument, nsnull);
 | |
|   nsCOMPtr<nsIPresShell> shell;
 | |
|   nsCOMPtr<nsIPresShell> currentShell;
 | |
|   nsPresShellIterator iter(mDocument);
 | |
|   while ((shell = iter.GetNextShell())) {
 | |
|     currentShell.swap(shell);
 | |
|   }
 | |
|   return currentShell.get();
 | |
| }
 | |
| 
 | |
| nsPresContext*
 | |
| DocumentViewerImpl::GetPresContext()
 | |
| {
 | |
|   if (!GetIsPrintPreview()) {
 | |
|     return mPresContext;
 | |
|   }
 | |
|   nsIPresShell* shell = GetPresShell();
 | |
|   return shell ? shell->GetPresContext() : nsnull;
 | |
| }
 | |
| 
 | |
| nsIViewManager*
 | |
| DocumentViewerImpl::GetViewManager()
 | |
| {
 | |
|   if (!GetIsPrintPreview()) {
 | |
|     return mViewManager;
 | |
|   }
 | |
|   nsIPresShell* shell = GetPresShell();
 | |
|   return shell ? shell->GetViewManager() : nsnull;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::GetPresShell(nsIPresShell** aResult)
 | |
| {
 | |
|   nsIPresShell* shell = GetPresShell();
 | |
|   NS_IF_ADDREF(*aResult = shell);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::GetPresContext(nsPresContext** aResult)
 | |
| {
 | |
|   nsPresContext* pc = GetPresContext();
 | |
|   NS_IF_ADDREF(*aResult = pc);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::GetBounds(nsRect& aResult)
 | |
| {
 | |
|   NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
 | |
|   NS_PRECONDITION(mWindow, "null window");
 | |
|   if (mWindow) {
 | |
|     mWindow->GetBounds(aResult);
 | |
|   }
 | |
|   else {
 | |
|     aResult.SetRect(0, 0, 0, 0);
 | |
|   }
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::GetPreviousViewer(nsIContentViewer** aViewer)
 | |
| {
 | |
|   *aViewer = mPreviousViewer;
 | |
|   NS_IF_ADDREF(*aViewer);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::SetPreviousViewer(nsIContentViewer* aViewer)
 | |
| {
 | |
|   // NOTE:  |Show| sets |mPreviousViewer| to null without calling this
 | |
|   // function.
 | |
| 
 | |
|   if (aViewer) {
 | |
|     NS_ASSERTION(!mPreviousViewer,
 | |
|                  "can't set previous viewer when there already is one");
 | |
| 
 | |
|     // In a multiple chaining situation (which occurs when running a thrashing
 | |
|     // test like i-bench or jrgm's tests with no delay), we can build up a
 | |
|     // whole chain of viewers.  In order to avoid this, we always set our previous
 | |
|     // viewer to the MOST previous viewer in the chain, and then dump the intermediate
 | |
|     // link from the chain.  This ensures that at most only 2 documents are alive
 | |
|     // and undestroyed at any given time (the one that is showing and the one that
 | |
|     // is loading with painting suppressed).
 | |
|     // It's very important that if this ever gets changed the code
 | |
|     // before the RestorePresentation call in nsDocShell::InternalLoad
 | |
|     // be changed accordingly.
 | |
|     nsCOMPtr<nsIContentViewer> prevViewer;
 | |
|     aViewer->GetPreviousViewer(getter_AddRefs(prevViewer));
 | |
|     if (prevViewer) {
 | |
|       aViewer->SetPreviousViewer(nsnull);
 | |
|       aViewer->Destroy();
 | |
|       return SetPreviousViewer(prevViewer);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   mPreviousViewer = aViewer;
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::SetBounds(const nsRect& aBounds)
 | |
| {
 | |
|   NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
 | |
| 
 | |
|   if (mWindow) {
 | |
|     // Don't have the widget repaint. Layout will generate repaint requests
 | |
|     // during reflow
 | |
|     mWindow->Resize(aBounds.x, aBounds.y, aBounds.width, aBounds.height,
 | |
|                     PR_FALSE);
 | |
|   }
 | |
| 
 | |
|   // If there's a previous viewer, it's the one that's actually showing,
 | |
|   // so be sure to resize it as well so it paints over the right area.
 | |
|   // This may slow down the performance of the new page load, but resize
 | |
|   // during load is also probably a relatively unusual condition
 | |
|   // relating to things being hidden while something is loaded.  It so
 | |
|   // happens that Firefox does this a good bit with its infobar, and it
 | |
|   // looks ugly if we don't do this.
 | |
|   if (mPreviousViewer)
 | |
|     mPreviousViewer->SetBounds(aBounds);
 | |
| 
 | |
| #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
 | |
|   if (GetIsPrintPreview() && !mPrintEngine->GetIsCreatingPrintPreview()) {
 | |
|     mPrintEngine->GetPrintPreviewWindow()->Resize(aBounds.x, aBounds.y,
 | |
|                                                   aBounds.width, aBounds.height,
 | |
|                                                   PR_FALSE);
 | |
|   }
 | |
| #endif
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::Move(PRInt32 aX, PRInt32 aY)
 | |
| {
 | |
|   NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
 | |
|   NS_PRECONDITION(mWindow, "null window");
 | |
|   if (mWindow) {
 | |
|     mWindow->Move(aX, aY);
 | |
|   }
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::Show(void)
 | |
| {
 | |
|   NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
 | |
| 
 | |
|   // We don't need the previous viewer anymore since we're not
 | |
|   // displaying it.
 | |
|   if (mPreviousViewer) {
 | |
|     // This little dance *may* only be to keep
 | |
|     // PresShell::EndObservingDocument happy, but I'm not sure.
 | |
|     nsCOMPtr<nsIContentViewer> prevViewer(mPreviousViewer);
 | |
|     mPreviousViewer = nsnull;
 | |
|     prevViewer->Destroy();
 | |
| 
 | |
|     // Make sure we don't have too many cached ContentViewers
 | |
|     nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryReferent(mContainer);
 | |
|     if (treeItem) {
 | |
|       // We need to find the root DocShell since only that object has an
 | |
|       // SHistory and we need the SHistory to evict content viewers
 | |
|       nsCOMPtr<nsIDocShellTreeItem> root;
 | |
|       treeItem->GetSameTypeRootTreeItem(getter_AddRefs(root));
 | |
|       nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(root);
 | |
|       nsCOMPtr<nsISHistory> history;
 | |
|       webNav->GetSessionHistory(getter_AddRefs(history));
 | |
|       nsCOMPtr<nsISHistoryInternal> historyInt = do_QueryInterface(history);
 | |
|       if (historyInt) {
 | |
|         PRInt32 prevIndex,loadedIndex;
 | |
|         nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(treeItem);
 | |
|         docShell->GetPreviousTransIndex(&prevIndex);
 | |
|         docShell->GetLoadedTransIndex(&loadedIndex);
 | |
| #ifdef DEBUG_PAGE_CACHE
 | |
|         printf("About to evict content viewers: prev=%d, loaded=%d\n",
 | |
|                prevIndex, loadedIndex);
 | |
| #endif
 | |
|         historyInt->EvictContentViewers(prevIndex, loadedIndex);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (mWindow) {
 | |
|     mWindow->Show(PR_TRUE);
 | |
|   }
 | |
| 
 | |
|   if (mDocument && !mPresShell && !mWindow) {
 | |
|     nsresult rv;
 | |
| 
 | |
|     nsCOMPtr<nsIBaseWindow> base_win(do_QueryReferent(mContainer));
 | |
|     NS_ENSURE_TRUE(base_win, NS_ERROR_UNEXPECTED);
 | |
| 
 | |
|     base_win->GetParentWidget(&mParentWidget);
 | |
|     NS_ENSURE_TRUE(mParentWidget, NS_ERROR_UNEXPECTED);
 | |
|     mParentWidget->Release(); // GetParentWidget AddRefs, but mParentWidget is weak
 | |
| 
 | |
|     mDeviceContext = mParentWidget->GetDeviceContext();
 | |
| 
 | |
|     // Create presentation context
 | |
|     NS_ASSERTION(!mPresContext, "Shouldn't have a prescontext if we have no shell!");
 | |
|     mPresContext = new nsPresContext(mDocument, nsPresContext::eContext_Galley);
 | |
|     NS_ENSURE_TRUE(mPresContext, NS_ERROR_OUT_OF_MEMORY);
 | |
| 
 | |
|     rv = mPresContext->Init(mDeviceContext);
 | |
|     if (NS_FAILED(rv)) {
 | |
|       mPresContext = nsnull;
 | |
|       return rv;
 | |
|     }
 | |
| 
 | |
|     nsRect tbounds;
 | |
|     mParentWidget->GetBounds(tbounds);
 | |
| 
 | |
|     rv = MakeWindow(nsSize(mPresContext->DevPixelsToAppUnits(tbounds.width),
 | |
|                            mPresContext->DevPixelsToAppUnits(tbounds.height)));
 | |
|     if (NS_FAILED(rv))
 | |
|       return rv;
 | |
| 
 | |
|     if (mPresContext && base_win) {
 | |
|       nsCOMPtr<nsILinkHandler> linkHandler(do_GetInterface(base_win));
 | |
| 
 | |
|       if (linkHandler) {
 | |
|         mPresContext->SetLinkHandler(linkHandler);
 | |
|       }
 | |
| 
 | |
|       mPresContext->SetContainer(base_win);
 | |
|     }
 | |
| 
 | |
|     if (mPresContext) {
 | |
|       Hide();
 | |
| 
 | |
|       rv = InitPresentationStuff(PR_TRUE, PR_TRUE);
 | |
|     }
 | |
| 
 | |
|     // If we get here the document load has already started and the
 | |
|     // window is shown because some JS on the page caused it to be
 | |
|     // shown...
 | |
| 
 | |
|     nsCOMPtr<nsIPresShell> shellDeathGrip(mPresShell); // bug 378682
 | |
|     mPresShell->UnsuppressPainting();
 | |
|   }
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::Hide(void)
 | |
| {
 | |
|   NS_PRECONDITION(mWindow, "null window");
 | |
|   if (mWindow) {
 | |
|     mWindow->Show(PR_FALSE);
 | |
|   }
 | |
| 
 | |
|   if (!mPresShell)
 | |
|     return NS_OK;
 | |
| 
 | |
|   NS_ASSERTION(mPresContext, "Can't have a presshell and no prescontext!");
 | |
| 
 | |
|   // Avoid leaking the old viewer.
 | |
|   if (mPreviousViewer) {
 | |
|     mPreviousViewer->Destroy();
 | |
|     mPreviousViewer = nsnull;
 | |
|   }
 | |
| 
 | |
|   if (mIsSticky) {
 | |
|     // This window is sticky, that means that it might be shown again
 | |
|     // and we don't want the presshell n' all that to be thrown away
 | |
|     // just because the window is hidden.
 | |
| 
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   if (mDeviceContext) {
 | |
|     mDeviceContext->FlushFontCache();
 | |
|   }
 | |
| 
 | |
|   // Break circular reference (or something)
 | |
|   mPresShell->EndObservingDocument();
 | |
|   nsCOMPtr<nsISelection> selection;
 | |
| 
 | |
|   GetDocumentSelection(getter_AddRefs(selection));
 | |
| 
 | |
|   nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(selection));
 | |
| 
 | |
|   if (selPrivate && mSelectionListener) {
 | |
|     selPrivate->RemoveSelectionListener(mSelectionListener);
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mContainer));
 | |
|   if (docShell) {
 | |
|     PRBool saveLayoutState = PR_FALSE;
 | |
|     docShell->GetShouldSaveLayoutState(&saveLayoutState);
 | |
|     if (saveLayoutState) {
 | |
|       nsCOMPtr<nsILayoutHistoryState> layoutState;
 | |
|       mPresShell->CaptureHistoryState(getter_AddRefs(layoutState), PR_TRUE);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   mPresShell->Destroy();
 | |
|   // Clear weak refs
 | |
|   mPresContext->SetContainer(nsnull);
 | |
|   mPresContext->SetLinkHandler(nsnull);                             
 | |
| 
 | |
|   mPresShell     = nsnull;
 | |
|   mPresContext   = nsnull;
 | |
|   mViewManager   = nsnull;
 | |
|   mWindow        = nsnull;
 | |
|   mDeviceContext = nsnull;
 | |
|   mParentWidget  = nsnull;
 | |
| 
 | |
|   nsCOMPtr<nsIBaseWindow> base_win(do_QueryReferent(mContainer));
 | |
| 
 | |
|   if (base_win) {
 | |
|     base_win->SetParentWidget(nsnull);
 | |
|   }
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::SetEnableRendering(PRBool aOn)
 | |
| {
 | |
|   NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
 | |
|   mEnableRendering = aOn;
 | |
|   if (mViewManager) {
 | |
|     if (aOn) {
 | |
|       mViewManager->EnableRefresh(NS_VMREFRESH_IMMEDIATE);
 | |
|       nsIView* view;
 | |
|       mViewManager->GetRootView(view);   // views are not refCounted
 | |
|       if (view) {
 | |
|         mViewManager->UpdateView(view, NS_VMREFRESH_IMMEDIATE);
 | |
|       }
 | |
|     }
 | |
|     else {
 | |
|       mViewManager->DisableRefresh();
 | |
|     }
 | |
|   }
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::GetSticky(PRBool *aSticky)
 | |
| {
 | |
|   *aSticky = mIsSticky;
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::SetSticky(PRBool aSticky)
 | |
| {
 | |
|   mIsSticky = aSticky;
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::GetEnableRendering(PRBool* aResult)
 | |
| {
 | |
|   NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
 | |
|   NS_PRECONDITION(nsnull != aResult, "null OUT ptr");
 | |
|   if (aResult) {
 | |
|     *aResult = mEnableRendering;
 | |
|   }
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::RequestWindowClose(PRBool* aCanClose)
 | |
| {
 | |
| #ifdef NS_PRINTING
 | |
|   if (mPrintIsPending || (mPrintEngine && mPrintEngine->GetIsPrinting())) {
 | |
|     *aCanClose = PR_FALSE;
 | |
|     mDeferredWindowClose = PR_TRUE;
 | |
|   } else
 | |
| #endif
 | |
|     *aCanClose = PR_TRUE;
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| PR_STATIC_CALLBACK(PRBool)
 | |
| AppendAgentSheet(nsIStyleSheet *aSheet, void *aData)
 | |
| {
 | |
|   nsStyleSet *styleSet = static_cast<nsStyleSet*>(aData);
 | |
|   styleSet->AppendStyleSheet(nsStyleSet::eAgentSheet, aSheet);
 | |
|   return PR_TRUE;
 | |
| }
 | |
| 
 | |
| PR_STATIC_CALLBACK(PRBool)
 | |
| PrependUserSheet(nsIStyleSheet *aSheet, void *aData)
 | |
| {
 | |
|   nsStyleSet *styleSet = static_cast<nsStyleSet*>(aData);
 | |
|   styleSet->PrependStyleSheet(nsStyleSet::eUserSheet, aSheet);
 | |
|   return PR_TRUE;
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| DocumentViewerImpl::CreateStyleSet(nsIDocument* aDocument,
 | |
|                                    nsStyleSet** aStyleSet)
 | |
| {
 | |
|   // Make sure this does the same thing as PresShell::AddSheet wrt ordering.
 | |
| 
 | |
|   // this should eventually get expanded to allow for creating
 | |
|   // different sets for different media
 | |
|   if (!mUAStyleSheet) {
 | |
|     NS_WARNING("unable to load UA style sheet");
 | |
|   }
 | |
| 
 | |
|   nsStyleSet *styleSet = new nsStyleSet();
 | |
|   if (!styleSet) {
 | |
|     return NS_ERROR_OUT_OF_MEMORY;
 | |
|   }
 | |
| 
 | |
|   styleSet->BeginUpdate();
 | |
|   
 | |
|   // The document will fill in the document sheets when we create the presshell
 | |
|   
 | |
|   // Handle the user sheets.
 | |
|   nsCOMPtr<nsIDocShellTreeItem> docShell(do_QueryReferent(mContainer));
 | |
|   PRInt32 shellType;
 | |
|   docShell->GetItemType(&shellType);
 | |
|   nsICSSStyleSheet* sheet = nsnull;
 | |
|   if (shellType == nsIDocShellTreeItem::typeChrome) {
 | |
|     sheet = nsLayoutStylesheetCache::UserChromeSheet();
 | |
|   }
 | |
|   else {
 | |
|     sheet = nsLayoutStylesheetCache::UserContentSheet();
 | |
|   }
 | |
| 
 | |
|   if (sheet)
 | |
|     styleSet->AppendStyleSheet(nsStyleSet::eUserSheet, sheet);
 | |
| 
 | |
|   // Append chrome sheets (scrollbars + forms).
 | |
|   PRBool shouldOverride = PR_FALSE;
 | |
|   nsCOMPtr<nsIDocShell> ds(do_QueryInterface(docShell));
 | |
|   nsCOMPtr<nsIDOMEventTarget> chromeHandler;
 | |
|   nsCOMPtr<nsIURI> uri;
 | |
|   nsCOMPtr<nsICSSStyleSheet> csssheet;
 | |
| 
 | |
|   ds->GetChromeEventHandler(getter_AddRefs(chromeHandler));
 | |
|   if (chromeHandler) {
 | |
|     nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(chromeHandler));
 | |
|     nsCOMPtr<nsIContent> content(do_QueryInterface(elt));
 | |
|     if (elt && content) {
 | |
|       nsCOMPtr<nsIURI> baseURI = content->GetBaseURI();
 | |
| 
 | |
|       nsAutoString sheets;
 | |
|       elt->GetAttribute(NS_LITERAL_STRING("usechromesheets"), sheets);
 | |
|       if (!sheets.IsEmpty() && baseURI) {
 | |
|         nsCOMPtr<nsICSSLoader> cssLoader;
 | |
|         NS_NewCSSLoader(getter_AddRefs(cssLoader));
 | |
| 
 | |
|         char *str = ToNewCString(sheets);
 | |
|         char *newStr = str;
 | |
|         char *token;
 | |
|         while ( (token = nsCRT::strtok(newStr, ", ", &newStr)) ) {
 | |
|           NS_NewURI(getter_AddRefs(uri), nsDependentCString(token), nsnull,
 | |
|                     baseURI);
 | |
|           if (!uri) continue;
 | |
| 
 | |
|           cssLoader->LoadSheetSync(uri, getter_AddRefs(csssheet));
 | |
|           if (!sheet) continue;
 | |
| 
 | |
|           styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, csssheet);
 | |
|           shouldOverride = PR_TRUE;
 | |
|         }
 | |
|         nsMemory::Free(str);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!shouldOverride) {
 | |
|     sheet = nsLayoutStylesheetCache::ScrollbarsSheet();
 | |
|     if (sheet) {
 | |
|       styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   sheet = nsLayoutStylesheetCache::FormsSheet();
 | |
|   if (sheet) {
 | |
|     styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet);
 | |
|   }
 | |
| 
 | |
|   if (mUAStyleSheet) {
 | |
|     styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, mUAStyleSheet);
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsIStyleSheetService> dummy =
 | |
|     do_GetService(NS_STYLESHEETSERVICE_CONTRACTID);
 | |
| 
 | |
|   nsStyleSheetService *sheetService = nsStyleSheetService::gInstance;
 | |
|   if (sheetService) {
 | |
|     sheetService->AgentStyleSheets()->EnumerateForwards(AppendAgentSheet,
 | |
|                                                         styleSet);
 | |
|     sheetService->UserStyleSheets()->EnumerateBackwards(PrependUserSheet,
 | |
|                                                         styleSet);
 | |
|   }
 | |
| 
 | |
|   // Caller will handle calling EndUpdate, per contract.
 | |
|   *aStyleSet = styleSet;
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::ClearHistoryEntry()
 | |
| {
 | |
|   mSHEntry = nsnull;
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| //-------------------------------------------------------
 | |
| 
 | |
| nsresult
 | |
| DocumentViewerImpl::MakeWindow(const nsSize& aSize)
 | |
| {
 | |
|   nsresult rv;
 | |
| 
 | |
|   mViewManager = do_CreateInstance(kViewManagerCID, &rv);
 | |
|   if (NS_FAILED(rv))
 | |
|     return rv;
 | |
| 
 | |
|   nsIDeviceContext *dx = mPresContext->DeviceContext();
 | |
| 
 | |
|   rv = mViewManager->Init(dx);
 | |
|   if (NS_FAILED(rv))
 | |
|     return rv;
 | |
| 
 | |
|   // Create a child window of the parent that is our "root view/window"
 | |
|   // if aParentWidget has a view, we'll hook our view manager up to its view tree
 | |
|   nsIView* containerView = nsIView::GetViewFor(mParentWidget);
 | |
| 
 | |
|   if (containerView) {
 | |
|     // see if the containerView has already been hooked into a foreign view manager hierarchy
 | |
|     // if it has, then we have to hook into the hierarchy too otherwise bad things will happen.
 | |
|     nsIViewManager* containerVM = containerView->GetViewManager();
 | |
|     nsIView* pView = containerView;
 | |
|     do {
 | |
|       pView = pView->GetParent();
 | |
|     } while (pView && pView->GetViewManager() == containerVM);
 | |
| 
 | |
|     if (!pView) {
 | |
|       // OK, so the container is not already hooked up into a foreign view manager hierarchy.
 | |
|       // That means we can choose not to hook ourselves up.
 | |
|       //
 | |
|       // If the parent container is a chrome shell and we are a content shell
 | |
|       // then we won't hook into its view
 | |
|       // tree. This will improve performance a little bit (especially given scrolling/painting perf bugs)
 | |
|       // but is really just for peace of mind. This check can be removed if we want to support fancy
 | |
|       // chrome effects like transparent controls floating over content, transparent Web browsers, and
 | |
|       // things like that, and the perf bugs are fixed.
 | |
|       nsCOMPtr<nsIDocShellTreeItem> container(do_QueryReferent(mContainer));
 | |
|       nsCOMPtr<nsIDocShellTreeItem> sameTypeParent;
 | |
|       if (container) {
 | |
|         container->GetSameTypeParent(getter_AddRefs(sameTypeParent));
 | |
|       }
 | |
|       if (!sameTypeParent) {
 | |
|         containerView = nsnull;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // The root view is always at 0,0.
 | |
|   nsRect tbounds(nsPoint(0, 0), aSize);
 | |
|   // Create a view
 | |
|   nsIView* view = mViewManager->CreateView(tbounds, containerView);
 | |
|   if (!view)
 | |
|     return NS_ERROR_OUT_OF_MEMORY;
 | |
| 
 | |
|   // pass in a native widget to be the parent widget ONLY if the view hierarchy will stand alone.
 | |
|   // otherwise the view will find its own parent widget and "do the right thing" to
 | |
|   // establish a parent/child widget relationship
 | |
|   rv = view->CreateWidget(kWidgetCID, nsnull,
 | |
|                           containerView != nsnull ? nsnull : mParentWidget->GetNativeData(NS_NATIVE_WIDGET),
 | |
|                           PR_TRUE, PR_FALSE);
 | |
|   if (NS_FAILED(rv))
 | |
|     return rv;
 | |
| 
 | |
|   // Setup hierarchical relationship in view manager
 | |
|   mViewManager->SetRootView(view);
 | |
| 
 | |
|   mWindow = view->GetWidget();
 | |
| 
 | |
|   // This SetFocus is necessary so the Arrow Key and Page Key events
 | |
|   // go to the scrolled view as soon as the Window is created instead of going to
 | |
|   // the browser window (this enables keyboard scrolling of the document)
 | |
|   // mWindow->SetFocus();
 | |
| 
 | |
|   return rv;
 | |
| }
 | |
| 
 | |
| // Return the selection for the document. Note that text fields have their
 | |
| // own selection, which cannot be accessed with this method. Use
 | |
| // mPresShell->GetSelectionForCopy() instead.
 | |
| nsresult DocumentViewerImpl::GetDocumentSelection(nsISelection **aSelection)
 | |
| {
 | |
|   NS_ENSURE_ARG_POINTER(aSelection);
 | |
|   if (!mPresShell) {
 | |
|     return NS_ERROR_NOT_INITIALIZED;
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsISelectionController> selcon;
 | |
|   selcon = do_QueryInterface(mPresShell);
 | |
|   if (selcon)
 | |
|     return selcon->GetSelection(nsISelectionController::SELECTION_NORMAL,
 | |
|                                 aSelection);
 | |
|   return NS_ERROR_FAILURE;
 | |
| }
 | |
| 
 | |
| /* ========================================================================================
 | |
|  * nsIContentViewerEdit
 | |
|  * ======================================================================================== */
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::Search()
 | |
| {
 | |
|   // Nothing to do here.
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::GetSearchable(PRBool *aSearchable)
 | |
| {
 | |
|   // Nothing to do here.
 | |
|   *aSearchable = PR_FALSE;
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::ClearSelection()
 | |
| {
 | |
|   nsresult rv;
 | |
|   nsCOMPtr<nsISelection> selection;
 | |
| 
 | |
|   // use mPresShell->GetSelectionForCopy() ?
 | |
|   rv = GetDocumentSelection(getter_AddRefs(selection));
 | |
|   if (NS_FAILED(rv)) return rv;
 | |
| 
 | |
|   return selection->CollapseToStart();
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::SelectAll()
 | |
| {
 | |
|   // XXX this is a temporary implementation copied from nsWebShell
 | |
|   // for now. I think nsDocument and friends should have some helper
 | |
|   // functions to make this easier.
 | |
|   nsCOMPtr<nsISelection> selection;
 | |
|   nsresult rv;
 | |
| 
 | |
|   // use mPresShell->GetSelectionForCopy() ?
 | |
|   rv = GetDocumentSelection(getter_AddRefs(selection));
 | |
|   if (NS_FAILED(rv)) return rv;
 | |
| 
 | |
|   nsCOMPtr<nsIDOMHTMLDocument> htmldoc = do_QueryInterface(mDocument);
 | |
|   nsCOMPtr<nsIDOMNode> bodyNode;
 | |
| 
 | |
|   if (htmldoc)
 | |
|   {
 | |
|     nsCOMPtr<nsIDOMHTMLElement>bodyElement;
 | |
|     rv = htmldoc->GetBody(getter_AddRefs(bodyElement));
 | |
|     if (NS_FAILED(rv) || !bodyElement) return rv;
 | |
| 
 | |
|     bodyNode = do_QueryInterface(bodyElement);
 | |
|   }
 | |
|   else if (mDocument)
 | |
|   {
 | |
|     bodyNode = do_QueryInterface(mDocument->GetRootContent());
 | |
|   }
 | |
|   if (!bodyNode) return NS_ERROR_FAILURE;
 | |
| 
 | |
|   rv = selection->RemoveAllRanges();
 | |
|   if (NS_FAILED(rv)) return rv;
 | |
| 
 | |
|   rv = selection->SelectAllChildren(bodyNode);
 | |
|   return rv;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::CopySelection()
 | |
| {
 | |
|   PRBool preventDefault;
 | |
|   nsresult rv = FireClipboardEvent(NS_COPY, &preventDefault);
 | |
|   if (NS_FAILED(rv) || preventDefault)
 | |
|     return rv;
 | |
| 
 | |
|   return mPresShell->DoCopy();
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::CopyLinkLocation()
 | |
| {
 | |
|   NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);
 | |
|   nsCOMPtr<nsIDOMNode> node;
 | |
|   GetPopupLinkNode(getter_AddRefs(node));
 | |
|   // make noise if we're not in a link
 | |
|   NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
 | |
| 
 | |
|   nsAutoString locationText;
 | |
|   nsresult rv = mPresShell->GetLinkLocation(node, locationText);
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   nsCOMPtr<nsIClipboardHelper> clipboard(do_GetService("@mozilla.org/widget/clipboardhelper;1", &rv));
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   // copy the href onto the clipboard
 | |
|   return clipboard->CopyString(locationText);
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::CopyImage(PRInt32 aCopyFlags)
 | |
| {
 | |
|   NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);
 | |
|   nsCOMPtr<nsIImageLoadingContent> node;
 | |
|   GetPopupImageNode(getter_AddRefs(node));
 | |
|   // make noise if we're not in an image
 | |
|   NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
 | |
| 
 | |
|   return nsCopySupport::ImageCopy(node, aCopyFlags);
 | |
| }
 | |
| 
 | |
| nsresult DocumentViewerImpl::GetClipboardEventTarget(nsIDOMNode** aEventTarget)
 | |
| {
 | |
|   NS_ENSURE_ARG_POINTER(aEventTarget);
 | |
|   *aEventTarget = nsnull;
 | |
| 
 | |
|   if (!mPresShell)
 | |
|     return NS_ERROR_NOT_INITIALIZED;
 | |
| 
 | |
|   nsCOMPtr<nsISelection> sel;
 | |
|   nsresult rv = mPresShell->GetSelectionForCopy(getter_AddRefs(sel));
 | |
|   if (NS_FAILED(rv))
 | |
|     return rv;
 | |
|   if (!sel)
 | |
|     return NS_ERROR_FAILURE;
 | |
| 
 | |
|   return nsCopySupport::GetClipboardEventTarget(sel, aEventTarget);
 | |
| }
 | |
| 
 | |
| nsresult DocumentViewerImpl::FireClipboardEvent(PRUint32 msg,
 | |
|                                                 PRBool* aPreventDefault)
 | |
| {
 | |
|   *aPreventDefault = PR_FALSE;
 | |
| 
 | |
|   NS_ENSURE_TRUE(mPresContext, NS_ERROR_NOT_INITIALIZED);
 | |
|   NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);
 | |
| 
 | |
|   // It seems to be unsafe to fire an event handler during reflow (bug 393696)
 | |
|   PRBool isReflowing = PR_TRUE;
 | |
|   nsresult rv = mPresShell->IsReflowLocked(&isReflowing);
 | |
|   if (NS_FAILED(rv) || isReflowing)
 | |
|     return NS_OK;
 | |
| 
 | |
|   nsCOMPtr<nsIDOMNode> eventTarget;
 | |
|   rv = GetClipboardEventTarget(getter_AddRefs(eventTarget));
 | |
|   if (NS_FAILED(rv))
 | |
|     // On failure to get event target, just forget about it and don't fire.
 | |
|     return NS_OK;
 | |
| 
 | |
|   nsEventStatus status = nsEventStatus_eIgnore;
 | |
|   nsEvent evt(PR_TRUE, msg);
 | |
|   nsEventDispatcher::Dispatch(eventTarget, mPresContext, &evt, nsnull,
 | |
|                               &status);
 | |
|   // if event handler return'd false (PreventDefault)
 | |
|   if (status == nsEventStatus_eConsumeNoDefault)
 | |
|     *aPreventDefault = PR_TRUE;
 | |
| 
 | |
|   // Ensure that the calling function can use mPresShell -- if the event
 | |
|   // handler closed this window, mPresShell will be gone.
 | |
|   NS_ENSURE_STATE(mPresShell);
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::GetCopyable(PRBool *aCopyable)
 | |
| {
 | |
|   NS_ENSURE_ARG_POINTER(aCopyable);
 | |
|   *aCopyable = PR_FALSE;
 | |
| 
 | |
|   nsresult rv = FireClipboardEvent(NS_BEFORECOPY, aCopyable);
 | |
|   if (NS_FAILED(rv) || *aCopyable)
 | |
|     return rv;
 | |
| 
 | |
|   nsCOMPtr<nsISelection> selection;
 | |
|   rv = mPresShell->GetSelectionForCopy(getter_AddRefs(selection));
 | |
|   if (NS_FAILED(rv))
 | |
|     return rv;
 | |
| 
 | |
|   PRBool isCollapsed;
 | |
|   selection->GetIsCollapsed(&isCollapsed);
 | |
| 
 | |
|   *aCopyable = !isCollapsed;
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::CutSelection()
 | |
| {
 | |
|   // preventDefault's value is ignored because cut from the document has no
 | |
|   // default behaviour.
 | |
|   PRBool preventDefault;
 | |
|   return FireClipboardEvent(NS_CUT, &preventDefault);
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::GetCutable(PRBool *aCutable)
 | |
| {
 | |
|   NS_ENSURE_ARG_POINTER(aCutable);
 | |
|   *aCutable = PR_FALSE;
 | |
| 
 | |
|   // If event handler requests to prevent default behavior, enable
 | |
|   // the cut command -- pass aCutable in as aPreventDefault.
 | |
|   return FireClipboardEvent(NS_BEFORECUT, aCutable);
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::Paste()
 | |
| {
 | |
|   // preventDefault's value is ignored because paste into the document has no
 | |
|   // default behaviour.
 | |
|   PRBool preventDefault;
 | |
|   return FireClipboardEvent(NS_PASTE, &preventDefault);
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::GetPasteable(PRBool *aPasteable)
 | |
| {
 | |
|   NS_ENSURE_ARG_POINTER(aPasteable);
 | |
|   *aPasteable = PR_FALSE;
 | |
| 
 | |
|   // If event handler requests to prevent default behavior, enable
 | |
|   // the paste command -- pass aPasteable in as aPreventDefault.
 | |
|   return FireClipboardEvent(NS_BEFOREPASTE, aPasteable);
 | |
| }
 | |
| 
 | |
| /* AString getContents (in string mimeType, in boolean selectionOnly); */
 | |
| NS_IMETHODIMP DocumentViewerImpl::GetContents(const char *mimeType, PRBool selectionOnly, nsAString& aOutValue)
 | |
| {
 | |
|   NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);
 | |
|   return mPresShell->DoGetContents(nsDependentCString(mimeType), 0, selectionOnly, aOutValue);
 | |
| }
 | |
| 
 | |
| /* readonly attribute boolean canGetContents; */
 | |
| NS_IMETHODIMP DocumentViewerImpl::GetCanGetContents(PRBool *aCanGetContents)
 | |
| {
 | |
|   return GetCopyable(aCanGetContents);
 | |
| }
 | |
| 
 | |
| #ifdef XP_MAC
 | |
| #pragma mark -
 | |
| #endif
 | |
| 
 | |
| /* ========================================================================================
 | |
|  * nsIContentViewerFile
 | |
|  * ======================================================================================== */
 | |
| /** ---------------------------------------------------
 | |
|  *  See documentation above in the nsIContentViewerfile class definition
 | |
|  *	@update 01/24/00 dwc
 | |
|  */
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::Print(PRBool            aSilent,
 | |
|                           FILE *            aDebugFile,
 | |
|                           nsIPrintSettings* aPrintSettings)
 | |
| {
 | |
| #ifdef NS_PRINTING
 | |
|   nsCOMPtr<nsIPrintSettings> printSettings;
 | |
| 
 | |
| #ifdef NS_DEBUG
 | |
|   nsresult rv = NS_ERROR_FAILURE;
 | |
| 
 | |
|   mDebugFile = aDebugFile;
 | |
|   // if they don't pass in a PrintSettings, then make one
 | |
|   // it will have all the default values
 | |
|   printSettings = aPrintSettings;
 | |
|   nsCOMPtr<nsIPrintOptions> printOptions = do_GetService(sPrintOptionsContractID, &rv);
 | |
|   if (NS_SUCCEEDED(rv)) {
 | |
|     // if they don't pass in a PrintSettings, then make one
 | |
|     if (printSettings == nsnull) {
 | |
|       printOptions->CreatePrintSettings(getter_AddRefs(printSettings));
 | |
|     }
 | |
|     NS_ASSERTION(printSettings, "You can't PrintPreview without a PrintSettings!");
 | |
|   }
 | |
|   if (printSettings) printSettings->SetPrintSilent(aSilent);
 | |
|   if (printSettings) printSettings->SetShowPrintProgress(PR_FALSE);
 | |
| #endif
 | |
| 
 | |
| 
 | |
|   return Print(printSettings, nsnull);
 | |
| #else
 | |
|   return NS_ERROR_FAILURE;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /* [noscript] void printWithParent (in nsIDOMWindowInternal aParentWin, in nsIPrintSettings aThePrintSettings, in nsIWebProgressListener aWPListener); */
 | |
| NS_IMETHODIMP 
 | |
| DocumentViewerImpl::PrintWithParent(nsIDOMWindowInternal *aParentWin, nsIPrintSettings *aThePrintSettings, nsIWebProgressListener *aWPListener)
 | |
| {
 | |
| #ifdef NS_PRINTING
 | |
|   return Print(aThePrintSettings, aWPListener);
 | |
| #else
 | |
|   return NS_ERROR_FAILURE;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| // nsIContentViewerFile interface
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::GetPrintable(PRBool *aPrintable)
 | |
| {
 | |
|   NS_ENSURE_ARG_POINTER(aPrintable);
 | |
| 
 | |
|   *aPrintable = !GetIsPrinting();
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| //*****************************************************************************
 | |
| // nsIMarkupDocumentViewer
 | |
| //*****************************************************************************
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::ScrollToNode(nsIDOMNode* aNode)
 | |
| {
 | |
|    NS_ENSURE_ARG(aNode);
 | |
|    NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
 | |
|    nsCOMPtr<nsIPresShell> presShell;
 | |
|    NS_ENSURE_SUCCESS(GetPresShell(getter_AddRefs(presShell)), NS_ERROR_FAILURE);
 | |
| 
 | |
|    // Get the nsIContent interface, because that's what we need to
 | |
|    // get the primary frame
 | |
| 
 | |
|    nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
 | |
|    NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
 | |
| 
 | |
|    // Tell the PresShell to scroll to the primary frame of the content.
 | |
|    NS_ENSURE_SUCCESS(presShell->ScrollContentIntoView(content,
 | |
|                                                       NS_PRESSHELL_SCROLL_TOP,
 | |
|                                                       NS_PRESSHELL_SCROLL_ANYWHERE),
 | |
|                      NS_ERROR_FAILURE);
 | |
|    return NS_OK;
 | |
| }
 | |
| 
 | |
| void
 | |
| DocumentViewerImpl::CallChildren(CallChildFunc aFunc, void* aClosure)
 | |
| {
 | |
|   nsCOMPtr<nsIDocShellTreeNode> docShellNode(do_QueryReferent(mContainer));
 | |
|   if (docShellNode)
 | |
|   {
 | |
|     PRInt32 i;
 | |
|     PRInt32 n;
 | |
|     docShellNode->GetChildCount(&n);
 | |
|     for (i=0; i < n; i++)
 | |
|     {
 | |
|       nsCOMPtr<nsIDocShellTreeItem> child;
 | |
|       docShellNode->GetChildAt(i, getter_AddRefs(child));
 | |
|       nsCOMPtr<nsIDocShell> childAsShell(do_QueryInterface(child));
 | |
|       NS_ASSERTION(childAsShell, "null child in docshell");
 | |
|       if (childAsShell)
 | |
|       {
 | |
|         nsCOMPtr<nsIContentViewer> childCV;
 | |
|         childAsShell->GetContentViewer(getter_AddRefs(childCV));
 | |
|         if (childCV)
 | |
|         {
 | |
|           nsCOMPtr<nsIMarkupDocumentViewer> markupCV = do_QueryInterface(childCV);
 | |
|           if (markupCV) {
 | |
|             (*aFunc)(markupCV, aClosure);
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| struct ZoomInfo
 | |
| {
 | |
|   float mZoom;
 | |
| };
 | |
| 
 | |
| static void
 | |
| SetChildTextZoom(nsIMarkupDocumentViewer* aChild, void* aClosure)
 | |
| {
 | |
|   struct ZoomInfo* ZoomInfo = (struct ZoomInfo*) aClosure;
 | |
|   aChild->SetTextZoom(ZoomInfo->mZoom);
 | |
| }
 | |
| 
 | |
| static void
 | |
| SetChildFullZoom(nsIMarkupDocumentViewer* aChild, void* aClosure)
 | |
| {
 | |
|   struct ZoomInfo* ZoomInfo = (struct ZoomInfo*) aClosure;
 | |
|   aChild->SetFullZoom(ZoomInfo->mZoom);
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::SetTextZoom(float aTextZoom)
 | |
| {
 | |
|   if (!GetIsPrintPreview()) {
 | |
|     mTextZoom = aTextZoom;
 | |
|   }
 | |
|   nsCOMPtr<nsIViewManager> vm = GetViewManager();
 | |
|   if (vm) {
 | |
|     vm->BeginUpdateViewBatch();
 | |
|   }
 | |
|       
 | |
|   // Set the text zoom on all children of mContainer (even if our zoom didn't
 | |
|   // change, our children's zoom may be different, though it would be unusual).
 | |
|   // Do this first, in case kids are auto-sizing and post reflow commands on
 | |
|   // our presshell (which should be subsumed into our own style change reflow).
 | |
|   struct ZoomInfo ZoomInfo = { aTextZoom };
 | |
|   CallChildren(SetChildTextZoom, &ZoomInfo);
 | |
| 
 | |
|   // Now change our own zoom
 | |
|   nsPresContext* pc = GetPresContext();
 | |
|   if (pc && aTextZoom != mPresContext->TextZoom()) {
 | |
|       pc->SetTextZoom(aTextZoom);
 | |
|   }
 | |
| 
 | |
|   if (vm) {
 | |
|     vm->EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
 | |
|   }
 | |
|   
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::GetTextZoom(float* aTextZoom)
 | |
| {
 | |
|   NS_ENSURE_ARG_POINTER(aTextZoom);
 | |
|   nsPresContext* pc = GetPresContext();
 | |
|   *aTextZoom = pc ? pc->TextZoom() : 1.0f;
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::SetFullZoom(float aFullZoom)
 | |
| {
 | |
|   if (!GetIsPrintPreview()) {
 | |
|     mPageZoom = aFullZoom;
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsIViewManager> vm = GetViewManager();
 | |
|   if (vm) {
 | |
|     vm->BeginUpdateViewBatch();
 | |
|   }
 | |
| 
 | |
|   struct ZoomInfo ZoomInfo = { aFullZoom };
 | |
|   CallChildren(SetChildFullZoom, &ZoomInfo);
 | |
| 
 | |
|   nsPresContext* pc = GetPresContext();
 | |
|   if (pc) {
 | |
|     pc->SetFullZoom(aFullZoom);
 | |
|   }
 | |
| 
 | |
|   if (vm) {
 | |
|     vm->EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
 | |
|   }
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::GetFullZoom(float* aFullZoom)
 | |
| {
 | |
|   NS_ENSURE_ARG_POINTER(aFullZoom);
 | |
|   nsPresContext* pc = GetPresContext();
 | |
|   *aFullZoom = pc ? pc->GetFullZoom() : 1.0f;
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| static void
 | |
| SetChildAuthorStyleDisabled(nsIMarkupDocumentViewer* aChild, void* aClosure)
 | |
| {
 | |
|   PRBool styleDisabled  = *static_cast<PRBool*>(aClosure);
 | |
|   aChild->SetAuthorStyleDisabled(styleDisabled);
 | |
| }
 | |
| 
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::SetAuthorStyleDisabled(PRBool aStyleDisabled)
 | |
| {
 | |
|   if (mPresShell) {
 | |
|     mPresShell->SetAuthorStyleDisabled(aStyleDisabled);
 | |
|   }
 | |
|   CallChildren(SetChildAuthorStyleDisabled, &aStyleDisabled);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::GetAuthorStyleDisabled(PRBool* aStyleDisabled)
 | |
| {
 | |
|   if (mPresShell) {
 | |
|     *aStyleDisabled = mPresShell->GetAuthorStyleDisabled();
 | |
|   } else {
 | |
|     *aStyleDisabled = PR_FALSE;
 | |
|   }
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::GetDefaultCharacterSet(nsACString& aDefaultCharacterSet)
 | |
| {
 | |
|   NS_ENSURE_STATE(nsCOMPtr<nsISupports>(do_QueryReferent(mContainer)));
 | |
| 
 | |
|   if (mDefaultCharacterSet.IsEmpty())
 | |
|   {
 | |
|     const nsAdoptingString& defCharset =
 | |
|       nsContentUtils::GetLocalizedStringPref("intl.charset.default");
 | |
| 
 | |
|     if (!defCharset.IsEmpty())
 | |
|       LossyCopyUTF16toASCII(defCharset, mDefaultCharacterSet);
 | |
|     else
 | |
|       mDefaultCharacterSet.AssignLiteral("ISO-8859-1");
 | |
|   }
 | |
|   aDefaultCharacterSet = mDefaultCharacterSet;
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| static void
 | |
| SetChildDefaultCharacterSet(nsIMarkupDocumentViewer* aChild, void* aClosure)
 | |
| {
 | |
|   const nsACString* charset = static_cast<nsACString*>(aClosure);
 | |
|   aChild->SetDefaultCharacterSet(*charset);
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::SetDefaultCharacterSet(const nsACString& aDefaultCharacterSet)
 | |
| {
 | |
|   mDefaultCharacterSet = aDefaultCharacterSet;  // this does a copy of aDefaultCharacterSet
 | |
|   // now set the default char set on all children of mContainer
 | |
|   CallChildren(SetChildDefaultCharacterSet, (void*) &aDefaultCharacterSet);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| // XXX: SEMANTIC CHANGE!
 | |
| //      returns a copy of the string.  Caller is responsible for freeing result
 | |
| //      using Recycle(aForceCharacterSet)
 | |
| NS_IMETHODIMP DocumentViewerImpl::GetForceCharacterSet(nsACString& aForceCharacterSet)
 | |
| {
 | |
|   aForceCharacterSet = mForceCharacterSet;
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| static void
 | |
| SetChildForceCharacterSet(nsIMarkupDocumentViewer* aChild, void* aClosure)
 | |
| {
 | |
|   const nsACString* charset = static_cast<nsACString*>(aClosure);
 | |
|   aChild->SetForceCharacterSet(*charset);
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::SetForceCharacterSet(const nsACString& aForceCharacterSet)
 | |
| {
 | |
|   mForceCharacterSet = aForceCharacterSet;
 | |
|   // now set the force char set on all children of mContainer
 | |
|   CallChildren(SetChildForceCharacterSet, (void*) &aForceCharacterSet);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| // XXX: SEMANTIC CHANGE!
 | |
| //      returns a copy of the string.  Caller is responsible for freeing result
 | |
| //      using Recycle(aHintCharacterSet)
 | |
| NS_IMETHODIMP DocumentViewerImpl::GetHintCharacterSet(nsACString& aHintCharacterSet)
 | |
| {
 | |
| 
 | |
|   if(kCharsetUninitialized == mHintCharsetSource) {
 | |
|     aHintCharacterSet.Truncate();
 | |
|   } else {
 | |
|     aHintCharacterSet = mHintCharset;
 | |
|     // this can't possibly be right.  we can't set a value just because somebody got a related value!
 | |
|     //mHintCharsetSource = kCharsetUninitialized;
 | |
|   }
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::GetHintCharacterSetSource(PRInt32 *aHintCharacterSetSource)
 | |
| {
 | |
|   NS_ENSURE_ARG_POINTER(aHintCharacterSetSource);
 | |
| 
 | |
|   *aHintCharacterSetSource = mHintCharsetSource;
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::GetPrevDocCharacterSet(nsACString& aPrevDocCharacterSet)
 | |
| {
 | |
|   aPrevDocCharacterSet = mPrevDocCharacterSet;
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| static void
 | |
| SetChildPrevDocCharacterSet(nsIMarkupDocumentViewer* aChild, void* aClosure)
 | |
| {
 | |
|   const nsACString* charset = static_cast<nsACString*>(aClosure);
 | |
|   aChild->SetPrevDocCharacterSet(*charset);
 | |
| }
 | |
| 
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::SetPrevDocCharacterSet(const nsACString& aPrevDocCharacterSet)
 | |
| {
 | |
|   mPrevDocCharacterSet = aPrevDocCharacterSet;  
 | |
|   CallChildren(SetChildPrevDocCharacterSet, (void*) &aPrevDocCharacterSet);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| 
 | |
| static void
 | |
| SetChildHintCharacterSetSource(nsIMarkupDocumentViewer* aChild, void* aClosure)
 | |
| {
 | |
|   aChild->SetHintCharacterSetSource(NS_PTR_TO_INT32(aClosure));
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::SetHintCharacterSetSource(PRInt32 aHintCharacterSetSource)
 | |
| {
 | |
|   mHintCharsetSource = aHintCharacterSetSource;
 | |
|   // now set the hint char set source on all children of mContainer
 | |
|   CallChildren(SetChildHintCharacterSetSource,
 | |
|                       (void*) aHintCharacterSetSource);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| static void
 | |
| SetChildHintCharacterSet(nsIMarkupDocumentViewer* aChild, void* aClosure)
 | |
| {
 | |
|   const nsACString* charset = static_cast<nsACString*>(aClosure);
 | |
|   aChild->SetHintCharacterSet(*charset);
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::SetHintCharacterSet(const nsACString& aHintCharacterSet)
 | |
| {
 | |
|   mHintCharset = aHintCharacterSet;
 | |
|   // now set the hint char set on all children of mContainer
 | |
|   CallChildren(SetChildHintCharacterSet, (void*) &aHintCharacterSet);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| static void
 | |
| SetChildBidiOptions(nsIMarkupDocumentViewer* aChild, void* aClosure)
 | |
| {
 | |
|   aChild->SetBidiOptions(NS_PTR_TO_INT32(aClosure));
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::SetBidiTextDirection(PRUint8 aTextDirection)
 | |
| {
 | |
|   PRUint32 bidiOptions;
 | |
| 
 | |
|   GetBidiOptions(&bidiOptions);
 | |
|   SET_BIDI_OPTION_DIRECTION(bidiOptions, aTextDirection);
 | |
|   SetBidiOptions(bidiOptions);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::GetBidiTextDirection(PRUint8* aTextDirection)
 | |
| {
 | |
|   PRUint32 bidiOptions;
 | |
| 
 | |
|   if (aTextDirection) {
 | |
|     GetBidiOptions(&bidiOptions);
 | |
|     *aTextDirection = GET_BIDI_OPTION_DIRECTION(bidiOptions);
 | |
|   }
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::SetBidiTextType(PRUint8 aTextType)
 | |
| {
 | |
|   PRUint32 bidiOptions;
 | |
| 
 | |
|   GetBidiOptions(&bidiOptions);
 | |
|   SET_BIDI_OPTION_TEXTTYPE(bidiOptions, aTextType);
 | |
|   SetBidiOptions(bidiOptions);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::GetBidiTextType(PRUint8* aTextType)
 | |
| {
 | |
|   PRUint32 bidiOptions;
 | |
| 
 | |
|   if (aTextType) {
 | |
|     GetBidiOptions(&bidiOptions);
 | |
|     *aTextType = GET_BIDI_OPTION_TEXTTYPE(bidiOptions);
 | |
|   }
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::SetBidiControlsTextMode(PRUint8 aControlsTextMode)
 | |
| {
 | |
|   PRUint32 bidiOptions;
 | |
| 
 | |
|   GetBidiOptions(&bidiOptions);
 | |
|   SET_BIDI_OPTION_CONTROLSTEXTMODE(bidiOptions, aControlsTextMode);
 | |
|   SetBidiOptions(bidiOptions);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::GetBidiControlsTextMode(PRUint8* aControlsTextMode)
 | |
| {
 | |
|   PRUint32 bidiOptions;
 | |
| 
 | |
|   if (aControlsTextMode) {
 | |
|     GetBidiOptions(&bidiOptions);
 | |
|     *aControlsTextMode = GET_BIDI_OPTION_CONTROLSTEXTMODE(bidiOptions);
 | |
|   }
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::SetBidiNumeral(PRUint8 aNumeral)
 | |
| {
 | |
|   PRUint32 bidiOptions;
 | |
| 
 | |
|   GetBidiOptions(&bidiOptions);
 | |
|   SET_BIDI_OPTION_NUMERAL(bidiOptions, aNumeral);
 | |
|   SetBidiOptions(bidiOptions);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::GetBidiNumeral(PRUint8* aNumeral)
 | |
| {
 | |
|   PRUint32 bidiOptions;
 | |
| 
 | |
|   if (aNumeral) {
 | |
|     GetBidiOptions(&bidiOptions);
 | |
|     *aNumeral = GET_BIDI_OPTION_NUMERAL(bidiOptions);
 | |
|   }
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::SetBidiSupport(PRUint8 aSupport)
 | |
| {
 | |
|   PRUint32 bidiOptions;
 | |
| 
 | |
|   GetBidiOptions(&bidiOptions);
 | |
|   SET_BIDI_OPTION_SUPPORT(bidiOptions, aSupport);
 | |
|   SetBidiOptions(bidiOptions);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::GetBidiSupport(PRUint8* aSupport)
 | |
| {
 | |
|   PRUint32 bidiOptions;
 | |
| 
 | |
|   if (aSupport) {
 | |
|     GetBidiOptions(&bidiOptions);
 | |
|     *aSupport = GET_BIDI_OPTION_SUPPORT(bidiOptions);
 | |
|   }
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::SetBidiCharacterSet(PRUint8 aCharacterSet)
 | |
| {
 | |
|   PRUint32 bidiOptions;
 | |
| 
 | |
|   GetBidiOptions(&bidiOptions);
 | |
|   SET_BIDI_OPTION_CHARACTERSET(bidiOptions, aCharacterSet);
 | |
|   SetBidiOptions(bidiOptions);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::GetBidiCharacterSet(PRUint8* aCharacterSet)
 | |
| {
 | |
|   PRUint32 bidiOptions;
 | |
| 
 | |
|   if (aCharacterSet) {
 | |
|     GetBidiOptions(&bidiOptions);
 | |
|     *aCharacterSet = GET_BIDI_OPTION_CHARACTERSET(bidiOptions);
 | |
|   }
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::SetBidiOptions(PRUint32 aBidiOptions)
 | |
| {
 | |
|   if (mPresContext) {
 | |
|     mPresContext->SetBidi(aBidiOptions, PR_TRUE); // could cause reflow
 | |
|   }
 | |
|   // now set bidi on all children of mContainer
 | |
|   CallChildren(SetChildBidiOptions, (void*) aBidiOptions);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::GetBidiOptions(PRUint32* aBidiOptions)
 | |
| {
 | |
|   if (aBidiOptions) {
 | |
|     if (mPresContext) {
 | |
|       *aBidiOptions = mPresContext->GetBidi();
 | |
|     }
 | |
|     else
 | |
|       *aBidiOptions = IBMBIDI_DEFAULT_BIDI_OPTIONS;
 | |
|   }
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::SizeToContent()
 | |
| {
 | |
|    NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
 | |
| 
 | |
|    nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryReferent(mContainer));
 | |
|    NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
 | |
| 
 | |
|    nsCOMPtr<nsIDocShellTreeItem> docShellParent;
 | |
|    docShellAsItem->GetSameTypeParent(getter_AddRefs(docShellParent));
 | |
| 
 | |
|    // It's only valid to access this from a top frame.  Doesn't work from
 | |
|    // sub-frames.
 | |
|    NS_ENSURE_TRUE(!docShellParent, NS_ERROR_FAILURE);
 | |
| 
 | |
|    nsCOMPtr<nsIPresShell> presShell;
 | |
|    GetPresShell(getter_AddRefs(presShell));
 | |
|    NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
 | |
| 
 | |
|    // Flush out all content and style updates. We can't use a resize reflow
 | |
|    // because it won't change some sizes that a style change reflow will.
 | |
|    mDocument->FlushPendingNotifications(Flush_Layout);
 | |
| 
 | |
|   nsIFrame *root = presShell->GetRootFrame();
 | |
|   NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
 | |
| 
 | |
|   nscoord prefWidth;
 | |
|   {
 | |
|     nsCOMPtr<nsIRenderingContext> rcx;
 | |
|     presShell->CreateRenderingContext(root, getter_AddRefs(rcx));
 | |
|     NS_ENSURE_TRUE(rcx, NS_ERROR_FAILURE);
 | |
|     prefWidth = root->GetPrefWidth(rcx);
 | |
|   }
 | |
| 
 | |
|   nsresult rv = presShell->ResizeReflow(prefWidth, NS_UNCONSTRAINEDSIZE);
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|    nsCOMPtr<nsPresContext> presContext;
 | |
|    GetPresContext(getter_AddRefs(presContext));
 | |
|    NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
 | |
| 
 | |
|    PRInt32 width, height;
 | |
| 
 | |
|    // so how big is it?
 | |
|    nsRect shellArea = presContext->GetVisibleArea();
 | |
|    if (shellArea.width == NS_UNCONSTRAINEDSIZE ||
 | |
|        shellArea.height == NS_UNCONSTRAINEDSIZE) {
 | |
|      // Protect against bogus returns here
 | |
|      return NS_ERROR_FAILURE;
 | |
|    }
 | |
|    width = presContext->AppUnitsToDevPixels(shellArea.width);
 | |
|    height = presContext->AppUnitsToDevPixels(shellArea.height);
 | |
| 
 | |
|    nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
 | |
|    docShellAsItem->GetTreeOwner(getter_AddRefs(treeOwner));
 | |
|    NS_ENSURE_TRUE(treeOwner, NS_ERROR_FAILURE);
 | |
| 
 | |
|    /* presContext's size was calculated in app units and has already been
 | |
|       rounded to the equivalent pixels (so the width/height calculation
 | |
|       we just performed was probably exact, though it was based on
 | |
|       values already rounded during ResizeReflow). In a surprising
 | |
|       number of instances, this rounding makes a window which for want
 | |
|       of one extra pixel's width ends up wrapping the longest line of
 | |
|       text during actual window layout. This makes the window too short,
 | |
|       generally clipping the OK/Cancel buttons. Here we add one pixel
 | |
|       to the calculated width, to circumvent this problem. */
 | |
|    NS_ENSURE_SUCCESS(treeOwner->SizeShellTo(docShellAsItem, width+1, height),
 | |
|       NS_ERROR_FAILURE);
 | |
| 
 | |
|    return NS_OK;
 | |
| }
 | |
| 
 | |
| 
 | |
| NS_IMPL_ISUPPORTS1(nsDocViewerSelectionListener, nsISelectionListener)
 | |
| 
 | |
| nsresult nsDocViewerSelectionListener::Init(DocumentViewerImpl *aDocViewer)
 | |
| {
 | |
|   mDocViewer = aDocViewer;
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * GetPopupNode, GetPopupLinkNode and GetPopupImageNode are helpers
 | |
|  * for the cmd_copyLink / cmd_copyImageLocation / cmd_copyImageContents family
 | |
|  * of commands. The focus controller stores the popup node, these retrieve
 | |
|  * them and munge appropriately. Note that we have to store the popup node
 | |
|  * rather than retrieving it from EventStateManager::GetFocusedContent because
 | |
|  * not all content (images included) can receive focus.
 | |
|  */
 | |
| 
 | |
| nsresult
 | |
| DocumentViewerImpl::GetPopupNode(nsIDOMNode** aNode)
 | |
| {
 | |
|   NS_ENSURE_ARG_POINTER(aNode);
 | |
| 
 | |
|   nsresult rv;
 | |
| 
 | |
|   // get the document
 | |
|   nsCOMPtr<nsIDocument> document;
 | |
|   rv = GetDocument(getter_AddRefs(document));
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
|   NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
 | |
| 
 | |
| 
 | |
|   // get the private dom window
 | |
|   nsPIDOMWindow *privateWin = document->GetWindow();
 | |
|   NS_ENSURE_TRUE(privateWin, NS_ERROR_NOT_AVAILABLE);
 | |
| 
 | |
|   // get the focus controller
 | |
|   nsIFocusController *focusController = privateWin->GetRootFocusController();
 | |
|   NS_ENSURE_TRUE(focusController, NS_ERROR_FAILURE);
 | |
| 
 | |
|   // get the popup node
 | |
|   focusController->GetPopupNode(aNode); // addref happens here
 | |
| 
 | |
|   return rv;
 | |
| }
 | |
| 
 | |
| // GetPopupLinkNode: return popup link node or fail
 | |
| nsresult
 | |
| DocumentViewerImpl::GetPopupLinkNode(nsIDOMNode** aNode)
 | |
| {
 | |
|   NS_ENSURE_ARG_POINTER(aNode);
 | |
| 
 | |
|   // you get null unless i say so
 | |
|   *aNode = nsnull;
 | |
| 
 | |
|   // find popup node
 | |
|   nsCOMPtr<nsIDOMNode> node;
 | |
|   nsresult rv = GetPopupNode(getter_AddRefs(node));
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   // find out if we have a link in our ancestry
 | |
|   while (node) {
 | |
| 
 | |
|     // are we an anchor?
 | |
|     nsCOMPtr<nsIDOMHTMLAnchorElement> anchor(do_QueryInterface(node));
 | |
|     nsCOMPtr<nsIDOMHTMLAreaElement> area;
 | |
|     nsCOMPtr<nsIDOMHTMLLinkElement> link;
 | |
|     nsAutoString xlinkType;
 | |
|     if (!anchor) {
 | |
|       // area?
 | |
|       area = do_QueryInterface(node);
 | |
|       if (!area) {
 | |
|         // link?
 | |
|         link = do_QueryInterface(node);
 | |
|         if (!link) {
 | |
|           // XLink?
 | |
|           nsCOMPtr<nsIDOMElement> element(do_QueryInterface(node));
 | |
|           if (element) {
 | |
|             element->GetAttributeNS(NS_LITERAL_STRING("http://www.w3.org/1999/xlink"),NS_LITERAL_STRING("type"),xlinkType);
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     if (anchor || area || link || xlinkType.EqualsLiteral("simple")) {
 | |
|       *aNode = node;
 | |
|       NS_IF_ADDREF(*aNode); // addref
 | |
|       return NS_OK;
 | |
|     }
 | |
|     else {
 | |
|       // if not, get our parent and keep trying...
 | |
|       nsCOMPtr<nsIDOMNode> parentNode;
 | |
|       node->GetParentNode(getter_AddRefs(parentNode));
 | |
|       node = parentNode;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // if we have no node, fail
 | |
|   return NS_ERROR_FAILURE;
 | |
| }
 | |
| 
 | |
| // GetPopupLinkNode: return popup image node or fail
 | |
| nsresult
 | |
| DocumentViewerImpl::GetPopupImageNode(nsIImageLoadingContent** aNode)
 | |
| {
 | |
|   NS_ENSURE_ARG_POINTER(aNode);
 | |
| 
 | |
|   // you get null unless i say so
 | |
|   *aNode = nsnull;
 | |
| 
 | |
|   // find popup node
 | |
|   nsCOMPtr<nsIDOMNode> node;
 | |
|   nsresult rv = GetPopupNode(getter_AddRefs(node));
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   if (node)
 | |
|     CallQueryInterface(node, aNode);
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * XXX dr
 | |
|  * ------
 | |
|  * These two functions -- GetInLink and GetInImage -- are kind of annoying
 | |
|  * in that they only get called from the controller (in
 | |
|  * nsDOMWindowController::IsCommandEnabled). The actual construction of the
 | |
|  * context menus in communicator (nsContextMenu.js) has its own, redundant
 | |
|  * tests. No big deal, but good to keep in mind if we ever clean context
 | |
|  * menus.
 | |
|  */
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::GetInLink(PRBool* aInLink)
 | |
| {
 | |
| #ifdef DEBUG_dr
 | |
|   printf("dr :: DocumentViewerImpl::GetInLink\n");
 | |
| #endif
 | |
| 
 | |
|   NS_ENSURE_ARG_POINTER(aInLink);
 | |
| 
 | |
|   // we're not in a link unless i say so
 | |
|   *aInLink = PR_FALSE;
 | |
| 
 | |
|   // get the popup link
 | |
|   nsCOMPtr<nsIDOMNode> node;
 | |
|   nsresult rv = GetPopupLinkNode(getter_AddRefs(node));
 | |
|   if (NS_FAILED(rv)) return rv;
 | |
|   NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
 | |
| 
 | |
|   // if we made it here, we're in a link
 | |
|   *aInLink = PR_TRUE;
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::GetInImage(PRBool* aInImage)
 | |
| {
 | |
| #ifdef DEBUG_dr
 | |
|   printf("dr :: DocumentViewerImpl::GetInImage\n");
 | |
| #endif
 | |
| 
 | |
|   NS_ENSURE_ARG_POINTER(aInImage);
 | |
| 
 | |
|   // we're not in an image unless i say so
 | |
|   *aInImage = PR_FALSE;
 | |
| 
 | |
|   // get the popup image
 | |
|   nsCOMPtr<nsIImageLoadingContent> node;
 | |
|   nsresult rv = GetPopupImageNode(getter_AddRefs(node));
 | |
|   if (NS_FAILED(rv)) return rv;
 | |
|   NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
 | |
| 
 | |
|   // if we made it here, we're in an image
 | |
|   *aInImage = PR_TRUE;
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP nsDocViewerSelectionListener::NotifySelectionChanged(nsIDOMDocument *, nsISelection *, PRInt16)
 | |
| {
 | |
|   NS_ASSERTION(mDocViewer, "Should have doc viewer!");
 | |
| 
 | |
|   // get the selection state
 | |
|   nsCOMPtr<nsISelection> selection;
 | |
|   nsresult rv = mDocViewer->GetDocumentSelection(getter_AddRefs(selection));
 | |
|   if (NS_FAILED(rv)) return rv;
 | |
| 
 | |
|   PRBool selectionCollapsed;
 | |
|   selection->GetIsCollapsed(&selectionCollapsed);
 | |
|   // we only call UpdateCommands when the selection changes from collapsed
 | |
|   // to non-collapsed or vice versa. We might need another update string
 | |
|   // for simple selection changes, but that would be expenseive.
 | |
|   if (!mGotSelectionState || mSelectionWasCollapsed != selectionCollapsed)
 | |
|   {
 | |
|     nsCOMPtr<nsIDocument> theDoc;
 | |
|     mDocViewer->GetDocument(getter_AddRefs(theDoc));
 | |
|     if (!theDoc) return NS_ERROR_FAILURE;
 | |
| 
 | |
|     nsPIDOMWindow *domWindow = theDoc->GetWindow();
 | |
|     if (!domWindow) return NS_ERROR_FAILURE;
 | |
| 
 | |
|     domWindow->UpdateCommands(NS_LITERAL_STRING("select"));
 | |
|     mGotSelectionState = PR_TRUE;
 | |
|     mSelectionWasCollapsed = selectionCollapsed;
 | |
|   }
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| //nsDocViewerFocusListener
 | |
| NS_IMPL_ISUPPORTS2(nsDocViewerFocusListener,
 | |
|                    nsIDOMFocusListener,
 | |
|                    nsIDOMEventListener)
 | |
| 
 | |
| nsDocViewerFocusListener::nsDocViewerFocusListener()
 | |
| :mDocViewer(nsnull)
 | |
| {
 | |
| }
 | |
| 
 | |
| nsDocViewerFocusListener::~nsDocViewerFocusListener(){}
 | |
| 
 | |
| nsresult
 | |
| nsDocViewerFocusListener::HandleEvent(nsIDOMEvent* aEvent)
 | |
| {
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsDocViewerFocusListener::Focus(nsIDOMEvent* aEvent)
 | |
| {
 | |
|   nsCOMPtr<nsIPresShell> shell;
 | |
|   if(!mDocViewer)
 | |
|     return NS_ERROR_FAILURE;
 | |
| 
 | |
|   nsresult result = mDocViewer->GetPresShell(getter_AddRefs(shell));
 | |
|   if(NS_FAILED(result) || !shell)
 | |
|     return result?result:NS_ERROR_FAILURE;
 | |
|   nsCOMPtr<nsISelectionController> selCon;
 | |
|   selCon = do_QueryInterface(shell);
 | |
|   PRInt16 selectionStatus;
 | |
|   selCon->GetDisplaySelection(&selectionStatus);
 | |
| 
 | |
|   // If selection was disabled, re-enable it.
 | |
|   if(selectionStatus == nsISelectionController::SELECTION_DISABLED ||
 | |
|      selectionStatus == nsISelectionController::SELECTION_HIDDEN)
 | |
|   {
 | |
|     selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
 | |
|     selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL);
 | |
|   }
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsDocViewerFocusListener::Blur(nsIDOMEvent* aEvent)
 | |
| {
 | |
|   nsCOMPtr<nsIPresShell> shell;
 | |
|   if(!mDocViewer)
 | |
|     return NS_ERROR_FAILURE;
 | |
| 
 | |
|   nsresult result = mDocViewer->GetPresShell(getter_AddRefs(shell));
 | |
|   if(NS_FAILED(result) || !shell)
 | |
|     return result?result:NS_ERROR_FAILURE;
 | |
|   nsCOMPtr<nsISelectionController> selCon;
 | |
|   selCon = do_QueryInterface(shell);
 | |
|   PRInt16 selectionStatus;
 | |
|   selCon->GetDisplaySelection(&selectionStatus);
 | |
| 
 | |
|   // If selection was on, disable it.
 | |
|   if(selectionStatus == nsISelectionController::SELECTION_ON ||
 | |
|      selectionStatus == nsISelectionController::SELECTION_ATTENTION)
 | |
|   {
 | |
|     selCon->SetDisplaySelection(nsISelectionController::SELECTION_DISABLED);
 | |
|     selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL);
 | |
|   }
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| nsresult
 | |
| nsDocViewerFocusListener::Init(DocumentViewerImpl *aDocViewer)
 | |
| {
 | |
|   mDocViewer = aDocViewer;
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| /** ---------------------------------------------------
 | |
|  *  From nsIWebBrowserPrint
 | |
|  */
 | |
| 
 | |
| #ifdef NS_PRINTING
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::Print(nsIPrintSettings*       aPrintSettings,
 | |
|                           nsIWebProgressListener* aWebProgressListener)
 | |
| {
 | |
| 
 | |
| #ifdef MOZ_XUL
 | |
|   // Temporary code for Bug 136185 / Bug 240490
 | |
|   nsCOMPtr<nsIXULDocument> xulDoc(do_QueryInterface(mDocument));
 | |
|   if (xulDoc) {
 | |
|     nsPrintEngine::ShowPrintErrorDialog(NS_ERROR_GFX_PRINTER_NO_XUL);
 | |
|     return NS_ERROR_FAILURE;
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|   nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mContainer));
 | |
|   NS_ASSERTION(docShell, "This has to be a docshell");
 | |
| 
 | |
|   // Check to see if this document is still busy
 | |
|   // If it is busy and we aren't already "queued" up to print then
 | |
|   // Indicate there is a print pending and cache the args for later
 | |
|   PRUint32 busyFlags = nsIDocShell::BUSY_FLAGS_NONE;
 | |
|   if ((NS_FAILED(docShell->GetBusyFlags(&busyFlags)) ||
 | |
|        (busyFlags != nsIDocShell::BUSY_FLAGS_NONE && busyFlags & nsIDocShell::BUSY_FLAGS_PAGE_LOADING)) && 
 | |
|       !mPrintDocIsFullyLoaded) {
 | |
|     if (!mPrintIsPending) {
 | |
|       mCachedPrintSettings           = aPrintSettings;
 | |
|       mCachedPrintWebProgressListner = aWebProgressListener;
 | |
|       mPrintIsPending                = PR_TRUE;
 | |
|     }
 | |
|     PR_PL(("Printing Stopped - document is still busy!"));
 | |
|     return NS_ERROR_GFX_PRINTER_DOC_IS_BUSY;
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsIPresShell> presShell;
 | |
|   docShell->GetPresShell(getter_AddRefs(presShell));
 | |
|   if (!presShell || !mDocument || !mDeviceContext || !mParentWidget) {
 | |
|     PR_PL(("Can't Print without pres shell, document etc"));
 | |
|     return NS_ERROR_FAILURE;
 | |
|   }
 | |
| 
 | |
|   nsresult rv;
 | |
| 
 | |
|   // if we are printing another URL, then exit
 | |
|   // the reason we check here is because this method can be called while
 | |
|   // another is still in here (the printing dialog is a good example).
 | |
|   // the only time we can print more than one job at a time is the regression tests
 | |
|   if (GetIsPrinting()) {
 | |
|     // Let the user know we are not ready to print.
 | |
|     rv = NS_ERROR_NOT_AVAILABLE;
 | |
|     nsPrintEngine::ShowPrintErrorDialog(rv);
 | |
|     return rv;
 | |
|   }
 | |
| 
 | |
|   // If we are hosting a full-page plugin, tell it to print
 | |
|   // first. It shows its own native print UI.
 | |
|   nsCOMPtr<nsIPluginDocument> pDoc(do_QueryInterface(mDocument));
 | |
|   if (pDoc)
 | |
|     return pDoc->Print();
 | |
| 
 | |
|   if (!mPrintEngine) {
 | |
|     mPrintEngine = new nsPrintEngine();
 | |
|     NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_OUT_OF_MEMORY);
 | |
| 
 | |
|     rv = mPrintEngine->Initialize(this, docShell, mDocument, 
 | |
|                                   mDeviceContext, mParentWidget,
 | |
| #ifdef NS_DEBUG
 | |
|                                   mDebugFile
 | |
| #else
 | |
|                                   nsnull
 | |
| #endif
 | |
|                                   );
 | |
|     if (NS_FAILED(rv)) {
 | |
|       mPrintEngine->Destroy();
 | |
|       mPrintEngine = nsnull;
 | |
|       return rv;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   rv = mPrintEngine->Print(aPrintSettings, aWebProgressListener);
 | |
|   if (NS_FAILED(rv)) {
 | |
|     OnDonePrinting();
 | |
|   }
 | |
|   return rv;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::PrintPreview(nsIPrintSettings* aPrintSettings, 
 | |
|                                  nsIDOMWindow *aChildDOMWin, 
 | |
|                                  nsIWebProgressListener* aWebProgressListener)
 | |
| {
 | |
| #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
 | |
|   nsresult rv = NS_OK;
 | |
| 
 | |
|   if (GetIsPrinting()) {
 | |
|     nsPrintEngine::CloseProgressDialog(aWebProgressListener);
 | |
|     return NS_ERROR_FAILURE;
 | |
|   }
 | |
| 
 | |
| #ifdef MOZ_XUL
 | |
|   // Temporary code for Bug 136185 / Bug 240490
 | |
|   nsCOMPtr<nsIXULDocument> xulDoc(do_QueryInterface(mDocument));
 | |
|   if (xulDoc) {
 | |
|     nsPrintEngine::CloseProgressDialog(aWebProgressListener);
 | |
|     nsPrintEngine::ShowPrintErrorDialog(NS_ERROR_GFX_PRINTER_NO_XUL, PR_FALSE);
 | |
|     return NS_ERROR_FAILURE;
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|   nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mContainer));
 | |
|   NS_ASSERTION(docShell, "This has to be a docshell");
 | |
|   nsCOMPtr<nsIPresShell> presShell;
 | |
|   docShell->GetPresShell(getter_AddRefs(presShell));
 | |
|   if (!presShell || !mDocument || !mDeviceContext || !mParentWidget) {
 | |
|     PR_PL(("Can't Print Preview without pres shell, document etc"));
 | |
|     return NS_ERROR_FAILURE;
 | |
|   }
 | |
| 
 | |
|   if (!mPrintEngine) {
 | |
|     mPrintEngine = new nsPrintEngine();
 | |
|     NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_OUT_OF_MEMORY);
 | |
| 
 | |
|     rv = mPrintEngine->Initialize(this, docShell, mDocument,
 | |
|                                   mDeviceContext, mParentWidget,
 | |
| #ifdef NS_DEBUG
 | |
|                                   mDebugFile
 | |
| #else
 | |
|                                   nsnull
 | |
| #endif
 | |
|                                   );
 | |
|     if (NS_FAILED(rv)) {
 | |
|       mPrintEngine->Destroy();
 | |
|       mPrintEngine = nsnull;
 | |
|       return rv;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   rv = mPrintEngine->PrintPreview(aPrintSettings, aChildDOMWin, aWebProgressListener);
 | |
|   if (NS_FAILED(rv)) {
 | |
|     OnDonePrinting();
 | |
|   }
 | |
|   return rv;
 | |
| #else
 | |
|   return NS_ERROR_FAILURE;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| //----------------------------------------------------------------------
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::PrintPreviewNavigate(PRInt16 aType, PRInt32 aPageNum)
 | |
| {
 | |
|   if (!GetIsPrintPreview() ||
 | |
|       mPrintEngine->GetIsCreatingPrintPreview())
 | |
|     return NS_ERROR_FAILURE;
 | |
| 
 | |
|   nsIScrollableView* scrollableView = nsnull;
 | |
|   mPrintEngine->GetPrintPreviewViewManager()->GetRootScrollableView(&scrollableView);
 | |
|   if (scrollableView == nsnull)
 | |
|     return NS_OK;
 | |
| 
 | |
|   // Check to see if we can short circut scrolling to the top
 | |
|   if (aType == nsIWebBrowserPrint::PRINTPREVIEW_HOME ||
 | |
|       (aType == nsIWebBrowserPrint::PRINTPREVIEW_GOTO_PAGENUM && aPageNum == 1)) {
 | |
|     scrollableView->ScrollTo(0, 0, PR_TRUE);
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   // Finds the SimplePageSequencer frame
 | |
|   // in PP mPrtPreview->mPrintObject->mSeqFrame is null
 | |
|   nsIFrame* seqFrame  = nsnull;
 | |
|   PRInt32   pageCount = 0;
 | |
|   if (NS_FAILED(mPrintEngine->GetSeqFrameAndCountPages(seqFrame, pageCount))) {
 | |
|     return NS_ERROR_FAILURE;
 | |
|   }
 | |
| 
 | |
|   // Figure where we are currently scrolled to
 | |
|   nscoord x;
 | |
|   nscoord y;
 | |
|   scrollableView->GetScrollPosition(x, y);
 | |
| 
 | |
|   PRInt32    pageNum = 1;
 | |
|   nsIFrame * fndPageFrame  = nsnull;
 | |
|   nsIFrame * currentPage   = nsnull;
 | |
| 
 | |
|   // If it is "End" then just do a "goto" to the last page
 | |
|   if (aType == nsIWebBrowserPrint::PRINTPREVIEW_END) {
 | |
|     aType    = nsIWebBrowserPrint::PRINTPREVIEW_GOTO_PAGENUM;
 | |
|     aPageNum = pageCount;
 | |
|   }
 | |
| 
 | |
|   // Now, locate the current page we are on and
 | |
|   // and the page of the page number
 | |
|   nscoord gap = 0;
 | |
|   nsIFrame* pageFrame = seqFrame->GetFirstChild(nsnull);
 | |
|   while (pageFrame != nsnull) {
 | |
|     nsRect pageRect = pageFrame->GetRect();
 | |
|     if (pageNum == 1) {
 | |
|       gap = pageRect.y;
 | |
|     }
 | |
|     if (pageRect.Contains(pageRect.x, y)) {
 | |
|       currentPage = pageFrame;
 | |
|     }
 | |
|     if (pageNum == aPageNum) {
 | |
|       fndPageFrame = pageFrame;
 | |
|       break;
 | |
|     }
 | |
|     pageNum++;
 | |
|     pageFrame = pageFrame->GetNextSibling();
 | |
|   }
 | |
| 
 | |
|   if (aType == nsIWebBrowserPrint::PRINTPREVIEW_PREV_PAGE) {
 | |
|     if (currentPage) {
 | |
|       fndPageFrame = currentPage->GetPrevInFlow();
 | |
|       if (!fndPageFrame) {
 | |
|         return NS_OK;
 | |
|       }
 | |
|     } else {
 | |
|       return NS_OK;
 | |
|     }
 | |
|   } else if (aType == nsIWebBrowserPrint::PRINTPREVIEW_NEXT_PAGE) {
 | |
|     if (currentPage) {
 | |
|       fndPageFrame = currentPage->GetNextInFlow();
 | |
|       if (!fndPageFrame) {
 | |
|         return NS_OK;
 | |
|       }
 | |
|     } else {
 | |
|       return NS_OK;
 | |
|     }
 | |
|   } else { // If we get here we are doing "GoTo"
 | |
|     if (aPageNum < 0 || aPageNum > pageCount) {
 | |
|       return NS_OK;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (fndPageFrame && scrollableView) {
 | |
|     nscoord deadSpaceGapTwips = 0;
 | |
|     nsIPageSequenceFrame * sqf;
 | |
|     if (NS_SUCCEEDED(CallQueryInterface(seqFrame, &sqf))) {
 | |
|       sqf->GetDeadSpaceValue(&deadSpaceGapTwips);
 | |
|     }
 | |
|     nscoord deadSpaceGap = mPresContext->TwipsToAppUnits(deadSpaceGapTwips);
 | |
| 
 | |
|     // scroll so that top of page (plus the gray area) is at the top of the scroll area
 | |
|     scrollableView->ScrollTo(0, fndPageFrame->GetPosition().y-deadSpaceGap, PR_TRUE);
 | |
|   }
 | |
|   return NS_OK;
 | |
| 
 | |
| }
 | |
| 
 | |
| /* readonly attribute nsIPrintSettings globalPrintSettings; */
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::GetGlobalPrintSettings(nsIPrintSettings * *aGlobalPrintSettings)
 | |
| {
 | |
|   return nsPrintEngine::GetGlobalPrintSettings(aGlobalPrintSettings);
 | |
| }
 | |
| 
 | |
| /* readonly attribute boolean doingPrint; */
 | |
| // XXX This always returns PR_FALSE for subdocuments
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::GetDoingPrint(PRBool *aDoingPrint)
 | |
| {
 | |
|   NS_ENSURE_ARG_POINTER(aDoingPrint);
 | |
|   
 | |
|   *aDoingPrint = PR_FALSE;
 | |
|   if (mPrintEngine) {
 | |
|     // XXX shouldn't this be GetDoingPrint() ?
 | |
|     return mPrintEngine->GetDoingPrintPreview(aDoingPrint);
 | |
|   } 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| /* readonly attribute boolean doingPrintPreview; */
 | |
| // XXX This always returns PR_FALSE for subdocuments
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::GetDoingPrintPreview(PRBool *aDoingPrintPreview)
 | |
| {
 | |
|   NS_ENSURE_ARG_POINTER(aDoingPrintPreview);
 | |
| 
 | |
|   *aDoingPrintPreview = PR_FALSE;
 | |
|   if (mPrintEngine) {
 | |
|     return mPrintEngine->GetDoingPrintPreview(aDoingPrintPreview);
 | |
|   }
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| /* readonly attribute nsIPrintSettings currentPrintSettings; */
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::GetCurrentPrintSettings(nsIPrintSettings * *aCurrentPrintSettings)
 | |
| {
 | |
|   NS_ENSURE_ARG_POINTER(aCurrentPrintSettings);
 | |
| 
 | |
|   *aCurrentPrintSettings = nsnull;
 | |
|   NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
 | |
| 
 | |
|   return mPrintEngine->GetCurrentPrintSettings(aCurrentPrintSettings);
 | |
| }
 | |
| 
 | |
| 
 | |
| /* readonly attribute nsIDOMWindow currentChildDOMWindow; */
 | |
| NS_IMETHODIMP 
 | |
| DocumentViewerImpl::GetCurrentChildDOMWindow(nsIDOMWindow * *aCurrentChildDOMWindow)
 | |
| {
 | |
|   NS_ENSURE_ARG_POINTER(aCurrentChildDOMWindow);
 | |
|   *aCurrentChildDOMWindow = nsnull;
 | |
|   return NS_ERROR_NOT_IMPLEMENTED;
 | |
| }
 | |
| 
 | |
| /* void cancel (); */
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::Cancel()
 | |
| {
 | |
|   NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
 | |
|   return mPrintEngine->Cancelled();
 | |
| }
 | |
| 
 | |
| /* void exitPrintPreview (); */
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::ExitPrintPreview()
 | |
| {
 | |
|   if (GetIsPrinting()) return NS_ERROR_FAILURE;
 | |
|   NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
 | |
| 
 | |
|   if (GetIsPrintPreview()) {
 | |
|     ReturnToGalleyPresentation();
 | |
|   }
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| //----------------------------------------------------------------------------------
 | |
| // Enumerate all the documents for their titles
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::EnumerateDocumentNames(PRUint32* aCount,
 | |
|                                            PRUnichar*** aResult)
 | |
| {
 | |
| #ifdef NS_PRINTING
 | |
|   NS_ENSURE_ARG(aCount);
 | |
|   NS_ENSURE_ARG_POINTER(aResult);
 | |
|   NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
 | |
| 
 | |
|   return mPrintEngine->EnumerateDocumentNames(aCount, aResult);
 | |
| #else
 | |
|   return NS_ERROR_FAILURE;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /* readonly attribute boolean isFramesetFrameSelected; */
 | |
| NS_IMETHODIMP 
 | |
| DocumentViewerImpl::GetIsFramesetFrameSelected(PRBool *aIsFramesetFrameSelected)
 | |
| {
 | |
| #ifdef NS_PRINTING
 | |
|   *aIsFramesetFrameSelected = PR_FALSE;
 | |
|   NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
 | |
| 
 | |
|   return mPrintEngine->GetIsFramesetFrameSelected(aIsFramesetFrameSelected);
 | |
| #else
 | |
|   return NS_ERROR_FAILURE;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /* readonly attribute long printPreviewNumPages; */
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::GetPrintPreviewNumPages(PRInt32 *aPrintPreviewNumPages)
 | |
| {
 | |
| #ifdef NS_PRINTING
 | |
|   NS_ENSURE_ARG_POINTER(aPrintPreviewNumPages);
 | |
|   NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
 | |
| 
 | |
|   return mPrintEngine->GetPrintPreviewNumPages(aPrintPreviewNumPages);
 | |
| #else
 | |
|   return NS_ERROR_FAILURE;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /* readonly attribute boolean isFramesetDocument; */
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::GetIsFramesetDocument(PRBool *aIsFramesetDocument)
 | |
| {
 | |
| #ifdef NS_PRINTING
 | |
|   *aIsFramesetDocument = PR_FALSE;
 | |
|   NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
 | |
| 
 | |
|   return mPrintEngine->GetIsFramesetDocument(aIsFramesetDocument);
 | |
| #else
 | |
|   return NS_ERROR_FAILURE;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /* readonly attribute boolean isIFrameSelected; */
 | |
| NS_IMETHODIMP 
 | |
| DocumentViewerImpl::GetIsIFrameSelected(PRBool *aIsIFrameSelected)
 | |
| {
 | |
| #ifdef NS_PRINTING
 | |
|   *aIsIFrameSelected = PR_FALSE;
 | |
|   NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
 | |
| 
 | |
|   return mPrintEngine->GetIsIFrameSelected(aIsIFrameSelected);
 | |
| #else
 | |
|   return NS_ERROR_FAILURE;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /* readonly attribute boolean isRangeSelection; */
 | |
| NS_IMETHODIMP 
 | |
| DocumentViewerImpl::GetIsRangeSelection(PRBool *aIsRangeSelection)
 | |
| {
 | |
| #ifdef NS_PRINTING
 | |
|   *aIsRangeSelection = PR_FALSE;
 | |
|   NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
 | |
| 
 | |
|   return mPrintEngine->GetIsRangeSelection(aIsRangeSelection);
 | |
| #else
 | |
|   return NS_ERROR_FAILURE;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| //----------------------------------------------------------------------------------
 | |
| // Printing/Print Preview Helpers
 | |
| //----------------------------------------------------------------------------------
 | |
| 
 | |
| //----------------------------------------------------------------------------------
 | |
| // Walks the document tree and tells each DocShell whether Printing/PP is happening
 | |
| void 
 | |
| DocumentViewerImpl::SetIsPrintingInDocShellTree(nsIDocShellTreeNode* aParentNode, 
 | |
|                                                 PRBool               aIsPrintingOrPP, 
 | |
|                                                 PRBool               aStartAtTop)
 | |
| {
 | |
|   NS_ASSERTION(aParentNode, "Parent can't be NULL!");
 | |
| 
 | |
|   nsCOMPtr<nsIDocShellTreeItem> parentItem(do_QueryInterface(aParentNode));
 | |
| 
 | |
|   // find top of "same parent" tree
 | |
|   if (aStartAtTop) {
 | |
|     while (parentItem) {
 | |
|       nsCOMPtr<nsIDocShellTreeItem> parent;
 | |
|       parentItem->GetSameTypeParent(getter_AddRefs(parent));
 | |
|       if (!parent) {
 | |
|         break;
 | |
|       }
 | |
|       parentItem = do_QueryInterface(parent);
 | |
|     }
 | |
|   }
 | |
|   NS_ASSERTION(parentItem, "parentItem can't be null");
 | |
| 
 | |
|   // Check to see if the DocShell's ContentViewer is printing/PP
 | |
|   nsCOMPtr<nsIContentViewerContainer> viewerContainer(do_QueryInterface(parentItem));
 | |
|   if (viewerContainer) {
 | |
|     viewerContainer->SetIsPrinting(aIsPrintingOrPP);
 | |
|   }
 | |
| 
 | |
|   // Traverse children to see if any of them are printing.
 | |
|   PRInt32 n;
 | |
|   aParentNode->GetChildCount(&n);
 | |
|   for (PRInt32 i=0; i < n; i++) {
 | |
|     nsCOMPtr<nsIDocShellTreeItem> child;
 | |
|     aParentNode->GetChildAt(i, getter_AddRefs(child));
 | |
|     nsCOMPtr<nsIDocShellTreeNode> childAsNode(do_QueryInterface(child));
 | |
|     NS_ASSERTION(childAsNode, "child isn't nsIDocShellTreeNode");
 | |
|     if (childAsNode) {
 | |
|       SetIsPrintingInDocShellTree(childAsNode, aIsPrintingOrPP, PR_FALSE);
 | |
|     }
 | |
|   }
 | |
| 
 | |
| }
 | |
| #endif // NS_PRINTING
 | |
| 
 | |
| //------------------------------------------------------------
 | |
| // XXX this always returns PR_FALSE for subdocuments
 | |
| PRBool
 | |
| DocumentViewerImpl::GetIsPrinting()
 | |
| {
 | |
| #ifdef NS_PRINTING
 | |
|   if (mPrintEngine) {
 | |
|     return mPrintEngine->GetIsPrinting();
 | |
|   }
 | |
| #endif
 | |
|   return PR_FALSE; 
 | |
| }
 | |
| 
 | |
| //------------------------------------------------------------
 | |
| // Notification from the PrintEngine of the current Printing status
 | |
| void
 | |
| DocumentViewerImpl::SetIsPrinting(PRBool aIsPrinting)
 | |
| {
 | |
| #ifdef NS_PRINTING
 | |
|   // Set all the docShells in the docshell tree to be printing.
 | |
|   // that way if anyone of them tries to "navigate" it can't
 | |
|   if (mContainer) {
 | |
|     nsCOMPtr<nsIDocShellTreeNode> docShellTreeNode(do_QueryReferent(mContainer));
 | |
|     NS_ASSERTION(docShellTreeNode, "mContainer has to be a nsIDocShellTreeNode");
 | |
|     SetIsPrintingInDocShellTree(docShellTreeNode, aIsPrinting, PR_TRUE);
 | |
|   }
 | |
| #endif
 | |
| }
 | |
| 
 | |
| //------------------------------------------------------------
 | |
| // The PrintEngine holds the current value
 | |
| // this called from inside the DocViewer.
 | |
| // XXX it always returns PR_FALSE for subdocuments
 | |
| PRBool
 | |
| DocumentViewerImpl::GetIsPrintPreview()
 | |
| {
 | |
| #ifdef NS_PRINTING
 | |
|   if (mPrintEngine) {
 | |
|     return mPrintEngine->GetIsPrintPreview();
 | |
|   }
 | |
| #endif
 | |
|   return PR_FALSE; 
 | |
| }
 | |
| 
 | |
| //------------------------------------------------------------
 | |
| // Notification from the PrintEngine of the current PP status
 | |
| void
 | |
| DocumentViewerImpl::SetIsPrintPreview(PRBool aIsPrintPreview)
 | |
| {
 | |
| #ifdef NS_PRINTING
 | |
|   // Set all the docShells in the docshell tree to be printing.
 | |
|   // that way if anyone of them tries to "navigate" it can't
 | |
|   if (mContainer) {
 | |
|     nsCOMPtr<nsIDocShellTreeNode> docShellTreeNode(do_QueryReferent(mContainer));
 | |
|     NS_ASSERTION(docShellTreeNode, "mContainer has to be a nsIDocShellTreeNode");
 | |
|     SetIsPrintingInDocShellTree(docShellTreeNode, aIsPrintPreview, PR_TRUE);
 | |
|   }
 | |
| #endif
 | |
| }
 | |
| 
 | |
| //----------------------------------------------------------------------------------
 | |
| // nsIDocumentViewerPrint IFace
 | |
| //----------------------------------------------------------------------------------
 | |
| 
 | |
| //------------------------------------------------------------
 | |
| void
 | |
| DocumentViewerImpl::IncrementDestroyRefCount()
 | |
| {
 | |
|   ++mDestroyRefCount;
 | |
| }
 | |
| 
 | |
| //------------------------------------------------------------
 | |
| 
 | |
| static void ResetFocusState(nsIDocShell* aDocShell);
 | |
| 
 | |
| void
 | |
| DocumentViewerImpl::ReturnToGalleyPresentation()
 | |
| {
 | |
| #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
 | |
|   if (!GetIsPrintPreview()) {
 | |
|     NS_ERROR("Wow, we should never get here!");
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   SetIsPrintPreview(PR_FALSE);
 | |
| 
 | |
|   mPrintEngine->TurnScriptingOn(PR_TRUE);
 | |
|   mPrintEngine->Destroy();
 | |
|   mPrintEngine = nsnull;
 | |
| 
 | |
|   mViewManager->EnableRefresh(NS_VMREFRESH_DEFERRED);
 | |
| 
 | |
|   nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mContainer));
 | |
|   ResetFocusState(docShell);
 | |
| 
 | |
|   SetTextZoom(mTextZoom);
 | |
|   SetFullZoom(mPageZoom);
 | |
|   Show();
 | |
| 
 | |
| #endif // NS_PRINTING && NS_PRINT_PREVIEW
 | |
| }
 | |
| 
 | |
| //------------------------------------------------------------
 | |
| // Reset ESM focus for all descendent doc shells.
 | |
| static void
 | |
| ResetFocusState(nsIDocShell* aDocShell)
 | |
| {
 | |
|   nsCOMPtr<nsISimpleEnumerator> docShellEnumerator;
 | |
|   aDocShell->GetDocShellEnumerator(nsIDocShellTreeItem::typeContent,
 | |
|                                    nsIDocShell::ENUMERATE_FORWARDS,
 | |
|                                    getter_AddRefs(docShellEnumerator));
 | |
|   
 | |
|   nsCOMPtr<nsIDocShell> currentDocShell;
 | |
|   nsCOMPtr<nsISupports> currentContainer;
 | |
|   PRBool hasMoreDocShells;
 | |
|   while (NS_SUCCEEDED(docShellEnumerator->HasMoreElements(&hasMoreDocShells))
 | |
|          && hasMoreDocShells) {
 | |
|     docShellEnumerator->GetNext(getter_AddRefs(currentContainer));
 | |
|     currentDocShell = do_QueryInterface(currentContainer);
 | |
|     if (!currentDocShell) {
 | |
|       break;
 | |
|     }
 | |
|     nsCOMPtr<nsPresContext> presContext;
 | |
|     currentDocShell->GetPresContext(getter_AddRefs(presContext));
 | |
|     nsIEventStateManager* esm =
 | |
|       presContext ? presContext->EventStateManager() : nsnull;
 | |
|     if (esm) {
 | |
|        esm->SetContentState(nsnull, NS_EVENT_STATE_FOCUS);
 | |
|        esm->SetFocusedContent(nsnull);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| //------------------------------------------------------------
 | |
| // This called ONLY when printing has completed and the DV
 | |
| // is being notified that it should get rid of the PrintEngine.
 | |
| //
 | |
| // BUT, if we are in Print Preview then we want to ignore the 
 | |
| // notification (we do not get rid of the PrintEngine)
 | |
| // 
 | |
| // One small caveat: 
 | |
| //   This IS called from two places in this module for cleaning
 | |
| //   up when an error occurred during the start up printing 
 | |
| //   and print preview
 | |
| //
 | |
| void
 | |
| DocumentViewerImpl::OnDonePrinting() 
 | |
| {
 | |
| #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
 | |
|   if (mPrintEngine) {
 | |
|     if (GetIsPrintPreview()) {
 | |
|       mPrintEngine->DestroyPrintingData();
 | |
|     } else {
 | |
|       mPrintEngine->Destroy();
 | |
|       mPrintEngine = nsnull;
 | |
|     }
 | |
| 
 | |
|     // We are done printing, now cleanup 
 | |
|     if (mDeferredWindowClose) {
 | |
|       mDeferredWindowClose = PR_FALSE;
 | |
|       nsCOMPtr<nsISupports> container = do_QueryReferent(mContainer);
 | |
|       nsCOMPtr<nsIDOMWindowInternal> win = do_GetInterface(container);
 | |
|       if (win)
 | |
|         win->Close();
 | |
|     } else if (mClosingWhilePrinting) {
 | |
|       if (mDocument) {
 | |
|         mDocument->SetScriptGlobalObject(nsnull);
 | |
|         mDocument->Destroy();
 | |
|         mDocument = nsnull;
 | |
|       }
 | |
|       mClosingWhilePrinting = PR_FALSE;
 | |
|       NS_RELEASE_THIS();
 | |
|     }
 | |
|   }
 | |
| #endif // NS_PRINTING && NS_PRINT_PREVIEW
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP DocumentViewerImpl::SetPageMode(PRBool aPageMode, nsIPrintSettings* aPrintSettings)
 | |
| {
 | |
|   // XXX Page mode is only partially working; it's currently used for
 | |
|   // reftests that require a paginated context
 | |
|   mIsPageMode = aPageMode;
 | |
|   // Get the current size of what is being viewed
 | |
|   nsRect bounds;
 | |
|   mWindow->GetBounds(bounds);
 | |
| 
 | |
|   if (mPresShell) {
 | |
|     // Break circular reference (or something)
 | |
|     mPresShell->EndObservingDocument();
 | |
|     nsCOMPtr<nsISelection> selection;
 | |
|     nsresult rv = GetDocumentSelection(getter_AddRefs(selection));
 | |
|     nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(selection));
 | |
|     if (NS_SUCCEEDED(rv) && selPrivate && mSelectionListener)
 | |
|       selPrivate->RemoveSelectionListener(mSelectionListener);
 | |
|     mPresShell->Destroy();
 | |
|   }
 | |
| 
 | |
|   if (mPresContext) {
 | |
|     mPresContext->SetContainer(nsnull);
 | |
|     mPresContext->SetLinkHandler(nsnull);
 | |
|   }
 | |
| 
 | |
|   mPresShell    = nsnull;
 | |
|   mPresContext  = nsnull;
 | |
|   mViewManager  = nsnull;
 | |
|   mWindow       = nsnull;
 | |
| 
 | |
|   NS_ENSURE_STATE(mDocument);
 | |
|   if (aPageMode)
 | |
|   {    
 | |
|     mPresContext =
 | |
|       new nsPresContext(mDocument, nsPresContext::eContext_PageLayout);
 | |
|     NS_ENSURE_TRUE(mPresContext, NS_ERROR_OUT_OF_MEMORY);
 | |
|     mPresContext->SetPaginatedScrolling(PR_TRUE);
 | |
|     mPresContext->SetPrintSettings(aPrintSettings);
 | |
|     nsresult rv = mPresContext->Init(mDeviceContext);
 | |
|     NS_ENSURE_SUCCESS(rv, rv);
 | |
|   }
 | |
|   InitInternal(mParentWidget, nsnull, mDeviceContext, bounds, PR_TRUE, PR_FALSE, PR_FALSE);
 | |
|   mViewManager->EnableRefresh(NS_VMREFRESH_NO_SYNC);
 | |
| 
 | |
|   Show();
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DocumentViewerImpl::GetHistoryEntry(nsISHEntry **aHistoryEntry)
 | |
| {
 | |
|   NS_IF_ADDREF(*aHistoryEntry = mSHEntry);
 | |
|   return NS_OK;
 | |
| }
 | 
