michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 sw=2 et tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* container for a document and its presentation */ michael@0: michael@0: #include "nscore.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsCRT.h" michael@0: #include "nsString.h" michael@0: #include "nsReadableUtils.h" michael@0: #include "nsIContent.h" michael@0: #include "nsIContentViewerContainer.h" michael@0: #include "nsIContentViewer.h" michael@0: #include "nsIDocumentViewerPrint.h" michael@0: #include "nsIDOMBeforeUnloadEvent.h" michael@0: #include "nsIDocument.h" michael@0: #include "nsIDOMWindowUtils.h" michael@0: #include "nsPresContext.h" michael@0: #include "nsIPresShell.h" michael@0: #include "nsStyleSet.h" michael@0: #include "nsCSSStyleSheet.h" michael@0: #include "nsIFrame.h" michael@0: #include "nsIWritablePropertyBag2.h" michael@0: #include "nsSubDocumentFrame.h" michael@0: michael@0: #include "nsILinkHandler.h" michael@0: #include "nsIDOMDocument.h" michael@0: #include "nsISelectionListener.h" michael@0: #include "nsISelectionPrivate.h" michael@0: #include "nsIDOMHTMLDocument.h" michael@0: #include "nsIDOMHTMLElement.h" michael@0: #include "nsContentUtils.h" michael@0: #include "nsLayoutStylesheetCache.h" michael@0: #ifdef ACCESSIBILITY michael@0: #include "mozilla/a11y/DocAccessible.h" michael@0: #endif michael@0: #include "mozilla/BasicEvents.h" michael@0: #include "mozilla/Preferences.h" michael@0: #include "mozilla/dom/EncodingUtils.h" michael@0: #include "mozilla/WeakPtr.h" michael@0: michael@0: #include "nsViewManager.h" michael@0: #include "nsView.h" michael@0: michael@0: #include "nsIPageSequenceFrame.h" michael@0: #include "nsNetUtil.h" michael@0: #include "nsIContentViewerEdit.h" michael@0: #include "nsIContentViewerFile.h" michael@0: #include "mozilla/css/Loader.h" michael@0: #include "nsIMarkupDocumentViewer.h" michael@0: #include "nsIInterfaceRequestor.h" michael@0: #include "nsIInterfaceRequestorUtils.h" michael@0: #include "nsDocShell.h" michael@0: #include "nsIBaseWindow.h" michael@0: #include "nsILayoutHistoryState.h" michael@0: #include "nsCharsetSource.h" michael@0: #include "nsHTMLReflowState.h" michael@0: #include "nsIImageLoadingContent.h" michael@0: #include "nsCopySupport.h" michael@0: #include "nsIDOMHTMLFrameSetElement.h" michael@0: #ifdef MOZ_XUL michael@0: #include "nsIXULDocument.h" michael@0: #include "nsXULPopupManager.h" michael@0: #endif michael@0: michael@0: #include "nsIClipboardHelper.h" michael@0: michael@0: #include "nsPIDOMWindow.h" michael@0: #include "nsDOMNavigationTiming.h" michael@0: #include "nsPIWindowRoot.h" michael@0: #include "nsJSEnvironment.h" michael@0: #include "nsFocusManager.h" michael@0: michael@0: #include "nsIScrollableFrame.h" michael@0: #include "nsStyleSheetService.h" michael@0: #include "nsRenderingContext.h" michael@0: #include "nsILoadContext.h" michael@0: michael@0: #include "nsIPrompt.h" michael@0: #include "imgIContainer.h" // image animation mode constants michael@0: michael@0: //-------------------------- michael@0: // Printing Include michael@0: //--------------------------- michael@0: #ifdef NS_PRINTING michael@0: michael@0: #include "nsIWebBrowserPrint.h" michael@0: michael@0: #include "nsPrintEngine.h" michael@0: michael@0: // Print Options michael@0: #include "nsIPrintSettings.h" michael@0: #include "nsIPrintOptions.h" michael@0: #include "nsISimpleEnumerator.h" michael@0: michael@0: #ifdef DEBUG michael@0: // PrintOptions is now implemented by PrintSettingsService michael@0: static const char sPrintOptionsContractID[] = michael@0: "@mozilla.org/gfx/printsettings-service;1"; michael@0: #endif // DEBUG michael@0: michael@0: #include "nsIPluginDocument.h" michael@0: michael@0: #endif // NS_PRINTING michael@0: michael@0: //focus michael@0: #include "nsIDOMEventTarget.h" michael@0: #include "nsIDOMEventListener.h" michael@0: #include "nsISelectionController.h" michael@0: michael@0: #include "mozilla/EventDispatcher.h" michael@0: #include "nsISHEntry.h" michael@0: #include "nsISHistory.h" michael@0: #include "nsISHistoryInternal.h" michael@0: #include "nsIWebNavigation.h" michael@0: #include "nsXMLHttpRequest.h" michael@0: michael@0: //paint forcing michael@0: #include michael@0: michael@0: #include "mozilla/dom/Element.h" michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::dom; michael@0: michael@0: #define BEFOREUNLOAD_DISABLED_PREFNAME "dom.disable_beforeunload" michael@0: michael@0: //----------------------------------------------------- michael@0: // PR LOGGING michael@0: #ifdef MOZ_LOGGING michael@0: #define FORCE_PR_LOG /* Allow logging in the release build */ michael@0: #endif michael@0: michael@0: #include "prlog.h" michael@0: michael@0: #ifdef PR_LOGGING michael@0: michael@0: #ifdef NS_PRINTING michael@0: static PRLogModuleInfo * michael@0: GetPrintingLog() michael@0: { michael@0: static PRLogModuleInfo *sLog; michael@0: if (!sLog) michael@0: sLog = PR_NewLogModule("printing"); michael@0: return sLog; michael@0: } michael@0: #define PR_PL(_p1) PR_LOG(GetPrintingLog(), PR_LOG_DEBUG, _p1); michael@0: #endif // NS_PRINTING michael@0: michael@0: #define PRT_YESNO(_p) ((_p)?"YES":"NO") michael@0: #else michael@0: #define PRT_YESNO(_p) michael@0: #define PR_PL(_p1) michael@0: #endif michael@0: //----------------------------------------------------- michael@0: michael@0: class nsDocumentViewer; michael@0: class nsPrintEventDispatcher; michael@0: michael@0: // a small delegate class used to avoid circular references michael@0: michael@0: class nsDocViewerSelectionListener : public nsISelectionListener michael@0: { michael@0: public: michael@0: michael@0: // nsISupports interface... michael@0: NS_DECL_ISUPPORTS michael@0: michael@0: // nsISelectionListerner interface michael@0: NS_DECL_NSISELECTIONLISTENER michael@0: michael@0: nsDocViewerSelectionListener() michael@0: : mDocViewer(nullptr) michael@0: , mGotSelectionState(false) michael@0: , mSelectionWasCollapsed(false) michael@0: { michael@0: } michael@0: michael@0: virtual ~nsDocViewerSelectionListener() {} michael@0: michael@0: nsresult Init(nsDocumentViewer *aDocViewer); michael@0: michael@0: protected: michael@0: michael@0: nsDocumentViewer* mDocViewer; michael@0: bool mGotSelectionState; michael@0: bool mSelectionWasCollapsed; michael@0: michael@0: }; michael@0: michael@0: michael@0: /** editor Implementation of the FocusListener interface michael@0: */ michael@0: class nsDocViewerFocusListener : public nsIDOMEventListener michael@0: { michael@0: public: michael@0: /** default constructor michael@0: */ michael@0: nsDocViewerFocusListener(); michael@0: /** default destructor michael@0: */ michael@0: virtual ~nsDocViewerFocusListener(); michael@0: michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_NSIDOMEVENTLISTENER michael@0: michael@0: nsresult Init(nsDocumentViewer *aDocViewer); michael@0: michael@0: private: michael@0: nsDocumentViewer* mDocViewer; michael@0: }; michael@0: michael@0: michael@0: //------------------------------------------------------------- michael@0: class nsDocumentViewer : public nsIContentViewer, michael@0: public nsIContentViewerEdit, michael@0: public nsIContentViewerFile, michael@0: public nsIMarkupDocumentViewer, michael@0: public nsIDocumentViewerPrint michael@0: michael@0: #ifdef NS_PRINTING michael@0: , public nsIWebBrowserPrint michael@0: #endif michael@0: michael@0: { michael@0: friend class nsDocViewerSelectionListener; michael@0: friend class nsPagePrintTimer; michael@0: friend class nsPrintEngine; michael@0: michael@0: public: michael@0: nsDocumentViewer(); michael@0: michael@0: NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW michael@0: michael@0: // nsISupports interface... michael@0: NS_DECL_ISUPPORTS michael@0: michael@0: // nsIContentViewer interface... michael@0: NS_DECL_NSICONTENTVIEWER michael@0: michael@0: // nsIContentViewerEdit michael@0: NS_DECL_NSICONTENTVIEWEREDIT michael@0: michael@0: // nsIContentViewerFile michael@0: NS_DECL_NSICONTENTVIEWERFILE michael@0: michael@0: // nsIMarkupDocumentViewer michael@0: NS_DECL_NSIMARKUPDOCUMENTVIEWER michael@0: michael@0: #ifdef NS_PRINTING michael@0: // nsIWebBrowserPrint michael@0: NS_DECL_NSIWEBBROWSERPRINT michael@0: #endif michael@0: michael@0: typedef void (*CallChildFunc)(nsIMarkupDocumentViewer* aViewer, michael@0: void* aClosure); michael@0: void CallChildren(CallChildFunc aFunc, void* aClosure); michael@0: michael@0: // nsIDocumentViewerPrint Printing Methods michael@0: NS_DECL_NSIDOCUMENTVIEWERPRINT michael@0: michael@0: michael@0: static void DispatchBeforePrint(nsIDocument* aTop) michael@0: { michael@0: DispatchEventToWindowTree(aTop, NS_LITERAL_STRING("beforeprint")); michael@0: } michael@0: static void DispatchAfterPrint(nsIDocument* aTop) michael@0: { michael@0: DispatchEventToWindowTree(aTop, NS_LITERAL_STRING("afterprint")); michael@0: } michael@0: static void DispatchEventToWindowTree(nsIDocument* aTop, michael@0: const nsAString& aEvent); michael@0: michael@0: protected: michael@0: virtual ~nsDocumentViewer(); michael@0: michael@0: private: michael@0: /** michael@0: * Creates a view manager, root view, and widget for the root view, setting michael@0: * mViewManager and mWindow. michael@0: * @param aSize the initial size in appunits michael@0: * @param aContainerView the container view to hook our root view up michael@0: * to as a child, or null if this will be the root view manager michael@0: */ michael@0: nsresult MakeWindow(const nsSize& aSize, nsView* aContainerView); michael@0: michael@0: /** michael@0: * Create our device context michael@0: */ michael@0: nsresult CreateDeviceContext(nsView* aContainerView); michael@0: michael@0: /** michael@0: * If aDoCreation is true, this creates the device context, creates a michael@0: * prescontext if necessary, and calls MakeWindow. michael@0: * michael@0: * If aForceSetNewDocument is false, then SetNewDocument won't be michael@0: * called if the window's current document is already mDocument. michael@0: */ michael@0: nsresult InitInternal(nsIWidget* aParentWidget, michael@0: nsISupports *aState, michael@0: const nsIntRect& aBounds, michael@0: bool aDoCreation, michael@0: bool aNeedMakeCX = true, michael@0: bool aForceSetNewDocument = true); michael@0: /** michael@0: * @param aDoInitialReflow set to true if you want to kick off the initial michael@0: * reflow michael@0: */ michael@0: nsresult InitPresentationStuff(bool aDoInitialReflow); michael@0: michael@0: nsresult GetPopupNode(nsIDOMNode** aNode); michael@0: nsresult GetPopupLinkNode(nsIDOMNode** aNode); michael@0: nsresult GetPopupImageNode(nsIImageLoadingContent** aNode); michael@0: michael@0: void PrepareToStartLoad(void); michael@0: michael@0: nsresult SyncParentSubDocMap(); michael@0: michael@0: nsresult GetDocumentSelection(nsISelection **aSelection); michael@0: michael@0: void DestroyPresShell(); michael@0: void DestroyPresContext(); michael@0: michael@0: #ifdef NS_PRINTING michael@0: // Called when the DocViewer is notified that the state michael@0: // of Printing or PP has changed michael@0: void SetIsPrintingInDocShellTree(nsIDocShellTreeItem* aParentNode, michael@0: bool aIsPrintingOrPP, michael@0: bool aStartAtTop); michael@0: #endif // NS_PRINTING michael@0: michael@0: // Whether we should attach to the top level widget. This is true if we michael@0: // are sharing/recycling a single base widget and not creating multiple michael@0: // child widgets. michael@0: bool ShouldAttachToTopLevel(); michael@0: michael@0: protected: michael@0: // These return the current shell/prescontext etc. michael@0: nsIPresShell* GetPresShell(); michael@0: nsPresContext* GetPresContext(); michael@0: nsViewManager* GetViewManager(); michael@0: michael@0: void DetachFromTopLevelWidget(); michael@0: michael@0: // IMPORTANT: The ownership implicit in the following member michael@0: // variables has been explicitly checked and set using nsCOMPtr michael@0: // for owning pointers and raw COM interface pointers for weak michael@0: // (ie, non owning) references. If you add any members to this michael@0: // class, please make the ownership explicit (pinkerton, scc). michael@0: michael@0: WeakPtr mContainer; // it owns me! michael@0: nsWeakPtr mTopContainerWhilePrinting; michael@0: nsRefPtr mDeviceContext; // We create and own this baby michael@0: michael@0: // the following six items are explicitly in this order michael@0: // so they will be destroyed in the reverse order (pinkerton, scc) michael@0: nsCOMPtr mDocument; michael@0: nsCOMPtr mWindow; // may be null michael@0: nsRefPtr mViewManager; michael@0: nsRefPtr mPresContext; michael@0: nsCOMPtr mPresShell; michael@0: michael@0: nsCOMPtr mSelectionListener; michael@0: nsRefPtr mFocusListener; michael@0: michael@0: nsCOMPtr mPreviousViewer; michael@0: nsCOMPtr mSHEntry; michael@0: michael@0: nsIWidget* mParentWidget; // purposely won't be ref counted. May be null michael@0: bool mAttachedToParent; // view is attached to the parent widget michael@0: michael@0: nsIntRect mBounds; michael@0: michael@0: // mTextZoom/mPageZoom record the textzoom/pagezoom of the first (galley) michael@0: // presshell only. michael@0: float mTextZoom; // Text zoom, defaults to 1.0 michael@0: float mPageZoom; michael@0: int mMinFontSize; michael@0: michael@0: int16_t mNumURLStarts; michael@0: int16_t mDestroyRefCount; // a second "refcount" for the document viewer's "destroy" michael@0: michael@0: unsigned mStopped : 1; michael@0: unsigned mLoaded : 1; michael@0: unsigned mDeferredWindowClose : 1; michael@0: // document management data michael@0: // these items are specific to markup documents (html and xml) michael@0: // may consider splitting these out into a subclass michael@0: unsigned mIsSticky : 1; michael@0: unsigned mInPermitUnload : 1; michael@0: unsigned mInPermitUnloadPrompt: 1; michael@0: michael@0: #ifdef NS_PRINTING michael@0: unsigned mClosingWhilePrinting : 1; michael@0: michael@0: #if NS_PRINT_PREVIEW michael@0: unsigned mPrintPreviewZoomed : 1; michael@0: michael@0: // These data members support delayed printing when the document is loading michael@0: unsigned mPrintIsPending : 1; michael@0: unsigned mPrintDocIsFullyLoaded : 1; michael@0: nsCOMPtr mCachedPrintSettings; michael@0: nsCOMPtr mCachedPrintWebProgressListner; michael@0: michael@0: nsRefPtr mPrintEngine; michael@0: float mOriginalPrintPreviewScale; michael@0: float mPrintPreviewZoom; michael@0: nsAutoPtr mBeforeAndAfterPrint; michael@0: #endif // NS_PRINT_PREVIEW michael@0: michael@0: #ifdef DEBUG michael@0: FILE* mDebugFile; michael@0: #endif // DEBUG michael@0: #endif // NS_PRINTING michael@0: michael@0: /* character set member data */ michael@0: int32_t mHintCharsetSource; michael@0: nsCString mHintCharset; michael@0: nsCString mForceCharacterSet; michael@0: michael@0: bool mIsPageMode; michael@0: bool mCallerIsClosingWindow; michael@0: bool mInitializedForPrintPreview; michael@0: bool mHidden; michael@0: }; michael@0: michael@0: class nsPrintEventDispatcher michael@0: { michael@0: public: michael@0: nsPrintEventDispatcher(nsIDocument* aTop) : mTop(aTop) michael@0: { michael@0: nsDocumentViewer::DispatchBeforePrint(mTop); michael@0: } michael@0: ~nsPrintEventDispatcher() michael@0: { michael@0: nsDocumentViewer::DispatchAfterPrint(mTop); michael@0: } michael@0: michael@0: nsCOMPtr mTop; michael@0: }; michael@0: michael@0: class nsDocumentShownDispatcher : public nsRunnable michael@0: { michael@0: public: michael@0: nsDocumentShownDispatcher(nsCOMPtr aDocument) michael@0: : mDocument(aDocument) {} michael@0: michael@0: NS_IMETHOD Run() MOZ_OVERRIDE; michael@0: michael@0: private: michael@0: nsCOMPtr mDocument; michael@0: }; michael@0: michael@0: michael@0: //------------------------------------------------------------------ michael@0: // nsDocumentViewer michael@0: //------------------------------------------------------------------ michael@0: michael@0: //------------------------------------------------------------------ michael@0: already_AddRefed michael@0: NS_NewContentViewer() michael@0: { michael@0: nsRefPtr viewer = new nsDocumentViewer(); michael@0: return viewer.forget(); michael@0: } michael@0: michael@0: void nsDocumentViewer::PrepareToStartLoad() michael@0: { michael@0: mStopped = false; michael@0: mLoaded = false; michael@0: mAttachedToParent = false; michael@0: mDeferredWindowClose = false; michael@0: mCallerIsClosingWindow = false; michael@0: michael@0: #ifdef NS_PRINTING michael@0: mPrintIsPending = false; michael@0: mPrintDocIsFullyLoaded = false; michael@0: mClosingWhilePrinting = false; michael@0: michael@0: // Make sure we have destroyed it and cleared the data member michael@0: if (mPrintEngine) { michael@0: mPrintEngine->Destroy(); michael@0: mPrintEngine = nullptr; michael@0: #ifdef NS_PRINT_PREVIEW michael@0: SetIsPrintPreview(false); michael@0: #endif michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: mDebugFile = nullptr; michael@0: #endif michael@0: michael@0: #endif // NS_PRINTING michael@0: } michael@0: michael@0: // Note: operator new zeros our memory, so no need to init things to null. michael@0: nsDocumentViewer::nsDocumentViewer() michael@0: : mTextZoom(1.0), mPageZoom(1.0), mMinFontSize(0), michael@0: mIsSticky(true), michael@0: #ifdef NS_PRINT_PREVIEW michael@0: mPrintPreviewZoom(1.0), michael@0: #endif michael@0: mHintCharsetSource(kCharsetUninitialized), michael@0: mInitializedForPrintPreview(false), michael@0: mHidden(false) michael@0: { michael@0: PrepareToStartLoad(); michael@0: } michael@0: michael@0: NS_IMPL_ADDREF(nsDocumentViewer) michael@0: NS_IMPL_RELEASE(nsDocumentViewer) michael@0: michael@0: NS_INTERFACE_MAP_BEGIN(nsDocumentViewer) michael@0: NS_INTERFACE_MAP_ENTRY(nsIContentViewer) michael@0: NS_INTERFACE_MAP_ENTRY(nsIMarkupDocumentViewer) michael@0: NS_INTERFACE_MAP_ENTRY(nsIContentViewerFile) michael@0: NS_INTERFACE_MAP_ENTRY(nsIContentViewerEdit) michael@0: NS_INTERFACE_MAP_ENTRY(nsIDocumentViewerPrint) michael@0: NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentViewer) michael@0: #ifdef NS_PRINTING michael@0: NS_INTERFACE_MAP_ENTRY(nsIWebBrowserPrint) michael@0: #endif michael@0: NS_INTERFACE_MAP_END michael@0: michael@0: nsDocumentViewer::~nsDocumentViewer() michael@0: { michael@0: if (mDocument) { michael@0: Close(nullptr); michael@0: mDocument->Destroy(); michael@0: } michael@0: michael@0: NS_ASSERTION(!mPresShell && !mPresContext, michael@0: "User did not call nsIContentViewer::Destroy"); michael@0: if (mPresShell || mPresContext) { michael@0: // Make sure we don't hand out a reference to the content viewer to michael@0: // the SHEntry! michael@0: mSHEntry = nullptr; michael@0: michael@0: Destroy(); michael@0: } michael@0: michael@0: // XXX(?) Revoke pending invalidate events michael@0: } michael@0: michael@0: /* michael@0: * This method is called by the Document Loader once a document has michael@0: * been created for a particular data stream... The content viewer michael@0: * must cache this document for later use when Init(...) is called. michael@0: * michael@0: * This method is also called when an out of band document.write() happens. michael@0: * In that case, the document passed in is the same as the previous document. michael@0: */ michael@0: /* virtual */ void michael@0: nsDocumentViewer::LoadStart(nsIDocument* aDocument) michael@0: { michael@0: MOZ_ASSERT(aDocument); michael@0: michael@0: if (!mDocument) { michael@0: mDocument = aDocument; michael@0: } michael@0: } michael@0: michael@0: nsresult michael@0: nsDocumentViewer::SyncParentSubDocMap() michael@0: { michael@0: nsCOMPtr item(mContainer); michael@0: nsCOMPtr pwin(do_GetInterface(item)); michael@0: nsCOMPtr content; michael@0: michael@0: if (mDocument && pwin) { michael@0: content = do_QueryInterface(pwin->GetFrameElementInternal()); michael@0: } michael@0: michael@0: if (content) { michael@0: nsCOMPtr parent; michael@0: item->GetParent(getter_AddRefs(parent)); michael@0: michael@0: nsCOMPtr parent_win(do_GetInterface(parent)); michael@0: michael@0: if (parent_win) { michael@0: nsCOMPtr dom_doc; michael@0: parent_win->GetDocument(getter_AddRefs(dom_doc)); michael@0: michael@0: nsCOMPtr parent_doc(do_QueryInterface(dom_doc)); michael@0: michael@0: if (parent_doc) { michael@0: if (mDocument && michael@0: parent_doc->GetSubDocumentFor(content) != mDocument) { michael@0: mDocument->SuppressEventHandling(nsIDocument::eEvents, michael@0: parent_doc->EventHandlingSuppressed()); michael@0: } michael@0: return parent_doc->SetSubDocumentFor(content->AsElement(), mDocument); michael@0: } michael@0: } michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::SetContainer(nsIDocShell* aContainer) michael@0: { michael@0: mContainer = static_cast(aContainer)->asWeakPtr(); michael@0: if (mPresContext) { michael@0: mPresContext->SetContainer(mContainer); michael@0: } michael@0: michael@0: // We're loading a new document into the window where this document michael@0: // viewer lives, sync the parent document's frame element -> sub michael@0: // document map michael@0: michael@0: return SyncParentSubDocMap(); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::GetContainer(nsIDocShell** aResult) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aResult); michael@0: michael@0: nsCOMPtr container(mContainer); michael@0: container.swap(*aResult); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::Init(nsIWidget* aParentWidget, michael@0: const nsIntRect& aBounds) michael@0: { michael@0: return InitInternal(aParentWidget, nullptr, aBounds, true); michael@0: } michael@0: michael@0: nsresult michael@0: nsDocumentViewer::InitPresentationStuff(bool aDoInitialReflow) michael@0: { michael@0: if (GetIsPrintPreview()) michael@0: return NS_OK; michael@0: michael@0: NS_ASSERTION(!mPresShell, michael@0: "Someone should have destroyed the presshell!"); michael@0: michael@0: // Create the style set... michael@0: nsStyleSet *styleSet; michael@0: nsresult rv = CreateStyleSet(mDocument, &styleSet); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // Now make the shell for the document michael@0: mPresShell = mDocument->CreateShell(mPresContext, mViewManager, styleSet); michael@0: if (!mPresShell) { michael@0: delete styleSet; michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: // We're done creating the style set michael@0: styleSet->EndUpdate(); michael@0: michael@0: if (aDoInitialReflow) { michael@0: // Since Initialize() will create frames for *all* items michael@0: // that are currently in the document tree, we need to flush michael@0: // any pending notifications to prevent the content sink from michael@0: // duplicating layout frames for content it has added to the tree michael@0: // but hasn't notified the document about. (Bug 154018) michael@0: // michael@0: // Note that we are flushing before we add mPresShell as an observer michael@0: // to avoid bogus notifications. michael@0: michael@0: mDocument->FlushPendingNotifications(Flush_ContentAndNotify); michael@0: } michael@0: michael@0: mPresShell->BeginObservingDocument(); michael@0: michael@0: // Initialize our view manager michael@0: int32_t p2a = mPresContext->AppUnitsPerDevPixel(); michael@0: MOZ_ASSERT(p2a == mPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel()); michael@0: nscoord width = p2a * mBounds.width; michael@0: nscoord height = p2a * mBounds.height; michael@0: michael@0: mViewManager->SetWindowDimensions(width, height); michael@0: mPresContext->SetTextZoom(mTextZoom); michael@0: mPresContext->SetFullZoom(mPageZoom); michael@0: mPresContext->SetBaseMinFontSize(mMinFontSize); michael@0: michael@0: p2a = mPresContext->AppUnitsPerDevPixel(); // zoom may have changed it michael@0: width = p2a * mBounds.width; michael@0: height = p2a * mBounds.height; michael@0: if (aDoInitialReflow) { michael@0: nsCOMPtr shellGrip = mPresShell; michael@0: // Initial reflow michael@0: mPresShell->Initialize(width, height); michael@0: } else { michael@0: // Store the visible area so it's available for other callers of michael@0: // Initialize, like nsContentSink::StartLayout. michael@0: mPresContext->SetVisibleArea(nsRect(0, 0, width, height)); michael@0: } michael@0: michael@0: // now register ourselves as a selection listener, so that we get michael@0: // called when the selection changes in the window michael@0: if (!mSelectionListener) { michael@0: nsDocViewerSelectionListener *selectionListener = michael@0: new nsDocViewerSelectionListener(); michael@0: michael@0: selectionListener->Init(this); michael@0: michael@0: // mSelectionListener is a owning reference michael@0: mSelectionListener = selectionListener; michael@0: } michael@0: michael@0: nsCOMPtr selection; michael@0: rv = GetDocumentSelection(getter_AddRefs(selection)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsCOMPtr selPrivate(do_QueryInterface(selection)); michael@0: rv = selPrivate->AddSelectionListener(mSelectionListener); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: // Save old listener so we can unregister it michael@0: nsRefPtr oldFocusListener = mFocusListener; michael@0: michael@0: // focus listener michael@0: // michael@0: // now register ourselves as a focus listener, so that we get called michael@0: // when the focus changes in the window michael@0: nsDocViewerFocusListener *focusListener = new nsDocViewerFocusListener(); michael@0: michael@0: focusListener->Init(this); michael@0: michael@0: // mFocusListener is a strong reference michael@0: mFocusListener = focusListener; michael@0: michael@0: if (mDocument) { michael@0: mDocument->AddEventListener(NS_LITERAL_STRING("focus"), michael@0: mFocusListener, michael@0: false, false); michael@0: mDocument->AddEventListener(NS_LITERAL_STRING("blur"), michael@0: mFocusListener, michael@0: false, false); michael@0: michael@0: if (oldFocusListener) { michael@0: mDocument->RemoveEventListener(NS_LITERAL_STRING("focus"), michael@0: oldFocusListener, false); michael@0: mDocument->RemoveEventListener(NS_LITERAL_STRING("blur"), michael@0: oldFocusListener, false); michael@0: } michael@0: } michael@0: michael@0: if (aDoInitialReflow && mDocument) { michael@0: mDocument->ScrollToRef(); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: static nsPresContext* michael@0: CreatePresContext(nsIDocument* aDocument, michael@0: nsPresContext::nsPresContextType aType, michael@0: nsView* aContainerView) michael@0: { michael@0: if (aContainerView) michael@0: return new nsPresContext(aDocument, aType); michael@0: return new nsRootPresContext(aDocument, aType); michael@0: } michael@0: michael@0: //----------------------------------------------- michael@0: // This method can be used to initial the "presentation" michael@0: // The aDoCreation indicates whether it should create michael@0: // all the new objects or just initialize the existing ones michael@0: nsresult michael@0: nsDocumentViewer::InitInternal(nsIWidget* aParentWidget, michael@0: nsISupports *aState, michael@0: const nsIntRect& aBounds, michael@0: bool aDoCreation, michael@0: bool aNeedMakeCX /*= true*/, michael@0: bool aForceSetNewDocument /* = true*/) michael@0: { michael@0: if (mIsPageMode) { michael@0: // XXXbz should the InitInternal in SetPageMode just pass false michael@0: // here itself? michael@0: aForceSetNewDocument = false; michael@0: } michael@0: michael@0: // We don't want any scripts to run here. That can cause flushing, michael@0: // which can cause reentry into initialization of this document viewer, michael@0: // which would be disastrous. michael@0: nsAutoScriptBlocker blockScripts; michael@0: michael@0: mParentWidget = aParentWidget; // not ref counted michael@0: mBounds = aBounds; michael@0: michael@0: nsresult rv = NS_OK; michael@0: NS_ENSURE_TRUE(mDocument, NS_ERROR_NULL_POINTER); michael@0: michael@0: nsView* containerView = FindContainerView(); michael@0: michael@0: bool makeCX = false; michael@0: if (aDoCreation) { michael@0: nsresult rv = CreateDeviceContext(containerView); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // XXXbz this is a nasty hack to do with the fact that we create michael@0: // presentations both in Init() and in Show()... Ideally we would only do michael@0: // it in one place (Show()) and require that callers call init(), open(), michael@0: // show() in that order or something. michael@0: if (!mPresContext && michael@0: (aParentWidget || containerView || mDocument->IsBeingUsedAsImage() || michael@0: (mDocument->GetDisplayDocument() && michael@0: mDocument->GetDisplayDocument()->GetShell()))) { michael@0: // Create presentation context michael@0: if (mIsPageMode) { michael@0: //Presentation context already created in SetPageMode which is calling this method michael@0: } else { michael@0: mPresContext = CreatePresContext(mDocument, michael@0: nsPresContext::eContext_Galley, containerView); michael@0: } michael@0: NS_ENSURE_TRUE(mPresContext, NS_ERROR_OUT_OF_MEMORY); michael@0: michael@0: nsresult rv = mPresContext->Init(mDeviceContext); michael@0: if (NS_FAILED(rv)) { michael@0: mPresContext = nullptr; michael@0: return rv; michael@0: } michael@0: michael@0: #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW) michael@0: makeCX = !GetIsPrintPreview() && aNeedMakeCX; // needs to be true except when we are already in PP or we are enabling/disabling paginated mode. michael@0: #else michael@0: makeCX = true; michael@0: #endif michael@0: } michael@0: michael@0: if (mPresContext) { michael@0: // Create the ViewManager and Root View... michael@0: michael@0: // We must do this before we tell the script global object about michael@0: // this new document since doing that will cause us to re-enter michael@0: // into nsSubDocumentFrame code through reflows caused by michael@0: // FlushPendingNotifications() calls down the road... michael@0: michael@0: rv = MakeWindow(nsSize(mPresContext->DevPixelsToAppUnits(aBounds.width), michael@0: mPresContext->DevPixelsToAppUnits(aBounds.height)), michael@0: containerView); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: Hide(); michael@0: michael@0: #ifdef NS_PRINT_PREVIEW michael@0: if (mIsPageMode) { michael@0: // I'm leaving this in a broken state for the moment; we should michael@0: // be measuring/scaling with the print device context, not the michael@0: // screen device context, but this is good enough to allow michael@0: // printing reftests to work. michael@0: double pageWidth = 0, pageHeight = 0; michael@0: mPresContext->GetPrintSettings()->GetEffectivePageSize(&pageWidth, michael@0: &pageHeight); michael@0: mPresContext->SetPageSize( michael@0: nsSize(mPresContext->CSSTwipsToAppUnits(NSToIntFloor(pageWidth)), michael@0: mPresContext->CSSTwipsToAppUnits(NSToIntFloor(pageHeight)))); michael@0: mPresContext->SetIsRootPaginatedDocument(true); michael@0: mPresContext->SetPageScale(1.0f); michael@0: } michael@0: #endif michael@0: } else { michael@0: // Avoid leaking the old viewer. michael@0: if (mPreviousViewer) { michael@0: mPreviousViewer->Destroy(); michael@0: mPreviousViewer = nullptr; michael@0: } michael@0: } michael@0: } michael@0: michael@0: nsCOMPtr requestor(mContainer); michael@0: if (requestor) { michael@0: if (mPresContext) { michael@0: nsCOMPtr linkHandler; michael@0: requestor->GetInterface(NS_GET_IID(nsILinkHandler), michael@0: getter_AddRefs(linkHandler)); michael@0: michael@0: mPresContext->SetContainer(mContainer); michael@0: mPresContext->SetLinkHandler(linkHandler); michael@0: } michael@0: michael@0: // Set script-context-owner in the document michael@0: michael@0: nsCOMPtr window; michael@0: requestor->GetInterface(NS_GET_IID(nsPIDOMWindow), michael@0: getter_AddRefs(window)); michael@0: michael@0: if (window) { michael@0: nsCOMPtr curDoc = window->GetExtantDoc(); michael@0: if (aForceSetNewDocument || curDoc != mDocument) { michael@0: window->SetNewDocument(mDocument, aState, false); michael@0: nsJSContext::LoadStart(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (aDoCreation && mPresContext) { michael@0: // The ViewManager and Root View was created above (in michael@0: // MakeWindow())... michael@0: michael@0: rv = InitPresentationStuff(!makeCX); michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: void nsDocumentViewer::SetNavigationTiming(nsDOMNavigationTiming* timing) michael@0: { michael@0: NS_ASSERTION(mDocument, "Must have a document to set navigation timing."); michael@0: if (mDocument) { michael@0: mDocument->SetNavigationTiming(timing); michael@0: } michael@0: } michael@0: michael@0: // michael@0: // LoadComplete(aStatus) michael@0: // michael@0: // aStatus - The status returned from loading the document. michael@0: // michael@0: // This method is called by the container when the document has been michael@0: // completely loaded. michael@0: // michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::LoadComplete(nsresult aStatus) michael@0: { michael@0: /* We need to protect ourself against auto-destruction in case the michael@0: window is closed while processing the OnLoad event. See bug michael@0: http://bugzilla.mozilla.org/show_bug.cgi?id=78445 for more michael@0: explanation. michael@0: */ michael@0: nsRefPtr kungFuDeathGrip(this); michael@0: michael@0: // Flush out layout so it's up-to-date by the time onload is called. michael@0: // Note that this could destroy the window, so do this before michael@0: // checking for our mDocument and its window. michael@0: if (mPresShell && !mStopped) { michael@0: // Hold strong ref because this could conceivably run script michael@0: nsCOMPtr shell = mPresShell; michael@0: shell->FlushPendingNotifications(Flush_Layout); michael@0: } michael@0: michael@0: nsresult rv = NS_OK; michael@0: NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE); michael@0: michael@0: // First, get the window from the document... michael@0: nsCOMPtr window = mDocument->GetWindow(); michael@0: michael@0: mLoaded = true; michael@0: michael@0: // Now, fire either an OnLoad or OnError event to the document... michael@0: bool restoring = false; michael@0: // XXXbz imagelib kills off the document load for a full-page image with michael@0: // NS_ERROR_PARSED_DATA_CACHED if it's in the cache. So we want to treat michael@0: // that one as a success code; otherwise whether we fire onload for the image michael@0: // will depend on whether it's cached! michael@0: if(window && michael@0: (NS_SUCCEEDED(aStatus) || aStatus == NS_ERROR_PARSED_DATA_CACHED)) { michael@0: nsEventStatus status = nsEventStatus_eIgnore; michael@0: WidgetEvent event(true, NS_LOAD); michael@0: event.mFlags.mBubbles = false; michael@0: // XXX Dispatching to |window|, but using |document| as the target. michael@0: event.target = mDocument; michael@0: michael@0: // If the document presentation is being restored, we don't want to fire michael@0: // onload to the document content since that would likely confuse scripts michael@0: // on the page. michael@0: michael@0: nsIDocShell *docShell = window->GetDocShell(); michael@0: NS_ENSURE_TRUE(docShell, NS_ERROR_UNEXPECTED); michael@0: michael@0: docShell->GetRestoringDocument(&restoring); michael@0: if (!restoring) { michael@0: NS_ASSERTION(mDocument->IsXUL() || // readyState for XUL is bogus michael@0: mDocument->GetReadyStateEnum() == michael@0: nsIDocument::READYSTATE_INTERACTIVE || michael@0: // test_stricttransportsecurity.html has old-style michael@0: // docshell-generated about:blank docs reach this code! michael@0: (mDocument->GetReadyStateEnum() == michael@0: nsIDocument::READYSTATE_UNINITIALIZED && michael@0: NS_IsAboutBlank(mDocument->GetDocumentURI())), michael@0: "Bad readystate"); michael@0: nsCOMPtr d = mDocument; michael@0: mDocument->SetReadyStateInternal(nsIDocument::READYSTATE_COMPLETE); michael@0: michael@0: nsRefPtr timing(d->GetNavigationTiming()); michael@0: if (timing) { michael@0: timing->NotifyLoadEventStart(); michael@0: } michael@0: michael@0: // Dispatch observer notification to notify observers document load is complete. michael@0: nsCOMPtr os = mozilla::services::GetObserverService(); michael@0: nsIPrincipal *principal = d->NodePrincipal(); michael@0: os->NotifyObservers(d, michael@0: nsContentUtils::IsSystemPrincipal(principal) ? michael@0: "chrome-document-loaded" : michael@0: "content-document-loaded", michael@0: nullptr); michael@0: michael@0: EventDispatcher::Dispatch(window, mPresContext, &event, nullptr, &status); michael@0: if (timing) { michael@0: timing->NotifyLoadEventEnd(); michael@0: } michael@0: } michael@0: } else { michael@0: // XXX: Should fire error event to the document... michael@0: } michael@0: michael@0: // Notify the document that it has been shown (regardless of whether michael@0: // it was just loaded). Note: mDocument may be null now if the above michael@0: // firing of onload caused the document to unload. michael@0: if (mDocument) { michael@0: // Re-get window, since it might have changed during above firing of onload michael@0: window = mDocument->GetWindow(); michael@0: if (window) { michael@0: nsIDocShell *docShell = window->GetDocShell(); michael@0: bool isInUnload; michael@0: if (docShell && NS_SUCCEEDED(docShell->GetIsInUnload(&isInUnload)) && michael@0: !isInUnload) { michael@0: mDocument->OnPageShow(restoring, nullptr); michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (!mStopped) { michael@0: if (mDocument) { michael@0: mDocument->ScrollToRef(); michael@0: } michael@0: michael@0: // Now that the document has loaded, we can tell the presshell michael@0: // to unsuppress painting. michael@0: if (mPresShell) { michael@0: nsCOMPtr shellDeathGrip(mPresShell); michael@0: mPresShell->UnsuppressPainting(); michael@0: // mPresShell could have been removed now, see bug 378682/421432 michael@0: if (mPresShell) { michael@0: mPresShell->LoadComplete(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: nsJSContext::LoadEnd(); michael@0: michael@0: #ifdef NS_PRINTING michael@0: // Check to see if someone tried to print during the load michael@0: if (mPrintIsPending) { michael@0: mPrintIsPending = false; michael@0: mPrintDocIsFullyLoaded = true; michael@0: Print(mCachedPrintSettings, mCachedPrintWebProgressListner); michael@0: mCachedPrintSettings = nullptr; michael@0: mCachedPrintWebProgressListner = nullptr; michael@0: } michael@0: #endif michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::PermitUnload(bool aCallerClosesWindow, michael@0: bool *aPermitUnload) michael@0: { michael@0: bool shouldPrompt = true; michael@0: return PermitUnloadInternal(aCallerClosesWindow, &shouldPrompt, michael@0: aPermitUnload); michael@0: } michael@0: michael@0: michael@0: nsresult michael@0: nsDocumentViewer::PermitUnloadInternal(bool aCallerClosesWindow, michael@0: bool *aShouldPrompt, michael@0: bool *aPermitUnload) michael@0: { michael@0: AutoDontWarnAboutSyncXHR disableSyncXHRWarning; michael@0: michael@0: *aPermitUnload = true; michael@0: michael@0: if (!mDocument michael@0: || mInPermitUnload michael@0: || mCallerIsClosingWindow michael@0: || mInPermitUnloadPrompt) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: static bool sIsBeforeUnloadDisabled; michael@0: static bool sBeforeUnloadPrefCached = false; michael@0: michael@0: if (!sBeforeUnloadPrefCached ) { michael@0: sBeforeUnloadPrefCached = true; michael@0: Preferences::AddBoolVarCache(&sIsBeforeUnloadDisabled, michael@0: BEFOREUNLOAD_DISABLED_PREFNAME); michael@0: } michael@0: michael@0: // If the user has turned off onbeforeunload warnings, no need to check. michael@0: if (sIsBeforeUnloadDisabled) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: // First, get the script global object from the document... michael@0: nsPIDOMWindow *window = mDocument->GetWindow(); michael@0: michael@0: if (!window) { michael@0: // This is odd, but not fatal michael@0: NS_WARNING("window not set for document!"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_ASSERTION(nsContentUtils::IsSafeToRunScript(), "This is unsafe"); michael@0: michael@0: // Now, fire an BeforeUnload event to the document and see if it's ok michael@0: // to unload... michael@0: nsCOMPtr domDoc = do_QueryInterface(mDocument); michael@0: nsCOMPtr event; michael@0: domDoc->CreateEvent(NS_LITERAL_STRING("beforeunloadevent"), michael@0: getter_AddRefs(event)); michael@0: nsCOMPtr beforeUnload = do_QueryInterface(event); michael@0: NS_ENSURE_STATE(beforeUnload); michael@0: nsresult rv = event->InitEvent(NS_LITERAL_STRING("beforeunload"), michael@0: false, true); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // Dispatching to |window|, but using |document| as the target. michael@0: event->SetTarget(mDocument); michael@0: event->SetTrusted(true); michael@0: michael@0: // In evil cases we might be destroyed while handling the michael@0: // onbeforeunload event, don't let that happen. (see also bug#331040) michael@0: nsRefPtr kungFuDeathGrip(this); michael@0: michael@0: { michael@0: // Never permit popups from the beforeunload handler, no matter michael@0: // how we get here. michael@0: nsAutoPopupStatePusher popupStatePusher(openAbused, true); michael@0: michael@0: // Never permit dialogs from the beforeunload handler michael@0: nsCOMPtr utils = do_GetInterface(window); michael@0: bool dialogsWereEnabled = false; michael@0: utils->AreDialogsEnabled(&dialogsWereEnabled); michael@0: utils->DisableDialogs(); michael@0: michael@0: mInPermitUnload = true; michael@0: EventDispatcher::DispatchDOMEvent(window, nullptr, event, mPresContext, michael@0: nullptr); michael@0: mInPermitUnload = false; michael@0: if (dialogsWereEnabled) { michael@0: utils->EnableDialogs(); michael@0: } michael@0: } michael@0: michael@0: nsCOMPtr docShell(mContainer); michael@0: nsAutoString text; michael@0: beforeUnload->GetReturnValue(text); michael@0: if (*aShouldPrompt && (event->GetInternalNSEvent()->mFlags.mDefaultPrevented || michael@0: !text.IsEmpty())) { michael@0: // Ask the user if it's ok to unload the current page michael@0: michael@0: nsCOMPtr prompt = do_GetInterface(docShell); michael@0: michael@0: if (prompt) { michael@0: nsCOMPtr promptBag = do_QueryInterface(prompt); michael@0: if (promptBag) { michael@0: bool isTabModalPromptAllowed; michael@0: GetIsTabModalPromptAllowed(&isTabModalPromptAllowed); michael@0: promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), michael@0: isTabModalPromptAllowed); michael@0: } michael@0: michael@0: nsXPIDLString title, message, stayLabel, leaveLabel; michael@0: rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES, michael@0: "OnBeforeUnloadTitle", michael@0: title); michael@0: nsresult tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES, michael@0: "OnBeforeUnloadMessage", michael@0: message); michael@0: if (NS_FAILED(tmp)) { michael@0: rv = tmp; michael@0: } michael@0: tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES, michael@0: "OnBeforeUnloadLeaveButton", michael@0: leaveLabel); michael@0: if (NS_FAILED(tmp)) { michael@0: rv = tmp; michael@0: } michael@0: tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES, michael@0: "OnBeforeUnloadStayButton", michael@0: stayLabel); michael@0: if (NS_FAILED(tmp)) { michael@0: rv = tmp; michael@0: } michael@0: michael@0: if (NS_FAILED(rv) || !title || !message || !stayLabel || !leaveLabel) { michael@0: NS_ERROR("Failed to get strings from dom.properties!"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Although the exact value is ignored, we must not pass invalid michael@0: // bool values through XPConnect. michael@0: bool dummy = false; michael@0: int32_t buttonPressed = 0; michael@0: uint32_t buttonFlags = (nsIPrompt::BUTTON_POS_0_DEFAULT | michael@0: (nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_0) | michael@0: (nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_1)); michael@0: michael@0: nsAutoSyncOperation sync(mDocument); michael@0: mInPermitUnloadPrompt = true; michael@0: rv = prompt->ConfirmEx(title, message, buttonFlags, michael@0: leaveLabel, stayLabel, nullptr, nullptr, michael@0: &dummy, &buttonPressed); michael@0: mInPermitUnloadPrompt = false; michael@0: michael@0: // If the prompt aborted, we tell our consumer that it is not allowed michael@0: // to unload the page. One reason that prompts abort is that the user michael@0: // performed some action that caused the page to unload while our prompt michael@0: // was active. In those cases we don't want our consumer to also unload michael@0: // the page. michael@0: // michael@0: // XXX: Are there other cases where prompts can abort? Is it ok to michael@0: // prevent unloading the page in those cases? michael@0: if (NS_FAILED(rv)) { michael@0: *aPermitUnload = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Button 0 == leave, button 1 == stay michael@0: *aPermitUnload = (buttonPressed == 0); michael@0: // If the user decided to go ahead, make sure not to prompt the user again michael@0: // by toggling the internal prompting bool to false: michael@0: if (*aPermitUnload) { michael@0: *aShouldPrompt = false; michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (docShell) { michael@0: int32_t childCount; michael@0: docShell->GetChildCount(&childCount); michael@0: michael@0: for (int32_t i = 0; i < childCount && *aPermitUnload; ++i) { michael@0: nsCOMPtr item; michael@0: docShell->GetChildAt(i, getter_AddRefs(item)); michael@0: michael@0: nsCOMPtr docShell(do_QueryInterface(item)); michael@0: michael@0: if (docShell) { michael@0: nsCOMPtr cv; michael@0: docShell->GetContentViewer(getter_AddRefs(cv)); michael@0: michael@0: if (cv) { michael@0: cv->PermitUnloadInternal(aCallerClosesWindow, aShouldPrompt, michael@0: aPermitUnload); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (aCallerClosesWindow && *aPermitUnload) michael@0: mCallerIsClosingWindow = true; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::GetBeforeUnloadFiring(bool* aInEvent) michael@0: { michael@0: *aInEvent = mInPermitUnload; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::GetInPermitUnload(bool* aInEvent) michael@0: { michael@0: *aInEvent = mInPermitUnloadPrompt; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::ResetCloseWindow() michael@0: { michael@0: mCallerIsClosingWindow = false; michael@0: michael@0: nsCOMPtr docShell(mContainer); michael@0: if (docShell) { michael@0: int32_t childCount; michael@0: docShell->GetChildCount(&childCount); michael@0: michael@0: for (int32_t i = 0; i < childCount; ++i) { michael@0: nsCOMPtr item; michael@0: docShell->GetChildAt(i, getter_AddRefs(item)); michael@0: michael@0: nsCOMPtr docShell(do_QueryInterface(item)); michael@0: michael@0: if (docShell) { michael@0: nsCOMPtr cv; michael@0: docShell->GetContentViewer(getter_AddRefs(cv)); michael@0: michael@0: if (cv) { michael@0: cv->ResetCloseWindow(); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::PageHide(bool aIsUnload) michael@0: { michael@0: AutoDontWarnAboutSyncXHR disableSyncXHRWarning; michael@0: michael@0: mHidden = true; michael@0: michael@0: if (!mDocument) { michael@0: return NS_ERROR_NULL_POINTER; michael@0: } michael@0: michael@0: mDocument->OnPageHide(!aIsUnload, nullptr); michael@0: michael@0: // inform the window so that the focus state is reset. michael@0: NS_ENSURE_STATE(mDocument); michael@0: nsPIDOMWindow *window = mDocument->GetWindow(); michael@0: if (window) michael@0: window->PageHidden(); michael@0: michael@0: if (aIsUnload) { michael@0: // Poke the GC. The window might be collectable garbage now. michael@0: nsJSContext::PokeGC(JS::gcreason::PAGE_HIDE, NS_GC_DELAY * 2); michael@0: michael@0: // if Destroy() was called during OnPageHide(), mDocument is nullptr. michael@0: NS_ENSURE_STATE(mDocument); michael@0: michael@0: // First, get the window from the document... michael@0: nsPIDOMWindow *window = mDocument->GetWindow(); michael@0: michael@0: if (!window) { michael@0: // Fail if no window is available... michael@0: NS_WARNING("window not set for document!"); michael@0: return NS_ERROR_NULL_POINTER; michael@0: } michael@0: michael@0: // Now, fire an Unload event to the document... michael@0: nsEventStatus status = nsEventStatus_eIgnore; michael@0: WidgetEvent event(true, NS_PAGE_UNLOAD); michael@0: event.mFlags.mBubbles = false; michael@0: // XXX Dispatching to |window|, but using |document| as the target. michael@0: event.target = mDocument; michael@0: michael@0: // Never permit popups from the unload handler, no matter how we get michael@0: // here. michael@0: nsAutoPopupStatePusher popupStatePusher(openAbused, true); michael@0: michael@0: EventDispatcher::Dispatch(window, mPresContext, &event, nullptr, &status); michael@0: } michael@0: michael@0: #ifdef MOZ_XUL michael@0: // look for open menupopups and close them after the unload event, in case michael@0: // the unload event listeners open any new popups michael@0: nsContentUtils::HidePopupsInDocument(mDocument); michael@0: #endif michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: static void michael@0: AttachContainerRecurse(nsIDocShell* aShell) michael@0: { michael@0: nsCOMPtr viewer; michael@0: aShell->GetContentViewer(getter_AddRefs(viewer)); michael@0: if (viewer) { michael@0: nsIDocument* doc = viewer->GetDocument(); michael@0: if (doc) { michael@0: doc->SetContainer(static_cast(aShell)); michael@0: } michael@0: nsRefPtr pc; michael@0: viewer->GetPresContext(getter_AddRefs(pc)); michael@0: if (pc) { michael@0: pc->SetContainer(static_cast(aShell)); michael@0: pc->SetLinkHandler(nsCOMPtr(do_QueryInterface(aShell))); michael@0: } michael@0: nsCOMPtr presShell; michael@0: viewer->GetPresShell(getter_AddRefs(presShell)); michael@0: if (presShell) { michael@0: presShell->SetForwardingContainer(WeakPtr()); michael@0: } michael@0: } michael@0: michael@0: // Now recurse through the children michael@0: int32_t childCount; michael@0: aShell->GetChildCount(&childCount); michael@0: for (int32_t i = 0; i < childCount; ++i) { michael@0: nsCOMPtr childItem; michael@0: aShell->GetChildAt(i, getter_AddRefs(childItem)); michael@0: AttachContainerRecurse(nsCOMPtr(do_QueryInterface(childItem))); michael@0: } michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::Open(nsISupports *aState, nsISHEntry *aSHEntry) michael@0: { michael@0: NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED); michael@0: michael@0: if (mDocument) michael@0: mDocument->SetContainer(mContainer); michael@0: michael@0: nsresult rv = InitInternal(mParentWidget, aState, mBounds, false); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: mHidden = false; michael@0: michael@0: if (mPresShell) michael@0: mPresShell->SetForwardingContainer(WeakPtr()); michael@0: michael@0: // Rehook the child presentations. The child shells are still in michael@0: // session history, so get them from there. michael@0: michael@0: if (aSHEntry) { michael@0: nsCOMPtr item; michael@0: int32_t itemIndex = 0; michael@0: while (NS_SUCCEEDED(aSHEntry->ChildShellAt(itemIndex++, michael@0: getter_AddRefs(item))) && item) { michael@0: AttachContainerRecurse(nsCOMPtr(do_QueryInterface(item))); michael@0: } michael@0: } michael@0: michael@0: SyncParentSubDocMap(); michael@0: michael@0: if (mFocusListener && mDocument) { michael@0: mDocument->AddEventListener(NS_LITERAL_STRING("focus"), mFocusListener, michael@0: false, false); michael@0: mDocument->AddEventListener(NS_LITERAL_STRING("blur"), mFocusListener, michael@0: false, false); michael@0: } michael@0: michael@0: // XXX re-enable image animations once that works correctly michael@0: michael@0: PrepareToStartLoad(); michael@0: michael@0: // When loading a page from the bfcache with puppet widgets, we do the michael@0: // widget attachment here (it is otherwise done in MakeWindow, which is michael@0: // called for non-bfcache pages in the history, but not bfcache pages). michael@0: // Attachment is necessary, since we get detached when another page michael@0: // is browsed to. That is, if we are one page A, then when we go to michael@0: // page B, we detach. So page A's view has no widget. If we then go michael@0: // back to it, and it is in the bfcache, we will use that view, which michael@0: // doesn't have a widget. The attach call here will properly attach us. michael@0: if (nsIWidget::UsePuppetWidgets() && mPresContext && michael@0: ShouldAttachToTopLevel()) { michael@0: // If the old view is already attached to our parent, detach michael@0: DetachFromTopLevelWidget(); michael@0: michael@0: nsViewManager *vm = GetViewManager(); michael@0: NS_ABORT_IF_FALSE(vm, "no view manager"); michael@0: nsView* v = vm->GetRootView(); michael@0: NS_ABORT_IF_FALSE(v, "no root view"); michael@0: NS_ABORT_IF_FALSE(mParentWidget, "no mParentWidget to set"); michael@0: v->AttachToTopLevelWidget(mParentWidget); michael@0: michael@0: mAttachedToParent = true; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::Close(nsISHEntry *aSHEntry) michael@0: { michael@0: // All callers are supposed to call close to break circular michael@0: // references. If we do this stuff in the destructor, the michael@0: // destructor might never be called (especially if we're being michael@0: // used from JS. michael@0: michael@0: mSHEntry = aSHEntry; michael@0: michael@0: // Close is also needed to disable scripts during paint suppression, michael@0: // since we transfer the existing global object to the new document michael@0: // that is loaded. In the future, the global object may become a proxy michael@0: // for an object that can be switched in and out so that we don't need michael@0: // to disable scripts during paint suppression. michael@0: michael@0: if (!mDocument) michael@0: return NS_OK; michael@0: michael@0: #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW) michael@0: // Turn scripting back on michael@0: // after PrintPreview had turned it off michael@0: if (GetIsPrintPreview() && mPrintEngine) { michael@0: mPrintEngine->TurnScriptingOn(true); michael@0: } michael@0: #endif michael@0: michael@0: #ifdef NS_PRINTING michael@0: // A Close was called while we were printing michael@0: // so don't clear the ScriptGlobalObject michael@0: // or clear the mDocument below michael@0: if (mPrintEngine && !mClosingWhilePrinting) { michael@0: mClosingWhilePrinting = true; michael@0: } else michael@0: #endif michael@0: { michael@0: // out of band cleanup of docshell michael@0: mDocument->SetScriptGlobalObject(nullptr); michael@0: michael@0: if (!mSHEntry && mDocument) michael@0: mDocument->RemovedFromDocShell(); michael@0: } michael@0: michael@0: if (mFocusListener && mDocument) { michael@0: mDocument->RemoveEventListener(NS_LITERAL_STRING("focus"), mFocusListener, michael@0: false); michael@0: mDocument->RemoveEventListener(NS_LITERAL_STRING("blur"), mFocusListener, michael@0: false); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: static void michael@0: DetachContainerRecurse(nsIDocShell *aShell) michael@0: { michael@0: // Unhook this docshell's presentation michael@0: nsCOMPtr viewer; michael@0: aShell->GetContentViewer(getter_AddRefs(viewer)); michael@0: if (viewer) { michael@0: nsIDocument* doc = viewer->GetDocument(); michael@0: if (doc) { michael@0: doc->SetContainer(nullptr); michael@0: } michael@0: nsRefPtr pc; michael@0: viewer->GetPresContext(getter_AddRefs(pc)); michael@0: if (pc) { michael@0: pc->Detach(); michael@0: } michael@0: nsCOMPtr presShell; michael@0: viewer->GetPresShell(getter_AddRefs(presShell)); michael@0: if (presShell) { michael@0: auto weakShell = static_cast(aShell)->asWeakPtr(); michael@0: presShell->SetForwardingContainer(weakShell); michael@0: } michael@0: } michael@0: michael@0: // Now recurse through the children michael@0: int32_t childCount; michael@0: aShell->GetChildCount(&childCount); michael@0: for (int32_t i = 0; i < childCount; ++i) { michael@0: nsCOMPtr childItem; michael@0: aShell->GetChildAt(i, getter_AddRefs(childItem)); michael@0: DetachContainerRecurse(nsCOMPtr(do_QueryInterface(childItem))); michael@0: } michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::Destroy() michael@0: { michael@0: NS_ASSERTION(mDocument, "No document in Destroy()!"); michael@0: michael@0: #ifdef NS_PRINTING michael@0: // Here is where we check to see if the document was still being prepared michael@0: // for printing when it was asked to be destroy from someone externally michael@0: // This usually happens if the document is unloaded while the user is in the michael@0: // Print Dialog michael@0: // michael@0: // So we flip the bool to remember that the document is going away michael@0: // and we can clean up and abort later after returning from the Print Dialog michael@0: if (mPrintEngine) { michael@0: if (mPrintEngine->CheckBeforeDestroy()) { michael@0: return NS_OK; michael@0: } michael@0: } michael@0: mBeforeAndAfterPrint = nullptr; michael@0: #endif michael@0: michael@0: // Don't let the document get unloaded while we are printing. michael@0: // this could happen if we hit the back button during printing. michael@0: // We also keep the viewer from being cached in session history, since michael@0: // we require all documents there to be sanitized. michael@0: if (mDestroyRefCount != 0) { michael@0: --mDestroyRefCount; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // If we were told to put ourselves into session history instead of destroy michael@0: // the presentation, do that now. michael@0: if (mSHEntry) { michael@0: if (mPresShell) michael@0: mPresShell->Freeze(); michael@0: michael@0: // Make sure the presentation isn't torn down by Hide(). michael@0: mSHEntry->SetSticky(mIsSticky); michael@0: mIsSticky = true; michael@0: michael@0: bool savePresentation = mDocument ? mDocument->IsBFCachingAllowed() : true; michael@0: michael@0: // Remove our root view from the view hierarchy. michael@0: if (mPresShell) { michael@0: nsViewManager *vm = mPresShell->GetViewManager(); michael@0: if (vm) { michael@0: nsView *rootView = vm->GetRootView(); michael@0: michael@0: if (rootView) { michael@0: nsView *rootViewParent = rootView->GetParent(); michael@0: if (rootViewParent) { michael@0: nsViewManager *parentVM = rootViewParent->GetViewManager(); michael@0: if (parentVM) { michael@0: parentVM->RemoveChild(rootView); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: Hide(); michael@0: michael@0: // This is after Hide() so that the user doesn't see the inputs clear. michael@0: if (mDocument) { michael@0: mDocument->Sanitize(); michael@0: } michael@0: michael@0: // Reverse ownership. Do this *after* calling sanitize so that sanitize michael@0: // doesn't cause mutations that make the SHEntry drop the presentation michael@0: michael@0: // Grab a reference to mSHEntry before calling into things like michael@0: // SyncPresentationState that might mess with our members. michael@0: nsCOMPtr shEntry = mSHEntry; // we'll need this below michael@0: mSHEntry = nullptr; michael@0: michael@0: if (savePresentation) { michael@0: shEntry->SetContentViewer(this); michael@0: } michael@0: michael@0: // Always sync the presentation state. That way even if someone screws up michael@0: // and shEntry has no window state at this point we'll be ok; we just won't michael@0: // cache ourselves. michael@0: shEntry->SyncPresentationState(); michael@0: michael@0: // Shut down accessibility for the document before we start to tear it down. michael@0: #ifdef ACCESSIBILITY michael@0: if (mPresShell) { michael@0: a11y::DocAccessible* docAcc = mPresShell->GetDocAccessible(); michael@0: if (docAcc) { michael@0: docAcc->Shutdown(); michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: // Break the link from the document/presentation to the docshell, so that michael@0: // link traversals cannot affect the currently-loaded document. michael@0: // When the presentation is restored, Open() and InitInternal() will reset michael@0: // these pointers to their original values. michael@0: michael@0: if (mDocument) { michael@0: mDocument->SetContainer(nullptr); michael@0: } michael@0: if (mPresContext) { michael@0: mPresContext->Detach(); michael@0: } michael@0: if (mPresShell) { michael@0: mPresShell->SetForwardingContainer(mContainer); michael@0: } michael@0: michael@0: // Do the same for our children. Note that we need to get the child michael@0: // docshells from the SHEntry now; the docshell will have cleared them. michael@0: nsCOMPtr item; michael@0: int32_t itemIndex = 0; michael@0: while (NS_SUCCEEDED(shEntry->ChildShellAt(itemIndex++, michael@0: getter_AddRefs(item))) && item) { michael@0: DetachContainerRecurse(nsCOMPtr(do_QueryInterface(item))); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // The document was not put in the bfcache michael@0: michael@0: if (mPresShell) { michael@0: DestroyPresShell(); michael@0: } michael@0: if (mDocument) { michael@0: mDocument->Destroy(); michael@0: mDocument = nullptr; michael@0: } michael@0: michael@0: // All callers are supposed to call destroy to break circular michael@0: // references. If we do this stuff in the destructor, the michael@0: // destructor might never be called (especially if we're being michael@0: // used from JS. michael@0: michael@0: #ifdef NS_PRINTING michael@0: if (mPrintEngine) { michael@0: #ifdef NS_PRINT_PREVIEW michael@0: bool doingPrintPreview; michael@0: mPrintEngine->GetDoingPrintPreview(&doingPrintPreview); michael@0: if (doingPrintPreview) { michael@0: mPrintEngine->FinishPrintPreview(); michael@0: } michael@0: #endif michael@0: michael@0: mPrintEngine->Destroy(); michael@0: mPrintEngine = nullptr; michael@0: } michael@0: #endif michael@0: michael@0: // Avoid leaking the old viewer. michael@0: if (mPreviousViewer) { michael@0: mPreviousViewer->Destroy(); michael@0: mPreviousViewer = nullptr; michael@0: } michael@0: michael@0: mDeviceContext = nullptr; michael@0: michael@0: if (mPresContext) { michael@0: DestroyPresContext(); michael@0: } michael@0: michael@0: mWindow = nullptr; michael@0: mViewManager = nullptr; michael@0: mContainer = WeakPtr(); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::Stop(void) michael@0: { michael@0: NS_ASSERTION(mDocument, "Stop called too early or too late"); michael@0: if (mDocument) { michael@0: mDocument->StopDocumentLoad(); michael@0: } michael@0: michael@0: if (!mHidden && (mLoaded || mStopped) && mPresContext && !mSHEntry) michael@0: mPresContext->SetImageAnimationMode(imgIContainer::kDontAnimMode); michael@0: michael@0: mStopped = true; michael@0: michael@0: if (!mLoaded && mPresShell) { michael@0: // Well, we might as well paint what we have so far. michael@0: nsCOMPtr shellDeathGrip(mPresShell); // bug 378682 michael@0: mPresShell->UnsuppressPainting(); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::GetDOMDocument(nsIDOMDocument **aResult) michael@0: { michael@0: NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE); michael@0: return CallQueryInterface(mDocument, aResult); michael@0: } michael@0: michael@0: NS_IMETHODIMP_(nsIDocument *) michael@0: nsDocumentViewer::GetDocument() michael@0: { michael@0: return mDocument; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::SetDOMDocument(nsIDOMDocument *aDocument) michael@0: { michael@0: // Assumptions: michael@0: // michael@0: // 1) this document viewer has been initialized with a call to Init(). michael@0: // 2) the stylesheets associated with the document have been added michael@0: // to the document. michael@0: michael@0: // XXX Right now, this method assumes that the layout of the current michael@0: // document hasn't started yet. More cleanup will probably be michael@0: // necessary to make this method work for the case when layout *has* michael@0: // occurred for the current document. michael@0: // That work can happen when and if it is needed. michael@0: michael@0: if (!aDocument) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: nsCOMPtr newDoc = do_QueryInterface(aDocument); michael@0: NS_ENSURE_TRUE(newDoc, NS_ERROR_UNEXPECTED); michael@0: michael@0: return SetDocumentInternal(newDoc, false); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::SetDocumentInternal(nsIDocument* aDocument, michael@0: bool aForceReuseInnerWindow) michael@0: { michael@0: MOZ_ASSERT(aDocument); michael@0: michael@0: // Set new container michael@0: aDocument->SetContainer(mContainer); michael@0: michael@0: if (mDocument != aDocument) { michael@0: if (mDocument->IsStaticDocument()) { michael@0: mDocument->SetScriptGlobalObject(nullptr); michael@0: mDocument->Destroy(); michael@0: } michael@0: // Replace the old document with the new one. Do this only when michael@0: // the new document really is a new document. michael@0: mDocument = aDocument; michael@0: michael@0: // Set the script global object on the new document michael@0: nsCOMPtr window = michael@0: do_GetInterface(static_cast(mContainer.get())); michael@0: if (window) { michael@0: window->SetNewDocument(aDocument, nullptr, aForceReuseInnerWindow); michael@0: } michael@0: michael@0: // Clear the list of old child docshells. Child docshells for the new michael@0: // document will be constructed as frames are created. michael@0: if (!aDocument->IsStaticDocument()) { michael@0: nsCOMPtr node(mContainer); michael@0: if (node) { michael@0: int32_t count; michael@0: node->GetChildCount(&count); michael@0: for (int32_t i = 0; i < count; ++i) { michael@0: nsCOMPtr child; michael@0: node->GetChildAt(0, getter_AddRefs(child)); michael@0: node->RemoveChild(child); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: nsresult rv = SyncParentSubDocMap(); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // Replace the current pres shell with a new shell for the new document michael@0: michael@0: if (mPresShell) { michael@0: DestroyPresShell(); michael@0: } michael@0: michael@0: if (mPresContext) { michael@0: DestroyPresContext(); michael@0: michael@0: mWindow = nullptr; michael@0: InitInternal(mParentWidget, nullptr, mBounds, true, true, false); michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: nsIPresShell* michael@0: nsDocumentViewer::GetPresShell() michael@0: { michael@0: return mPresShell; michael@0: } michael@0: michael@0: nsPresContext* michael@0: nsDocumentViewer::GetPresContext() michael@0: { michael@0: return mPresContext; michael@0: } michael@0: michael@0: nsViewManager* michael@0: nsDocumentViewer::GetViewManager() michael@0: { michael@0: return mViewManager; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::GetPresShell(nsIPresShell** aResult) michael@0: { michael@0: nsIPresShell* shell = GetPresShell(); michael@0: NS_IF_ADDREF(*aResult = shell); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::GetPresContext(nsPresContext** aResult) michael@0: { michael@0: nsPresContext* pc = GetPresContext(); michael@0: NS_IF_ADDREF(*aResult = pc); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::GetBounds(nsIntRect& aResult) michael@0: { michael@0: NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE); michael@0: aResult = mBounds; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::GetPreviousViewer(nsIContentViewer** aViewer) michael@0: { michael@0: *aViewer = mPreviousViewer; michael@0: NS_IF_ADDREF(*aViewer); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::SetPreviousViewer(nsIContentViewer* aViewer) michael@0: { michael@0: // NOTE: |Show| sets |mPreviousViewer| to null without calling this michael@0: // function. michael@0: michael@0: if (aViewer) { michael@0: NS_ASSERTION(!mPreviousViewer, michael@0: "can't set previous viewer when there already is one"); michael@0: michael@0: // In a multiple chaining situation (which occurs when running a thrashing michael@0: // test like i-bench or jrgm's tests with no delay), we can build up a michael@0: // whole chain of viewers. In order to avoid this, we always set our previous michael@0: // viewer to the MOST previous viewer in the chain, and then dump the intermediate michael@0: // link from the chain. This ensures that at most only 2 documents are alive michael@0: // and undestroyed at any given time (the one that is showing and the one that michael@0: // is loading with painting suppressed). michael@0: // It's very important that if this ever gets changed the code michael@0: // before the RestorePresentation call in nsDocShell::InternalLoad michael@0: // be changed accordingly. michael@0: nsCOMPtr prevViewer; michael@0: aViewer->GetPreviousViewer(getter_AddRefs(prevViewer)); michael@0: if (prevViewer) { michael@0: aViewer->SetPreviousViewer(nullptr); michael@0: aViewer->Destroy(); michael@0: return SetPreviousViewer(prevViewer); michael@0: } michael@0: } michael@0: michael@0: mPreviousViewer = aViewer; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::SetBounds(const nsIntRect& aBounds) michael@0: { michael@0: NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE); michael@0: michael@0: mBounds = aBounds; michael@0: if (mWindow) { michael@0: if (!mAttachedToParent) { michael@0: // Don't have the widget repaint. Layout will generate repaint requests michael@0: // during reflow. michael@0: mWindow->Resize(aBounds.x, aBounds.y, michael@0: aBounds.width, aBounds.height, michael@0: false); michael@0: } michael@0: } else if (mPresContext && mViewManager) { michael@0: int32_t p2a = mPresContext->AppUnitsPerDevPixel(); michael@0: mViewManager->SetWindowDimensions(NSIntPixelsToAppUnits(mBounds.width, p2a), michael@0: NSIntPixelsToAppUnits(mBounds.height, p2a)); michael@0: } michael@0: michael@0: // If there's a previous viewer, it's the one that's actually showing, michael@0: // so be sure to resize it as well so it paints over the right area. michael@0: // This may slow down the performance of the new page load, but resize michael@0: // during load is also probably a relatively unusual condition michael@0: // relating to things being hidden while something is loaded. It so michael@0: // happens that Firefox does this a good bit with its infobar, and it michael@0: // looks ugly if we don't do this. michael@0: if (mPreviousViewer) { michael@0: nsCOMPtr previousViewer = mPreviousViewer; michael@0: previousViewer->SetBounds(aBounds); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::Move(int32_t aX, int32_t aY) michael@0: { michael@0: NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE); michael@0: mBounds.MoveTo(aX, aY); michael@0: if (mWindow) { michael@0: mWindow->Move(aX, aY); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::Show(void) michael@0: { michael@0: NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE); michael@0: michael@0: // We don't need the previous viewer anymore since we're not michael@0: // displaying it. michael@0: if (mPreviousViewer) { michael@0: // This little dance *may* only be to keep michael@0: // PresShell::EndObservingDocument happy, but I'm not sure. michael@0: nsCOMPtr prevViewer(mPreviousViewer); michael@0: mPreviousViewer = nullptr; michael@0: prevViewer->Destroy(); michael@0: michael@0: // Make sure we don't have too many cached ContentViewers michael@0: nsCOMPtr treeItem(mContainer); michael@0: if (treeItem) { michael@0: // We need to find the root DocShell since only that object has an michael@0: // SHistory and we need the SHistory to evict content viewers michael@0: nsCOMPtr root; michael@0: treeItem->GetSameTypeRootTreeItem(getter_AddRefs(root)); michael@0: nsCOMPtr webNav = do_QueryInterface(root); michael@0: nsCOMPtr history; michael@0: webNav->GetSessionHistory(getter_AddRefs(history)); michael@0: nsCOMPtr historyInt = do_QueryInterface(history); michael@0: if (historyInt) { michael@0: int32_t prevIndex,loadedIndex; michael@0: nsCOMPtr docShell = do_QueryInterface(treeItem); michael@0: docShell->GetPreviousTransIndex(&prevIndex); michael@0: docShell->GetLoadedTransIndex(&loadedIndex); michael@0: #ifdef DEBUG_PAGE_CACHE michael@0: printf("About to evict content viewers: prev=%d, loaded=%d\n", michael@0: prevIndex, loadedIndex); michael@0: #endif michael@0: historyInt->EvictOutOfRangeContentViewers(loadedIndex); michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (mWindow) { michael@0: // When attached to a top level xul window, we do not need to call michael@0: // Show on the widget. Underlying window management code handles michael@0: // this when the window is initialized. michael@0: if (!mAttachedToParent) { michael@0: mWindow->Show(true); michael@0: } michael@0: } michael@0: michael@0: if (mDocument && !mPresShell) { michael@0: NS_ASSERTION(!mWindow, "Window already created but no presshell?"); michael@0: michael@0: nsCOMPtr base_win(mContainer); michael@0: if (base_win) { michael@0: base_win->GetParentWidget(&mParentWidget); michael@0: if (mParentWidget) { michael@0: mParentWidget->Release(); // GetParentWidget AddRefs, but mParentWidget is weak michael@0: } michael@0: } michael@0: michael@0: nsView* containerView = FindContainerView(); michael@0: michael@0: nsresult rv = CreateDeviceContext(containerView); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // Create presentation context michael@0: NS_ASSERTION(!mPresContext, "Shouldn't have a prescontext if we have no shell!"); michael@0: mPresContext = CreatePresContext(mDocument, michael@0: nsPresContext::eContext_Galley, containerView); michael@0: NS_ENSURE_TRUE(mPresContext, NS_ERROR_OUT_OF_MEMORY); michael@0: michael@0: rv = mPresContext->Init(mDeviceContext); michael@0: if (NS_FAILED(rv)) { michael@0: mPresContext = nullptr; michael@0: return rv; michael@0: } michael@0: michael@0: rv = MakeWindow(nsSize(mPresContext->DevPixelsToAppUnits(mBounds.width), michael@0: mPresContext->DevPixelsToAppUnits(mBounds.height)), michael@0: containerView); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: if (mPresContext && base_win) { michael@0: nsCOMPtr linkHandler(do_GetInterface(base_win)); michael@0: michael@0: if (linkHandler) { michael@0: mPresContext->SetLinkHandler(linkHandler); michael@0: } michael@0: michael@0: mPresContext->SetContainer(mContainer); michael@0: } michael@0: michael@0: if (mPresContext) { michael@0: Hide(); michael@0: michael@0: rv = InitPresentationStuff(mDocument->MayStartLayout()); michael@0: } michael@0: michael@0: // If we get here the document load has already started and the michael@0: // window is shown because some JS on the page caused it to be michael@0: // shown... michael@0: michael@0: if (mPresShell) { michael@0: nsCOMPtr shellDeathGrip(mPresShell); // bug 378682 michael@0: mPresShell->UnsuppressPainting(); michael@0: } michael@0: } michael@0: michael@0: // Notify observers that a new page has been shown. This will get run michael@0: // from the event loop after we actually draw the page. michael@0: NS_DispatchToMainThread(new nsDocumentShownDispatcher(mDocument)); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::Hide(void) michael@0: { michael@0: if (!mAttachedToParent && mWindow) { michael@0: mWindow->Show(false); michael@0: } michael@0: michael@0: if (!mPresShell) michael@0: return NS_OK; michael@0: michael@0: NS_ASSERTION(mPresContext, "Can't have a presshell and no prescontext!"); michael@0: michael@0: // Avoid leaking the old viewer. michael@0: if (mPreviousViewer) { michael@0: mPreviousViewer->Destroy(); michael@0: mPreviousViewer = nullptr; michael@0: } michael@0: michael@0: if (mIsSticky) { michael@0: // This window is sticky, that means that it might be shown again michael@0: // and we don't want the presshell n' all that to be thrown away michael@0: // just because the window is hidden. michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsCOMPtr docShell(mContainer); michael@0: if (docShell) { michael@0: nsCOMPtr layoutState; michael@0: mPresShell->CaptureHistoryState(getter_AddRefs(layoutState)); michael@0: } michael@0: michael@0: DestroyPresShell(); michael@0: michael@0: DestroyPresContext(); michael@0: michael@0: mViewManager = nullptr; michael@0: mWindow = nullptr; michael@0: mDeviceContext = nullptr; michael@0: mParentWidget = nullptr; michael@0: michael@0: nsCOMPtr base_win(mContainer); michael@0: michael@0: if (base_win && !mAttachedToParent) { michael@0: base_win->SetParentWidget(nullptr); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::GetSticky(bool *aSticky) michael@0: { michael@0: *aSticky = mIsSticky; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::SetSticky(bool aSticky) michael@0: { michael@0: mIsSticky = aSticky; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::RequestWindowClose(bool* aCanClose) michael@0: { michael@0: #ifdef NS_PRINTING michael@0: if (mPrintIsPending || (mPrintEngine && mPrintEngine->GetIsPrinting())) { michael@0: *aCanClose = false; michael@0: mDeferredWindowClose = true; michael@0: } else michael@0: #endif michael@0: *aCanClose = true; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: static bool michael@0: AppendAgentSheet(nsIStyleSheet *aSheet, void *aData) michael@0: { michael@0: nsStyleSet *styleSet = static_cast(aData); michael@0: styleSet->AppendStyleSheet(nsStyleSet::eAgentSheet, aSheet); michael@0: return true; michael@0: } michael@0: michael@0: static bool michael@0: PrependUserSheet(nsIStyleSheet *aSheet, void *aData) michael@0: { michael@0: nsStyleSet *styleSet = static_cast(aData); michael@0: styleSet->PrependStyleSheet(nsStyleSet::eUserSheet, aSheet); michael@0: return true; michael@0: } michael@0: michael@0: nsresult michael@0: nsDocumentViewer::CreateStyleSet(nsIDocument* aDocument, michael@0: nsStyleSet** aStyleSet) michael@0: { michael@0: // Make sure this does the same thing as PresShell::AddSheet wrt ordering. michael@0: michael@0: // this should eventually get expanded to allow for creating michael@0: // different sets for different media michael@0: nsStyleSet *styleSet = new nsStyleSet(); michael@0: michael@0: styleSet->BeginUpdate(); michael@0: michael@0: // The document will fill in the document sheets when we create the presshell michael@0: michael@0: // Handle the user sheets. michael@0: nsCSSStyleSheet* sheet = nullptr; michael@0: if (nsContentUtils::IsInChromeDocshell(aDocument)) { michael@0: sheet = nsLayoutStylesheetCache::UserChromeSheet(); michael@0: } michael@0: else { michael@0: sheet = nsLayoutStylesheetCache::UserContentSheet(); michael@0: } michael@0: michael@0: if (sheet) michael@0: styleSet->AppendStyleSheet(nsStyleSet::eUserSheet, sheet); michael@0: michael@0: // Append chrome sheets (scrollbars + forms). michael@0: bool shouldOverride = false; michael@0: // We don't want a docshell here for external resource docs, so just michael@0: // look at mContainer. michael@0: nsCOMPtr ds(mContainer); michael@0: nsCOMPtr chromeHandler; michael@0: nsCOMPtr uri; michael@0: nsRefPtr csssheet; michael@0: michael@0: if (ds) { michael@0: ds->GetChromeEventHandler(getter_AddRefs(chromeHandler)); michael@0: } michael@0: if (chromeHandler) { michael@0: nsCOMPtr elt(do_QueryInterface(chromeHandler)); michael@0: nsCOMPtr content(do_QueryInterface(elt)); michael@0: if (elt && content) { michael@0: nsCOMPtr baseURI = content->GetBaseURI(); michael@0: michael@0: nsAutoString sheets; michael@0: elt->GetAttribute(NS_LITERAL_STRING("usechromesheets"), sheets); michael@0: if (!sheets.IsEmpty() && baseURI) { michael@0: nsRefPtr cssLoader = new mozilla::css::Loader(); michael@0: michael@0: char *str = ToNewCString(sheets); michael@0: char *newStr = str; michael@0: char *token; michael@0: while ( (token = nsCRT::strtok(newStr, ", ", &newStr)) ) { michael@0: NS_NewURI(getter_AddRefs(uri), nsDependentCString(token), nullptr, michael@0: baseURI); michael@0: if (!uri) continue; michael@0: michael@0: cssLoader->LoadSheetSync(uri, getter_AddRefs(csssheet)); michael@0: if (!csssheet) continue; michael@0: michael@0: styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, csssheet); michael@0: shouldOverride = true; michael@0: } michael@0: nsMemory::Free(str); michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (!shouldOverride) { michael@0: sheet = nsLayoutStylesheetCache::ScrollbarsSheet(); michael@0: if (sheet) { michael@0: styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet); michael@0: } michael@0: } michael@0: michael@0: sheet = nsLayoutStylesheetCache::NumberControlSheet(); michael@0: if (sheet) { michael@0: styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet); michael@0: } michael@0: michael@0: sheet = nsLayoutStylesheetCache::FormsSheet(); michael@0: if (sheet) { michael@0: styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet); michael@0: } michael@0: michael@0: sheet = nsLayoutStylesheetCache::FullScreenOverrideSheet(); michael@0: if (sheet) { michael@0: styleSet->PrependStyleSheet(nsStyleSet::eOverrideSheet, sheet); michael@0: } michael@0: michael@0: // Make sure to clone the quirk sheet so that it can be usefully michael@0: // enabled/disabled as needed. michael@0: nsRefPtr quirkClone; michael@0: nsCSSStyleSheet* quirkSheet; michael@0: if (!nsLayoutStylesheetCache::UASheet() || michael@0: !(quirkSheet = nsLayoutStylesheetCache::QuirkSheet()) || michael@0: !(quirkClone = quirkSheet->Clone(nullptr, nullptr, nullptr, nullptr)) || michael@0: !sheet) { michael@0: delete styleSet; michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: // quirk.css needs to come after the regular UA sheet (or more precisely, michael@0: // after the html.css and so forth that the UA sheet imports). michael@0: styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, quirkClone); michael@0: styleSet->SetQuirkStyleSheet(quirkClone); michael@0: styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, michael@0: nsLayoutStylesheetCache::UASheet()); michael@0: michael@0: nsStyleSheetService *sheetService = nsStyleSheetService::GetInstance(); michael@0: if (sheetService) { michael@0: sheetService->AgentStyleSheets()->EnumerateForwards(AppendAgentSheet, michael@0: styleSet); michael@0: sheetService->UserStyleSheets()->EnumerateBackwards(PrependUserSheet, michael@0: styleSet); michael@0: } michael@0: michael@0: // Caller will handle calling EndUpdate, per contract. michael@0: *aStyleSet = styleSet; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::ClearHistoryEntry() michael@0: { michael@0: mSHEntry = nullptr; michael@0: return NS_OK; michael@0: } michael@0: michael@0: //------------------------------------------------------- michael@0: michael@0: nsresult michael@0: nsDocumentViewer::MakeWindow(const nsSize& aSize, nsView* aContainerView) michael@0: { michael@0: if (GetIsPrintPreview()) michael@0: return NS_OK; michael@0: michael@0: bool shouldAttach = ShouldAttachToTopLevel(); michael@0: michael@0: if (shouldAttach) { michael@0: // If the old view is already attached to our parent, detach michael@0: DetachFromTopLevelWidget(); michael@0: } michael@0: michael@0: mViewManager = new nsViewManager(); michael@0: michael@0: nsDeviceContext *dx = mPresContext->DeviceContext(); michael@0: michael@0: nsresult rv = mViewManager->Init(dx); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: // The root view is always at 0,0. michael@0: nsRect tbounds(nsPoint(0, 0), aSize); michael@0: // Create a view michael@0: nsView* view = mViewManager->CreateView(tbounds, aContainerView); michael@0: if (!view) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: // Create a widget if we were given a parent widget or don't have a michael@0: // container view that we can hook up to without a widget. michael@0: // Don't create widgets for ResourceDocs (external resources & svg images), michael@0: // because when they're displayed, they're painted into *another* document's michael@0: // widget. michael@0: if (!mDocument->IsResourceDoc() && michael@0: (mParentWidget || !aContainerView)) { michael@0: // pass in a native widget to be the parent widget ONLY if the view hierarchy will stand alone. michael@0: // otherwise the view will find its own parent widget and "do the right thing" to michael@0: // establish a parent/child widget relationship michael@0: nsWidgetInitData initData; michael@0: nsWidgetInitData* initDataPtr; michael@0: if (!mParentWidget) { michael@0: initDataPtr = &initData; michael@0: initData.mWindowType = eWindowType_invisible; michael@0: } else { michael@0: initDataPtr = nullptr; michael@0: } michael@0: michael@0: if (shouldAttach) { michael@0: // Reuse the top level parent widget. michael@0: rv = view->AttachToTopLevelWidget(mParentWidget); michael@0: mAttachedToParent = true; michael@0: } michael@0: else if (!aContainerView && mParentWidget) { michael@0: rv = view->CreateWidgetForParent(mParentWidget, initDataPtr, michael@0: true, false); michael@0: } michael@0: else { michael@0: rv = view->CreateWidget(initDataPtr, true, false); michael@0: } michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: } michael@0: michael@0: // Setup hierarchical relationship in view manager michael@0: mViewManager->SetRootView(view); michael@0: michael@0: mWindow = view->GetWidget(); michael@0: michael@0: // This SetFocus is necessary so the Arrow Key and Page Key events michael@0: // go to the scrolled view as soon as the Window is created instead of going to michael@0: // the browser window (this enables keyboard scrolling of the document) michael@0: // mWindow->SetFocus(); michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: void michael@0: nsDocumentViewer::DetachFromTopLevelWidget() michael@0: { michael@0: if (mViewManager) { michael@0: nsView* oldView = mViewManager->GetRootView(); michael@0: if (oldView && oldView->IsAttachedToTopLevel()) { michael@0: oldView->DetachFromTopLevelWidget(); michael@0: } michael@0: } michael@0: mAttachedToParent = false; michael@0: } michael@0: michael@0: nsView* michael@0: nsDocumentViewer::FindContainerView() michael@0: { michael@0: nsView* containerView = nullptr; michael@0: michael@0: if (mContainer) { michael@0: nsCOMPtr docShellItem(mContainer); michael@0: nsCOMPtr pwin(do_GetInterface(docShellItem)); michael@0: if (pwin) { michael@0: nsCOMPtr containerElement = do_QueryInterface(pwin->GetFrameElementInternal()); michael@0: if (!containerElement) { michael@0: return nullptr; michael@0: } michael@0: nsCOMPtr parentPresShell; michael@0: if (docShellItem) { michael@0: nsCOMPtr parentDocShellItem; michael@0: docShellItem->GetParent(getter_AddRefs(parentDocShellItem)); michael@0: if (parentDocShellItem) { michael@0: nsCOMPtr parentDocShell = do_QueryInterface(parentDocShellItem); michael@0: parentPresShell = parentDocShell->GetPresShell(); michael@0: } michael@0: } michael@0: if (!parentPresShell) { michael@0: nsCOMPtr parentDoc = containerElement->GetCurrentDoc(); michael@0: if (parentDoc) { michael@0: parentPresShell = parentDoc->GetShell(); michael@0: } michael@0: } michael@0: if (!parentPresShell) { michael@0: NS_WARNING("Subdocument container has no presshell"); michael@0: } else { michael@0: nsIFrame* f = parentPresShell->GetRealPrimaryFrameFor(containerElement); michael@0: if (f) { michael@0: nsIFrame* subdocFrame = f->GetContentInsertionFrame(); michael@0: // subdocFrame might not be a subdocument frame; the frame michael@0: // constructor can treat a as an inline in some XBL michael@0: // cases. Treat that as display:none, the document is not michael@0: // displayed. michael@0: if (subdocFrame->GetType() == nsGkAtoms::subDocumentFrame) { michael@0: NS_ASSERTION(subdocFrame->GetView(), "Subdoc frames must have views"); michael@0: nsView* innerView = michael@0: static_cast(subdocFrame)->EnsureInnerView(); michael@0: containerView = innerView; michael@0: } else { michael@0: NS_WARNING("Subdocument container has non-subdocument frame"); michael@0: } michael@0: } else { michael@0: NS_WARNING("Subdocument container has no frame"); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: return containerView; michael@0: } michael@0: michael@0: nsresult michael@0: nsDocumentViewer::CreateDeviceContext(nsView* aContainerView) michael@0: { michael@0: NS_PRECONDITION(!mPresShell && !mWindow, michael@0: "This will screw up our existing presentation"); michael@0: NS_PRECONDITION(mDocument, "Gotta have a document here"); michael@0: michael@0: nsIDocument* doc = mDocument->GetDisplayDocument(); michael@0: if (doc) { michael@0: NS_ASSERTION(!aContainerView, "External resource document embedded somewhere?"); michael@0: // We want to use our display document's device context if possible michael@0: nsIPresShell* shell = doc->GetShell(); michael@0: if (shell) { michael@0: nsPresContext* ctx = shell->GetPresContext(); michael@0: if (ctx) { michael@0: mDeviceContext = ctx->DeviceContext(); michael@0: return NS_OK; michael@0: } michael@0: } michael@0: } michael@0: michael@0: // Create a device context even if we already have one, since our widget michael@0: // might have changed. michael@0: nsIWidget* widget = nullptr; michael@0: if (aContainerView) { michael@0: widget = aContainerView->GetNearestWidget(nullptr); michael@0: } michael@0: if (!widget) { michael@0: widget = mParentWidget; michael@0: } michael@0: if (widget) { michael@0: widget = widget->GetTopLevelWidget(); michael@0: } michael@0: michael@0: mDeviceContext = new nsDeviceContext(); michael@0: mDeviceContext->Init(widget); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Return the selection for the document. Note that text fields have their michael@0: // own selection, which cannot be accessed with this method. michael@0: nsresult nsDocumentViewer::GetDocumentSelection(nsISelection **aSelection) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aSelection); michael@0: if (!mPresShell) { michael@0: return NS_ERROR_NOT_INITIALIZED; michael@0: } michael@0: michael@0: nsCOMPtr selcon; michael@0: selcon = do_QueryInterface(mPresShell); michael@0: if (selcon) michael@0: return selcon->GetSelection(nsISelectionController::SELECTION_NORMAL, michael@0: aSelection); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: /* ======================================================================================== michael@0: * nsIContentViewerEdit michael@0: * ======================================================================================== */ michael@0: michael@0: NS_IMETHODIMP nsDocumentViewer::ClearSelection() michael@0: { michael@0: nsresult rv; michael@0: nsCOMPtr selection; michael@0: michael@0: // use nsCopySupport::GetSelectionForCopy() ? michael@0: rv = GetDocumentSelection(getter_AddRefs(selection)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: return selection->CollapseToStart(); michael@0: } michael@0: michael@0: NS_IMETHODIMP nsDocumentViewer::SelectAll() michael@0: { michael@0: // XXX this is a temporary implementation copied from nsWebShell michael@0: // for now. I think nsDocument and friends should have some helper michael@0: // functions to make this easier. michael@0: nsCOMPtr selection; michael@0: nsresult rv; michael@0: michael@0: // use nsCopySupport::GetSelectionForCopy() ? michael@0: rv = GetDocumentSelection(getter_AddRefs(selection)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsCOMPtr htmldoc = do_QueryInterface(mDocument); michael@0: nsCOMPtr bodyNode; michael@0: michael@0: if (htmldoc) michael@0: { michael@0: nsCOMPtrbodyElement; michael@0: rv = htmldoc->GetBody(getter_AddRefs(bodyElement)); michael@0: if (NS_FAILED(rv) || !bodyElement) return rv; michael@0: michael@0: bodyNode = do_QueryInterface(bodyElement); michael@0: } michael@0: else if (mDocument) michael@0: { michael@0: bodyNode = do_QueryInterface(mDocument->GetRootElement()); michael@0: } michael@0: if (!bodyNode) return NS_ERROR_FAILURE; michael@0: michael@0: rv = selection->RemoveAllRanges(); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: rv = selection->SelectAllChildren(bodyNode); michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsDocumentViewer::CopySelection() michael@0: { michael@0: nsCopySupport::FireClipboardEvent(NS_COPY, nsIClipboard::kGlobalClipboard, mPresShell, nullptr); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsDocumentViewer::CopyLinkLocation() michael@0: { michael@0: NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED); michael@0: nsCOMPtr node; michael@0: GetPopupLinkNode(getter_AddRefs(node)); michael@0: // make noise if we're not in a link michael@0: NS_ENSURE_TRUE(node, NS_ERROR_FAILURE); michael@0: michael@0: nsCOMPtr elm(do_QueryInterface(node)); michael@0: NS_ENSURE_TRUE(elm, NS_ERROR_FAILURE); michael@0: michael@0: nsAutoString locationText; michael@0: nsContentUtils::GetLinkLocation(elm, locationText); michael@0: if (locationText.IsEmpty()) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: nsresult rv = NS_OK; michael@0: nsCOMPtr clipboard(do_GetService("@mozilla.org/widget/clipboardhelper;1", &rv)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // copy the href onto the clipboard michael@0: nsCOMPtr doc = do_QueryInterface(mDocument); michael@0: return clipboard->CopyString(locationText, doc); michael@0: } michael@0: michael@0: NS_IMETHODIMP nsDocumentViewer::CopyImage(int32_t aCopyFlags) michael@0: { michael@0: NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED); michael@0: nsCOMPtr node; michael@0: GetPopupImageNode(getter_AddRefs(node)); michael@0: // make noise if we're not in an image michael@0: NS_ENSURE_TRUE(node, NS_ERROR_FAILURE); michael@0: michael@0: nsCOMPtr loadContext(mContainer); michael@0: return nsCopySupport::ImageCopy(node, loadContext, aCopyFlags); michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP nsDocumentViewer::GetCopyable(bool *aCopyable) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aCopyable); michael@0: *aCopyable = nsCopySupport::CanCopy(mDocument); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* AString getContents (in string mimeType, in boolean selectionOnly); */ michael@0: NS_IMETHODIMP nsDocumentViewer::GetContents(const char *mimeType, bool selectionOnly, nsAString& aOutValue) michael@0: { michael@0: aOutValue.Truncate(); michael@0: michael@0: NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED); michael@0: NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_INITIALIZED); michael@0: michael@0: // Now we have the selection. Make sure it's nonzero: michael@0: nsCOMPtr sel; michael@0: if (selectionOnly) { michael@0: nsCopySupport::GetSelectionForCopy(mDocument, getter_AddRefs(sel)); michael@0: NS_ENSURE_TRUE(sel, NS_ERROR_FAILURE); michael@0: michael@0: bool isCollapsed; michael@0: sel->GetIsCollapsed(&isCollapsed); michael@0: if (isCollapsed) michael@0: return NS_OK; michael@0: } michael@0: michael@0: // call the copy code michael@0: return nsCopySupport::GetContents(nsDependentCString(mimeType), 0, sel, michael@0: mDocument, aOutValue); michael@0: } michael@0: michael@0: /* readonly attribute boolean canGetContents; */ michael@0: NS_IMETHODIMP nsDocumentViewer::GetCanGetContents(bool *aCanGetContents) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aCanGetContents); michael@0: *aCanGetContents = false; michael@0: NS_ENSURE_STATE(mDocument); michael@0: *aCanGetContents = nsCopySupport::CanCopy(mDocument); michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: /* ======================================================================================== michael@0: * nsIContentViewerFile michael@0: * ======================================================================================== */ michael@0: /** --------------------------------------------------- michael@0: * See documentation above in the nsIContentViewerfile class definition michael@0: * @update 01/24/00 dwc michael@0: */ michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::Print(bool aSilent, michael@0: FILE * aDebugFile, michael@0: nsIPrintSettings* aPrintSettings) michael@0: { michael@0: #ifdef NS_PRINTING michael@0: nsCOMPtr printSettings; michael@0: michael@0: #ifdef DEBUG michael@0: nsresult rv = NS_ERROR_FAILURE; michael@0: michael@0: mDebugFile = aDebugFile; michael@0: // if they don't pass in a PrintSettings, then make one michael@0: // it will have all the default values michael@0: printSettings = aPrintSettings; michael@0: nsCOMPtr printOptions = do_GetService(sPrintOptionsContractID, &rv); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: // if they don't pass in a PrintSettings, then make one michael@0: if (printSettings == nullptr) { michael@0: printOptions->CreatePrintSettings(getter_AddRefs(printSettings)); michael@0: } michael@0: NS_ASSERTION(printSettings, "You can't PrintPreview without a PrintSettings!"); michael@0: } michael@0: if (printSettings) printSettings->SetPrintSilent(aSilent); michael@0: if (printSettings) printSettings->SetShowPrintProgress(false); michael@0: #endif michael@0: michael@0: michael@0: return Print(printSettings, nullptr); michael@0: #else michael@0: return NS_ERROR_FAILURE; michael@0: #endif michael@0: } michael@0: michael@0: // nsIContentViewerFile interface michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::GetPrintable(bool *aPrintable) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aPrintable); michael@0: michael@0: *aPrintable = !GetIsPrinting(); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: //***************************************************************************** michael@0: // nsIMarkupDocumentViewer michael@0: //***************************************************************************** michael@0: michael@0: NS_IMETHODIMP nsDocumentViewer::ScrollToNode(nsIDOMNode* aNode) michael@0: { michael@0: NS_ENSURE_ARG(aNode); michael@0: NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE); michael@0: nsCOMPtr presShell; michael@0: NS_ENSURE_SUCCESS(GetPresShell(getter_AddRefs(presShell)), NS_ERROR_FAILURE); michael@0: michael@0: // Get the nsIContent interface, because that's what we need to michael@0: // get the primary frame michael@0: michael@0: nsCOMPtr content(do_QueryInterface(aNode)); michael@0: NS_ENSURE_TRUE(content, NS_ERROR_FAILURE); michael@0: michael@0: // Tell the PresShell to scroll to the primary frame of the content. michael@0: NS_ENSURE_SUCCESS( michael@0: presShell->ScrollContentIntoView(content, michael@0: nsIPresShell::ScrollAxis( michael@0: nsIPresShell::SCROLL_TOP, michael@0: nsIPresShell::SCROLL_ALWAYS), michael@0: nsIPresShell::ScrollAxis(), michael@0: nsIPresShell::SCROLL_OVERFLOW_HIDDEN), michael@0: NS_ERROR_FAILURE); michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: nsDocumentViewer::CallChildren(CallChildFunc aFunc, void* aClosure) michael@0: { michael@0: nsCOMPtr docShell(mContainer); michael@0: if (docShell) michael@0: { michael@0: int32_t i; michael@0: int32_t n; michael@0: docShell->GetChildCount(&n); michael@0: for (i=0; i < n; i++) michael@0: { michael@0: nsCOMPtr child; michael@0: docShell->GetChildAt(i, getter_AddRefs(child)); michael@0: nsCOMPtr childAsShell(do_QueryInterface(child)); michael@0: NS_ASSERTION(childAsShell, "null child in docshell"); michael@0: if (childAsShell) michael@0: { michael@0: nsCOMPtr childCV; michael@0: childAsShell->GetContentViewer(getter_AddRefs(childCV)); michael@0: if (childCV) michael@0: { michael@0: nsCOMPtr markupCV = do_QueryInterface(childCV); michael@0: if (markupCV) { michael@0: (*aFunc)(markupCV, aClosure); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: struct LineBoxInfo michael@0: { michael@0: nscoord mMaxLineBoxWidth; michael@0: }; michael@0: michael@0: static void michael@0: ChangeChildPaintingEnabled(nsIMarkupDocumentViewer* aChild, void* aClosure) michael@0: { michael@0: bool* enablePainting = (bool*) aClosure; michael@0: if (*enablePainting) { michael@0: aChild->ResumePainting(); michael@0: } else { michael@0: aChild->PausePainting(); michael@0: } michael@0: } michael@0: michael@0: static void michael@0: ChangeChildMaxLineBoxWidth(nsIMarkupDocumentViewer* aChild, void* aClosure) michael@0: { michael@0: struct LineBoxInfo* lbi = (struct LineBoxInfo*) aClosure; michael@0: aChild->ChangeMaxLineBoxWidth(lbi->mMaxLineBoxWidth); michael@0: } michael@0: michael@0: struct ZoomInfo michael@0: { michael@0: float mZoom; michael@0: }; michael@0: michael@0: static void michael@0: SetChildTextZoom(nsIMarkupDocumentViewer* aChild, void* aClosure) michael@0: { michael@0: struct ZoomInfo* ZoomInfo = (struct ZoomInfo*) aClosure; michael@0: aChild->SetTextZoom(ZoomInfo->mZoom); michael@0: } michael@0: michael@0: static void michael@0: SetChildMinFontSize(nsIMarkupDocumentViewer* aChild, void* aClosure) michael@0: { michael@0: nsCOMPtr branch = michael@0: do_QueryInterface(aChild); michael@0: branch->SetMinFontSize(NS_PTR_TO_INT32(aClosure)); michael@0: } michael@0: michael@0: static void michael@0: SetChildFullZoom(nsIMarkupDocumentViewer* aChild, void* aClosure) michael@0: { michael@0: struct ZoomInfo* ZoomInfo = (struct ZoomInfo*) aClosure; michael@0: aChild->SetFullZoom(ZoomInfo->mZoom); michael@0: } michael@0: michael@0: static bool michael@0: SetExtResourceTextZoom(nsIDocument* aDocument, void* aClosure) michael@0: { michael@0: // Would it be better to enumerate external resource viewers instead? michael@0: nsIPresShell* shell = aDocument->GetShell(); michael@0: if (shell) { michael@0: nsPresContext* ctxt = shell->GetPresContext(); michael@0: if (ctxt) { michael@0: struct ZoomInfo* ZoomInfo = static_cast(aClosure); michael@0: ctxt->SetTextZoom(ZoomInfo->mZoom); michael@0: } michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: static bool michael@0: SetExtResourceMinFontSize(nsIDocument* aDocument, void* aClosure) michael@0: { michael@0: nsIPresShell* shell = aDocument->GetShell(); michael@0: if (shell) { michael@0: nsPresContext* ctxt = shell->GetPresContext(); michael@0: if (ctxt) { michael@0: ctxt->SetBaseMinFontSize(NS_PTR_TO_INT32(aClosure)); michael@0: } michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: static bool michael@0: SetExtResourceFullZoom(nsIDocument* aDocument, void* aClosure) michael@0: { michael@0: // Would it be better to enumerate external resource viewers instead? michael@0: nsIPresShell* shell = aDocument->GetShell(); michael@0: if (shell) { michael@0: nsPresContext* ctxt = shell->GetPresContext(); michael@0: if (ctxt) { michael@0: struct ZoomInfo* ZoomInfo = static_cast(aClosure); michael@0: ctxt->SetFullZoom(ZoomInfo->mZoom); michael@0: } michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::SetTextZoom(float aTextZoom) michael@0: { michael@0: // If we don't have a document, then we need to bail. michael@0: if (!mDocument) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: if (GetIsPrintPreview()) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: mTextZoom = aTextZoom; michael@0: michael@0: // Set the text zoom on all children of mContainer (even if our zoom didn't michael@0: // change, our children's zoom may be different, though it would be unusual). michael@0: // Do this first, in case kids are auto-sizing and post reflow commands on michael@0: // our presshell (which should be subsumed into our own style change reflow). michael@0: struct ZoomInfo ZoomInfo = { aTextZoom }; michael@0: CallChildren(SetChildTextZoom, &ZoomInfo); michael@0: michael@0: // Now change our own zoom michael@0: nsPresContext* pc = GetPresContext(); michael@0: if (pc && aTextZoom != mPresContext->TextZoom()) { michael@0: pc->SetTextZoom(aTextZoom); michael@0: } michael@0: michael@0: // And do the external resources michael@0: mDocument->EnumerateExternalResources(SetExtResourceTextZoom, &ZoomInfo); michael@0: michael@0: nsContentUtils::DispatchChromeEvent(mDocument, static_cast(mDocument), michael@0: NS_LITERAL_STRING("TextZoomChange"), michael@0: true, true); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::GetTextZoom(float* aTextZoom) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aTextZoom); michael@0: nsPresContext* pc = GetPresContext(); michael@0: *aTextZoom = pc ? pc->TextZoom() : 1.0f; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::SetMinFontSize(int32_t aMinFontSize) michael@0: { michael@0: // If we don't have a document, then we need to bail. michael@0: if (!mDocument) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: if (GetIsPrintPreview()) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: mMinFontSize = aMinFontSize; michael@0: michael@0: // Set the min font on all children of mContainer (even if our min font didn't michael@0: // change, our children's min font may be different, though it would be unusual). michael@0: // Do this first, in case kids are auto-sizing and post reflow commands on michael@0: // our presshell (which should be subsumed into our own style change reflow). michael@0: CallChildren(SetChildMinFontSize, NS_INT32_TO_PTR(aMinFontSize)); michael@0: michael@0: // Now change our own min font michael@0: nsPresContext* pc = GetPresContext(); michael@0: if (pc && aMinFontSize != mPresContext->MinFontSize(nullptr)) { michael@0: pc->SetBaseMinFontSize(aMinFontSize); michael@0: } michael@0: michael@0: // And do the external resources michael@0: mDocument->EnumerateExternalResources(SetExtResourceMinFontSize, michael@0: NS_INT32_TO_PTR(aMinFontSize)); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::GetMinFontSize(int32_t* aMinFontSize) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aMinFontSize); michael@0: nsPresContext* pc = GetPresContext(); michael@0: *aMinFontSize = pc ? pc->BaseMinFontSize() : 0; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::SetFullZoom(float aFullZoom) michael@0: { michael@0: #ifdef NS_PRINT_PREVIEW michael@0: if (GetIsPrintPreview()) { michael@0: nsPresContext* pc = GetPresContext(); michael@0: NS_ENSURE_TRUE(pc, NS_OK); michael@0: nsCOMPtr shell = pc->GetPresShell(); michael@0: NS_ENSURE_TRUE(shell, NS_OK); michael@0: michael@0: if (!mPrintPreviewZoomed) { michael@0: mOriginalPrintPreviewScale = pc->GetPrintPreviewScale(); michael@0: mPrintPreviewZoomed = true; michael@0: } michael@0: michael@0: mPrintPreviewZoom = aFullZoom; michael@0: pc->SetPrintPreviewScale(aFullZoom * mOriginalPrintPreviewScale); michael@0: nsIPageSequenceFrame* pf = shell->GetPageSequenceFrame(); michael@0: if (pf) { michael@0: nsIFrame* f = do_QueryFrame(pf); michael@0: shell->FrameNeedsReflow(f, nsIPresShell::eResize, NS_FRAME_IS_DIRTY); michael@0: } michael@0: michael@0: nsIFrame* rootFrame = shell->GetRootFrame(); michael@0: if (rootFrame) { michael@0: rootFrame->InvalidateFrame(); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: #endif michael@0: michael@0: // If we don't have a document, then we need to bail. michael@0: if (!mDocument) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: mPageZoom = aFullZoom; michael@0: michael@0: struct ZoomInfo ZoomInfo = { aFullZoom }; michael@0: CallChildren(SetChildFullZoom, &ZoomInfo); michael@0: michael@0: nsPresContext* pc = GetPresContext(); michael@0: if (pc) { michael@0: pc->SetFullZoom(aFullZoom); michael@0: } michael@0: michael@0: // And do the external resources michael@0: mDocument->EnumerateExternalResources(SetExtResourceFullZoom, &ZoomInfo); michael@0: michael@0: nsContentUtils::DispatchChromeEvent(mDocument, static_cast(mDocument), michael@0: NS_LITERAL_STRING("FullZoomChange"), michael@0: true, true); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::GetFullZoom(float* aFullZoom) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aFullZoom); michael@0: #ifdef NS_PRINT_PREVIEW michael@0: if (GetIsPrintPreview()) { michael@0: *aFullZoom = mPrintPreviewZoom; michael@0: return NS_OK; michael@0: } michael@0: #endif michael@0: // Check the prescontext first because it might have a temporary michael@0: // setting for print-preview michael@0: nsPresContext* pc = GetPresContext(); michael@0: *aFullZoom = pc ? pc->GetFullZoom() : mPageZoom; michael@0: return NS_OK; michael@0: } michael@0: michael@0: static void michael@0: SetChildAuthorStyleDisabled(nsIMarkupDocumentViewer* aChild, void* aClosure) michael@0: { michael@0: bool styleDisabled = *static_cast(aClosure); michael@0: aChild->SetAuthorStyleDisabled(styleDisabled); michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::SetAuthorStyleDisabled(bool aStyleDisabled) michael@0: { michael@0: if (mPresShell) { michael@0: mPresShell->SetAuthorStyleDisabled(aStyleDisabled); michael@0: } michael@0: CallChildren(SetChildAuthorStyleDisabled, &aStyleDisabled); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::GetAuthorStyleDisabled(bool* aStyleDisabled) michael@0: { michael@0: if (mPresShell) { michael@0: *aStyleDisabled = mPresShell->GetAuthorStyleDisabled(); michael@0: } else { michael@0: *aStyleDisabled = false; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: static bool michael@0: ExtResourceEmulateMedium(nsIDocument* aDocument, void* aClosure) michael@0: { michael@0: nsIPresShell* shell = aDocument->GetShell(); michael@0: if (shell) { michael@0: nsPresContext* ctxt = shell->GetPresContext(); michael@0: if (ctxt) { michael@0: const nsAString* mediaType = static_cast(aClosure); michael@0: ctxt->EmulateMedium(*mediaType); michael@0: } michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: static void michael@0: ChildEmulateMedium(nsIMarkupDocumentViewer* aChild, void* aClosure) michael@0: { michael@0: const nsAString* mediaType = static_cast(aClosure); michael@0: aChild->EmulateMedium(*mediaType); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::EmulateMedium(const nsAString& aMediaType) michael@0: { michael@0: if (mPresContext) { michael@0: mPresContext->EmulateMedium(aMediaType); michael@0: } michael@0: CallChildren(ChildEmulateMedium, const_cast(&aMediaType)); michael@0: michael@0: if (mDocument) { michael@0: mDocument->EnumerateExternalResources(ExtResourceEmulateMedium, michael@0: const_cast(&aMediaType)); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: static bool michael@0: ExtResourceStopEmulatingMedium(nsIDocument* aDocument, void* aClosure) michael@0: { michael@0: nsIPresShell* shell = aDocument->GetShell(); michael@0: if (shell) { michael@0: nsPresContext* ctxt = shell->GetPresContext(); michael@0: if (ctxt) { michael@0: ctxt->StopEmulatingMedium(); michael@0: } michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: static void michael@0: ChildStopEmulatingMedium(nsIMarkupDocumentViewer* aChild, void* aClosure) michael@0: { michael@0: aChild->StopEmulatingMedium(); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::StopEmulatingMedium() michael@0: { michael@0: if (mPresContext) { michael@0: mPresContext->StopEmulatingMedium(); michael@0: } michael@0: CallChildren(ChildStopEmulatingMedium, nullptr); michael@0: michael@0: if (mDocument) { michael@0: mDocument->EnumerateExternalResources(ExtResourceStopEmulatingMedium, michael@0: nullptr); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsDocumentViewer::GetForceCharacterSet(nsACString& aForceCharacterSet) michael@0: { michael@0: aForceCharacterSet = mForceCharacterSet; michael@0: return NS_OK; michael@0: } michael@0: michael@0: static void michael@0: SetChildForceCharacterSet(nsIMarkupDocumentViewer* aChild, void* aClosure) michael@0: { michael@0: const nsACString* charset = static_cast(aClosure); michael@0: aChild->SetForceCharacterSet(*charset); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::SetForceCharacterSet(const nsACString& aForceCharacterSet) michael@0: { michael@0: mForceCharacterSet = aForceCharacterSet; michael@0: // now set the force char set on all children of mContainer michael@0: CallChildren(SetChildForceCharacterSet, (void*) &aForceCharacterSet); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsDocumentViewer::GetHintCharacterSet(nsACString& aHintCharacterSet) michael@0: { michael@0: michael@0: if(kCharsetUninitialized == mHintCharsetSource) { michael@0: aHintCharacterSet.Truncate(); michael@0: } else { michael@0: aHintCharacterSet = mHintCharset; michael@0: // this can't possibly be right. we can't set a value just because somebody got a related value! michael@0: //mHintCharsetSource = kCharsetUninitialized; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsDocumentViewer::GetHintCharacterSetSource(int32_t *aHintCharacterSetSource) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aHintCharacterSetSource); michael@0: michael@0: *aHintCharacterSetSource = mHintCharsetSource; michael@0: return NS_OK; michael@0: } michael@0: michael@0: static void michael@0: SetChildHintCharacterSetSource(nsIMarkupDocumentViewer* aChild, void* aClosure) michael@0: { michael@0: aChild->SetHintCharacterSetSource(NS_PTR_TO_INT32(aClosure)); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::SetHintCharacterSetSource(int32_t aHintCharacterSetSource) michael@0: { michael@0: mHintCharsetSource = aHintCharacterSetSource; michael@0: // now set the hint char set source on all children of mContainer michael@0: CallChildren(SetChildHintCharacterSetSource, michael@0: NS_INT32_TO_PTR(aHintCharacterSetSource)); michael@0: return NS_OK; michael@0: } michael@0: michael@0: static void michael@0: SetChildHintCharacterSet(nsIMarkupDocumentViewer* aChild, void* aClosure) michael@0: { michael@0: const nsACString* charset = static_cast(aClosure); michael@0: aChild->SetHintCharacterSet(*charset); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::SetHintCharacterSet(const nsACString& aHintCharacterSet) michael@0: { michael@0: mHintCharset = aHintCharacterSet; michael@0: // now set the hint char set on all children of mContainer michael@0: CallChildren(SetChildHintCharacterSet, (void*) &aHintCharacterSet); michael@0: return NS_OK; michael@0: } michael@0: michael@0: static void michael@0: AppendChildSubtree(nsIMarkupDocumentViewer* aChild, void* aClosure) michael@0: { michael@0: nsTArray >& array = michael@0: *static_cast >*>(aClosure); michael@0: aChild->AppendSubtree(array); michael@0: } michael@0: michael@0: NS_IMETHODIMP nsDocumentViewer::AppendSubtree(nsTArray >& aArray) michael@0: { michael@0: aArray.AppendElement(this); michael@0: CallChildren(AppendChildSubtree, &aArray); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::PausePainting() michael@0: { michael@0: bool enablePaint = false; michael@0: CallChildren(ChangeChildPaintingEnabled, &enablePaint); michael@0: michael@0: nsIPresShell* presShell = GetPresShell(); michael@0: if (presShell) { michael@0: presShell->PausePainting(); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::ResumePainting() michael@0: { michael@0: bool enablePaint = true; michael@0: CallChildren(ChangeChildPaintingEnabled, &enablePaint); michael@0: michael@0: nsIPresShell* presShell = GetPresShell(); michael@0: if (presShell) { michael@0: presShell->ResumePainting(); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::ChangeMaxLineBoxWidth(int32_t aMaxLineBoxWidth) michael@0: { michael@0: // Change the max line box width for all children. michael@0: struct LineBoxInfo lbi = { aMaxLineBoxWidth }; michael@0: CallChildren(ChangeChildMaxLineBoxWidth, &lbi); michael@0: michael@0: // Now, change our max line box width. michael@0: // Convert to app units, since our input is in CSS pixels. michael@0: nscoord mlbw = nsPresContext::CSSPixelsToAppUnits(aMaxLineBoxWidth); michael@0: nsIPresShell* presShell = GetPresShell(); michael@0: if (presShell) { michael@0: presShell->SetMaxLineBoxWidth(mlbw); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::GetContentSize(int32_t* aWidth, int32_t* aHeight) michael@0: { michael@0: NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE); michael@0: michael@0: // Skip doing this on docshell-less documents for now michael@0: nsCOMPtr docShellAsItem(mContainer); michael@0: NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_NOT_AVAILABLE); michael@0: michael@0: nsCOMPtr docShellParent; michael@0: docShellAsItem->GetSameTypeParent(getter_AddRefs(docShellParent)); michael@0: michael@0: // It's only valid to access this from a top frame. Doesn't work from michael@0: // sub-frames. michael@0: NS_ENSURE_TRUE(!docShellParent, NS_ERROR_FAILURE); michael@0: michael@0: nsCOMPtr presShell; michael@0: GetPresShell(getter_AddRefs(presShell)); michael@0: NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE); michael@0: michael@0: // Flush out all content and style updates. We can't use a resize reflow michael@0: // because it won't change some sizes that a style change reflow will. michael@0: mDocument->FlushPendingNotifications(Flush_Layout); michael@0: michael@0: nsIFrame *root = presShell->GetRootFrame(); michael@0: NS_ENSURE_TRUE(root, NS_ERROR_FAILURE); michael@0: michael@0: nscoord prefWidth; michael@0: { michael@0: nsRefPtr rcx = michael@0: presShell->CreateReferenceRenderingContext(); michael@0: prefWidth = root->GetPrefWidth(rcx); michael@0: } michael@0: michael@0: nsresult rv = presShell->ResizeReflow(prefWidth, NS_UNCONSTRAINEDSIZE); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsRefPtr presContext; michael@0: GetPresContext(getter_AddRefs(presContext)); michael@0: NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE); michael@0: michael@0: // so how big is it? michael@0: nsRect shellArea = presContext->GetVisibleArea(); michael@0: // Protect against bogus returns here michael@0: NS_ENSURE_TRUE(shellArea.width != NS_UNCONSTRAINEDSIZE && michael@0: shellArea.height != NS_UNCONSTRAINEDSIZE, michael@0: NS_ERROR_FAILURE); michael@0: michael@0: *aWidth = presContext->AppUnitsToDevPixels(shellArea.width); michael@0: *aHeight = presContext->AppUnitsToDevPixels(shellArea.height); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: NS_IMPL_ISUPPORTS(nsDocViewerSelectionListener, nsISelectionListener) michael@0: michael@0: nsresult nsDocViewerSelectionListener::Init(nsDocumentViewer *aDocViewer) michael@0: { michael@0: mDocViewer = aDocViewer; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* michael@0: * GetPopupNode, GetPopupLinkNode and GetPopupImageNode are helpers michael@0: * for the cmd_copyLink / cmd_copyImageLocation / cmd_copyImageContents family michael@0: * of commands. The focus controller stores the popup node, these retrieve michael@0: * them and munge appropriately. Note that we have to store the popup node michael@0: * rather than retrieving it from EventStateManager::GetFocusedContent because michael@0: * not all content (images included) can receive focus. michael@0: */ michael@0: michael@0: nsresult michael@0: nsDocumentViewer::GetPopupNode(nsIDOMNode** aNode) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aNode); michael@0: michael@0: *aNode = nullptr; michael@0: michael@0: // get the document michael@0: nsIDocument* document = GetDocument(); michael@0: NS_ENSURE_TRUE(document, NS_ERROR_FAILURE); michael@0: michael@0: // get the private dom window michael@0: nsCOMPtr window(document->GetWindow()); michael@0: NS_ENSURE_TRUE(window, NS_ERROR_NOT_AVAILABLE); michael@0: if (window) { michael@0: nsCOMPtr root = window->GetTopWindowRoot(); michael@0: NS_ENSURE_TRUE(root, NS_ERROR_FAILURE); michael@0: michael@0: // get the popup node michael@0: nsCOMPtr node = root->GetPopupNode(); michael@0: #ifdef MOZ_XUL michael@0: if (!node) { michael@0: nsPIDOMWindow* rootWindow = root->GetWindow(); michael@0: if (rootWindow) { michael@0: nsCOMPtr rootDoc = rootWindow->GetExtantDoc(); michael@0: if (rootDoc) { michael@0: nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); michael@0: if (pm) { michael@0: node = pm->GetLastTriggerPopupNode(rootDoc); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: #endif michael@0: node.swap(*aNode); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // GetPopupLinkNode: return popup link node or fail michael@0: nsresult michael@0: nsDocumentViewer::GetPopupLinkNode(nsIDOMNode** aNode) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aNode); michael@0: michael@0: // you get null unless i say so michael@0: *aNode = nullptr; michael@0: michael@0: // find popup node michael@0: nsCOMPtr node; michael@0: nsresult rv = GetPopupNode(getter_AddRefs(node)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // find out if we have a link in our ancestry michael@0: while (node) { michael@0: michael@0: nsCOMPtr content(do_QueryInterface(node)); michael@0: if (content) { michael@0: nsCOMPtr hrefURI = content->GetHrefURI(); michael@0: if (hrefURI) { michael@0: *aNode = node; michael@0: NS_IF_ADDREF(*aNode); // addref michael@0: return NS_OK; michael@0: } michael@0: } michael@0: michael@0: // get our parent and keep trying... michael@0: nsCOMPtr parentNode; michael@0: node->GetParentNode(getter_AddRefs(parentNode)); michael@0: node = parentNode; michael@0: } michael@0: michael@0: // if we have no node, fail michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: // GetPopupLinkNode: return popup image node or fail michael@0: nsresult michael@0: nsDocumentViewer::GetPopupImageNode(nsIImageLoadingContent** aNode) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aNode); michael@0: michael@0: // you get null unless i say so michael@0: *aNode = nullptr; michael@0: michael@0: // find popup node michael@0: nsCOMPtr node; michael@0: nsresult rv = GetPopupNode(getter_AddRefs(node)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: if (node) michael@0: CallQueryInterface(node, aNode); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* michael@0: * XXX dr michael@0: * ------ michael@0: * These two functions -- GetInLink and GetInImage -- are kind of annoying michael@0: * in that they only get called from the controller (in michael@0: * nsDOMWindowController::IsCommandEnabled). The actual construction of the michael@0: * context menus in communicator (nsContextMenu.js) has its own, redundant michael@0: * tests. No big deal, but good to keep in mind if we ever clean context michael@0: * menus. michael@0: */ michael@0: michael@0: NS_IMETHODIMP nsDocumentViewer::GetInLink(bool* aInLink) michael@0: { michael@0: #ifdef DEBUG_dr michael@0: printf("dr :: nsDocumentViewer::GetInLink\n"); michael@0: #endif michael@0: michael@0: NS_ENSURE_ARG_POINTER(aInLink); michael@0: michael@0: // we're not in a link unless i say so michael@0: *aInLink = false; michael@0: michael@0: // get the popup link michael@0: nsCOMPtr node; michael@0: nsresult rv = GetPopupLinkNode(getter_AddRefs(node)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: NS_ENSURE_TRUE(node, NS_ERROR_FAILURE); michael@0: michael@0: // if we made it here, we're in a link michael@0: *aInLink = true; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsDocumentViewer::GetInImage(bool* aInImage) michael@0: { michael@0: #ifdef DEBUG_dr michael@0: printf("dr :: nsDocumentViewer::GetInImage\n"); michael@0: #endif michael@0: michael@0: NS_ENSURE_ARG_POINTER(aInImage); michael@0: michael@0: // we're not in an image unless i say so michael@0: *aInImage = false; michael@0: michael@0: // get the popup image michael@0: nsCOMPtr node; michael@0: nsresult rv = GetPopupImageNode(getter_AddRefs(node)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: NS_ENSURE_TRUE(node, NS_ERROR_FAILURE); michael@0: michael@0: // if we made it here, we're in an image michael@0: *aInImage = true; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsDocViewerSelectionListener::NotifySelectionChanged(nsIDOMDocument *, nsISelection *, int16_t) michael@0: { michael@0: NS_ASSERTION(mDocViewer, "Should have doc viewer!"); michael@0: michael@0: // get the selection state michael@0: nsCOMPtr selection; michael@0: nsresult rv = mDocViewer->GetDocumentSelection(getter_AddRefs(selection)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: bool selectionCollapsed; michael@0: selection->GetIsCollapsed(&selectionCollapsed); michael@0: // we only call UpdateCommands when the selection changes from collapsed michael@0: // to non-collapsed or vice versa. We might need another update string michael@0: // for simple selection changes, but that would be expenseive. michael@0: if (!mGotSelectionState || mSelectionWasCollapsed != selectionCollapsed) michael@0: { michael@0: nsIDocument* theDoc = mDocViewer->GetDocument(); michael@0: if (!theDoc) return NS_ERROR_FAILURE; michael@0: michael@0: nsPIDOMWindow *domWindow = theDoc->GetWindow(); michael@0: if (!domWindow) return NS_ERROR_FAILURE; michael@0: michael@0: domWindow->UpdateCommands(NS_LITERAL_STRING("select")); michael@0: mGotSelectionState = true; michael@0: mSelectionWasCollapsed = selectionCollapsed; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: //nsDocViewerFocusListener michael@0: NS_IMPL_ISUPPORTS(nsDocViewerFocusListener, michael@0: nsIDOMEventListener) michael@0: michael@0: nsDocViewerFocusListener::nsDocViewerFocusListener() michael@0: :mDocViewer(nullptr) michael@0: { michael@0: } michael@0: michael@0: nsDocViewerFocusListener::~nsDocViewerFocusListener(){} michael@0: michael@0: nsresult michael@0: nsDocViewerFocusListener::HandleEvent(nsIDOMEvent* aEvent) michael@0: { michael@0: NS_ENSURE_STATE(mDocViewer); michael@0: michael@0: nsCOMPtr shell; michael@0: mDocViewer->GetPresShell(getter_AddRefs(shell)); michael@0: NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE); michael@0: michael@0: nsCOMPtr selCon = do_QueryInterface(shell); michael@0: int16_t selectionStatus; michael@0: selCon->GetDisplaySelection(&selectionStatus); michael@0: michael@0: nsAutoString eventType; michael@0: aEvent->GetType(eventType); michael@0: if (eventType.EqualsLiteral("focus")) { michael@0: // If selection was disabled, re-enable it. michael@0: if(selectionStatus == nsISelectionController::SELECTION_DISABLED || michael@0: selectionStatus == nsISelectionController::SELECTION_HIDDEN) { michael@0: selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON); michael@0: selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL); michael@0: } michael@0: } else { michael@0: NS_ABORT_IF_FALSE(eventType.EqualsLiteral("blur"), michael@0: "Unexpected event type"); michael@0: // If selection was on, disable it. michael@0: if(selectionStatus == nsISelectionController::SELECTION_ON || michael@0: selectionStatus == nsISelectionController::SELECTION_ATTENTION) { michael@0: selCon->SetDisplaySelection(nsISelectionController::SELECTION_DISABLED); michael@0: selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL); michael@0: } michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsDocViewerFocusListener::Init(nsDocumentViewer *aDocViewer) michael@0: { michael@0: mDocViewer = aDocViewer; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /** --------------------------------------------------- michael@0: * From nsIWebBrowserPrint michael@0: */ michael@0: michael@0: #ifdef NS_PRINTING michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::Print(nsIPrintSettings* aPrintSettings, michael@0: nsIWebProgressListener* aWebProgressListener) michael@0: { michael@0: // Printing XUL documents is not supported. michael@0: nsCOMPtr xulDoc(do_QueryInterface(mDocument)); michael@0: if (xulDoc) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: if (!mContainer) { michael@0: PR_PL(("Container was destroyed yet we are still trying to use it!")); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsCOMPtr docShell(mContainer); michael@0: NS_ENSURE_STATE(docShell); michael@0: michael@0: // Check to see if this document is still busy michael@0: // If it is busy and we aren't already "queued" up to print then michael@0: // Indicate there is a print pending and cache the args for later michael@0: uint32_t busyFlags = nsIDocShell::BUSY_FLAGS_NONE; michael@0: if ((NS_FAILED(docShell->GetBusyFlags(&busyFlags)) || michael@0: (busyFlags != nsIDocShell::BUSY_FLAGS_NONE && busyFlags & nsIDocShell::BUSY_FLAGS_PAGE_LOADING)) && michael@0: !mPrintDocIsFullyLoaded) { michael@0: if (!mPrintIsPending) { michael@0: mCachedPrintSettings = aPrintSettings; michael@0: mCachedPrintWebProgressListner = aWebProgressListener; michael@0: mPrintIsPending = true; michael@0: } michael@0: PR_PL(("Printing Stopped - document is still busy!")); michael@0: return NS_ERROR_GFX_PRINTER_DOC_IS_BUSY; michael@0: } michael@0: michael@0: if (!mDocument || !mDeviceContext) { michael@0: PR_PL(("Can't Print without a document and a device context")); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsresult rv; michael@0: michael@0: // if we are printing another URL, then exit michael@0: // the reason we check here is because this method can be called while michael@0: // another is still in here (the printing dialog is a good example). michael@0: // the only time we can print more than one job at a time is the regression tests michael@0: if (GetIsPrinting()) { michael@0: // Let the user know we are not ready to print. michael@0: rv = NS_ERROR_NOT_AVAILABLE; michael@0: nsPrintEngine::ShowPrintErrorDialog(rv); michael@0: return rv; michael@0: } michael@0: michael@0: nsAutoPtr beforeAndAfterPrint( michael@0: new nsPrintEventDispatcher(mDocument)); michael@0: NS_ENSURE_STATE(!GetIsPrinting()); michael@0: // If we are hosting a full-page plugin, tell it to print michael@0: // first. It shows its own native print UI. michael@0: nsCOMPtr pDoc(do_QueryInterface(mDocument)); michael@0: if (pDoc) michael@0: return pDoc->Print(); michael@0: michael@0: if (!mPrintEngine) { michael@0: NS_ENSURE_STATE(mDeviceContext); michael@0: mPrintEngine = new nsPrintEngine(); michael@0: michael@0: rv = mPrintEngine->Initialize(this, mContainer, mDocument, michael@0: float(mDeviceContext->AppUnitsPerCSSInch()) / michael@0: float(mDeviceContext->AppUnitsPerDevPixel()) / michael@0: mPageZoom, michael@0: #ifdef DEBUG michael@0: mDebugFile michael@0: #else michael@0: nullptr michael@0: #endif michael@0: ); michael@0: if (NS_FAILED(rv)) { michael@0: mPrintEngine->Destroy(); michael@0: mPrintEngine = nullptr; michael@0: return rv; michael@0: } michael@0: } michael@0: if (mPrintEngine->HasPrintCallbackCanvas()) { michael@0: mBeforeAndAfterPrint = beforeAndAfterPrint; michael@0: } michael@0: dom::Element* root = mDocument->GetRootElement(); michael@0: if (root && root->HasAttr(kNameSpaceID_None, nsGkAtoms::mozdisallowselectionprint)) { michael@0: mPrintEngine->SetDisallowSelectionPrint(true); michael@0: } michael@0: if (root && root->HasAttr(kNameSpaceID_None, nsGkAtoms::moznomarginboxes)) { michael@0: mPrintEngine->SetNoMarginBoxes(true); michael@0: } michael@0: rv = mPrintEngine->Print(aPrintSettings, aWebProgressListener); michael@0: if (NS_FAILED(rv)) { michael@0: OnDonePrinting(); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::PrintPreview(nsIPrintSettings* aPrintSettings, michael@0: nsIDOMWindow *aChildDOMWin, michael@0: nsIWebProgressListener* aWebProgressListener) michael@0: { michael@0: #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW) michael@0: NS_WARN_IF_FALSE(IsInitializedForPrintPreview(), michael@0: "Using docshell.printPreview is the preferred way for print previewing!"); michael@0: michael@0: NS_ENSURE_ARG_POINTER(aChildDOMWin); michael@0: nsresult rv = NS_OK; michael@0: michael@0: if (GetIsPrinting()) { michael@0: nsPrintEngine::CloseProgressDialog(aWebProgressListener); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: // Printing XUL documents is not supported. michael@0: nsCOMPtr xulDoc(do_QueryInterface(mDocument)); michael@0: if (xulDoc) { michael@0: nsPrintEngine::CloseProgressDialog(aWebProgressListener); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsCOMPtr docShell(mContainer); michael@0: if (!docShell || !mDeviceContext) { michael@0: PR_PL(("Can't Print Preview without device context and docshell")); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsCOMPtr domDoc; michael@0: aChildDOMWin->GetDocument(getter_AddRefs(domDoc)); michael@0: nsCOMPtr doc = do_QueryInterface(domDoc); michael@0: NS_ENSURE_STATE(doc); michael@0: michael@0: nsAutoPtr beforeAndAfterPrint( michael@0: new nsPrintEventDispatcher(doc)); michael@0: NS_ENSURE_STATE(!GetIsPrinting()); michael@0: if (!mPrintEngine) { michael@0: mPrintEngine = new nsPrintEngine(); michael@0: michael@0: rv = mPrintEngine->Initialize(this, mContainer, doc, michael@0: float(mDeviceContext->AppUnitsPerCSSInch()) / michael@0: float(mDeviceContext->AppUnitsPerDevPixel()) / michael@0: mPageZoom, michael@0: #ifdef DEBUG michael@0: mDebugFile michael@0: #else michael@0: nullptr michael@0: #endif michael@0: ); michael@0: if (NS_FAILED(rv)) { michael@0: mPrintEngine->Destroy(); michael@0: mPrintEngine = nullptr; michael@0: return rv; michael@0: } michael@0: } michael@0: if (mPrintEngine->HasPrintCallbackCanvas()) { michael@0: mBeforeAndAfterPrint = beforeAndAfterPrint; michael@0: } michael@0: dom::Element* root = doc->GetRootElement(); michael@0: if (root && root->HasAttr(kNameSpaceID_None, nsGkAtoms::mozdisallowselectionprint)) { michael@0: PR_PL(("PrintPreview: found mozdisallowselectionprint")); michael@0: mPrintEngine->SetDisallowSelectionPrint(true); michael@0: } michael@0: if (root && root->HasAttr(kNameSpaceID_None, nsGkAtoms::moznomarginboxes)) { michael@0: PR_PL(("PrintPreview: found moznomarginboxes")); michael@0: mPrintEngine->SetNoMarginBoxes(true); michael@0: } michael@0: rv = mPrintEngine->PrintPreview(aPrintSettings, aChildDOMWin, aWebProgressListener); michael@0: mPrintPreviewZoomed = false; michael@0: if (NS_FAILED(rv)) { michael@0: OnDonePrinting(); michael@0: } michael@0: return rv; michael@0: #else michael@0: return NS_ERROR_FAILURE; michael@0: #endif michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::PrintPreviewNavigate(int16_t aType, int32_t aPageNum) michael@0: { michael@0: if (!GetIsPrintPreview() || michael@0: mPrintEngine->GetIsCreatingPrintPreview()) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: nsIScrollableFrame* sf = michael@0: mPrintEngine->GetPrintPreviewPresShell()->GetRootScrollFrameAsScrollable(); michael@0: if (!sf) michael@0: return NS_OK; michael@0: michael@0: // Check to see if we can short circut scrolling to the top michael@0: if (aType == nsIWebBrowserPrint::PRINTPREVIEW_HOME || michael@0: (aType == nsIWebBrowserPrint::PRINTPREVIEW_GOTO_PAGENUM && aPageNum == 1)) { michael@0: sf->ScrollTo(nsPoint(0, 0), nsIScrollableFrame::INSTANT); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Finds the SimplePageSequencer frame michael@0: // in PP mPrtPreview->mPrintObject->mSeqFrame is null michael@0: nsIFrame* seqFrame = nullptr; michael@0: int32_t pageCount = 0; michael@0: if (NS_FAILED(mPrintEngine->GetSeqFrameAndCountPages(seqFrame, pageCount))) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: // Figure where we are currently scrolled to michael@0: nsPoint pt = sf->GetScrollPosition(); michael@0: michael@0: int32_t pageNum = 1; michael@0: nsIFrame * fndPageFrame = nullptr; michael@0: nsIFrame * currentPage = nullptr; michael@0: michael@0: // If it is "End" then just do a "goto" to the last page michael@0: if (aType == nsIWebBrowserPrint::PRINTPREVIEW_END) { michael@0: aType = nsIWebBrowserPrint::PRINTPREVIEW_GOTO_PAGENUM; michael@0: aPageNum = pageCount; michael@0: } michael@0: michael@0: // Now, locate the current page we are on and michael@0: // and the page of the page number michael@0: nsIFrame* pageFrame = seqFrame->GetFirstPrincipalChild(); michael@0: while (pageFrame != nullptr) { michael@0: nsRect pageRect = pageFrame->GetRect(); michael@0: if (pageRect.Contains(pageRect.x, pt.y)) { michael@0: currentPage = pageFrame; michael@0: } michael@0: if (pageNum == aPageNum) { michael@0: fndPageFrame = pageFrame; michael@0: break; michael@0: } michael@0: pageNum++; michael@0: pageFrame = pageFrame->GetNextSibling(); michael@0: } michael@0: michael@0: if (aType == nsIWebBrowserPrint::PRINTPREVIEW_PREV_PAGE) { michael@0: if (currentPage) { michael@0: fndPageFrame = currentPage->GetPrevInFlow(); michael@0: if (!fndPageFrame) { michael@0: return NS_OK; michael@0: } michael@0: } else { michael@0: return NS_OK; michael@0: } michael@0: } else if (aType == nsIWebBrowserPrint::PRINTPREVIEW_NEXT_PAGE) { michael@0: if (currentPage) { michael@0: fndPageFrame = currentPage->GetNextInFlow(); michael@0: if (!fndPageFrame) { michael@0: return NS_OK; michael@0: } michael@0: } else { michael@0: return NS_OK; michael@0: } michael@0: } else { // If we get here we are doing "GoTo" michael@0: if (aPageNum < 0 || aPageNum > pageCount) { michael@0: return NS_OK; michael@0: } michael@0: } michael@0: michael@0: if (fndPageFrame) { michael@0: nscoord newYPosn = michael@0: nscoord(mPrintEngine->GetPrintPreviewScale() * fndPageFrame->GetPosition().y); michael@0: sf->ScrollTo(nsPoint(pt.x, newYPosn), nsIScrollableFrame::INSTANT); michael@0: } michael@0: return NS_OK; michael@0: michael@0: } michael@0: michael@0: /* readonly attribute nsIPrintSettings globalPrintSettings; */ michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::GetGlobalPrintSettings(nsIPrintSettings * *aGlobalPrintSettings) michael@0: { michael@0: return nsPrintEngine::GetGlobalPrintSettings(aGlobalPrintSettings); michael@0: } michael@0: michael@0: /* readonly attribute boolean doingPrint; */ michael@0: // XXX This always returns false for subdocuments michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::GetDoingPrint(bool *aDoingPrint) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aDoingPrint); michael@0: michael@0: *aDoingPrint = false; michael@0: if (mPrintEngine) { michael@0: // XXX shouldn't this be GetDoingPrint() ? michael@0: return mPrintEngine->GetDoingPrintPreview(aDoingPrint); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute boolean doingPrintPreview; */ michael@0: // XXX This always returns false for subdocuments michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::GetDoingPrintPreview(bool *aDoingPrintPreview) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aDoingPrintPreview); michael@0: michael@0: *aDoingPrintPreview = false; michael@0: if (mPrintEngine) { michael@0: return mPrintEngine->GetDoingPrintPreview(aDoingPrintPreview); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute nsIPrintSettings currentPrintSettings; */ michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::GetCurrentPrintSettings(nsIPrintSettings * *aCurrentPrintSettings) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aCurrentPrintSettings); michael@0: michael@0: *aCurrentPrintSettings = nullptr; michael@0: NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE); michael@0: michael@0: return mPrintEngine->GetCurrentPrintSettings(aCurrentPrintSettings); michael@0: } michael@0: michael@0: michael@0: /* readonly attribute nsIDOMWindow currentChildDOMWindow; */ michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::GetCurrentChildDOMWindow(nsIDOMWindow * *aCurrentChildDOMWindow) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aCurrentChildDOMWindow); michael@0: *aCurrentChildDOMWindow = nullptr; michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: /* void cancel (); */ michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::Cancel() michael@0: { michael@0: NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE); michael@0: return mPrintEngine->Cancelled(); michael@0: } michael@0: michael@0: /* void exitPrintPreview (); */ michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::ExitPrintPreview() michael@0: { michael@0: if (GetIsPrinting()) michael@0: return NS_ERROR_FAILURE; michael@0: NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE); michael@0: michael@0: if (GetIsPrintPreview()) { michael@0: ReturnToGalleyPresentation(); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: //---------------------------------------------------------------------------------- michael@0: // Enumerate all the documents for their titles michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::EnumerateDocumentNames(uint32_t* aCount, michael@0: char16_t*** aResult) michael@0: { michael@0: #ifdef NS_PRINTING michael@0: NS_ENSURE_ARG(aCount); michael@0: NS_ENSURE_ARG_POINTER(aResult); michael@0: NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE); michael@0: michael@0: return mPrintEngine->EnumerateDocumentNames(aCount, aResult); michael@0: #else michael@0: return NS_ERROR_FAILURE; michael@0: #endif michael@0: } michael@0: michael@0: /* readonly attribute boolean isFramesetFrameSelected; */ michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::GetIsFramesetFrameSelected(bool *aIsFramesetFrameSelected) michael@0: { michael@0: #ifdef NS_PRINTING michael@0: *aIsFramesetFrameSelected = false; michael@0: NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE); michael@0: michael@0: return mPrintEngine->GetIsFramesetFrameSelected(aIsFramesetFrameSelected); michael@0: #else michael@0: return NS_ERROR_FAILURE; michael@0: #endif michael@0: } michael@0: michael@0: /* readonly attribute long printPreviewNumPages; */ michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::GetPrintPreviewNumPages(int32_t *aPrintPreviewNumPages) michael@0: { michael@0: #ifdef NS_PRINTING michael@0: NS_ENSURE_ARG_POINTER(aPrintPreviewNumPages); michael@0: NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE); michael@0: michael@0: return mPrintEngine->GetPrintPreviewNumPages(aPrintPreviewNumPages); michael@0: #else michael@0: return NS_ERROR_FAILURE; michael@0: #endif michael@0: } michael@0: michael@0: /* readonly attribute boolean isFramesetDocument; */ michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::GetIsFramesetDocument(bool *aIsFramesetDocument) michael@0: { michael@0: #ifdef NS_PRINTING michael@0: *aIsFramesetDocument = false; michael@0: NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE); michael@0: michael@0: return mPrintEngine->GetIsFramesetDocument(aIsFramesetDocument); michael@0: #else michael@0: return NS_ERROR_FAILURE; michael@0: #endif michael@0: } michael@0: michael@0: /* readonly attribute boolean isIFrameSelected; */ michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::GetIsIFrameSelected(bool *aIsIFrameSelected) michael@0: { michael@0: #ifdef NS_PRINTING michael@0: *aIsIFrameSelected = false; michael@0: NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE); michael@0: michael@0: return mPrintEngine->GetIsIFrameSelected(aIsIFrameSelected); michael@0: #else michael@0: return NS_ERROR_FAILURE; michael@0: #endif michael@0: } michael@0: michael@0: /* readonly attribute boolean isRangeSelection; */ michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::GetIsRangeSelection(bool *aIsRangeSelection) michael@0: { michael@0: #ifdef NS_PRINTING michael@0: *aIsRangeSelection = false; michael@0: NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE); michael@0: michael@0: return mPrintEngine->GetIsRangeSelection(aIsRangeSelection); michael@0: #else michael@0: return NS_ERROR_FAILURE; michael@0: #endif michael@0: } michael@0: michael@0: //---------------------------------------------------------------------------------- michael@0: // Printing/Print Preview Helpers michael@0: //---------------------------------------------------------------------------------- michael@0: michael@0: //---------------------------------------------------------------------------------- michael@0: // Walks the document tree and tells each DocShell whether Printing/PP is happening michael@0: void michael@0: nsDocumentViewer::SetIsPrintingInDocShellTree(nsIDocShellTreeItem* aParentNode, michael@0: bool aIsPrintingOrPP, michael@0: bool aStartAtTop) michael@0: { michael@0: nsCOMPtr parentItem(do_QueryInterface(aParentNode)); michael@0: michael@0: // find top of "same parent" tree michael@0: if (aStartAtTop) { michael@0: if (aIsPrintingOrPP) { michael@0: while (parentItem) { michael@0: nsCOMPtr parent; michael@0: parentItem->GetSameTypeParent(getter_AddRefs(parent)); michael@0: if (!parent) { michael@0: break; michael@0: } michael@0: parentItem = do_QueryInterface(parent); michael@0: } michael@0: mTopContainerWhilePrinting = do_GetWeakReference(parentItem); michael@0: } else { michael@0: parentItem = do_QueryReferent(mTopContainerWhilePrinting); michael@0: } michael@0: } michael@0: michael@0: // Check to see if the DocShell's ContentViewer is printing/PP michael@0: nsCOMPtr viewerContainer(do_QueryInterface(parentItem)); michael@0: if (viewerContainer) { michael@0: viewerContainer->SetIsPrinting(aIsPrintingOrPP); michael@0: } michael@0: michael@0: if (!aParentNode) { michael@0: return; michael@0: } michael@0: michael@0: // Traverse children to see if any of them are printing. michael@0: int32_t n; michael@0: aParentNode->GetChildCount(&n); michael@0: for (int32_t i=0; i < n; i++) { michael@0: nsCOMPtr child; michael@0: aParentNode->GetChildAt(i, getter_AddRefs(child)); michael@0: NS_ASSERTION(child, "child isn't nsIDocShell"); michael@0: if (child) { michael@0: SetIsPrintingInDocShellTree(child, aIsPrintingOrPP, false); michael@0: } michael@0: } michael@0: michael@0: } michael@0: #endif // NS_PRINTING michael@0: michael@0: bool michael@0: nsDocumentViewer::ShouldAttachToTopLevel() michael@0: { michael@0: if (!mParentWidget) michael@0: return false; michael@0: michael@0: nsCOMPtr containerItem(mContainer); michael@0: if (!containerItem) michael@0: return false; michael@0: michael@0: // We always attach when using puppet widgets michael@0: if (nsIWidget::UsePuppetWidgets()) michael@0: return true; michael@0: michael@0: #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) michael@0: // On windows, in the parent process we also attach, but just to michael@0: // chrome items michael@0: nsWindowType winType = mParentWidget->WindowType(); michael@0: if ((winType == eWindowType_toplevel || michael@0: winType == eWindowType_dialog || michael@0: winType == eWindowType_invisible) && michael@0: containerItem->ItemType() == nsIDocShellTreeItem::typeChrome) { michael@0: return true; michael@0: } michael@0: #endif michael@0: michael@0: return false; michael@0: } michael@0: michael@0: bool CollectDocuments(nsIDocument* aDocument, void* aData) michael@0: { michael@0: if (aDocument) { michael@0: static_cast*>(aData)->AppendObject(aDocument); michael@0: aDocument->EnumerateSubDocuments(CollectDocuments, aData); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: nsDocumentViewer::DispatchEventToWindowTree(nsIDocument* aDoc, michael@0: const nsAString& aEvent) michael@0: { michael@0: nsCOMArray targets; michael@0: CollectDocuments(aDoc, &targets); michael@0: for (int32_t i = 0; i < targets.Count(); ++i) { michael@0: nsIDocument* d = targets[i]; michael@0: nsContentUtils::DispatchTrustedEvent(d, d->GetWindow(), michael@0: aEvent, false, false, nullptr); michael@0: } michael@0: } michael@0: michael@0: //------------------------------------------------------------ michael@0: // XXX this always returns false for subdocuments michael@0: bool michael@0: nsDocumentViewer::GetIsPrinting() michael@0: { michael@0: #ifdef NS_PRINTING michael@0: if (mPrintEngine) { michael@0: return mPrintEngine->GetIsPrinting(); michael@0: } michael@0: #endif michael@0: return false; michael@0: } michael@0: michael@0: //------------------------------------------------------------ michael@0: // Notification from the PrintEngine of the current Printing status michael@0: void michael@0: nsDocumentViewer::SetIsPrinting(bool aIsPrinting) michael@0: { michael@0: #ifdef NS_PRINTING michael@0: // Set all the docShells in the docshell tree to be printing. michael@0: // that way if anyone of them tries to "navigate" it can't michael@0: nsCOMPtr docShell(mContainer); michael@0: if (docShell || !aIsPrinting) { michael@0: SetIsPrintingInDocShellTree(docShell, aIsPrinting, true); michael@0: } else { michael@0: NS_WARNING("Did you close a window before printing?"); michael@0: } michael@0: michael@0: if (!aIsPrinting) { michael@0: mBeforeAndAfterPrint = nullptr; michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: //------------------------------------------------------------ michael@0: // The PrintEngine holds the current value michael@0: // this called from inside the DocViewer. michael@0: // XXX it always returns false for subdocuments michael@0: bool michael@0: nsDocumentViewer::GetIsPrintPreview() michael@0: { michael@0: #ifdef NS_PRINTING michael@0: if (mPrintEngine) { michael@0: return mPrintEngine->GetIsPrintPreview(); michael@0: } michael@0: #endif michael@0: return false; michael@0: } michael@0: michael@0: //------------------------------------------------------------ michael@0: // Notification from the PrintEngine of the current PP status michael@0: void michael@0: nsDocumentViewer::SetIsPrintPreview(bool aIsPrintPreview) michael@0: { michael@0: #ifdef NS_PRINTING michael@0: // Set all the docShells in the docshell tree to be printing. michael@0: // that way if anyone of them tries to "navigate" it can't michael@0: nsCOMPtr docShell(mContainer); michael@0: if (docShell || !aIsPrintPreview) { michael@0: SetIsPrintingInDocShellTree(docShell, aIsPrintPreview, true); michael@0: } michael@0: if (!aIsPrintPreview) { michael@0: mBeforeAndAfterPrint = nullptr; michael@0: } michael@0: #endif michael@0: if (!aIsPrintPreview) { michael@0: if (mPresShell) { michael@0: DestroyPresShell(); michael@0: } michael@0: mWindow = nullptr; michael@0: mViewManager = nullptr; michael@0: mPresContext = nullptr; michael@0: mPresShell = nullptr; michael@0: } michael@0: } michael@0: michael@0: //---------------------------------------------------------------------------------- michael@0: // nsIDocumentViewerPrint IFace michael@0: //---------------------------------------------------------------------------------- michael@0: michael@0: //------------------------------------------------------------ michael@0: void michael@0: nsDocumentViewer::IncrementDestroyRefCount() michael@0: { michael@0: ++mDestroyRefCount; michael@0: } michael@0: michael@0: //------------------------------------------------------------ michael@0: michael@0: #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW) michael@0: //------------------------------------------------------------ michael@0: // Reset ESM focus for all descendent doc shells. michael@0: static void michael@0: ResetFocusState(nsIDocShell* aDocShell) michael@0: { michael@0: nsIFocusManager* fm = nsFocusManager::GetFocusManager(); michael@0: if (!fm) michael@0: return; michael@0: michael@0: nsCOMPtr docShellEnumerator; michael@0: aDocShell->GetDocShellEnumerator(nsIDocShellTreeItem::typeContent, michael@0: nsIDocShell::ENUMERATE_FORWARDS, michael@0: getter_AddRefs(docShellEnumerator)); michael@0: michael@0: nsCOMPtr currentContainer; michael@0: bool hasMoreDocShells; michael@0: while (NS_SUCCEEDED(docShellEnumerator->HasMoreElements(&hasMoreDocShells)) michael@0: && hasMoreDocShells) { michael@0: docShellEnumerator->GetNext(getter_AddRefs(currentContainer)); michael@0: nsCOMPtr win = do_GetInterface(currentContainer); michael@0: if (win) michael@0: fm->ClearFocus(win); michael@0: } michael@0: } michael@0: #endif // NS_PRINTING && NS_PRINT_PREVIEW michael@0: michael@0: void michael@0: nsDocumentViewer::ReturnToGalleyPresentation() michael@0: { michael@0: #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW) michael@0: if (!GetIsPrintPreview()) { michael@0: NS_ERROR("Wow, we should never get here!"); michael@0: return; michael@0: } michael@0: michael@0: SetIsPrintPreview(false); michael@0: michael@0: mPrintEngine->TurnScriptingOn(true); michael@0: mPrintEngine->Destroy(); michael@0: mPrintEngine = nullptr; michael@0: michael@0: nsCOMPtr docShell(mContainer); michael@0: ResetFocusState(docShell); michael@0: michael@0: SetTextZoom(mTextZoom); michael@0: SetFullZoom(mPageZoom); michael@0: SetMinFontSize(mMinFontSize); michael@0: Show(); michael@0: michael@0: #endif // NS_PRINTING && NS_PRINT_PREVIEW michael@0: } michael@0: michael@0: //------------------------------------------------------------ michael@0: // This called ONLY when printing has completed and the DV michael@0: // is being notified that it should get rid of the PrintEngine. michael@0: // michael@0: // BUT, if we are in Print Preview then we want to ignore the michael@0: // notification (we do not get rid of the PrintEngine) michael@0: // michael@0: // One small caveat: michael@0: // This IS called from two places in this module for cleaning michael@0: // up when an error occurred during the start up printing michael@0: // and print preview michael@0: // michael@0: void michael@0: nsDocumentViewer::OnDonePrinting() michael@0: { michael@0: #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW) michael@0: if (mPrintEngine) { michael@0: nsRefPtr pe = mPrintEngine; michael@0: if (GetIsPrintPreview()) { michael@0: pe->DestroyPrintingData(); michael@0: } else { michael@0: mPrintEngine = nullptr; michael@0: pe->Destroy(); michael@0: } michael@0: michael@0: // We are done printing, now cleanup michael@0: if (mDeferredWindowClose) { michael@0: mDeferredWindowClose = false; michael@0: nsCOMPtr win = michael@0: do_GetInterface(static_cast(mContainer)); michael@0: if (win) michael@0: win->Close(); michael@0: } else if (mClosingWhilePrinting) { michael@0: if (mDocument) { michael@0: mDocument->SetScriptGlobalObject(nullptr); michael@0: mDocument->Destroy(); michael@0: mDocument = nullptr; michael@0: } michael@0: mClosingWhilePrinting = false; michael@0: } michael@0: } michael@0: #endif // NS_PRINTING && NS_PRINT_PREVIEW michael@0: } michael@0: michael@0: NS_IMETHODIMP nsDocumentViewer::SetPageMode(bool aPageMode, nsIPrintSettings* aPrintSettings) michael@0: { michael@0: // XXX Page mode is only partially working; it's currently used for michael@0: // reftests that require a paginated context michael@0: mIsPageMode = aPageMode; michael@0: michael@0: if (mPresShell) { michael@0: DestroyPresShell(); michael@0: } michael@0: michael@0: if (mPresContext) { michael@0: DestroyPresContext(); michael@0: } michael@0: michael@0: mViewManager = nullptr; michael@0: mWindow = nullptr; michael@0: michael@0: NS_ENSURE_STATE(mDocument); michael@0: if (aPageMode) michael@0: { michael@0: mPresContext = CreatePresContext(mDocument, michael@0: nsPresContext::eContext_PageLayout, FindContainerView()); michael@0: NS_ENSURE_TRUE(mPresContext, NS_ERROR_OUT_OF_MEMORY); michael@0: mPresContext->SetPaginatedScrolling(true); michael@0: mPresContext->SetPrintSettings(aPrintSettings); michael@0: nsresult rv = mPresContext->Init(mDeviceContext); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: } michael@0: InitInternal(mParentWidget, nullptr, mBounds, true, false); michael@0: michael@0: Show(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::GetHistoryEntry(nsISHEntry **aHistoryEntry) michael@0: { michael@0: NS_IF_ADDREF(*aHistoryEntry = mSHEntry); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::GetIsTabModalPromptAllowed(bool *aAllowed) michael@0: { michael@0: *aAllowed = !mHidden; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocumentViewer::GetIsHidden(bool *aHidden) michael@0: { michael@0: *aHidden = mHidden; michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: nsDocumentViewer::DestroyPresShell() michael@0: { michael@0: // Break circular reference (or something) michael@0: mPresShell->EndObservingDocument(); michael@0: michael@0: nsCOMPtr selection; michael@0: GetDocumentSelection(getter_AddRefs(selection)); michael@0: nsCOMPtr selPrivate = do_QueryInterface(selection); michael@0: if (selPrivate && mSelectionListener) michael@0: selPrivate->RemoveSelectionListener(mSelectionListener); michael@0: michael@0: nsAutoScriptBlocker scriptBlocker; michael@0: mPresShell->Destroy(); michael@0: mPresShell = nullptr; michael@0: } michael@0: michael@0: void michael@0: nsDocumentViewer::DestroyPresContext() michael@0: { michael@0: mPresContext->Detach(); michael@0: mPresContext = nullptr; michael@0: } michael@0: michael@0: bool michael@0: nsDocumentViewer::IsInitializedForPrintPreview() michael@0: { michael@0: return mInitializedForPrintPreview; michael@0: } michael@0: michael@0: void michael@0: nsDocumentViewer::InitializeForPrintPreview() michael@0: { michael@0: mInitializedForPrintPreview = true; michael@0: } michael@0: michael@0: void michael@0: nsDocumentViewer::SetPrintPreviewPresentation(nsViewManager* aViewManager, michael@0: nsPresContext* aPresContext, michael@0: nsIPresShell* aPresShell) michael@0: { michael@0: if (mPresShell) { michael@0: DestroyPresShell(); michael@0: } michael@0: michael@0: mWindow = nullptr; michael@0: mViewManager = aViewManager; michael@0: mPresContext = aPresContext; michael@0: mPresShell = aPresShell; michael@0: } michael@0: michael@0: // Fires the "document-shown" event so that interested parties are aware of it. michael@0: NS_IMETHODIMP michael@0: nsDocumentShownDispatcher::Run() michael@0: { michael@0: nsCOMPtr observerService = michael@0: mozilla::services::GetObserverService(); michael@0: if (observerService) { michael@0: observerService->NotifyObservers(mDocument, "document-shown", nullptr); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: