Bug 54488 - "[Mac] Non-draggable widgets in background windows should look disabled...
[mozilla-central.git] / layout / base / nsDocumentViewer.cpp
blobf0a8b1080834d5ae025891b442cf8d55c5560203
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 sw=2 et tw=80: */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is Mozilla Communicator client code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
24 * Dan Rosen <dr@netscape.com>
25 * Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
26 * Mats Palmgren <mats.palmgren@bredband.net>
28 * Alternatively, the contents of this file may be used under the terms of
29 * either of the GNU General Public License Version 2 or later (the "GPL"),
30 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 * in which case the provisions of the GPL or the LGPL are applicable instead
32 * of those above. If you wish to allow use of your version of this file only
33 * under the terms of either the GPL or the LGPL, and not to allow others to
34 * use your version of this file under the terms of the MPL, indicate your
35 * decision by deleting the provisions above and replace them with the notice
36 * and other provisions required by the GPL or the LGPL. If you do not delete
37 * the provisions above, a recipient may use your version of this file under
38 * the terms of any one of the MPL, the GPL or the LGPL.
40 * ***** END LICENSE BLOCK ***** */
42 /* container for a document and its presentation */
44 #include "nscore.h"
45 #include "nsCOMPtr.h"
46 #include "nsCRT.h"
47 #include "nsString.h"
48 #include "nsReadableUtils.h"
49 #include "nsISupports.h"
50 #include "nsIContent.h"
51 #include "nsIContentViewerContainer.h"
52 #include "nsIDocumentViewer.h"
53 #include "nsIDocumentViewerPrint.h"
55 #include "nsIDocument.h"
56 #include "nsPresContext.h"
57 #include "nsIPresShell.h"
58 #include "nsIEventStateManager.h"
59 #include "nsStyleSet.h"
60 #include "nsIStyleSheet.h"
61 #include "nsICSSStyleSheet.h"
62 #include "nsIFrame.h"
64 #include "nsILinkHandler.h"
65 #include "nsIDOMDocument.h"
66 #include "nsISelectionListener.h"
67 #include "nsISelectionPrivate.h"
68 #include "nsIDOMHTMLDocument.h"
69 #include "nsIDOMNSHTMLDocument.h"
70 #include "nsIDOMHTMLCollection.h"
71 #include "nsIDOMHTMLElement.h"
72 #include "nsIDOMRange.h"
73 #include "nsContentCID.h"
74 #include "nsLayoutCID.h"
75 #include "nsContentUtils.h"
76 #include "nsLayoutStylesheetCache.h"
78 #include "nsViewsCID.h"
79 #include "nsWidgetsCID.h"
80 #include "nsIDeviceContext.h"
81 #include "nsIDeviceContextSpec.h"
82 #include "nsIViewManager.h"
83 #include "nsIView.h"
85 #include "nsIPageSequenceFrame.h"
86 #include "nsIURL.h"
87 #include "nsNetUtil.h"
88 #include "nsIContentViewerEdit.h"
89 #include "nsIContentViewerFile.h"
90 #include "nsICSSLoader.h"
91 #include "nsIMarkupDocumentViewer.h"
92 #include "nsIInterfaceRequestor.h"
93 #include "nsIInterfaceRequestorUtils.h"
94 #include "nsIDocShellTreeItem.h"
95 #include "nsIDocShellTreeNode.h"
96 #include "nsIDocShellTreeOwner.h"
97 #include "nsIDocShell.h"
98 #include "nsIBaseWindow.h"
99 #include "nsIFrameDebug.h"
100 #include "nsILayoutHistoryState.h"
101 #include "nsIParser.h"
102 #include "nsGUIEvent.h"
103 #include "nsHTMLReflowState.h"
104 #include "nsIDOMHTMLAnchorElement.h"
105 #include "nsIDOMHTMLAreaElement.h"
106 #include "nsIDOMHTMLLinkElement.h"
107 #include "nsIImageLoadingContent.h"
108 #include "nsCopySupport.h"
109 #include "nsIDOMHTMLFrameSetElement.h"
110 #ifdef MOZ_XUL
111 #include "nsIXULDocument.h"
112 #include "nsXULPopupManager.h"
113 #endif
114 #include "nsPrintfCString.h"
116 #include "nsIClipboardHelper.h"
118 #include "nsPIDOMWindow.h"
119 #include "nsJSEnvironment.h"
120 #include "nsIFocusController.h"
121 #include "nsIMenuParent.h"
123 #include "nsIScrollableView.h"
124 #include "nsIHTMLDocument.h"
125 #include "nsITimelineService.h"
126 #include "nsGfxCIID.h"
127 #include "nsStyleSheetService.h"
129 #include "nsIPrompt.h"
130 #include "imgIContainer.h" // image animation mode constants
132 //--------------------------
133 // Printing Include
134 //---------------------------
135 #ifdef NS_PRINTING
137 #include "nsIWebBrowserPrint.h"
139 #include "nsPrintEngine.h"
141 // Print Options
142 #include "nsIPrintSettings.h"
143 #include "nsIPrintSettingsService.h"
144 #include "nsIPrintOptions.h"
145 #include "nsIServiceManager.h"
146 #include "nsISimpleEnumerator.h"
147 #include "nsXPCOM.h"
148 #include "nsISupportsPrimitives.h"
150 // PrintOptions is now implemented by PrintSettingsService
151 static const char sPrintOptionsContractID[] = "@mozilla.org/gfx/printsettings-service;1";
153 // Printing Events
154 #include "nsPrintPreviewListener.h"
156 #include "nsIDOMHTMLFrameElement.h"
157 #include "nsIDOMHTMLIFrameElement.h"
158 #include "nsIDOMHTMLObjectElement.h"
159 #include "nsIPluginDocument.h"
161 // Print Progress
162 #include "nsIPrintProgress.h"
163 #include "nsIPrintProgressParams.h"
165 // Print error dialog
166 #include "nsIWindowWatcher.h"
168 // Printing
169 #include "nsPrintEngine.h"
170 #include "nsPagePrintTimer.h"
172 #endif // NS_PRINTING
174 // FrameSet
175 #include "nsIDocument.h"
177 //focus
178 #include "nsIDOMEventTarget.h"
179 #include "nsIDOMFocusListener.h"
180 #include "nsISelectionController.h"
182 #include "nsBidiUtils.h"
183 #include "nsISHEntry.h"
184 #include "nsISHistory.h"
185 #include "nsISHistoryInternal.h"
186 #include "nsIWebNavigation.h"
187 #include "nsWeakPtr.h"
188 #include "nsEventDispatcher.h"
189 #include "nsPresShellIterator.h"
191 //paint forcing
192 #include "prenv.h"
193 #include <stdio.h>
195 //switch to page layout
196 #include "nsGfxCIID.h"
198 #ifdef NS_DEBUG
200 #undef NOISY_VIEWER
201 #else
202 #undef NOISY_VIEWER
203 #endif
205 //-----------------------------------------------------
206 // PR LOGGING
207 #ifdef MOZ_LOGGING
208 #define FORCE_PR_LOG /* Allow logging in the release build */
209 #endif
211 #include "prlog.h"
213 #ifdef PR_LOGGING
215 static PRLogModuleInfo * kPrintingLogMod = PR_NewLogModule("printing");
216 #define PR_PL(_p1) PR_LOG(kPrintingLogMod, PR_LOG_DEBUG, _p1);
218 #define PRT_YESNO(_p) ((_p)?"YES":"NO")
219 #else
220 #define PRT_YESNO(_p)
221 #define PR_PL(_p1)
222 #endif
223 //-----------------------------------------------------
225 class DocumentViewerImpl;
227 // a small delegate class used to avoid circular references
229 #ifdef XP_MAC
230 #pragma mark ** nsDocViewerSelectionListener **
231 #endif
233 class nsDocViewerSelectionListener : public nsISelectionListener
235 public:
237 // nsISupports interface...
238 NS_DECL_ISUPPORTS
240 // nsISelectionListerner interface
241 NS_DECL_NSISELECTIONLISTENER
243 nsDocViewerSelectionListener()
244 : mDocViewer(NULL)
245 , mGotSelectionState(PR_FALSE)
246 , mSelectionWasCollapsed(PR_FALSE)
250 virtual ~nsDocViewerSelectionListener() {}
252 nsresult Init(DocumentViewerImpl *aDocViewer);
254 protected:
256 DocumentViewerImpl* mDocViewer;
257 PRPackedBool mGotSelectionState;
258 PRPackedBool mSelectionWasCollapsed;
263 /** editor Implementation of the FocusListener interface
265 class nsDocViewerFocusListener : public nsIDOMFocusListener
267 public:
268 /** default constructor
270 nsDocViewerFocusListener();
271 /** default destructor
273 virtual ~nsDocViewerFocusListener();
276 /*interfaces for addref and release and queryinterface*/
277 NS_DECL_ISUPPORTS
279 /*BEGIN implementations of focus event handler interface*/
280 NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
281 NS_IMETHOD Focus(nsIDOMEvent* aEvent);
282 NS_IMETHOD Blur(nsIDOMEvent* aEvent);
283 /*END implementations of focus event handler interface*/
284 nsresult Init(DocumentViewerImpl *aDocViewer);
286 private:
287 DocumentViewerImpl* mDocViewer;
292 #ifdef XP_MAC
293 #pragma mark ** DocumentViewerImpl **
294 #endif
296 //-------------------------------------------------------------
297 class DocumentViewerImpl : public nsIDocumentViewer,
298 public nsIContentViewerEdit,
299 public nsIContentViewerFile,
300 public nsIMarkupDocumentViewer,
301 public nsIDocumentViewerPrint
303 #ifdef NS_PRINTING
304 , public nsIWebBrowserPrint
305 #endif
308 friend class nsDocViewerSelectionListener;
309 friend class nsPagePrintTimer;
310 friend class nsPrintEngine;
312 public:
313 DocumentViewerImpl();
315 NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
317 // nsISupports interface...
318 NS_DECL_ISUPPORTS
320 // nsIContentViewer interface...
321 NS_DECL_NSICONTENTVIEWER
323 // nsIDocumentViewer interface...
324 NS_IMETHOD SetUAStyleSheet(nsIStyleSheet* aUAStyleSheet);
325 NS_IMETHOD GetDocument(nsIDocument** aResult);
326 NS_IMETHOD GetPresShell(nsIPresShell** aResult);
327 NS_IMETHOD GetPresContext(nsPresContext** aResult);
329 // nsIContentViewerEdit
330 NS_DECL_NSICONTENTVIEWEREDIT
332 // nsIContentViewerFile
333 NS_DECL_NSICONTENTVIEWERFILE
335 // nsIMarkupDocumentViewer
336 NS_DECL_NSIMARKUPDOCUMENTVIEWER
338 #ifdef NS_PRINTING
339 // nsIWebBrowserPrint
340 NS_DECL_NSIWEBBROWSERPRINT
341 #endif
343 typedef void (*CallChildFunc)(nsIMarkupDocumentViewer* aViewer,
344 void* aClosure);
345 void CallChildren(CallChildFunc aFunc, void* aClosure);
347 // nsIDocumentViewerPrint Printing Methods
348 NS_DECL_NSIDOCUMENTVIEWERPRINT
350 protected:
351 virtual ~DocumentViewerImpl();
353 private:
355 * Creates a view manager, root view, and widget for the root view, setting
356 * mViewManager and mWindow.
357 * @param aSize the initial size in appunits
359 nsresult MakeWindow(const nsSize& aSize);
362 * Create our device context
364 nsresult CreateDeviceContext(nsIWidget* aWidget);
367 * Make sure to set up mDeviceContext as needed before calling this
369 nsresult InitInternal(nsIWidget* aParentWidget,
370 nsISupports *aState,
371 const nsRect& aBounds,
372 PRBool aDoCreation,
373 PRBool aInPrintPreview,
374 PRBool aNeedMakeCX = PR_TRUE);
376 * @param aDoInitialReflow set to true if you want to kick off the initial
377 * reflow
378 * @param aReenableRefresh set to true if you want this to reenable refresh
379 * before returning; otherwise this will return with refresh disabled
380 * in the view manager
382 nsresult InitPresentationStuff(PRBool aDoInitialReflow, PRBool aReenableRefresh);
384 nsresult GetPopupNode(nsIDOMNode** aNode);
385 nsresult GetPopupLinkNode(nsIDOMNode** aNode);
386 nsresult GetPopupImageNode(nsIImageLoadingContent** aNode);
388 void PrepareToStartLoad(void);
390 nsresult SyncParentSubDocMap();
392 nsresult GetDocumentSelection(nsISelection **aSelection);
394 nsresult GetClipboardEventTarget(nsIDOMNode **aEventTarget);
395 nsresult FireClipboardEvent(PRUint32 msg, PRBool* aPreventDefault);
397 #ifdef NS_PRINTING
398 // Called when the DocViewer is notified that the state
399 // of Printing or PP has changed
400 void SetIsPrintingInDocShellTree(nsIDocShellTreeNode* aParentNode,
401 PRBool aIsPrintingOrPP,
402 PRBool aStartAtTop);
403 #endif // NS_PRINTING
405 protected:
406 // These return the current shell/prescontext etc.
407 nsIPresShell* GetPresShell();
408 nsPresContext* GetPresContext();
409 nsIViewManager* GetViewManager();
411 // IMPORTANT: The ownership implicit in the following member
412 // variables has been explicitly checked and set using nsCOMPtr
413 // for owning pointers and raw COM interface pointers for weak
414 // (ie, non owning) references. If you add any members to this
415 // class, please make the ownership explicit (pinkerton, scc).
417 nsWeakPtr mContainer; // it owns me!
418 nsCOMPtr<nsIDeviceContext> mDeviceContext; // We create and own this baby
420 // the following six items are explicitly in this order
421 // so they will be destroyed in the reverse order (pinkerton, scc)
422 nsCOMPtr<nsIDocument> mDocument;
423 nsCOMPtr<nsIWidget> mWindow; // ??? should we really own it?
424 nsCOMPtr<nsIViewManager> mViewManager;
425 nsCOMPtr<nsPresContext> mPresContext;
426 nsCOMPtr<nsIPresShell> mPresShell;
428 nsCOMPtr<nsIStyleSheet> mUAStyleSheet;
430 nsCOMPtr<nsISelectionListener> mSelectionListener;
431 nsCOMPtr<nsIDOMFocusListener> mFocusListener;
433 nsCOMPtr<nsIContentViewer> mPreviousViewer;
434 nsCOMPtr<nsISHEntry> mSHEntry;
436 nsIWidget* mParentWidget; // purposely won't be ref counted
438 // mTextZoom/mPageZoom record the textzoom/pagezoom of the first (galley)
439 // presshell only.
440 float mTextZoom; // Text zoom, defaults to 1.0
441 float mPageZoom;
443 PRInt16 mNumURLStarts;
444 PRInt16 mDestroyRefCount; // a second "refcount" for the document viewer's "destroy"
446 unsigned mEnableRendering : 1;
447 unsigned mStopped : 1;
448 unsigned mLoaded : 1;
449 unsigned mDeferredWindowClose : 1;
450 // document management data
451 // these items are specific to markup documents (html and xml)
452 // may consider splitting these out into a subclass
453 unsigned mIsSticky : 1;
454 unsigned mInPermitUnload : 1;
456 #ifdef NS_PRINTING
457 unsigned mClosingWhilePrinting : 1;
459 #if NS_PRINT_PREVIEW
460 // These data members support delayed printing when the document is loading
461 unsigned mPrintIsPending : 1;
462 unsigned mPrintDocIsFullyLoaded : 1;
463 nsCOMPtr<nsIPrintSettings> mCachedPrintSettings;
464 nsCOMPtr<nsIWebProgressListener> mCachedPrintWebProgressListner;
466 nsCOMPtr<nsPrintEngine> mPrintEngine;
467 #endif // NS_PRINT_PREVIEW
469 #ifdef NS_DEBUG
470 FILE* mDebugFile;
471 #endif // NS_DEBUG
472 #endif // NS_PRINTING
474 /* character set member data */
475 PRInt32 mHintCharsetSource;
476 nsCString mHintCharset;
477 nsCString mDefaultCharacterSet;
478 nsCString mForceCharacterSet;
479 nsCString mPrevDocCharacterSet;
481 PRPackedBool mIsPageMode;
485 //------------------------------------------------------------------
486 // DocumentViewerImpl
487 //------------------------------------------------------------------
488 // Class IDs
489 static NS_DEFINE_CID(kViewManagerCID, NS_VIEW_MANAGER_CID);
490 static NS_DEFINE_CID(kWidgetCID, NS_CHILD_CID);
491 static NS_DEFINE_CID(kDeviceContextCID, NS_DEVICE_CONTEXT_CID);
493 //------------------------------------------------------------------
494 nsresult
495 NS_NewDocumentViewer(nsIDocumentViewer** aResult)
497 *aResult = new DocumentViewerImpl();
498 if (!*aResult) {
499 return NS_ERROR_OUT_OF_MEMORY;
502 NS_ADDREF(*aResult);
504 return NS_OK;
507 void DocumentViewerImpl::PrepareToStartLoad()
509 mEnableRendering = PR_TRUE;
510 mStopped = PR_FALSE;
511 mLoaded = PR_FALSE;
512 mDeferredWindowClose = PR_FALSE;
514 #ifdef NS_PRINTING
515 mPrintIsPending = PR_FALSE;
516 mPrintDocIsFullyLoaded = PR_FALSE;
517 mClosingWhilePrinting = PR_FALSE;
519 // Make sure we have destroyed it and cleared the data member
520 if (mPrintEngine) {
521 mPrintEngine->Destroy();
522 mPrintEngine = nsnull;
525 #ifdef NS_PRINT_PREVIEW
526 SetIsPrintPreview(PR_FALSE);
527 #endif
529 #ifdef NS_DEBUG
530 mDebugFile = nsnull;
531 #endif
533 #endif // NS_PRINTING
536 // Note: operator new zeros our memory, so no need to init things to null.
537 DocumentViewerImpl::DocumentViewerImpl()
538 : mTextZoom(1.0), mPageZoom(1.0),
539 mIsSticky(PR_TRUE),
540 mHintCharsetSource(kCharsetUninitialized)
542 PrepareToStartLoad();
545 NS_IMPL_ADDREF(DocumentViewerImpl)
546 NS_IMPL_RELEASE(DocumentViewerImpl)
548 NS_INTERFACE_MAP_BEGIN(DocumentViewerImpl)
549 NS_INTERFACE_MAP_ENTRY(nsIContentViewer)
550 NS_INTERFACE_MAP_ENTRY(nsIDocumentViewer)
551 NS_INTERFACE_MAP_ENTRY(nsIMarkupDocumentViewer)
552 NS_INTERFACE_MAP_ENTRY(nsIContentViewerFile)
553 NS_INTERFACE_MAP_ENTRY(nsIContentViewerEdit)
554 NS_INTERFACE_MAP_ENTRY(nsIDocumentViewerPrint)
555 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentViewer)
556 #ifdef NS_PRINTING
557 NS_INTERFACE_MAP_ENTRY(nsIWebBrowserPrint)
558 #endif
559 NS_INTERFACE_MAP_END
561 DocumentViewerImpl::~DocumentViewerImpl()
563 if (mDocument) {
564 Close(nsnull);
565 mDocument->Destroy();
568 NS_ASSERTION(!mPresShell && !mPresContext,
569 "User did not call nsIContentViewer::Destroy");
570 if (mPresShell || mPresContext) {
571 // Make sure we don't hand out a reference to the content viewer to
572 // the SHEntry!
573 mSHEntry = nsnull;
575 Destroy();
578 // XXX(?) Revoke pending invalidate events
582 * This method is called by the Document Loader once a document has
583 * been created for a particular data stream... The content viewer
584 * must cache this document for later use when Init(...) is called.
586 * This method is also called when an out of band document.write() happens.
587 * In that case, the document passed in is the same as the previous document.
589 NS_IMETHODIMP
590 DocumentViewerImpl::LoadStart(nsISupports *aDoc)
592 #ifdef NOISY_VIEWER
593 printf("DocumentViewerImpl::LoadStart\n");
594 #endif
596 nsresult rv = NS_OK;
597 if (!mDocument) {
598 mDocument = do_QueryInterface(aDoc, &rv);
600 else if (mDocument == aDoc) {
601 // Reset the document viewer's state back to what it was
602 // when the document load started.
603 PrepareToStartLoad();
606 return rv;
609 nsresult
610 DocumentViewerImpl::SyncParentSubDocMap()
612 nsCOMPtr<nsIDocShellTreeItem> item(do_QueryReferent(mContainer));
613 nsCOMPtr<nsPIDOMWindow> pwin(do_GetInterface(item));
614 nsCOMPtr<nsIContent> content;
616 if (mDocument && pwin) {
617 content = do_QueryInterface(pwin->GetFrameElementInternal());
620 if (content) {
621 nsCOMPtr<nsIDocShellTreeItem> parent;
622 item->GetParent(getter_AddRefs(parent));
624 nsCOMPtr<nsIDOMWindow> parent_win(do_GetInterface(parent));
626 if (parent_win) {
627 nsCOMPtr<nsIDOMDocument> dom_doc;
628 parent_win->GetDocument(getter_AddRefs(dom_doc));
630 nsCOMPtr<nsIDocument> parent_doc(do_QueryInterface(dom_doc));
632 if (parent_doc) {
633 return parent_doc->SetSubDocumentFor(content, mDocument);
638 return NS_OK;
641 NS_IMETHODIMP
642 DocumentViewerImpl::SetContainer(nsISupports* aContainer)
644 mContainer = do_GetWeakReference(aContainer);
645 if (mPresContext) {
646 mPresContext->SetContainer(aContainer);
649 // We're loading a new document into the window where this document
650 // viewer lives, sync the parent document's frame element -> sub
651 // document map
653 return SyncParentSubDocMap();
656 NS_IMETHODIMP
657 DocumentViewerImpl::GetContainer(nsISupports** aResult)
659 NS_ENSURE_ARG_POINTER(aResult);
661 *aResult = nsnull;
662 nsCOMPtr<nsISupports> container = do_QueryReferent(mContainer);
663 container.swap(*aResult);
664 return NS_OK;
667 NS_IMETHODIMP
668 DocumentViewerImpl::Init(nsIWidget* aParentWidget,
669 const nsRect& aBounds)
671 nsresult rv = CreateDeviceContext(aParentWidget);
672 NS_ENSURE_SUCCESS(rv, rv);
674 return InitInternal(aParentWidget, nsnull, aBounds, PR_TRUE, PR_FALSE);
677 nsresult
678 DocumentViewerImpl::InitPresentationStuff(PRBool aDoInitialReflow, PRBool aReenableRefresh)
680 // Create the style set...
681 nsStyleSet *styleSet;
682 nsresult rv = CreateStyleSet(mDocument, &styleSet);
683 NS_ENSURE_SUCCESS(rv, rv);
685 // Now make the shell for the document
686 rv = mDocument->CreateShell(mPresContext, mViewManager, styleSet,
687 getter_AddRefs(mPresShell));
688 if (NS_FAILED(rv)) {
689 delete styleSet;
690 return rv;
693 // We're done creating the style set
694 styleSet->EndUpdate();
696 if (aDoInitialReflow) {
697 // Since InitialReflow() will create frames for *all* items
698 // that are currently in the document tree, we need to flush
699 // any pending notifications to prevent the content sink from
700 // duplicating layout frames for content it has added to the tree
701 // but hasn't notified the document about. (Bug 154018)
703 // Note that we are flushing before we add mPresShell as an observer
704 // to avoid bogus notifications.
706 mDocument->FlushPendingNotifications(Flush_ContentAndNotify);
709 mPresShell->BeginObservingDocument();
711 // Initialize our view manager
712 nsRect bounds;
713 mWindow->GetBounds(bounds);
715 nscoord width = mPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel() * bounds.width;
716 nscoord height = mPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel() * bounds.height;
718 mViewManager->DisableRefresh();
719 mViewManager->SetWindowDimensions(width, height);
720 mPresContext->SetTextZoom(mTextZoom);
721 mPresContext->SetFullZoom(mPageZoom);
723 // Setup default view manager background color
725 // This may be overridden by the docshell with the background color
726 // for the last document loaded into the docshell
727 mViewManager->SetDefaultBackgroundColor(mPresContext->DefaultBackgroundColor());
729 if (aDoInitialReflow) {
730 nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(mDocument);
731 if (htmlDoc) {
732 nsCOMPtr<nsIDOMHTMLFrameSetElement> frameset =
733 do_QueryInterface(mDocument->GetRootContent());
734 htmlDoc->SetIsFrameset(frameset != nsnull);
737 nsCOMPtr<nsIPresShell> shellGrip = mPresShell;
738 // Initial reflow
739 mPresShell->InitialReflow(width, height);
740 } else {
741 // Store the visible area so it's available for other callers of
742 // InitialReflow, like nsContentSink::StartLayout.
743 mPresContext->SetVisibleArea(nsRect(0, 0, width, height));
746 // Now trigger a refresh
747 if (aReenableRefresh && mEnableRendering && mViewManager) {
748 mViewManager->EnableRefresh(NS_VMREFRESH_IMMEDIATE);
751 // now register ourselves as a selection listener, so that we get
752 // called when the selection changes in the window
753 nsDocViewerSelectionListener *selectionListener =
754 new nsDocViewerSelectionListener();
755 NS_ENSURE_TRUE(selectionListener, NS_ERROR_OUT_OF_MEMORY);
757 selectionListener->Init(this);
759 // mSelectionListener is a owning reference
760 mSelectionListener = selectionListener;
762 nsCOMPtr<nsISelection> selection;
763 rv = GetDocumentSelection(getter_AddRefs(selection));
764 NS_ENSURE_SUCCESS(rv, rv);
766 nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(selection));
767 rv = selPrivate->AddSelectionListener(mSelectionListener);
768 if (NS_FAILED(rv))
769 return rv;
771 // Save old listener so we can unregister it
772 nsCOMPtr<nsIDOMFocusListener> oldFocusListener = mFocusListener;
774 // focus listener
776 // now register ourselves as a focus listener, so that we get called
777 // when the focus changes in the window
778 nsDocViewerFocusListener *focusListener;
779 NS_NEWXPCOM(focusListener, nsDocViewerFocusListener);
780 NS_ENSURE_TRUE(focusListener, NS_ERROR_OUT_OF_MEMORY);
782 focusListener->Init(this);
784 // mFocusListener is a strong reference
785 mFocusListener = focusListener;
787 if (mDocument) {
788 rv = mDocument->AddEventListenerByIID(mFocusListener,
789 NS_GET_IID(nsIDOMFocusListener));
790 NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register focus listener");
791 if (oldFocusListener) {
792 rv = mDocument->RemoveEventListenerByIID(oldFocusListener,
793 NS_GET_IID(nsIDOMFocusListener));
794 NS_ASSERTION(NS_SUCCEEDED(rv), "failed to remove focus listener");
798 return NS_OK;
801 //-----------------------------------------------
802 // This method can be used to initial the "presentation"
803 // The aDoCreation indicates whether it should create
804 // all the new objects or just initialize the existing ones
805 nsresult
806 DocumentViewerImpl::InitInternal(nsIWidget* aParentWidget,
807 nsISupports *aState,
808 const nsRect& aBounds,
809 PRBool aDoCreation,
810 PRBool aInPrintPreview,
811 PRBool aNeedMakeCX /*= PR_TRUE*/)
813 mParentWidget = aParentWidget; // not ref counted
815 nsresult rv = NS_OK;
816 NS_ENSURE_TRUE(mDocument, NS_ERROR_NULL_POINTER);
818 PRBool makeCX = PR_FALSE;
819 if (aDoCreation) {
820 if (aParentWidget && !mPresContext) {
821 // Create presentation context
822 if (mIsPageMode) {
823 //Presentation context already created in SetPageMode which is calling this method
825 else
826 mPresContext =
827 new nsPresContext(mDocument, nsPresContext::eContext_Galley);
828 NS_ENSURE_TRUE(mPresContext, NS_ERROR_OUT_OF_MEMORY);
830 nsresult rv = mPresContext->Init(mDeviceContext);
831 if (NS_FAILED(rv)) {
832 mPresContext = nsnull;
833 return rv;
836 #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
837 makeCX = !GetIsPrintPreview() && aNeedMakeCX; // needs to be true except when we are already in PP or we are enabling/disabling paginated mode.
838 #else
839 makeCX = PR_TRUE;
840 #endif
843 if (mPresContext) {
844 // Create the ViewManager and Root View...
846 // We must do this before we tell the script global object about
847 // this new document since doing that will cause us to re-enter
848 // into nsSubDocumentFrame code through reflows caused by
849 // FlushPendingNotifications() calls down the road...
851 rv = MakeWindow(nsSize(mPresContext->DevPixelsToAppUnits(aBounds.width),
852 mPresContext->DevPixelsToAppUnits(aBounds.height)));
853 NS_ENSURE_SUCCESS(rv, rv);
854 Hide();
856 #ifdef NS_PRINT_PREVIEW
857 if (mIsPageMode) {
858 // I'm leaving this in a broken state for the moment; we should
859 // be measuring/scaling with the print device context, not the
860 // screen device context, but this is good enough to allow
861 // printing reftests to work.
862 #if 0
863 nsCOMPtr<nsIDeviceContextSpec> devspec =
864 do_CreateInstance("@mozilla.org/gfx/devicecontextspec;1", &rv);
865 NS_ENSURE_SUCCESS(rv, rv);
866 // mWindow has been initialized by preceding call to MakeWindow
867 rv = devspec->Init(mWindow, mPresContext->GetPrintSettings(), PR_FALSE);
868 NS_ENSURE_SUCCESS(rv, rv);
869 nsCOMPtr<nsIDeviceContext> devctx =
870 do_CreateInstance("@mozilla.org/gfx/devicecontext;1", &rv);
871 NS_ENSURE_SUCCESS(rv, rv);
872 rv = devctx->InitForPrinting(devspec);
873 NS_ENSURE_SUCCESS(rv, rv);
874 // XXX I'm breaking this code; I'm not sure I really want to mess with
875 // the document viewer at the moment to get the right device context
876 // (this won't break anyone, since page layout mode was never really
877 // usable)
878 #endif
879 double pageWidth = 0, pageHeight = 0;
880 mPresContext->GetPrintSettings()->GetEffectivePageSize(&pageWidth,
881 &pageHeight);
882 mPresContext->SetPageSize(
883 nsSize(mPresContext->TwipsToAppUnits(NSToIntFloor(pageWidth)),
884 mPresContext->TwipsToAppUnits(NSToIntFloor(pageHeight))));
885 mPresContext->SetIsRootPaginatedDocument(PR_TRUE);
886 mPresContext->SetPageScale(1.0f);
888 #endif
892 nsCOMPtr<nsIInterfaceRequestor> requestor(do_QueryReferent(mContainer));
893 if (requestor) {
894 if (mPresContext) {
895 nsCOMPtr<nsILinkHandler> linkHandler;
896 requestor->GetInterface(NS_GET_IID(nsILinkHandler),
897 getter_AddRefs(linkHandler));
899 mPresContext->SetContainer(requestor);
900 mPresContext->SetLinkHandler(linkHandler);
903 if (!aInPrintPreview) {
904 // Set script-context-owner in the document
906 nsCOMPtr<nsPIDOMWindow> window;
907 requestor->GetInterface(NS_GET_IID(nsPIDOMWindow),
908 getter_AddRefs(window));
910 if (window) {
911 window->SetNewDocument(mDocument, aState, PR_TRUE);
913 nsJSContext::LoadStart();
918 if (aDoCreation && mPresContext) {
919 // The ViewManager and Root View was created above (in
920 // MakeWindow())...
922 rv = InitPresentationStuff(!makeCX, !makeCX);
925 return rv;
929 // LoadComplete(aStatus)
931 // aStatus - The status returned from loading the document.
933 // This method is called by the container when the document has been
934 // completely loaded.
936 NS_IMETHODIMP
937 DocumentViewerImpl::LoadComplete(nsresult aStatus)
939 /* We need to protect ourself against auto-destruction in case the
940 window is closed while processing the OnLoad event. See bug
941 http://bugzilla.mozilla.org/show_bug.cgi?id=78445 for more
942 explanation.
944 nsCOMPtr<nsIDocumentViewer> kungFuDeathGrip(this);
946 // Flush out layout so it's up-to-date by the time onload is called.
947 // Note that this could destroy the window, so do this before
948 // checking for our mDocument and its window.
949 if (mPresShell && !mStopped) {
950 // Hold strong ref because this could conceivably run script
951 nsCOMPtr<nsIPresShell> shell = mPresShell;
952 shell->FlushPendingNotifications(Flush_Layout);
955 nsresult rv = NS_OK;
956 NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
958 // First, get the window from the document...
959 nsPIDOMWindow *window = mDocument->GetWindow();
961 // Fail if no window is available...
962 NS_ENSURE_TRUE(window, NS_ERROR_NULL_POINTER);
964 mLoaded = PR_TRUE;
966 // Now, fire either an OnLoad or OnError event to the document...
967 PRBool restoring = PR_FALSE;
968 if(NS_SUCCEEDED(aStatus)) {
969 nsEventStatus status = nsEventStatus_eIgnore;
970 nsEvent event(PR_TRUE, NS_LOAD);
971 event.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
972 // XXX Dispatching to |window|, but using |document| as the target.
973 event.target = mDocument;
975 // If the document presentation is being restored, we don't want to fire
976 // onload to the document content since that would likely confuse scripts
977 // on the page.
979 nsIDocShell *docShell = window->GetDocShell();
980 NS_ENSURE_TRUE(docShell, NS_ERROR_UNEXPECTED);
982 docShell->GetRestoringDocument(&restoring);
983 if (!restoring) {
984 nsEventDispatcher::Dispatch(window, mPresContext, &event, nsnull,
985 &status);
986 #ifdef MOZ_TIMELINE
987 // if navigator.xul's load is complete, the main nav window is visible
988 // mark that point.
990 //printf("DEBUG: getting uri from document (%p)\n", mDocument.get());
992 nsIURI *uri = mDocument ? mDocument->GetDocumentURI() : nsnull;
994 if (uri) {
995 //printf("DEBUG: getting spec for uri (%p)\n", uri.get());
996 nsCAutoString spec;
997 uri->GetSpec(spec);
998 if (spec.EqualsLiteral("chrome://navigator/content/navigator.xul") ||
999 spec.EqualsLiteral("chrome://browser/content/browser.xul")) {
1000 NS_TIMELINE_MARK("Navigator Window visible now");
1003 #endif /* MOZ_TIMELINE */
1005 } else {
1006 // XXX: Should fire error event to the document...
1009 // Notify the document that it has been shown (regardless of whether
1010 // it was just loaded). Note: mDocument may be null now if the above
1011 // firing of onload caused the document to unload.
1012 if (mDocument)
1013 mDocument->OnPageShow(restoring);
1015 // Now that the document has loaded, we can tell the presshell
1016 // to unsuppress painting.
1017 if (mPresShell && !mStopped) {
1018 nsCOMPtr<nsIPresShell> shellDeathGrip(mPresShell);
1019 mPresShell->UnsuppressPainting();
1020 // mPresShell could have been removed now, see bug 378682/421432
1021 if (mPresShell) {
1022 mPresShell->ScrollToAnchor();
1026 nsJSContext::LoadEnd();
1028 #ifdef NS_PRINTING
1029 // Check to see if someone tried to print during the load
1030 if (mPrintIsPending) {
1031 mPrintIsPending = PR_FALSE;
1032 mPrintDocIsFullyLoaded = PR_TRUE;
1033 Print(mCachedPrintSettings, mCachedPrintWebProgressListner);
1034 mCachedPrintSettings = nsnull;
1035 mCachedPrintWebProgressListner = nsnull;
1037 #endif
1039 return rv;
1042 NS_IMETHODIMP
1043 DocumentViewerImpl::PermitUnload(PRBool *aPermitUnload)
1045 *aPermitUnload = PR_TRUE;
1047 if (!mDocument || mInPermitUnload) {
1048 return NS_OK;
1051 // First, get the script global object from the document...
1052 nsPIDOMWindow *window = mDocument->GetWindow();
1054 if (!window) {
1055 // This is odd, but not fatal
1056 NS_WARNING("window not set for document!");
1057 return NS_OK;
1060 NS_ASSERTION(nsContentUtils::IsSafeToRunScript(), "This is unsafe");
1062 // Now, fire an BeforeUnload event to the document and see if it's ok
1063 // to unload...
1064 nsEventStatus status = nsEventStatus_eIgnore;
1065 nsBeforePageUnloadEvent event(PR_TRUE, NS_BEFORE_PAGE_UNLOAD);
1066 event.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
1067 // XXX Dispatching to |window|, but using |document| as the target.
1068 event.target = mDocument;
1069 nsresult rv = NS_OK;
1071 // In evil cases we might be destroyed while handling the
1072 // onbeforeunload event, don't let that happen. (see also bug#331040)
1073 nsRefPtr<DocumentViewerImpl> kungFuDeathGrip(this);
1076 // Never permit popups from the beforeunload handler, no matter
1077 // how we get here.
1078 nsAutoPopupStatePusher popupStatePusher(openAbused, PR_TRUE);
1080 mInPermitUnload = PR_TRUE;
1081 nsEventDispatcher::Dispatch(window, mPresContext, &event, nsnull, &status);
1082 mInPermitUnload = PR_FALSE;
1085 nsCOMPtr<nsIDocShellTreeNode> docShellNode(do_QueryReferent(mContainer));
1087 if (NS_SUCCEEDED(rv) && (event.flags & NS_EVENT_FLAG_NO_DEFAULT ||
1088 !event.text.IsEmpty())) {
1089 // Ask the user if it's ok to unload the current page
1091 nsCOMPtr<nsIPrompt> prompt = do_GetInterface(docShellNode);
1093 if (prompt) {
1094 nsXPIDLString preMsg, postMsg;
1095 rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
1096 "OnBeforeUnloadPreMessage",
1097 preMsg);
1098 rv |= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
1099 "OnBeforeUnloadPostMessage",
1100 postMsg);
1102 // GetStringFromName can succeed, yet give NULL strings back.
1103 if (NS_FAILED(rv) || preMsg.IsEmpty() || postMsg.IsEmpty()) {
1104 NS_ERROR("Failed to get strings from dom.properties!");
1105 return NS_OK;
1108 // Limit the length of the text the page can inject into this
1109 // dialogue to 1024 characters.
1110 PRInt32 len = PR_MIN(event.text.Length(), 1024);
1112 nsAutoString msg;
1113 if (len == 0) {
1114 msg = preMsg + NS_LITERAL_STRING("\n\n") + postMsg;
1115 } else {
1116 msg = preMsg + NS_LITERAL_STRING("\n\n") +
1117 StringHead(event.text, len) +
1118 NS_LITERAL_STRING("\n\n") + postMsg;
1121 // This doesn't pass a title, which makes the title be
1122 // "Confirm", is that ok, or do we want a localizable title for
1123 // this dialogue?
1124 if (NS_FAILED(prompt->Confirm(nsnull, msg.get(), aPermitUnload))) {
1125 *aPermitUnload = PR_TRUE;
1130 if (docShellNode) {
1131 PRInt32 childCount;
1132 docShellNode->GetChildCount(&childCount);
1134 for (PRInt32 i = 0; i < childCount && *aPermitUnload; ++i) {
1135 nsCOMPtr<nsIDocShellTreeItem> item;
1136 docShellNode->GetChildAt(i, getter_AddRefs(item));
1138 nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(item));
1140 if (docShell) {
1141 nsCOMPtr<nsIContentViewer> cv;
1142 docShell->GetContentViewer(getter_AddRefs(cv));
1144 if (cv) {
1145 cv->PermitUnload(aPermitUnload);
1151 return NS_OK;
1154 NS_IMETHODIMP
1155 DocumentViewerImpl::PageHide(PRBool aIsUnload)
1157 mEnableRendering = PR_FALSE;
1159 if (!mDocument) {
1160 return NS_ERROR_NULL_POINTER;
1163 mDocument->OnPageHide(!aIsUnload);
1164 if (aIsUnload) {
1165 // if Destroy() was called during OnPageHide(), mDocument is nsnull.
1166 NS_ENSURE_STATE(mDocument);
1168 // First, get the window from the document...
1169 nsPIDOMWindow *window = mDocument->GetWindow();
1171 if (!window) {
1172 // Fail if no window is available...
1173 NS_ERROR("window not set for document!");
1174 return NS_ERROR_NULL_POINTER;
1177 // Now, fire an Unload event to the document...
1178 nsEventStatus status = nsEventStatus_eIgnore;
1179 nsEvent event(PR_TRUE, NS_PAGE_UNLOAD);
1180 event.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
1181 // XXX Dispatching to |window|, but using |document| as the target.
1182 event.target = mDocument;
1184 // Never permit popups from the unload handler, no matter how we get
1185 // here.
1186 nsAutoPopupStatePusher popupStatePusher(openAbused, PR_TRUE);
1188 nsEventDispatcher::Dispatch(window, mPresContext, &event, nsnull, &status);
1191 #ifdef MOZ_XUL
1192 // look for open menupopups and close them after the unload event, in case
1193 // the unload event listeners open any new popups
1194 if (mDocument)
1195 nsContentUtils::HidePopupsInDocument(mDocument);
1196 #endif
1198 return NS_OK;
1201 static void
1202 AttachContainerRecurse(nsIDocShell* aShell)
1204 nsCOMPtr<nsIContentViewer> viewer;
1205 aShell->GetContentViewer(getter_AddRefs(viewer));
1206 nsCOMPtr<nsIDocumentViewer> docViewer = do_QueryInterface(viewer);
1207 if (docViewer) {
1208 nsCOMPtr<nsIDocument> doc;
1209 docViewer->GetDocument(getter_AddRefs(doc));
1210 if (doc) {
1211 doc->SetContainer(aShell);
1213 nsCOMPtr<nsPresContext> pc;
1214 docViewer->GetPresContext(getter_AddRefs(pc));
1215 if (pc) {
1216 pc->SetContainer(aShell);
1217 pc->SetLinkHandler(nsCOMPtr<nsILinkHandler>(do_QueryInterface(aShell)));
1219 nsCOMPtr<nsIPresShell> presShell;
1220 docViewer->GetPresShell(getter_AddRefs(presShell));
1221 if (presShell) {
1222 presShell->SetForwardingContainer(nsnull);
1226 // Now recurse through the children
1227 nsCOMPtr<nsIDocShellTreeNode> node = do_QueryInterface(aShell);
1228 NS_ASSERTION(node, "docshells must implement nsIDocShellTreeNode");
1230 PRInt32 childCount;
1231 node->GetChildCount(&childCount);
1232 for (PRInt32 i = 0; i < childCount; ++i) {
1233 nsCOMPtr<nsIDocShellTreeItem> childItem;
1234 node->GetChildAt(i, getter_AddRefs(childItem));
1235 AttachContainerRecurse(nsCOMPtr<nsIDocShell>(do_QueryInterface(childItem)));
1239 NS_IMETHODIMP
1240 DocumentViewerImpl::Open(nsISupports *aState, nsISHEntry *aSHEntry)
1242 NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);
1244 // Our container might have gone away while we were closed.
1245 // If this is the case, we must fail to open so we don't crash.
1246 nsCOMPtr<nsISupports> container = do_QueryReferent(mContainer);
1247 if (!container)
1248 return NS_ERROR_NOT_AVAILABLE;
1250 nsRect bounds;
1251 mWindow->GetBounds(bounds);
1253 nsresult rv = InitInternal(mParentWidget, aState, bounds, PR_FALSE, PR_FALSE);
1254 NS_ENSURE_SUCCESS(rv, rv);
1256 if (mDocument)
1257 mDocument->SetContainer(nsCOMPtr<nsISupports>(do_QueryReferent(mContainer)));
1259 if (mPresShell)
1260 mPresShell->SetForwardingContainer(nsnull);
1262 // Rehook the child presentations. The child shells are still in
1263 // session history, so get them from there.
1265 nsCOMPtr<nsIDocShellTreeItem> item;
1266 PRInt32 itemIndex = 0;
1267 while (NS_SUCCEEDED(aSHEntry->ChildShellAt(itemIndex++,
1268 getter_AddRefs(item))) && item) {
1269 AttachContainerRecurse(nsCOMPtr<nsIDocShell>(do_QueryInterface(item)));
1272 SyncParentSubDocMap();
1274 if (mFocusListener && mDocument) {
1275 mDocument->AddEventListenerByIID(mFocusListener,
1276 NS_GET_IID(nsIDOMFocusListener));
1279 // XXX re-enable image animations once that works correctly
1281 PrepareToStartLoad();
1282 return NS_OK;
1285 NS_IMETHODIMP
1286 DocumentViewerImpl::Close(nsISHEntry *aSHEntry)
1288 // All callers are supposed to call close to break circular
1289 // references. If we do this stuff in the destructor, the
1290 // destructor might never be called (especially if we're being
1291 // used from JS.
1293 mSHEntry = aSHEntry;
1295 // Close is also needed to disable scripts during paint suppression,
1296 // since we transfer the existing global object to the new document
1297 // that is loaded. In the future, the global object may become a proxy
1298 // for an object that can be switched in and out so that we don't need
1299 // to disable scripts during paint suppression.
1301 if (!mDocument)
1302 return NS_OK;
1304 #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
1305 // Turn scripting back on
1306 // after PrintPreview had turned it off
1307 if (GetIsPrintPreview() && mPrintEngine) {
1308 mPrintEngine->TurnScriptingOn(PR_TRUE);
1310 #endif
1312 #ifdef NS_PRINTING
1313 // A Close was called while we were printing
1314 // so don't clear the ScriptGlobalObject
1315 // or clear the mDocument below
1316 // Also, do an extra addref to keep the viewer from going away.
1317 if (mPrintEngine && !mClosingWhilePrinting) {
1318 mClosingWhilePrinting = PR_TRUE;
1319 NS_ADDREF_THIS();
1320 } else
1321 #endif
1323 // out of band cleanup of webshell
1324 mDocument->SetScriptGlobalObject(nsnull);
1326 if (!mSHEntry)
1327 mDocument->RemovedFromDocShell();
1330 if (mFocusListener && mDocument) {
1331 mDocument->RemoveEventListenerByIID(mFocusListener,
1332 NS_GET_IID(nsIDOMFocusListener));
1335 return NS_OK;
1338 static void
1339 DetachContainerRecurse(nsIDocShell *aShell)
1341 // Unhook this docshell's presentation
1342 nsCOMPtr<nsIContentViewer> viewer;
1343 aShell->GetContentViewer(getter_AddRefs(viewer));
1344 nsCOMPtr<nsIDocumentViewer> docViewer = do_QueryInterface(viewer);
1345 if (docViewer) {
1346 nsCOMPtr<nsIDocument> doc;
1347 docViewer->GetDocument(getter_AddRefs(doc));
1348 if (doc) {
1349 doc->SetContainer(nsnull);
1351 nsCOMPtr<nsPresContext> pc;
1352 docViewer->GetPresContext(getter_AddRefs(pc));
1353 if (pc) {
1354 pc->SetContainer(nsnull);
1355 pc->SetLinkHandler(nsnull);
1357 nsCOMPtr<nsIPresShell> presShell;
1358 docViewer->GetPresShell(getter_AddRefs(presShell));
1359 if (presShell) {
1360 presShell->SetForwardingContainer(nsWeakPtr(do_GetWeakReference(aShell)));
1364 // Now recurse through the children
1365 nsCOMPtr<nsIDocShellTreeNode> node = do_QueryInterface(aShell);
1366 NS_ASSERTION(node, "docshells must implement nsIDocShellTreeNode");
1368 PRInt32 childCount;
1369 node->GetChildCount(&childCount);
1370 for (PRInt32 i = 0; i < childCount; ++i) {
1371 nsCOMPtr<nsIDocShellTreeItem> childItem;
1372 node->GetChildAt(i, getter_AddRefs(childItem));
1373 DetachContainerRecurse(nsCOMPtr<nsIDocShell>(do_QueryInterface(childItem)));
1377 NS_IMETHODIMP
1378 DocumentViewerImpl::Destroy()
1380 NS_ASSERTION(mDocument, "No document in Destroy()!");
1382 #ifdef NS_PRINTING
1383 // Here is where we check to see if the docment was still being prepared
1384 // for printing when it was asked to be destroy from someone externally
1385 // This usually happens if the document is unloaded while the user is in the Print Dialog
1387 // So we flip the bool to remember that the document is going away
1388 // and we can clean up and abort later after returning from the Print Dialog
1389 if (mPrintEngine) {
1390 if (mPrintEngine->CheckBeforeDestroy()) {
1391 return NS_OK;
1394 #endif
1396 // Don't let the document get unloaded while we are printing.
1397 // this could happen if we hit the back button during printing.
1398 // We also keep the viewer from being cached in session history, since
1399 // we require all documents there to be sanitized.
1400 if (mDestroyRefCount != 0) {
1401 --mDestroyRefCount;
1402 return NS_OK;
1405 // If we were told to put ourselves into session history instead of destroy
1406 // the presentation, do that now.
1407 if (mSHEntry) {
1408 if (mPresShell)
1409 mPresShell->Freeze();
1411 // Make sure the presentation isn't torn down by Hide().
1412 mSHEntry->SetSticky(mIsSticky);
1413 mIsSticky = PR_TRUE;
1415 PRBool savePresentation = PR_TRUE;
1417 // Remove our root view from the view hierarchy.
1418 if (mPresShell) {
1419 nsIViewManager *vm = mPresShell->GetViewManager();
1420 if (vm) {
1421 nsIView *rootView = nsnull;
1422 vm->GetRootView(rootView);
1424 if (rootView) {
1425 nsIView *rootViewParent = rootView->GetParent();
1426 if (rootViewParent) {
1427 nsIViewManager *parentVM = rootViewParent->GetViewManager();
1428 if (parentVM) {
1429 parentVM->RemoveChild(rootView);
1436 Hide();
1438 // This is after Hide() so that the user doesn't see the inputs clear.
1439 if (mDocument) {
1440 nsresult rv = mDocument->Sanitize();
1441 if (NS_FAILED(rv)) {
1442 // If we failed to sanitize, don't save presentation.
1443 savePresentation = PR_FALSE;
1448 // Reverse ownership. Do this *after* calling sanitize so that sanitize
1449 // doesn't cause mutations that make the SHEntry drop the presentation
1450 if (savePresentation) {
1451 mSHEntry->SetContentViewer(this);
1453 else {
1454 mSHEntry->SyncPresentationState();
1456 nsCOMPtr<nsISHEntry> shEntry = mSHEntry; // we'll need this below
1457 mSHEntry = nsnull;
1459 // Break the link from the document/presentation to the docshell, so that
1460 // link traversals cannot affect the currently-loaded document.
1461 // When the presentation is restored, Open() and InitInternal() will reset
1462 // these pointers to their original values.
1464 if (mDocument)
1465 mDocument->SetContainer(nsnull);
1466 if (mPresContext) {
1467 mPresContext->SetLinkHandler(nsnull);
1468 mPresContext->SetContainer(nsnull);
1470 if (mPresShell)
1471 mPresShell->SetForwardingContainer(mContainer);
1473 // Do the same for our children. Note that we need to get the child
1474 // docshells from the SHEntry now; the docshell will have cleared them.
1475 nsCOMPtr<nsIDocShellTreeItem> item;
1476 PRInt32 itemIndex = 0;
1477 while (NS_SUCCEEDED(shEntry->ChildShellAt(itemIndex++,
1478 getter_AddRefs(item))) && item) {
1479 DetachContainerRecurse(nsCOMPtr<nsIDocShell>(do_QueryInterface(item)));
1482 return NS_OK;
1485 if (mDocument) {
1486 mDocument->Destroy();
1487 mDocument = nsnull;
1490 // All callers are supposed to call destroy to break circular
1491 // references. If we do this stuff in the destructor, the
1492 // destructor might never be called (especially if we're being
1493 // used from JS.
1495 #ifdef NS_PRINTING
1496 if (mPrintEngine) {
1497 #ifdef NS_PRINT_PREVIEW
1498 PRBool doingPrintPreview;
1499 mPrintEngine->GetDoingPrintPreview(&doingPrintPreview);
1500 if (doingPrintPreview) {
1501 mPrintEngine->FinishPrintPreview();
1503 #endif
1505 mPrintEngine->Destroy();
1506 mPrintEngine = nsnull;
1508 #endif
1510 // Avoid leaking the old viewer.
1511 if (mPreviousViewer) {
1512 mPreviousViewer->Destroy();
1513 mPreviousViewer = nsnull;
1516 mDeviceContext = nsnull;
1518 if (mPresShell) {
1519 // Break circular reference (or something)
1520 mPresShell->EndObservingDocument();
1522 nsCOMPtr<nsISelection> selection;
1523 GetDocumentSelection(getter_AddRefs(selection));
1525 nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(selection));
1527 if (selPrivate && mSelectionListener)
1528 selPrivate->RemoveSelectionListener(mSelectionListener);
1530 mPresShell->Destroy();
1531 mPresShell = nsnull;
1534 if (mPresContext) {
1535 mPresContext->SetContainer(nsnull);
1536 mPresContext->SetLinkHandler(nsnull);
1537 mPresContext = nsnull;
1540 mContainer = nsnull;
1542 return NS_OK;
1545 NS_IMETHODIMP
1546 DocumentViewerImpl::Stop(void)
1548 NS_ASSERTION(mDocument, "Stop called too early or too late");
1549 if (mDocument) {
1550 mDocument->StopDocumentLoad();
1553 if (mEnableRendering && (mLoaded || mStopped) && mPresContext && !mSHEntry)
1554 mPresContext->SetImageAnimationMode(imgIContainer::kDontAnimMode);
1556 mStopped = PR_TRUE;
1558 if (!mLoaded && mPresShell) {
1559 // Well, we might as well paint what we have so far.
1560 nsCOMPtr<nsIPresShell> shellDeathGrip(mPresShell); // bug 378682
1561 mPresShell->UnsuppressPainting();
1564 return NS_OK;
1567 NS_IMETHODIMP
1568 DocumentViewerImpl::GetDOMDocument(nsIDOMDocument **aResult)
1570 NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
1571 return CallQueryInterface(mDocument, aResult);
1574 NS_IMETHODIMP
1575 DocumentViewerImpl::SetDOMDocument(nsIDOMDocument *aDocument)
1577 // Assumptions:
1579 // 1) this document viewer has been initialized with a call to Init().
1580 // 2) the stylesheets associated with the document have been added
1581 // to the document.
1583 // XXX Right now, this method assumes that the layout of the current
1584 // document hasn't started yet. More cleanup will probably be
1585 // necessary to make this method work for the case when layout *has*
1586 // occurred for the current document.
1587 // That work can happen when and if it is needed.
1589 nsresult rv;
1590 if (!aDocument)
1591 return NS_ERROR_NULL_POINTER;
1593 nsCOMPtr<nsIDocument> newDoc = do_QueryInterface(aDocument, &rv);
1594 if (NS_FAILED(rv)) return rv;
1596 // Set new container
1597 nsCOMPtr<nsISupports> container = do_QueryReferent(mContainer);
1598 newDoc->SetContainer(container);
1600 if (mDocument != newDoc) {
1601 // Replace the old document with the new one. Do this only when
1602 // the new document really is a new document.
1603 mDocument = newDoc;
1605 // Set the script global object on the new document
1606 nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(container);
1607 if (window) {
1608 window->SetNewDocument(newDoc, nsnull, PR_TRUE);
1611 // Clear the list of old child docshells. CChild docshells for the new
1612 // document will be constructed as frames are created.
1613 nsCOMPtr<nsIDocShellTreeNode> node = do_QueryInterface(container);
1614 if (node) {
1615 PRInt32 count;
1616 node->GetChildCount(&count);
1617 for (PRInt32 i = 0; i < count; ++i) {
1618 nsCOMPtr<nsIDocShellTreeItem> child;
1619 node->GetChildAt(0, getter_AddRefs(child));
1620 node->RemoveChild(child);
1625 rv = SyncParentSubDocMap();
1626 NS_ENSURE_SUCCESS(rv, rv);
1628 // Replace the current pres shell with a new shell for the new document
1630 nsCOMPtr<nsILinkHandler> linkHandler;
1631 if (mPresShell) {
1632 nsSize currentSize(0, 0);
1634 if (mViewManager) {
1635 mViewManager->GetWindowDimensions(&currentSize.width, &currentSize.height);
1638 if (mPresContext) {
1639 // Save the linkhandler (nsPresShell::Destroy removes it from
1640 // mPresContext).
1641 linkHandler = mPresContext->GetLinkHandler();
1644 mPresShell->EndObservingDocument();
1645 mPresShell->Destroy();
1647 mPresShell = nsnull;
1649 // This destroys the root view because it was associated with the root frame,
1650 // which has been torn down. Recreate the viewmanager and root view.
1651 MakeWindow(currentSize);
1654 // And if we're already given a prescontext...
1655 if (mPresContext) {
1656 // If we had a linkHandler and it got removed, put it back.
1657 if (linkHandler) {
1658 mPresContext->SetLinkHandler(linkHandler);
1661 rv = InitPresentationStuff(PR_FALSE, PR_TRUE);
1664 return rv;
1667 NS_IMETHODIMP
1668 DocumentViewerImpl::SetUAStyleSheet(nsIStyleSheet* aUAStyleSheet)
1670 NS_ASSERTION(aUAStyleSheet, "unexpected null pointer");
1671 nsCOMPtr<nsICSSStyleSheet> sheet(do_QueryInterface(aUAStyleSheet));
1672 if (sheet) {
1673 nsCOMPtr<nsICSSStyleSheet> newSheet;
1674 sheet->Clone(nsnull, nsnull, nsnull, nsnull, getter_AddRefs(newSheet));
1675 mUAStyleSheet = newSheet;
1677 return NS_OK;
1680 NS_IMETHODIMP
1681 DocumentViewerImpl::GetDocument(nsIDocument** aResult)
1683 NS_IF_ADDREF(*aResult = mDocument);
1685 return NS_OK;
1688 nsIPresShell*
1689 DocumentViewerImpl::GetPresShell()
1691 if (!GetIsPrintPreview()) {
1692 return mPresShell;
1694 NS_ENSURE_TRUE(mDocument, nsnull);
1695 nsCOMPtr<nsIPresShell> shell;
1696 nsCOMPtr<nsIPresShell> currentShell;
1697 nsPresShellIterator iter(mDocument);
1698 while ((shell = iter.GetNextShell())) {
1699 currentShell.swap(shell);
1701 return currentShell.get();
1704 nsPresContext*
1705 DocumentViewerImpl::GetPresContext()
1707 if (!GetIsPrintPreview()) {
1708 return mPresContext;
1710 nsIPresShell* shell = GetPresShell();
1711 return shell ? shell->GetPresContext() : nsnull;
1714 nsIViewManager*
1715 DocumentViewerImpl::GetViewManager()
1717 if (!GetIsPrintPreview()) {
1718 return mViewManager;
1720 nsIPresShell* shell = GetPresShell();
1721 return shell ? shell->GetViewManager() : nsnull;
1724 NS_IMETHODIMP
1725 DocumentViewerImpl::GetPresShell(nsIPresShell** aResult)
1727 nsIPresShell* shell = GetPresShell();
1728 NS_IF_ADDREF(*aResult = shell);
1729 return NS_OK;
1732 NS_IMETHODIMP
1733 DocumentViewerImpl::GetPresContext(nsPresContext** aResult)
1735 nsPresContext* pc = GetPresContext();
1736 NS_IF_ADDREF(*aResult = pc);
1737 return NS_OK;
1740 NS_IMETHODIMP
1741 DocumentViewerImpl::GetBounds(nsRect& aResult)
1743 NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
1744 NS_PRECONDITION(mWindow, "null window");
1745 if (mWindow) {
1746 mWindow->GetBounds(aResult);
1748 else {
1749 aResult.SetRect(0, 0, 0, 0);
1751 return NS_OK;
1754 NS_IMETHODIMP
1755 DocumentViewerImpl::GetPreviousViewer(nsIContentViewer** aViewer)
1757 *aViewer = mPreviousViewer;
1758 NS_IF_ADDREF(*aViewer);
1759 return NS_OK;
1762 NS_IMETHODIMP
1763 DocumentViewerImpl::SetPreviousViewer(nsIContentViewer* aViewer)
1765 // NOTE: |Show| sets |mPreviousViewer| to null without calling this
1766 // function.
1768 if (aViewer) {
1769 NS_ASSERTION(!mPreviousViewer,
1770 "can't set previous viewer when there already is one");
1772 // In a multiple chaining situation (which occurs when running a thrashing
1773 // test like i-bench or jrgm's tests with no delay), we can build up a
1774 // whole chain of viewers. In order to avoid this, we always set our previous
1775 // viewer to the MOST previous viewer in the chain, and then dump the intermediate
1776 // link from the chain. This ensures that at most only 2 documents are alive
1777 // and undestroyed at any given time (the one that is showing and the one that
1778 // is loading with painting suppressed).
1779 // It's very important that if this ever gets changed the code
1780 // before the RestorePresentation call in nsDocShell::InternalLoad
1781 // be changed accordingly.
1782 nsCOMPtr<nsIContentViewer> prevViewer;
1783 aViewer->GetPreviousViewer(getter_AddRefs(prevViewer));
1784 if (prevViewer) {
1785 aViewer->SetPreviousViewer(nsnull);
1786 aViewer->Destroy();
1787 return SetPreviousViewer(prevViewer);
1791 mPreviousViewer = aViewer;
1792 return NS_OK;
1795 NS_IMETHODIMP
1796 DocumentViewerImpl::SetBounds(const nsRect& aBounds)
1798 NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
1800 if (mWindow) {
1801 // Don't have the widget repaint. Layout will generate repaint requests
1802 // during reflow
1803 mWindow->Resize(aBounds.x, aBounds.y, aBounds.width, aBounds.height,
1804 PR_FALSE);
1807 // If there's a previous viewer, it's the one that's actually showing,
1808 // so be sure to resize it as well so it paints over the right area.
1809 // This may slow down the performance of the new page load, but resize
1810 // during load is also probably a relatively unusual condition
1811 // relating to things being hidden while something is loaded. It so
1812 // happens that Firefox does this a good bit with its infobar, and it
1813 // looks ugly if we don't do this.
1814 if (mPreviousViewer)
1815 mPreviousViewer->SetBounds(aBounds);
1817 #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
1818 if (GetIsPrintPreview() && !mPrintEngine->GetIsCreatingPrintPreview()) {
1819 mPrintEngine->GetPrintPreviewWindow()->Resize(aBounds.x, aBounds.y,
1820 aBounds.width, aBounds.height,
1821 PR_FALSE);
1823 #endif
1824 return NS_OK;
1827 NS_IMETHODIMP
1828 DocumentViewerImpl::Move(PRInt32 aX, PRInt32 aY)
1830 NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
1831 NS_PRECONDITION(mWindow, "null window");
1832 if (mWindow) {
1833 mWindow->Move(aX, aY);
1835 return NS_OK;
1838 NS_IMETHODIMP
1839 DocumentViewerImpl::Show(void)
1841 NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
1843 // We don't need the previous viewer anymore since we're not
1844 // displaying it.
1845 if (mPreviousViewer) {
1846 // This little dance *may* only be to keep
1847 // PresShell::EndObservingDocument happy, but I'm not sure.
1848 nsCOMPtr<nsIContentViewer> prevViewer(mPreviousViewer);
1849 mPreviousViewer = nsnull;
1850 prevViewer->Destroy();
1852 // Make sure we don't have too many cached ContentViewers
1853 nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryReferent(mContainer);
1854 if (treeItem) {
1855 // We need to find the root DocShell since only that object has an
1856 // SHistory and we need the SHistory to evict content viewers
1857 nsCOMPtr<nsIDocShellTreeItem> root;
1858 treeItem->GetSameTypeRootTreeItem(getter_AddRefs(root));
1859 nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(root);
1860 nsCOMPtr<nsISHistory> history;
1861 webNav->GetSessionHistory(getter_AddRefs(history));
1862 nsCOMPtr<nsISHistoryInternal> historyInt = do_QueryInterface(history);
1863 if (historyInt) {
1864 PRInt32 prevIndex,loadedIndex;
1865 nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(treeItem);
1866 docShell->GetPreviousTransIndex(&prevIndex);
1867 docShell->GetLoadedTransIndex(&loadedIndex);
1868 #ifdef DEBUG_PAGE_CACHE
1869 printf("About to evict content viewers: prev=%d, loaded=%d\n",
1870 prevIndex, loadedIndex);
1871 #endif
1872 historyInt->EvictContentViewers(prevIndex, loadedIndex);
1877 if (mWindow) {
1878 mWindow->Show(PR_TRUE);
1881 if (mDocument && !mPresShell && !mWindow) {
1882 nsCOMPtr<nsIBaseWindow> base_win(do_QueryReferent(mContainer));
1883 NS_ENSURE_TRUE(base_win, NS_ERROR_UNEXPECTED);
1885 base_win->GetParentWidget(&mParentWidget);
1886 NS_ENSURE_TRUE(mParentWidget, NS_ERROR_UNEXPECTED);
1887 mParentWidget->Release(); // GetParentWidget AddRefs, but mParentWidget is weak
1889 nsresult rv = CreateDeviceContext(mParentWidget);
1890 NS_ENSURE_SUCCESS(rv, rv);
1892 // Create presentation context
1893 NS_ASSERTION(!mPresContext, "Shouldn't have a prescontext if we have no shell!");
1894 mPresContext = new nsPresContext(mDocument, nsPresContext::eContext_Galley);
1895 NS_ENSURE_TRUE(mPresContext, NS_ERROR_OUT_OF_MEMORY);
1897 rv = mPresContext->Init(mDeviceContext);
1898 if (NS_FAILED(rv)) {
1899 mPresContext = nsnull;
1900 return rv;
1903 nsRect tbounds;
1904 mParentWidget->GetBounds(tbounds);
1906 rv = MakeWindow(nsSize(mPresContext->DevPixelsToAppUnits(tbounds.width),
1907 mPresContext->DevPixelsToAppUnits(tbounds.height)));
1908 if (NS_FAILED(rv))
1909 return rv;
1911 if (mPresContext && base_win) {
1912 nsCOMPtr<nsILinkHandler> linkHandler(do_GetInterface(base_win));
1914 if (linkHandler) {
1915 mPresContext->SetLinkHandler(linkHandler);
1918 mPresContext->SetContainer(base_win);
1921 if (mPresContext) {
1922 Hide();
1924 rv = InitPresentationStuff(mDocument->MayStartLayout(),
1925 mDocument->MayStartLayout());
1928 // If we get here the document load has already started and the
1929 // window is shown because some JS on the page caused it to be
1930 // shown...
1932 nsCOMPtr<nsIPresShell> shellDeathGrip(mPresShell); // bug 378682
1933 mPresShell->UnsuppressPainting();
1936 return NS_OK;
1939 NS_IMETHODIMP
1940 DocumentViewerImpl::Hide(void)
1942 NS_PRECONDITION(mWindow, "null window");
1943 if (mWindow) {
1944 mWindow->Show(PR_FALSE);
1947 if (!mPresShell)
1948 return NS_OK;
1950 NS_ASSERTION(mPresContext, "Can't have a presshell and no prescontext!");
1952 // Avoid leaking the old viewer.
1953 if (mPreviousViewer) {
1954 mPreviousViewer->Destroy();
1955 mPreviousViewer = nsnull;
1958 if (mIsSticky) {
1959 // This window is sticky, that means that it might be shown again
1960 // and we don't want the presshell n' all that to be thrown away
1961 // just because the window is hidden.
1963 return NS_OK;
1966 // Break circular reference (or something)
1967 mPresShell->EndObservingDocument();
1968 nsCOMPtr<nsISelection> selection;
1970 GetDocumentSelection(getter_AddRefs(selection));
1972 nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(selection));
1974 if (selPrivate && mSelectionListener) {
1975 selPrivate->RemoveSelectionListener(mSelectionListener);
1978 nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mContainer));
1979 if (docShell) {
1980 PRBool saveLayoutState = PR_FALSE;
1981 docShell->GetShouldSaveLayoutState(&saveLayoutState);
1982 if (saveLayoutState) {
1983 nsCOMPtr<nsILayoutHistoryState> layoutState;
1984 mPresShell->CaptureHistoryState(getter_AddRefs(layoutState), PR_TRUE);
1988 mPresShell->Destroy();
1989 // Clear weak refs
1990 mPresContext->SetContainer(nsnull);
1991 mPresContext->SetLinkHandler(nsnull);
1993 mPresShell = nsnull;
1994 mPresContext = nsnull;
1995 mViewManager = nsnull;
1996 mWindow = nsnull;
1997 mDeviceContext = nsnull;
1998 mParentWidget = nsnull;
2000 nsCOMPtr<nsIBaseWindow> base_win(do_QueryReferent(mContainer));
2002 if (base_win) {
2003 base_win->SetParentWidget(nsnull);
2006 return NS_OK;
2008 NS_IMETHODIMP
2009 DocumentViewerImpl::SetEnableRendering(PRBool aOn)
2011 NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
2012 mEnableRendering = aOn;
2013 if (mViewManager) {
2014 if (aOn) {
2015 mViewManager->EnableRefresh(NS_VMREFRESH_IMMEDIATE);
2016 nsIView* view;
2017 mViewManager->GetRootView(view); // views are not refCounted
2018 if (view) {
2019 mViewManager->UpdateView(view, NS_VMREFRESH_IMMEDIATE);
2022 else {
2023 mViewManager->DisableRefresh();
2026 return NS_OK;
2029 NS_IMETHODIMP
2030 DocumentViewerImpl::GetSticky(PRBool *aSticky)
2032 *aSticky = mIsSticky;
2034 return NS_OK;
2037 NS_IMETHODIMP
2038 DocumentViewerImpl::SetSticky(PRBool aSticky)
2040 mIsSticky = aSticky;
2042 return NS_OK;
2045 NS_IMETHODIMP
2046 DocumentViewerImpl::GetEnableRendering(PRBool* aResult)
2048 NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
2049 NS_PRECONDITION(nsnull != aResult, "null OUT ptr");
2050 if (aResult) {
2051 *aResult = mEnableRendering;
2053 return NS_OK;
2056 NS_IMETHODIMP
2057 DocumentViewerImpl::RequestWindowClose(PRBool* aCanClose)
2059 #ifdef NS_PRINTING
2060 if (mPrintIsPending || (mPrintEngine && mPrintEngine->GetIsPrinting())) {
2061 *aCanClose = PR_FALSE;
2062 mDeferredWindowClose = PR_TRUE;
2063 } else
2064 #endif
2065 *aCanClose = PR_TRUE;
2067 return NS_OK;
2070 PR_STATIC_CALLBACK(PRBool)
2071 AppendAgentSheet(nsIStyleSheet *aSheet, void *aData)
2073 nsStyleSet *styleSet = static_cast<nsStyleSet*>(aData);
2074 styleSet->AppendStyleSheet(nsStyleSet::eAgentSheet, aSheet);
2075 return PR_TRUE;
2078 PR_STATIC_CALLBACK(PRBool)
2079 PrependUserSheet(nsIStyleSheet *aSheet, void *aData)
2081 nsStyleSet *styleSet = static_cast<nsStyleSet*>(aData);
2082 styleSet->PrependStyleSheet(nsStyleSet::eUserSheet, aSheet);
2083 return PR_TRUE;
2086 nsresult
2087 DocumentViewerImpl::CreateStyleSet(nsIDocument* aDocument,
2088 nsStyleSet** aStyleSet)
2090 // Make sure this does the same thing as PresShell::AddSheet wrt ordering.
2092 // this should eventually get expanded to allow for creating
2093 // different sets for different media
2094 if (!mUAStyleSheet) {
2095 NS_WARNING("unable to load UA style sheet");
2098 nsStyleSet *styleSet = new nsStyleSet();
2099 if (!styleSet) {
2100 return NS_ERROR_OUT_OF_MEMORY;
2103 styleSet->BeginUpdate();
2105 // The document will fill in the document sheets when we create the presshell
2107 // Handle the user sheets.
2108 nsCOMPtr<nsIDocShellTreeItem> docShell(do_QueryReferent(mContainer));
2109 PRInt32 shellType;
2110 docShell->GetItemType(&shellType);
2111 nsICSSStyleSheet* sheet = nsnull;
2112 if (shellType == nsIDocShellTreeItem::typeChrome) {
2113 sheet = nsLayoutStylesheetCache::UserChromeSheet();
2115 else {
2116 sheet = nsLayoutStylesheetCache::UserContentSheet();
2119 if (sheet)
2120 styleSet->AppendStyleSheet(nsStyleSet::eUserSheet, sheet);
2122 // Append chrome sheets (scrollbars + forms).
2123 PRBool shouldOverride = PR_FALSE;
2124 nsCOMPtr<nsIDocShell> ds(do_QueryInterface(docShell));
2125 nsCOMPtr<nsIDOMEventTarget> chromeHandler;
2126 nsCOMPtr<nsIURI> uri;
2127 nsCOMPtr<nsICSSStyleSheet> csssheet;
2129 ds->GetChromeEventHandler(getter_AddRefs(chromeHandler));
2130 if (chromeHandler) {
2131 nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(chromeHandler));
2132 nsCOMPtr<nsIContent> content(do_QueryInterface(elt));
2133 if (elt && content) {
2134 nsCOMPtr<nsIURI> baseURI = content->GetBaseURI();
2136 nsAutoString sheets;
2137 elt->GetAttribute(NS_LITERAL_STRING("usechromesheets"), sheets);
2138 if (!sheets.IsEmpty() && baseURI) {
2139 nsCOMPtr<nsICSSLoader> cssLoader;
2140 NS_NewCSSLoader(getter_AddRefs(cssLoader));
2142 char *str = ToNewCString(sheets);
2143 char *newStr = str;
2144 char *token;
2145 while ( (token = nsCRT::strtok(newStr, ", ", &newStr)) ) {
2146 NS_NewURI(getter_AddRefs(uri), nsDependentCString(token), nsnull,
2147 baseURI);
2148 if (!uri) continue;
2150 cssLoader->LoadSheetSync(uri, getter_AddRefs(csssheet));
2151 if (!sheet) continue;
2153 styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, csssheet);
2154 shouldOverride = PR_TRUE;
2156 nsMemory::Free(str);
2161 if (!shouldOverride) {
2162 sheet = nsLayoutStylesheetCache::ScrollbarsSheet();
2163 if (sheet) {
2164 styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet);
2168 sheet = nsLayoutStylesheetCache::FormsSheet();
2169 if (sheet) {
2170 styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet);
2173 if (mUAStyleSheet) {
2174 styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, mUAStyleSheet);
2177 nsCOMPtr<nsIStyleSheetService> dummy =
2178 do_GetService(NS_STYLESHEETSERVICE_CONTRACTID);
2180 nsStyleSheetService *sheetService = nsStyleSheetService::gInstance;
2181 if (sheetService) {
2182 sheetService->AgentStyleSheets()->EnumerateForwards(AppendAgentSheet,
2183 styleSet);
2184 sheetService->UserStyleSheets()->EnumerateBackwards(PrependUserSheet,
2185 styleSet);
2188 // Caller will handle calling EndUpdate, per contract.
2189 *aStyleSet = styleSet;
2190 return NS_OK;
2193 NS_IMETHODIMP
2194 DocumentViewerImpl::ClearHistoryEntry()
2196 mSHEntry = nsnull;
2197 return NS_OK;
2200 //-------------------------------------------------------
2202 nsresult
2203 DocumentViewerImpl::MakeWindow(const nsSize& aSize)
2205 nsresult rv;
2207 mViewManager = do_CreateInstance(kViewManagerCID, &rv);
2208 if (NS_FAILED(rv))
2209 return rv;
2211 nsIDeviceContext *dx = mPresContext->DeviceContext();
2213 rv = mViewManager->Init(dx);
2214 if (NS_FAILED(rv))
2215 return rv;
2217 // Create a child window of the parent that is our "root view/window"
2218 // if aParentWidget has a view, we'll hook our view manager up to its view tree
2219 nsIView* containerView = nsIView::GetViewFor(mParentWidget);
2221 if (containerView) {
2222 // see if the containerView has already been hooked into a foreign view manager hierarchy
2223 // if it has, then we have to hook into the hierarchy too otherwise bad things will happen.
2224 nsIViewManager* containerVM = containerView->GetViewManager();
2225 nsIView* pView = containerView;
2226 do {
2227 pView = pView->GetParent();
2228 } while (pView && pView->GetViewManager() == containerVM);
2230 if (!pView) {
2231 // OK, so the container is not already hooked up into a foreign view manager hierarchy.
2232 // That means we can choose not to hook ourselves up.
2234 // If the parent container is a chrome shell and we are a content shell
2235 // then we won't hook into its view
2236 // tree. This will improve performance a little bit (especially given scrolling/painting perf bugs)
2237 // but is really just for peace of mind. This check can be removed if we want to support fancy
2238 // chrome effects like transparent controls floating over content, transparent Web browsers, and
2239 // things like that, and the perf bugs are fixed.
2240 nsCOMPtr<nsIDocShellTreeItem> container(do_QueryReferent(mContainer));
2241 nsCOMPtr<nsIDocShellTreeItem> sameTypeParent;
2242 if (container) {
2243 container->GetSameTypeParent(getter_AddRefs(sameTypeParent));
2245 if (!sameTypeParent) {
2246 containerView = nsnull;
2251 // The root view is always at 0,0.
2252 nsRect tbounds(nsPoint(0, 0), aSize);
2253 // Create a view
2254 nsIView* view = mViewManager->CreateView(tbounds, containerView);
2255 if (!view)
2256 return NS_ERROR_OUT_OF_MEMORY;
2258 // pass in a native widget to be the parent widget ONLY if the view hierarchy will stand alone.
2259 // otherwise the view will find its own parent widget and "do the right thing" to
2260 // establish a parent/child widget relationship
2261 rv = view->CreateWidget(kWidgetCID, nsnull,
2262 containerView != nsnull ? nsnull : mParentWidget->GetNativeData(NS_NATIVE_WIDGET),
2263 PR_TRUE, PR_FALSE);
2264 if (NS_FAILED(rv))
2265 return rv;
2267 // Setup hierarchical relationship in view manager
2268 mViewManager->SetRootView(view);
2270 mWindow = view->GetWidget();
2272 // This SetFocus is necessary so the Arrow Key and Page Key events
2273 // go to the scrolled view as soon as the Window is created instead of going to
2274 // the browser window (this enables keyboard scrolling of the document)
2275 // mWindow->SetFocus();
2277 return rv;
2280 nsresult
2281 DocumentViewerImpl::CreateDeviceContext(nsIWidget* aWidget)
2283 NS_PRECONDITION(!mDeviceContext, "How come we're calling this?");
2284 if (aWidget) {
2285 mDeviceContext = do_CreateInstance(kDeviceContextCID);
2286 NS_ENSURE_TRUE(mDeviceContext, NS_ERROR_FAILURE);
2287 mDeviceContext->Init(aWidget->GetNativeData(NS_NATIVE_WIDGET));
2289 return NS_OK;
2292 // Return the selection for the document. Note that text fields have their
2293 // own selection, which cannot be accessed with this method. Use
2294 // mPresShell->GetSelectionForCopy() instead.
2295 nsresult DocumentViewerImpl::GetDocumentSelection(nsISelection **aSelection)
2297 NS_ENSURE_ARG_POINTER(aSelection);
2298 if (!mPresShell) {
2299 return NS_ERROR_NOT_INITIALIZED;
2302 nsCOMPtr<nsISelectionController> selcon;
2303 selcon = do_QueryInterface(mPresShell);
2304 if (selcon)
2305 return selcon->GetSelection(nsISelectionController::SELECTION_NORMAL,
2306 aSelection);
2307 return NS_ERROR_FAILURE;
2310 /* ========================================================================================
2311 * nsIContentViewerEdit
2312 * ======================================================================================== */
2314 NS_IMETHODIMP DocumentViewerImpl::Search()
2316 // Nothing to do here.
2317 return NS_OK;
2320 NS_IMETHODIMP DocumentViewerImpl::GetSearchable(PRBool *aSearchable)
2322 // Nothing to do here.
2323 *aSearchable = PR_FALSE;
2324 return NS_OK;
2327 NS_IMETHODIMP DocumentViewerImpl::ClearSelection()
2329 nsresult rv;
2330 nsCOMPtr<nsISelection> selection;
2332 // use mPresShell->GetSelectionForCopy() ?
2333 rv = GetDocumentSelection(getter_AddRefs(selection));
2334 if (NS_FAILED(rv)) return rv;
2336 return selection->CollapseToStart();
2339 NS_IMETHODIMP DocumentViewerImpl::SelectAll()
2341 // XXX this is a temporary implementation copied from nsWebShell
2342 // for now. I think nsDocument and friends should have some helper
2343 // functions to make this easier.
2344 nsCOMPtr<nsISelection> selection;
2345 nsresult rv;
2347 // use mPresShell->GetSelectionForCopy() ?
2348 rv = GetDocumentSelection(getter_AddRefs(selection));
2349 if (NS_FAILED(rv)) return rv;
2351 nsCOMPtr<nsIDOMHTMLDocument> htmldoc = do_QueryInterface(mDocument);
2352 nsCOMPtr<nsIDOMNode> bodyNode;
2354 if (htmldoc)
2356 nsCOMPtr<nsIDOMHTMLElement>bodyElement;
2357 rv = htmldoc->GetBody(getter_AddRefs(bodyElement));
2358 if (NS_FAILED(rv) || !bodyElement) return rv;
2360 bodyNode = do_QueryInterface(bodyElement);
2362 else if (mDocument)
2364 bodyNode = do_QueryInterface(mDocument->GetRootContent());
2366 if (!bodyNode) return NS_ERROR_FAILURE;
2368 rv = selection->RemoveAllRanges();
2369 if (NS_FAILED(rv)) return rv;
2371 rv = selection->SelectAllChildren(bodyNode);
2372 return rv;
2375 NS_IMETHODIMP DocumentViewerImpl::CopySelection()
2377 PRBool preventDefault;
2378 nsresult rv = FireClipboardEvent(NS_COPY, &preventDefault);
2379 if (NS_FAILED(rv) || preventDefault)
2380 return rv;
2382 return mPresShell->DoCopy();
2385 NS_IMETHODIMP DocumentViewerImpl::CopyLinkLocation()
2387 NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);
2388 nsCOMPtr<nsIDOMNode> node;
2389 GetPopupLinkNode(getter_AddRefs(node));
2390 // make noise if we're not in a link
2391 NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
2393 nsAutoString locationText;
2394 nsresult rv = mPresShell->GetLinkLocation(node, locationText);
2395 NS_ENSURE_SUCCESS(rv, rv);
2397 nsCOMPtr<nsIClipboardHelper> clipboard(do_GetService("@mozilla.org/widget/clipboardhelper;1", &rv));
2398 NS_ENSURE_SUCCESS(rv, rv);
2400 // copy the href onto the clipboard
2401 return clipboard->CopyString(locationText);
2404 NS_IMETHODIMP DocumentViewerImpl::CopyImage(PRInt32 aCopyFlags)
2406 NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);
2407 nsCOMPtr<nsIImageLoadingContent> node;
2408 GetPopupImageNode(getter_AddRefs(node));
2409 // make noise if we're not in an image
2410 NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
2412 return nsCopySupport::ImageCopy(node, aCopyFlags);
2415 nsresult DocumentViewerImpl::GetClipboardEventTarget(nsIDOMNode** aEventTarget)
2417 NS_ENSURE_ARG_POINTER(aEventTarget);
2418 *aEventTarget = nsnull;
2420 if (!mPresShell)
2421 return NS_ERROR_NOT_INITIALIZED;
2423 nsCOMPtr<nsISelection> sel;
2424 nsresult rv = mPresShell->GetSelectionForCopy(getter_AddRefs(sel));
2425 if (NS_FAILED(rv))
2426 return rv;
2427 if (!sel)
2428 return NS_ERROR_FAILURE;
2430 return nsCopySupport::GetClipboardEventTarget(sel, aEventTarget);
2433 nsresult DocumentViewerImpl::FireClipboardEvent(PRUint32 msg,
2434 PRBool* aPreventDefault)
2436 *aPreventDefault = PR_FALSE;
2438 NS_ENSURE_TRUE(mPresContext, NS_ERROR_NOT_INITIALIZED);
2439 NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);
2441 // It seems to be unsafe to fire an event handler during reflow (bug 393696)
2442 PRBool isReflowing = PR_TRUE;
2443 nsresult rv = mPresShell->IsReflowLocked(&isReflowing);
2444 if (NS_FAILED(rv) || isReflowing)
2445 return NS_OK;
2447 nsCOMPtr<nsIDOMNode> eventTarget;
2448 rv = GetClipboardEventTarget(getter_AddRefs(eventTarget));
2449 if (NS_FAILED(rv))
2450 // On failure to get event target, just forget about it and don't fire.
2451 return NS_OK;
2453 nsEventStatus status = nsEventStatus_eIgnore;
2454 nsEvent evt(PR_TRUE, msg);
2455 nsEventDispatcher::Dispatch(eventTarget, mPresContext, &evt, nsnull,
2456 &status);
2457 // if event handler return'd false (PreventDefault)
2458 if (status == nsEventStatus_eConsumeNoDefault)
2459 *aPreventDefault = PR_TRUE;
2461 // Ensure that the calling function can use mPresShell -- if the event
2462 // handler closed this window, mPresShell will be gone.
2463 NS_ENSURE_STATE(mPresShell);
2465 return NS_OK;
2468 NS_IMETHODIMP DocumentViewerImpl::GetCopyable(PRBool *aCopyable)
2470 NS_ENSURE_ARG_POINTER(aCopyable);
2471 *aCopyable = PR_FALSE;
2473 NS_ENSURE_STATE(mPresShell);
2474 nsCOMPtr<nsISelection> selection;
2475 nsresult rv = mPresShell->GetSelectionForCopy(getter_AddRefs(selection));
2476 if (NS_FAILED(rv))
2477 return rv;
2479 PRBool isCollapsed;
2480 selection->GetIsCollapsed(&isCollapsed);
2482 *aCopyable = !isCollapsed;
2483 return NS_OK;
2486 NS_IMETHODIMP DocumentViewerImpl::CutSelection()
2488 // preventDefault's value is ignored because cut from the document has no
2489 // default behaviour.
2490 PRBool preventDefault;
2491 return FireClipboardEvent(NS_CUT, &preventDefault);
2494 NS_IMETHODIMP DocumentViewerImpl::GetCutable(PRBool *aCutable)
2496 NS_ENSURE_ARG_POINTER(aCutable);
2497 *aCutable = PR_FALSE;
2498 return NS_OK;
2501 NS_IMETHODIMP DocumentViewerImpl::Paste()
2503 // preventDefault's value is ignored because paste into the document has no
2504 // default behaviour.
2505 PRBool preventDefault;
2506 return FireClipboardEvent(NS_PASTE, &preventDefault);
2509 NS_IMETHODIMP DocumentViewerImpl::GetPasteable(PRBool *aPasteable)
2511 NS_ENSURE_ARG_POINTER(aPasteable);
2512 *aPasteable = PR_FALSE;
2513 return NS_OK;
2516 /* AString getContents (in string mimeType, in boolean selectionOnly); */
2517 NS_IMETHODIMP DocumentViewerImpl::GetContents(const char *mimeType, PRBool selectionOnly, nsAString& aOutValue)
2519 NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);
2520 return mPresShell->DoGetContents(nsDependentCString(mimeType), 0, selectionOnly, aOutValue);
2523 /* readonly attribute boolean canGetContents; */
2524 NS_IMETHODIMP DocumentViewerImpl::GetCanGetContents(PRBool *aCanGetContents)
2526 return GetCopyable(aCanGetContents);
2529 #ifdef XP_MAC
2530 #pragma mark -
2531 #endif
2533 /* ========================================================================================
2534 * nsIContentViewerFile
2535 * ======================================================================================== */
2536 /** ---------------------------------------------------
2537 * See documentation above in the nsIContentViewerfile class definition
2538 * @update 01/24/00 dwc
2540 NS_IMETHODIMP
2541 DocumentViewerImpl::Print(PRBool aSilent,
2542 FILE * aDebugFile,
2543 nsIPrintSettings* aPrintSettings)
2545 #ifdef NS_PRINTING
2546 nsCOMPtr<nsIPrintSettings> printSettings;
2548 #ifdef NS_DEBUG
2549 nsresult rv = NS_ERROR_FAILURE;
2551 mDebugFile = aDebugFile;
2552 // if they don't pass in a PrintSettings, then make one
2553 // it will have all the default values
2554 printSettings = aPrintSettings;
2555 nsCOMPtr<nsIPrintOptions> printOptions = do_GetService(sPrintOptionsContractID, &rv);
2556 if (NS_SUCCEEDED(rv)) {
2557 // if they don't pass in a PrintSettings, then make one
2558 if (printSettings == nsnull) {
2559 printOptions->CreatePrintSettings(getter_AddRefs(printSettings));
2561 NS_ASSERTION(printSettings, "You can't PrintPreview without a PrintSettings!");
2563 if (printSettings) printSettings->SetPrintSilent(aSilent);
2564 if (printSettings) printSettings->SetShowPrintProgress(PR_FALSE);
2565 #endif
2568 return Print(printSettings, nsnull);
2569 #else
2570 return NS_ERROR_FAILURE;
2571 #endif
2574 /* [noscript] void printWithParent (in nsIDOMWindowInternal aParentWin, in nsIPrintSettings aThePrintSettings, in nsIWebProgressListener aWPListener); */
2575 NS_IMETHODIMP
2576 DocumentViewerImpl::PrintWithParent(nsIDOMWindowInternal *aParentWin, nsIPrintSettings *aThePrintSettings, nsIWebProgressListener *aWPListener)
2578 #ifdef NS_PRINTING
2579 return Print(aThePrintSettings, aWPListener);
2580 #else
2581 return NS_ERROR_FAILURE;
2582 #endif
2585 // nsIContentViewerFile interface
2586 NS_IMETHODIMP
2587 DocumentViewerImpl::GetPrintable(PRBool *aPrintable)
2589 NS_ENSURE_ARG_POINTER(aPrintable);
2591 *aPrintable = !GetIsPrinting();
2593 return NS_OK;
2596 //*****************************************************************************
2597 // nsIMarkupDocumentViewer
2598 //*****************************************************************************
2600 NS_IMETHODIMP DocumentViewerImpl::ScrollToNode(nsIDOMNode* aNode)
2602 NS_ENSURE_ARG(aNode);
2603 NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
2604 nsCOMPtr<nsIPresShell> presShell;
2605 NS_ENSURE_SUCCESS(GetPresShell(getter_AddRefs(presShell)), NS_ERROR_FAILURE);
2607 // Get the nsIContent interface, because that's what we need to
2608 // get the primary frame
2610 nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
2611 NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
2613 // Tell the PresShell to scroll to the primary frame of the content.
2614 NS_ENSURE_SUCCESS(presShell->ScrollContentIntoView(content,
2615 NS_PRESSHELL_SCROLL_TOP,
2616 NS_PRESSHELL_SCROLL_ANYWHERE),
2617 NS_ERROR_FAILURE);
2618 return NS_OK;
2621 void
2622 DocumentViewerImpl::CallChildren(CallChildFunc aFunc, void* aClosure)
2624 nsCOMPtr<nsIDocShellTreeNode> docShellNode(do_QueryReferent(mContainer));
2625 if (docShellNode)
2627 PRInt32 i;
2628 PRInt32 n;
2629 docShellNode->GetChildCount(&n);
2630 for (i=0; i < n; i++)
2632 nsCOMPtr<nsIDocShellTreeItem> child;
2633 docShellNode->GetChildAt(i, getter_AddRefs(child));
2634 nsCOMPtr<nsIDocShell> childAsShell(do_QueryInterface(child));
2635 NS_ASSERTION(childAsShell, "null child in docshell");
2636 if (childAsShell)
2638 nsCOMPtr<nsIContentViewer> childCV;
2639 childAsShell->GetContentViewer(getter_AddRefs(childCV));
2640 if (childCV)
2642 nsCOMPtr<nsIMarkupDocumentViewer> markupCV = do_QueryInterface(childCV);
2643 if (markupCV) {
2644 (*aFunc)(markupCV, aClosure);
2652 struct ZoomInfo
2654 float mZoom;
2657 static void
2658 SetChildTextZoom(nsIMarkupDocumentViewer* aChild, void* aClosure)
2660 struct ZoomInfo* ZoomInfo = (struct ZoomInfo*) aClosure;
2661 aChild->SetTextZoom(ZoomInfo->mZoom);
2664 static void
2665 SetChildFullZoom(nsIMarkupDocumentViewer* aChild, void* aClosure)
2667 struct ZoomInfo* ZoomInfo = (struct ZoomInfo*) aClosure;
2668 aChild->SetFullZoom(ZoomInfo->mZoom);
2671 NS_IMETHODIMP
2672 DocumentViewerImpl::SetTextZoom(float aTextZoom)
2674 if (!GetIsPrintPreview()) {
2675 mTextZoom = aTextZoom;
2678 nsIViewManager::UpdateViewBatch batch(GetViewManager());
2680 // Set the text zoom on all children of mContainer (even if our zoom didn't
2681 // change, our children's zoom may be different, though it would be unusual).
2682 // Do this first, in case kids are auto-sizing and post reflow commands on
2683 // our presshell (which should be subsumed into our own style change reflow).
2684 struct ZoomInfo ZoomInfo = { aTextZoom };
2685 CallChildren(SetChildTextZoom, &ZoomInfo);
2687 // Now change our own zoom
2688 nsPresContext* pc = GetPresContext();
2689 if (pc && aTextZoom != mPresContext->TextZoom()) {
2690 pc->SetTextZoom(aTextZoom);
2693 batch.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
2695 return NS_OK;
2698 NS_IMETHODIMP
2699 DocumentViewerImpl::GetTextZoom(float* aTextZoom)
2701 NS_ENSURE_ARG_POINTER(aTextZoom);
2702 nsPresContext* pc = GetPresContext();
2703 *aTextZoom = pc ? pc->TextZoom() : 1.0f;
2704 return NS_OK;
2707 NS_IMETHODIMP
2708 DocumentViewerImpl::SetFullZoom(float aFullZoom)
2710 if (!GetIsPrintPreview()) {
2711 mPageZoom = aFullZoom;
2714 nsIViewManager::UpdateViewBatch batch(GetViewManager());
2716 struct ZoomInfo ZoomInfo = { aFullZoom };
2717 CallChildren(SetChildFullZoom, &ZoomInfo);
2719 nsPresContext* pc = GetPresContext();
2720 if (pc) {
2721 pc->SetFullZoom(aFullZoom);
2724 batch.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
2726 return NS_OK;
2729 NS_IMETHODIMP
2730 DocumentViewerImpl::GetFullZoom(float* aFullZoom)
2732 NS_ENSURE_ARG_POINTER(aFullZoom);
2733 // Check the prescontext first because it might have a temporary
2734 // setting for print-preview
2735 nsPresContext* pc = GetPresContext();
2736 *aFullZoom = pc ? pc->GetFullZoom() : mPageZoom;
2737 return NS_OK;
2740 static void
2741 SetChildAuthorStyleDisabled(nsIMarkupDocumentViewer* aChild, void* aClosure)
2743 PRBool styleDisabled = *static_cast<PRBool*>(aClosure);
2744 aChild->SetAuthorStyleDisabled(styleDisabled);
2748 NS_IMETHODIMP
2749 DocumentViewerImpl::SetAuthorStyleDisabled(PRBool aStyleDisabled)
2751 if (mPresShell) {
2752 mPresShell->SetAuthorStyleDisabled(aStyleDisabled);
2754 CallChildren(SetChildAuthorStyleDisabled, &aStyleDisabled);
2755 return NS_OK;
2758 NS_IMETHODIMP
2759 DocumentViewerImpl::GetAuthorStyleDisabled(PRBool* aStyleDisabled)
2761 if (mPresShell) {
2762 *aStyleDisabled = mPresShell->GetAuthorStyleDisabled();
2763 } else {
2764 *aStyleDisabled = PR_FALSE;
2766 return NS_OK;
2769 NS_IMETHODIMP
2770 DocumentViewerImpl::GetDefaultCharacterSet(nsACString& aDefaultCharacterSet)
2772 NS_ENSURE_STATE(nsCOMPtr<nsISupports>(do_QueryReferent(mContainer)));
2774 if (mDefaultCharacterSet.IsEmpty())
2776 const nsAdoptingString& defCharset =
2777 nsContentUtils::GetLocalizedStringPref("intl.charset.default");
2779 if (!defCharset.IsEmpty())
2780 LossyCopyUTF16toASCII(defCharset, mDefaultCharacterSet);
2781 else
2782 mDefaultCharacterSet.AssignLiteral("ISO-8859-1");
2784 aDefaultCharacterSet = mDefaultCharacterSet;
2785 return NS_OK;
2788 static void
2789 SetChildDefaultCharacterSet(nsIMarkupDocumentViewer* aChild, void* aClosure)
2791 const nsACString* charset = static_cast<nsACString*>(aClosure);
2792 aChild->SetDefaultCharacterSet(*charset);
2795 NS_IMETHODIMP
2796 DocumentViewerImpl::SetDefaultCharacterSet(const nsACString& aDefaultCharacterSet)
2798 mDefaultCharacterSet = aDefaultCharacterSet; // this does a copy of aDefaultCharacterSet
2799 // now set the default char set on all children of mContainer
2800 CallChildren(SetChildDefaultCharacterSet, (void*) &aDefaultCharacterSet);
2801 return NS_OK;
2804 // XXX: SEMANTIC CHANGE!
2805 // returns a copy of the string. Caller is responsible for freeing result
2806 // using Recycle(aForceCharacterSet)
2807 NS_IMETHODIMP DocumentViewerImpl::GetForceCharacterSet(nsACString& aForceCharacterSet)
2809 aForceCharacterSet = mForceCharacterSet;
2810 return NS_OK;
2813 static void
2814 SetChildForceCharacterSet(nsIMarkupDocumentViewer* aChild, void* aClosure)
2816 const nsACString* charset = static_cast<nsACString*>(aClosure);
2817 aChild->SetForceCharacterSet(*charset);
2820 NS_IMETHODIMP
2821 DocumentViewerImpl::SetForceCharacterSet(const nsACString& aForceCharacterSet)
2823 mForceCharacterSet = aForceCharacterSet;
2824 // now set the force char set on all children of mContainer
2825 CallChildren(SetChildForceCharacterSet, (void*) &aForceCharacterSet);
2826 return NS_OK;
2829 // XXX: SEMANTIC CHANGE!
2830 // returns a copy of the string. Caller is responsible for freeing result
2831 // using Recycle(aHintCharacterSet)
2832 NS_IMETHODIMP DocumentViewerImpl::GetHintCharacterSet(nsACString& aHintCharacterSet)
2835 if(kCharsetUninitialized == mHintCharsetSource) {
2836 aHintCharacterSet.Truncate();
2837 } else {
2838 aHintCharacterSet = mHintCharset;
2839 // this can't possibly be right. we can't set a value just because somebody got a related value!
2840 //mHintCharsetSource = kCharsetUninitialized;
2842 return NS_OK;
2845 NS_IMETHODIMP DocumentViewerImpl::GetHintCharacterSetSource(PRInt32 *aHintCharacterSetSource)
2847 NS_ENSURE_ARG_POINTER(aHintCharacterSetSource);
2849 *aHintCharacterSetSource = mHintCharsetSource;
2850 return NS_OK;
2854 NS_IMETHODIMP DocumentViewerImpl::GetPrevDocCharacterSet(nsACString& aPrevDocCharacterSet)
2856 aPrevDocCharacterSet = mPrevDocCharacterSet;
2858 return NS_OK;
2861 static void
2862 SetChildPrevDocCharacterSet(nsIMarkupDocumentViewer* aChild, void* aClosure)
2864 const nsACString* charset = static_cast<nsACString*>(aClosure);
2865 aChild->SetPrevDocCharacterSet(*charset);
2869 NS_IMETHODIMP
2870 DocumentViewerImpl::SetPrevDocCharacterSet(const nsACString& aPrevDocCharacterSet)
2872 mPrevDocCharacterSet = aPrevDocCharacterSet;
2873 CallChildren(SetChildPrevDocCharacterSet, (void*) &aPrevDocCharacterSet);
2874 return NS_OK;
2878 static void
2879 SetChildHintCharacterSetSource(nsIMarkupDocumentViewer* aChild, void* aClosure)
2881 aChild->SetHintCharacterSetSource(NS_PTR_TO_INT32(aClosure));
2884 NS_IMETHODIMP
2885 DocumentViewerImpl::SetHintCharacterSetSource(PRInt32 aHintCharacterSetSource)
2887 mHintCharsetSource = aHintCharacterSetSource;
2888 // now set the hint char set source on all children of mContainer
2889 CallChildren(SetChildHintCharacterSetSource,
2890 (void*) aHintCharacterSetSource);
2891 return NS_OK;
2894 static void
2895 SetChildHintCharacterSet(nsIMarkupDocumentViewer* aChild, void* aClosure)
2897 const nsACString* charset = static_cast<nsACString*>(aClosure);
2898 aChild->SetHintCharacterSet(*charset);
2901 NS_IMETHODIMP
2902 DocumentViewerImpl::SetHintCharacterSet(const nsACString& aHintCharacterSet)
2904 mHintCharset = aHintCharacterSet;
2905 // now set the hint char set on all children of mContainer
2906 CallChildren(SetChildHintCharacterSet, (void*) &aHintCharacterSet);
2907 return NS_OK;
2910 static void
2911 SetChildBidiOptions(nsIMarkupDocumentViewer* aChild, void* aClosure)
2913 aChild->SetBidiOptions(NS_PTR_TO_INT32(aClosure));
2916 NS_IMETHODIMP DocumentViewerImpl::SetBidiTextDirection(PRUint8 aTextDirection)
2918 PRUint32 bidiOptions;
2920 GetBidiOptions(&bidiOptions);
2921 SET_BIDI_OPTION_DIRECTION(bidiOptions, aTextDirection);
2922 SetBidiOptions(bidiOptions);
2923 return NS_OK;
2926 NS_IMETHODIMP DocumentViewerImpl::GetBidiTextDirection(PRUint8* aTextDirection)
2928 PRUint32 bidiOptions;
2930 if (aTextDirection) {
2931 GetBidiOptions(&bidiOptions);
2932 *aTextDirection = GET_BIDI_OPTION_DIRECTION(bidiOptions);
2934 return NS_OK;
2937 NS_IMETHODIMP DocumentViewerImpl::SetBidiTextType(PRUint8 aTextType)
2939 PRUint32 bidiOptions;
2941 GetBidiOptions(&bidiOptions);
2942 SET_BIDI_OPTION_TEXTTYPE(bidiOptions, aTextType);
2943 SetBidiOptions(bidiOptions);
2944 return NS_OK;
2947 NS_IMETHODIMP DocumentViewerImpl::GetBidiTextType(PRUint8* aTextType)
2949 PRUint32 bidiOptions;
2951 if (aTextType) {
2952 GetBidiOptions(&bidiOptions);
2953 *aTextType = GET_BIDI_OPTION_TEXTTYPE(bidiOptions);
2955 return NS_OK;
2958 NS_IMETHODIMP DocumentViewerImpl::SetBidiControlsTextMode(PRUint8 aControlsTextMode)
2960 PRUint32 bidiOptions;
2962 GetBidiOptions(&bidiOptions);
2963 SET_BIDI_OPTION_CONTROLSTEXTMODE(bidiOptions, aControlsTextMode);
2964 SetBidiOptions(bidiOptions);
2965 return NS_OK;
2968 NS_IMETHODIMP DocumentViewerImpl::GetBidiControlsTextMode(PRUint8* aControlsTextMode)
2970 PRUint32 bidiOptions;
2972 if (aControlsTextMode) {
2973 GetBidiOptions(&bidiOptions);
2974 *aControlsTextMode = GET_BIDI_OPTION_CONTROLSTEXTMODE(bidiOptions);
2976 return NS_OK;
2979 NS_IMETHODIMP DocumentViewerImpl::SetBidiNumeral(PRUint8 aNumeral)
2981 PRUint32 bidiOptions;
2983 GetBidiOptions(&bidiOptions);
2984 SET_BIDI_OPTION_NUMERAL(bidiOptions, aNumeral);
2985 SetBidiOptions(bidiOptions);
2986 return NS_OK;
2989 NS_IMETHODIMP DocumentViewerImpl::GetBidiNumeral(PRUint8* aNumeral)
2991 PRUint32 bidiOptions;
2993 if (aNumeral) {
2994 GetBidiOptions(&bidiOptions);
2995 *aNumeral = GET_BIDI_OPTION_NUMERAL(bidiOptions);
2997 return NS_OK;
3000 NS_IMETHODIMP DocumentViewerImpl::SetBidiSupport(PRUint8 aSupport)
3002 PRUint32 bidiOptions;
3004 GetBidiOptions(&bidiOptions);
3005 SET_BIDI_OPTION_SUPPORT(bidiOptions, aSupport);
3006 SetBidiOptions(bidiOptions);
3007 return NS_OK;
3010 NS_IMETHODIMP DocumentViewerImpl::GetBidiSupport(PRUint8* aSupport)
3012 PRUint32 bidiOptions;
3014 if (aSupport) {
3015 GetBidiOptions(&bidiOptions);
3016 *aSupport = GET_BIDI_OPTION_SUPPORT(bidiOptions);
3018 return NS_OK;
3021 NS_IMETHODIMP DocumentViewerImpl::SetBidiCharacterSet(PRUint8 aCharacterSet)
3023 PRUint32 bidiOptions;
3025 GetBidiOptions(&bidiOptions);
3026 SET_BIDI_OPTION_CHARACTERSET(bidiOptions, aCharacterSet);
3027 SetBidiOptions(bidiOptions);
3028 return NS_OK;
3031 NS_IMETHODIMP DocumentViewerImpl::GetBidiCharacterSet(PRUint8* aCharacterSet)
3033 PRUint32 bidiOptions;
3035 if (aCharacterSet) {
3036 GetBidiOptions(&bidiOptions);
3037 *aCharacterSet = GET_BIDI_OPTION_CHARACTERSET(bidiOptions);
3039 return NS_OK;
3042 NS_IMETHODIMP DocumentViewerImpl::SetBidiOptions(PRUint32 aBidiOptions)
3044 if (mPresContext) {
3045 mPresContext->SetBidi(aBidiOptions, PR_TRUE); // could cause reflow
3047 // now set bidi on all children of mContainer
3048 CallChildren(SetChildBidiOptions, (void*) aBidiOptions);
3049 return NS_OK;
3052 NS_IMETHODIMP DocumentViewerImpl::GetBidiOptions(PRUint32* aBidiOptions)
3054 if (aBidiOptions) {
3055 if (mPresContext) {
3056 *aBidiOptions = mPresContext->GetBidi();
3058 else
3059 *aBidiOptions = IBMBIDI_DEFAULT_BIDI_OPTIONS;
3061 return NS_OK;
3064 NS_IMETHODIMP DocumentViewerImpl::SizeToContent()
3066 NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
3068 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryReferent(mContainer));
3069 NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
3071 nsCOMPtr<nsIDocShellTreeItem> docShellParent;
3072 docShellAsItem->GetSameTypeParent(getter_AddRefs(docShellParent));
3074 // It's only valid to access this from a top frame. Doesn't work from
3075 // sub-frames.
3076 NS_ENSURE_TRUE(!docShellParent, NS_ERROR_FAILURE);
3078 nsCOMPtr<nsIPresShell> presShell;
3079 GetPresShell(getter_AddRefs(presShell));
3080 NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
3082 // Flush out all content and style updates. We can't use a resize reflow
3083 // because it won't change some sizes that a style change reflow will.
3084 mDocument->FlushPendingNotifications(Flush_Layout);
3086 nsIFrame *root = presShell->GetRootFrame();
3087 NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
3089 nscoord prefWidth;
3091 nsCOMPtr<nsIRenderingContext> rcx;
3092 presShell->CreateRenderingContext(root, getter_AddRefs(rcx));
3093 NS_ENSURE_TRUE(rcx, NS_ERROR_FAILURE);
3094 prefWidth = root->GetPrefWidth(rcx);
3097 nsresult rv = presShell->ResizeReflow(prefWidth, NS_UNCONSTRAINEDSIZE);
3098 NS_ENSURE_SUCCESS(rv, rv);
3100 nsCOMPtr<nsPresContext> presContext;
3101 GetPresContext(getter_AddRefs(presContext));
3102 NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
3104 PRInt32 width, height;
3106 // so how big is it?
3107 nsRect shellArea = presContext->GetVisibleArea();
3108 // Protect against bogus returns here
3109 NS_ENSURE_TRUE(shellArea.width != NS_UNCONSTRAINEDSIZE &&
3110 shellArea.height != NS_UNCONSTRAINEDSIZE,
3111 NS_ERROR_FAILURE);
3112 width = presContext->AppUnitsToDevPixels(shellArea.width);
3113 height = presContext->AppUnitsToDevPixels(shellArea.height);
3115 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
3116 docShellAsItem->GetTreeOwner(getter_AddRefs(treeOwner));
3117 NS_ENSURE_TRUE(treeOwner, NS_ERROR_FAILURE);
3119 /* presContext's size was calculated in app units and has already been
3120 rounded to the equivalent pixels (so the width/height calculation
3121 we just performed was probably exact, though it was based on
3122 values already rounded during ResizeReflow). In a surprising
3123 number of instances, this rounding makes a window which for want
3124 of one extra pixel's width ends up wrapping the longest line of
3125 text during actual window layout. This makes the window too short,
3126 generally clipping the OK/Cancel buttons. Here we add one pixel
3127 to the calculated width, to circumvent this problem. */
3128 NS_ENSURE_SUCCESS(treeOwner->SizeShellTo(docShellAsItem, width+1, height),
3129 NS_ERROR_FAILURE);
3131 return NS_OK;
3135 NS_IMPL_ISUPPORTS1(nsDocViewerSelectionListener, nsISelectionListener)
3137 nsresult nsDocViewerSelectionListener::Init(DocumentViewerImpl *aDocViewer)
3139 mDocViewer = aDocViewer;
3140 return NS_OK;
3144 * GetPopupNode, GetPopupLinkNode and GetPopupImageNode are helpers
3145 * for the cmd_copyLink / cmd_copyImageLocation / cmd_copyImageContents family
3146 * of commands. The focus controller stores the popup node, these retrieve
3147 * them and munge appropriately. Note that we have to store the popup node
3148 * rather than retrieving it from EventStateManager::GetFocusedContent because
3149 * not all content (images included) can receive focus.
3152 nsresult
3153 DocumentViewerImpl::GetPopupNode(nsIDOMNode** aNode)
3155 NS_ENSURE_ARG_POINTER(aNode);
3157 nsresult rv;
3159 // get the document
3160 nsCOMPtr<nsIDocument> document;
3161 rv = GetDocument(getter_AddRefs(document));
3162 NS_ENSURE_SUCCESS(rv, rv);
3163 NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
3166 // get the private dom window
3167 nsPIDOMWindow *privateWin = document->GetWindow();
3168 NS_ENSURE_TRUE(privateWin, NS_ERROR_NOT_AVAILABLE);
3170 // get the focus controller
3171 nsIFocusController *focusController = privateWin->GetRootFocusController();
3172 NS_ENSURE_TRUE(focusController, NS_ERROR_FAILURE);
3174 // get the popup node
3175 focusController->GetPopupNode(aNode); // addref happens here
3177 return rv;
3180 // GetPopupLinkNode: return popup link node or fail
3181 nsresult
3182 DocumentViewerImpl::GetPopupLinkNode(nsIDOMNode** aNode)
3184 NS_ENSURE_ARG_POINTER(aNode);
3186 // you get null unless i say so
3187 *aNode = nsnull;
3189 // find popup node
3190 nsCOMPtr<nsIDOMNode> node;
3191 nsresult rv = GetPopupNode(getter_AddRefs(node));
3192 NS_ENSURE_SUCCESS(rv, rv);
3194 // find out if we have a link in our ancestry
3195 while (node) {
3197 // are we an anchor?
3198 nsCOMPtr<nsIDOMHTMLAnchorElement> anchor(do_QueryInterface(node));
3199 nsCOMPtr<nsIDOMHTMLAreaElement> area;
3200 nsCOMPtr<nsIDOMHTMLLinkElement> link;
3201 nsAutoString xlinkType;
3202 if (!anchor) {
3203 // area?
3204 area = do_QueryInterface(node);
3205 if (!area) {
3206 // link?
3207 link = do_QueryInterface(node);
3208 if (!link) {
3209 // XLink?
3210 nsCOMPtr<nsIDOMElement> element(do_QueryInterface(node));
3211 if (element) {
3212 element->GetAttributeNS(NS_LITERAL_STRING("http://www.w3.org/1999/xlink"),NS_LITERAL_STRING("type"),xlinkType);
3217 if (anchor || area || link || xlinkType.EqualsLiteral("simple")) {
3218 *aNode = node;
3219 NS_IF_ADDREF(*aNode); // addref
3220 return NS_OK;
3222 else {
3223 // if not, get our parent and keep trying...
3224 nsCOMPtr<nsIDOMNode> parentNode;
3225 node->GetParentNode(getter_AddRefs(parentNode));
3226 node = parentNode;
3230 // if we have no node, fail
3231 return NS_ERROR_FAILURE;
3234 // GetPopupLinkNode: return popup image node or fail
3235 nsresult
3236 DocumentViewerImpl::GetPopupImageNode(nsIImageLoadingContent** aNode)
3238 NS_ENSURE_ARG_POINTER(aNode);
3240 // you get null unless i say so
3241 *aNode = nsnull;
3243 // find popup node
3244 nsCOMPtr<nsIDOMNode> node;
3245 nsresult rv = GetPopupNode(getter_AddRefs(node));
3246 NS_ENSURE_SUCCESS(rv, rv);
3248 if (node)
3249 CallQueryInterface(node, aNode);
3251 return NS_OK;
3255 * XXX dr
3256 * ------
3257 * These two functions -- GetInLink and GetInImage -- are kind of annoying
3258 * in that they only get called from the controller (in
3259 * nsDOMWindowController::IsCommandEnabled). The actual construction of the
3260 * context menus in communicator (nsContextMenu.js) has its own, redundant
3261 * tests. No big deal, but good to keep in mind if we ever clean context
3262 * menus.
3265 NS_IMETHODIMP DocumentViewerImpl::GetInLink(PRBool* aInLink)
3267 #ifdef DEBUG_dr
3268 printf("dr :: DocumentViewerImpl::GetInLink\n");
3269 #endif
3271 NS_ENSURE_ARG_POINTER(aInLink);
3273 // we're not in a link unless i say so
3274 *aInLink = PR_FALSE;
3276 // get the popup link
3277 nsCOMPtr<nsIDOMNode> node;
3278 nsresult rv = GetPopupLinkNode(getter_AddRefs(node));
3279 if (NS_FAILED(rv)) return rv;
3280 NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
3282 // if we made it here, we're in a link
3283 *aInLink = PR_TRUE;
3284 return NS_OK;
3287 NS_IMETHODIMP DocumentViewerImpl::GetInImage(PRBool* aInImage)
3289 #ifdef DEBUG_dr
3290 printf("dr :: DocumentViewerImpl::GetInImage\n");
3291 #endif
3293 NS_ENSURE_ARG_POINTER(aInImage);
3295 // we're not in an image unless i say so
3296 *aInImage = PR_FALSE;
3298 // get the popup image
3299 nsCOMPtr<nsIImageLoadingContent> node;
3300 nsresult rv = GetPopupImageNode(getter_AddRefs(node));
3301 if (NS_FAILED(rv)) return rv;
3302 NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
3304 // if we made it here, we're in an image
3305 *aInImage = PR_TRUE;
3306 return NS_OK;
3309 NS_IMETHODIMP nsDocViewerSelectionListener::NotifySelectionChanged(nsIDOMDocument *, nsISelection *, PRInt16)
3311 NS_ASSERTION(mDocViewer, "Should have doc viewer!");
3313 // get the selection state
3314 nsCOMPtr<nsISelection> selection;
3315 nsresult rv = mDocViewer->GetDocumentSelection(getter_AddRefs(selection));
3316 if (NS_FAILED(rv)) return rv;
3318 PRBool selectionCollapsed;
3319 selection->GetIsCollapsed(&selectionCollapsed);
3320 // we only call UpdateCommands when the selection changes from collapsed
3321 // to non-collapsed or vice versa. We might need another update string
3322 // for simple selection changes, but that would be expenseive.
3323 if (!mGotSelectionState || mSelectionWasCollapsed != selectionCollapsed)
3325 nsCOMPtr<nsIDocument> theDoc;
3326 mDocViewer->GetDocument(getter_AddRefs(theDoc));
3327 if (!theDoc) return NS_ERROR_FAILURE;
3329 nsPIDOMWindow *domWindow = theDoc->GetWindow();
3330 if (!domWindow) return NS_ERROR_FAILURE;
3332 domWindow->UpdateCommands(NS_LITERAL_STRING("select"));
3333 mGotSelectionState = PR_TRUE;
3334 mSelectionWasCollapsed = selectionCollapsed;
3337 return NS_OK;
3340 //nsDocViewerFocusListener
3341 NS_IMPL_ISUPPORTS2(nsDocViewerFocusListener,
3342 nsIDOMFocusListener,
3343 nsIDOMEventListener)
3345 nsDocViewerFocusListener::nsDocViewerFocusListener()
3346 :mDocViewer(nsnull)
3350 nsDocViewerFocusListener::~nsDocViewerFocusListener(){}
3352 nsresult
3353 nsDocViewerFocusListener::HandleEvent(nsIDOMEvent* aEvent)
3355 return NS_OK;
3358 NS_IMETHODIMP
3359 nsDocViewerFocusListener::Focus(nsIDOMEvent* aEvent)
3361 nsCOMPtr<nsIPresShell> shell;
3362 if(!mDocViewer)
3363 return NS_ERROR_FAILURE;
3365 nsresult result = mDocViewer->GetPresShell(getter_AddRefs(shell));
3366 if(NS_FAILED(result) || !shell)
3367 return result?result:NS_ERROR_FAILURE;
3368 nsCOMPtr<nsISelectionController> selCon;
3369 selCon = do_QueryInterface(shell);
3370 PRInt16 selectionStatus;
3371 selCon->GetDisplaySelection(&selectionStatus);
3373 // If selection was disabled, re-enable it.
3374 if(selectionStatus == nsISelectionController::SELECTION_DISABLED ||
3375 selectionStatus == nsISelectionController::SELECTION_HIDDEN)
3377 selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
3378 selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL);
3380 return result;
3383 NS_IMETHODIMP
3384 nsDocViewerFocusListener::Blur(nsIDOMEvent* aEvent)
3386 nsCOMPtr<nsIPresShell> shell;
3387 if(!mDocViewer)
3388 return NS_ERROR_FAILURE;
3390 nsresult result = mDocViewer->GetPresShell(getter_AddRefs(shell));
3391 if(NS_FAILED(result) || !shell)
3392 return result?result:NS_ERROR_FAILURE;
3393 nsCOMPtr<nsISelectionController> selCon;
3394 selCon = do_QueryInterface(shell);
3395 PRInt16 selectionStatus;
3396 selCon->GetDisplaySelection(&selectionStatus);
3398 // If selection was on, disable it.
3399 if(selectionStatus == nsISelectionController::SELECTION_ON ||
3400 selectionStatus == nsISelectionController::SELECTION_ATTENTION)
3402 selCon->SetDisplaySelection(nsISelectionController::SELECTION_DISABLED);
3403 selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL);
3405 return result;
3409 nsresult
3410 nsDocViewerFocusListener::Init(DocumentViewerImpl *aDocViewer)
3412 mDocViewer = aDocViewer;
3413 return NS_OK;
3416 /** ---------------------------------------------------
3417 * From nsIWebBrowserPrint
3420 #ifdef NS_PRINTING
3422 NS_IMETHODIMP
3423 DocumentViewerImpl::Print(nsIPrintSettings* aPrintSettings,
3424 nsIWebProgressListener* aWebProgressListener)
3427 #ifdef MOZ_XUL
3428 // Temporary code for Bug 136185 / Bug 240490
3429 nsCOMPtr<nsIXULDocument> xulDoc(do_QueryInterface(mDocument));
3430 if (xulDoc) {
3431 nsPrintEngine::ShowPrintErrorDialog(NS_ERROR_GFX_PRINTER_NO_XUL);
3432 return NS_ERROR_FAILURE;
3434 #endif
3436 if (!mContainer) {
3437 PR_PL(("Container was destroyed yet we are still trying to use it!"));
3438 return NS_ERROR_FAILURE;
3441 nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mContainer));
3442 NS_ASSERTION(docShell, "This has to be a docshell");
3444 // Check to see if this document is still busy
3445 // If it is busy and we aren't already "queued" up to print then
3446 // Indicate there is a print pending and cache the args for later
3447 PRUint32 busyFlags = nsIDocShell::BUSY_FLAGS_NONE;
3448 if ((NS_FAILED(docShell->GetBusyFlags(&busyFlags)) ||
3449 (busyFlags != nsIDocShell::BUSY_FLAGS_NONE && busyFlags & nsIDocShell::BUSY_FLAGS_PAGE_LOADING)) &&
3450 !mPrintDocIsFullyLoaded) {
3451 if (!mPrintIsPending) {
3452 mCachedPrintSettings = aPrintSettings;
3453 mCachedPrintWebProgressListner = aWebProgressListener;
3454 mPrintIsPending = PR_TRUE;
3456 PR_PL(("Printing Stopped - document is still busy!"));
3457 return NS_ERROR_GFX_PRINTER_DOC_IS_BUSY;
3460 nsCOMPtr<nsIPresShell> presShell;
3461 docShell->GetPresShell(getter_AddRefs(presShell));
3462 if (!presShell || !mDocument || !mDeviceContext || !mParentWidget) {
3463 PR_PL(("Can't Print without pres shell, document etc"));
3464 return NS_ERROR_FAILURE;
3467 nsresult rv;
3469 // if we are printing another URL, then exit
3470 // the reason we check here is because this method can be called while
3471 // another is still in here (the printing dialog is a good example).
3472 // the only time we can print more than one job at a time is the regression tests
3473 if (GetIsPrinting()) {
3474 // Let the user know we are not ready to print.
3475 rv = NS_ERROR_NOT_AVAILABLE;
3476 nsPrintEngine::ShowPrintErrorDialog(rv);
3477 return rv;
3480 // If we are hosting a full-page plugin, tell it to print
3481 // first. It shows its own native print UI.
3482 nsCOMPtr<nsIPluginDocument> pDoc(do_QueryInterface(mDocument));
3483 if (pDoc)
3484 return pDoc->Print();
3486 if (!mPrintEngine) {
3487 mPrintEngine = new nsPrintEngine();
3488 NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_OUT_OF_MEMORY);
3490 rv = mPrintEngine->Initialize(this, docShell, mDocument,
3491 mDeviceContext, mParentWidget,
3492 #ifdef NS_DEBUG
3493 mDebugFile
3494 #else
3495 nsnull
3496 #endif
3498 if (NS_FAILED(rv)) {
3499 mPrintEngine->Destroy();
3500 mPrintEngine = nsnull;
3501 return rv;
3505 rv = mPrintEngine->Print(aPrintSettings, aWebProgressListener);
3506 if (NS_FAILED(rv)) {
3507 OnDonePrinting();
3509 return rv;
3512 NS_IMETHODIMP
3513 DocumentViewerImpl::PrintPreview(nsIPrintSettings* aPrintSettings,
3514 nsIDOMWindow *aChildDOMWin,
3515 nsIWebProgressListener* aWebProgressListener)
3517 #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
3518 nsresult rv = NS_OK;
3520 if (GetIsPrinting()) {
3521 nsPrintEngine::CloseProgressDialog(aWebProgressListener);
3522 return NS_ERROR_FAILURE;
3525 #ifdef MOZ_XUL
3526 // Temporary code for Bug 136185 / Bug 240490
3527 nsCOMPtr<nsIXULDocument> xulDoc(do_QueryInterface(mDocument));
3528 if (xulDoc) {
3529 nsPrintEngine::CloseProgressDialog(aWebProgressListener);
3530 nsPrintEngine::ShowPrintErrorDialog(NS_ERROR_GFX_PRINTER_NO_XUL, PR_FALSE);
3531 return NS_ERROR_FAILURE;
3533 #endif
3535 if (!mContainer) {
3536 PR_PL(("Container was destroyed yet we are still trying to use it!"));
3537 return NS_ERROR_FAILURE;
3540 nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mContainer));
3541 NS_ASSERTION(docShell, "This has to be a docshell");
3542 nsCOMPtr<nsIPresShell> presShell;
3543 docShell->GetPresShell(getter_AddRefs(presShell));
3544 if (!presShell || !mDocument || !mDeviceContext || !mParentWidget) {
3545 PR_PL(("Can't Print Preview without pres shell, document etc"));
3546 return NS_ERROR_FAILURE;
3549 if (!mPrintEngine) {
3550 mPrintEngine = new nsPrintEngine();
3551 NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_OUT_OF_MEMORY);
3553 rv = mPrintEngine->Initialize(this, docShell, mDocument,
3554 mDeviceContext, mParentWidget,
3555 #ifdef NS_DEBUG
3556 mDebugFile
3557 #else
3558 nsnull
3559 #endif
3561 if (NS_FAILED(rv)) {
3562 mPrintEngine->Destroy();
3563 mPrintEngine = nsnull;
3564 return rv;
3568 rv = mPrintEngine->PrintPreview(aPrintSettings, aChildDOMWin, aWebProgressListener);
3569 if (NS_FAILED(rv)) {
3570 OnDonePrinting();
3572 return rv;
3573 #else
3574 return NS_ERROR_FAILURE;
3575 #endif
3578 //----------------------------------------------------------------------
3579 NS_IMETHODIMP
3580 DocumentViewerImpl::PrintPreviewNavigate(PRInt16 aType, PRInt32 aPageNum)
3582 if (!GetIsPrintPreview() ||
3583 mPrintEngine->GetIsCreatingPrintPreview())
3584 return NS_ERROR_FAILURE;
3586 nsIScrollableView* scrollableView = nsnull;
3587 mPrintEngine->GetPrintPreviewViewManager()->GetRootScrollableView(&scrollableView);
3588 if (scrollableView == nsnull)
3589 return NS_OK;
3591 // Check to see if we can short circut scrolling to the top
3592 if (aType == nsIWebBrowserPrint::PRINTPREVIEW_HOME ||
3593 (aType == nsIWebBrowserPrint::PRINTPREVIEW_GOTO_PAGENUM && aPageNum == 1)) {
3594 scrollableView->ScrollTo(0, 0, PR_TRUE);
3595 return NS_OK;
3598 // Finds the SimplePageSequencer frame
3599 // in PP mPrtPreview->mPrintObject->mSeqFrame is null
3600 nsIFrame* seqFrame = nsnull;
3601 PRInt32 pageCount = 0;
3602 if (NS_FAILED(mPrintEngine->GetSeqFrameAndCountPages(seqFrame, pageCount))) {
3603 return NS_ERROR_FAILURE;
3606 // Figure where we are currently scrolled to
3607 nscoord x;
3608 nscoord y;
3609 scrollableView->GetScrollPosition(x, y);
3611 PRInt32 pageNum = 1;
3612 nsIFrame * fndPageFrame = nsnull;
3613 nsIFrame * currentPage = nsnull;
3615 // If it is "End" then just do a "goto" to the last page
3616 if (aType == nsIWebBrowserPrint::PRINTPREVIEW_END) {
3617 aType = nsIWebBrowserPrint::PRINTPREVIEW_GOTO_PAGENUM;
3618 aPageNum = pageCount;
3621 // Now, locate the current page we are on and
3622 // and the page of the page number
3623 nscoord gap = 0;
3624 nsIFrame* pageFrame = seqFrame->GetFirstChild(nsnull);
3625 while (pageFrame != nsnull) {
3626 nsRect pageRect = pageFrame->GetRect();
3627 if (pageNum == 1) {
3628 gap = pageRect.y;
3630 if (pageRect.Contains(pageRect.x, y)) {
3631 currentPage = pageFrame;
3633 if (pageNum == aPageNum) {
3634 fndPageFrame = pageFrame;
3635 break;
3637 pageNum++;
3638 pageFrame = pageFrame->GetNextSibling();
3641 if (aType == nsIWebBrowserPrint::PRINTPREVIEW_PREV_PAGE) {
3642 if (currentPage) {
3643 fndPageFrame = currentPage->GetPrevInFlow();
3644 if (!fndPageFrame) {
3645 return NS_OK;
3647 } else {
3648 return NS_OK;
3650 } else if (aType == nsIWebBrowserPrint::PRINTPREVIEW_NEXT_PAGE) {
3651 if (currentPage) {
3652 fndPageFrame = currentPage->GetNextInFlow();
3653 if (!fndPageFrame) {
3654 return NS_OK;
3656 } else {
3657 return NS_OK;
3659 } else { // If we get here we are doing "GoTo"
3660 if (aPageNum < 0 || aPageNum > pageCount) {
3661 return NS_OK;
3665 if (fndPageFrame && scrollableView) {
3666 nscoord deadSpaceGapTwips = 0;
3667 nsIPageSequenceFrame * sqf;
3668 if (NS_SUCCEEDED(CallQueryInterface(seqFrame, &sqf))) {
3669 sqf->GetDeadSpaceValue(&deadSpaceGapTwips);
3672 // To compute deadSpaceGap, use the same presContext as was used
3673 // to layout the seqFrame. (That presContext may have different
3674 // TwipsToAppUnits conversion from this->mPresContext)
3675 nscoord deadSpaceGap =
3676 seqFrame->PresContext()->TwipsToAppUnits(deadSpaceGapTwips);
3678 nscoord newYPosn =
3679 nscoord(mPrintEngine->GetPrintPreviewScale() *
3680 float(fndPageFrame->GetPosition().y - deadSpaceGap));
3681 scrollableView->ScrollTo(0, newYPosn, PR_TRUE);
3683 return NS_OK;
3687 /* readonly attribute nsIPrintSettings globalPrintSettings; */
3688 NS_IMETHODIMP
3689 DocumentViewerImpl::GetGlobalPrintSettings(nsIPrintSettings * *aGlobalPrintSettings)
3691 return nsPrintEngine::GetGlobalPrintSettings(aGlobalPrintSettings);
3694 /* readonly attribute boolean doingPrint; */
3695 // XXX This always returns PR_FALSE for subdocuments
3696 NS_IMETHODIMP
3697 DocumentViewerImpl::GetDoingPrint(PRBool *aDoingPrint)
3699 NS_ENSURE_ARG_POINTER(aDoingPrint);
3701 *aDoingPrint = PR_FALSE;
3702 if (mPrintEngine) {
3703 // XXX shouldn't this be GetDoingPrint() ?
3704 return mPrintEngine->GetDoingPrintPreview(aDoingPrint);
3706 return NS_OK;
3709 /* readonly attribute boolean doingPrintPreview; */
3710 // XXX This always returns PR_FALSE for subdocuments
3711 NS_IMETHODIMP
3712 DocumentViewerImpl::GetDoingPrintPreview(PRBool *aDoingPrintPreview)
3714 NS_ENSURE_ARG_POINTER(aDoingPrintPreview);
3716 *aDoingPrintPreview = PR_FALSE;
3717 if (mPrintEngine) {
3718 return mPrintEngine->GetDoingPrintPreview(aDoingPrintPreview);
3720 return NS_OK;
3723 /* readonly attribute nsIPrintSettings currentPrintSettings; */
3724 NS_IMETHODIMP
3725 DocumentViewerImpl::GetCurrentPrintSettings(nsIPrintSettings * *aCurrentPrintSettings)
3727 NS_ENSURE_ARG_POINTER(aCurrentPrintSettings);
3729 *aCurrentPrintSettings = nsnull;
3730 NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
3732 return mPrintEngine->GetCurrentPrintSettings(aCurrentPrintSettings);
3736 /* readonly attribute nsIDOMWindow currentChildDOMWindow; */
3737 NS_IMETHODIMP
3738 DocumentViewerImpl::GetCurrentChildDOMWindow(nsIDOMWindow * *aCurrentChildDOMWindow)
3740 NS_ENSURE_ARG_POINTER(aCurrentChildDOMWindow);
3741 *aCurrentChildDOMWindow = nsnull;
3742 return NS_ERROR_NOT_IMPLEMENTED;
3745 /* void cancel (); */
3746 NS_IMETHODIMP
3747 DocumentViewerImpl::Cancel()
3749 NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
3750 return mPrintEngine->Cancelled();
3753 /* void exitPrintPreview (); */
3754 NS_IMETHODIMP
3755 DocumentViewerImpl::ExitPrintPreview()
3757 if (GetIsPrinting()) return NS_ERROR_FAILURE;
3758 NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
3760 if (GetIsPrintPreview()) {
3761 ReturnToGalleyPresentation();
3763 return NS_OK;
3766 //----------------------------------------------------------------------------------
3767 // Enumerate all the documents for their titles
3768 NS_IMETHODIMP
3769 DocumentViewerImpl::EnumerateDocumentNames(PRUint32* aCount,
3770 PRUnichar*** aResult)
3772 #ifdef NS_PRINTING
3773 NS_ENSURE_ARG(aCount);
3774 NS_ENSURE_ARG_POINTER(aResult);
3775 NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
3777 return mPrintEngine->EnumerateDocumentNames(aCount, aResult);
3778 #else
3779 return NS_ERROR_FAILURE;
3780 #endif
3783 /* readonly attribute boolean isFramesetFrameSelected; */
3784 NS_IMETHODIMP
3785 DocumentViewerImpl::GetIsFramesetFrameSelected(PRBool *aIsFramesetFrameSelected)
3787 #ifdef NS_PRINTING
3788 *aIsFramesetFrameSelected = PR_FALSE;
3789 NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
3791 return mPrintEngine->GetIsFramesetFrameSelected(aIsFramesetFrameSelected);
3792 #else
3793 return NS_ERROR_FAILURE;
3794 #endif
3797 /* readonly attribute long printPreviewNumPages; */
3798 NS_IMETHODIMP
3799 DocumentViewerImpl::GetPrintPreviewNumPages(PRInt32 *aPrintPreviewNumPages)
3801 #ifdef NS_PRINTING
3802 NS_ENSURE_ARG_POINTER(aPrintPreviewNumPages);
3803 NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
3805 return mPrintEngine->GetPrintPreviewNumPages(aPrintPreviewNumPages);
3806 #else
3807 return NS_ERROR_FAILURE;
3808 #endif
3811 /* readonly attribute boolean isFramesetDocument; */
3812 NS_IMETHODIMP
3813 DocumentViewerImpl::GetIsFramesetDocument(PRBool *aIsFramesetDocument)
3815 #ifdef NS_PRINTING
3816 *aIsFramesetDocument = PR_FALSE;
3817 NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
3819 return mPrintEngine->GetIsFramesetDocument(aIsFramesetDocument);
3820 #else
3821 return NS_ERROR_FAILURE;
3822 #endif
3825 /* readonly attribute boolean isIFrameSelected; */
3826 NS_IMETHODIMP
3827 DocumentViewerImpl::GetIsIFrameSelected(PRBool *aIsIFrameSelected)
3829 #ifdef NS_PRINTING
3830 *aIsIFrameSelected = PR_FALSE;
3831 NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
3833 return mPrintEngine->GetIsIFrameSelected(aIsIFrameSelected);
3834 #else
3835 return NS_ERROR_FAILURE;
3836 #endif
3839 /* readonly attribute boolean isRangeSelection; */
3840 NS_IMETHODIMP
3841 DocumentViewerImpl::GetIsRangeSelection(PRBool *aIsRangeSelection)
3843 #ifdef NS_PRINTING
3844 *aIsRangeSelection = PR_FALSE;
3845 NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
3847 return mPrintEngine->GetIsRangeSelection(aIsRangeSelection);
3848 #else
3849 return NS_ERROR_FAILURE;
3850 #endif
3853 //----------------------------------------------------------------------------------
3854 // Printing/Print Preview Helpers
3855 //----------------------------------------------------------------------------------
3857 //----------------------------------------------------------------------------------
3858 // Walks the document tree and tells each DocShell whether Printing/PP is happening
3859 void
3860 DocumentViewerImpl::SetIsPrintingInDocShellTree(nsIDocShellTreeNode* aParentNode,
3861 PRBool aIsPrintingOrPP,
3862 PRBool aStartAtTop)
3864 NS_ASSERTION(aParentNode, "Parent can't be NULL!");
3866 nsCOMPtr<nsIDocShellTreeItem> parentItem(do_QueryInterface(aParentNode));
3868 // find top of "same parent" tree
3869 if (aStartAtTop) {
3870 while (parentItem) {
3871 nsCOMPtr<nsIDocShellTreeItem> parent;
3872 parentItem->GetSameTypeParent(getter_AddRefs(parent));
3873 if (!parent) {
3874 break;
3876 parentItem = do_QueryInterface(parent);
3879 NS_ASSERTION(parentItem, "parentItem can't be null");
3881 // Check to see if the DocShell's ContentViewer is printing/PP
3882 nsCOMPtr<nsIContentViewerContainer> viewerContainer(do_QueryInterface(parentItem));
3883 if (viewerContainer) {
3884 viewerContainer->SetIsPrinting(aIsPrintingOrPP);
3887 // Traverse children to see if any of them are printing.
3888 PRInt32 n;
3889 aParentNode->GetChildCount(&n);
3890 for (PRInt32 i=0; i < n; i++) {
3891 nsCOMPtr<nsIDocShellTreeItem> child;
3892 aParentNode->GetChildAt(i, getter_AddRefs(child));
3893 nsCOMPtr<nsIDocShellTreeNode> childAsNode(do_QueryInterface(child));
3894 NS_ASSERTION(childAsNode, "child isn't nsIDocShellTreeNode");
3895 if (childAsNode) {
3896 SetIsPrintingInDocShellTree(childAsNode, aIsPrintingOrPP, PR_FALSE);
3901 #endif // NS_PRINTING
3903 //------------------------------------------------------------
3904 // XXX this always returns PR_FALSE for subdocuments
3905 PRBool
3906 DocumentViewerImpl::GetIsPrinting()
3908 #ifdef NS_PRINTING
3909 if (mPrintEngine) {
3910 return mPrintEngine->GetIsPrinting();
3912 #endif
3913 return PR_FALSE;
3916 //------------------------------------------------------------
3917 // Notification from the PrintEngine of the current Printing status
3918 void
3919 DocumentViewerImpl::SetIsPrinting(PRBool aIsPrinting)
3921 #ifdef NS_PRINTING
3922 // Set all the docShells in the docshell tree to be printing.
3923 // that way if anyone of them tries to "navigate" it can't
3924 if (mContainer) {
3925 nsCOMPtr<nsIDocShellTreeNode> docShellTreeNode(do_QueryReferent(mContainer));
3926 NS_ASSERTION(docShellTreeNode, "mContainer has to be a nsIDocShellTreeNode");
3927 SetIsPrintingInDocShellTree(docShellTreeNode, aIsPrinting, PR_TRUE);
3929 #endif
3932 //------------------------------------------------------------
3933 // The PrintEngine holds the current value
3934 // this called from inside the DocViewer.
3935 // XXX it always returns PR_FALSE for subdocuments
3936 PRBool
3937 DocumentViewerImpl::GetIsPrintPreview()
3939 #ifdef NS_PRINTING
3940 if (mPrintEngine) {
3941 return mPrintEngine->GetIsPrintPreview();
3943 #endif
3944 return PR_FALSE;
3947 //------------------------------------------------------------
3948 // Notification from the PrintEngine of the current PP status
3949 void
3950 DocumentViewerImpl::SetIsPrintPreview(PRBool aIsPrintPreview)
3952 #ifdef NS_PRINTING
3953 // Set all the docShells in the docshell tree to be printing.
3954 // that way if anyone of them tries to "navigate" it can't
3955 if (mContainer) {
3956 nsCOMPtr<nsIDocShellTreeNode> docShellTreeNode(do_QueryReferent(mContainer));
3957 NS_ASSERTION(docShellTreeNode, "mContainer has to be a nsIDocShellTreeNode");
3958 SetIsPrintingInDocShellTree(docShellTreeNode, aIsPrintPreview, PR_TRUE);
3960 #endif
3963 //----------------------------------------------------------------------------------
3964 // nsIDocumentViewerPrint IFace
3965 //----------------------------------------------------------------------------------
3967 //------------------------------------------------------------
3968 void
3969 DocumentViewerImpl::IncrementDestroyRefCount()
3971 ++mDestroyRefCount;
3974 //------------------------------------------------------------
3976 static void ResetFocusState(nsIDocShell* aDocShell);
3978 void
3979 DocumentViewerImpl::ReturnToGalleyPresentation()
3981 #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
3982 if (!GetIsPrintPreview()) {
3983 NS_ERROR("Wow, we should never get here!");
3984 return;
3987 SetIsPrintPreview(PR_FALSE);
3989 mPrintEngine->TurnScriptingOn(PR_TRUE);
3990 mPrintEngine->Destroy();
3991 mPrintEngine = nsnull;
3993 mViewManager->EnableRefresh(NS_VMREFRESH_DEFERRED);
3995 nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mContainer));
3996 ResetFocusState(docShell);
3998 if (mPresContext)
3999 mPresContext->RestoreImageAnimationMode();
4001 SetTextZoom(mTextZoom);
4002 SetFullZoom(mPageZoom);
4003 Show();
4005 #endif // NS_PRINTING && NS_PRINT_PREVIEW
4008 //------------------------------------------------------------
4009 // Reset ESM focus for all descendent doc shells.
4010 static void
4011 ResetFocusState(nsIDocShell* aDocShell)
4013 nsCOMPtr<nsISimpleEnumerator> docShellEnumerator;
4014 aDocShell->GetDocShellEnumerator(nsIDocShellTreeItem::typeContent,
4015 nsIDocShell::ENUMERATE_FORWARDS,
4016 getter_AddRefs(docShellEnumerator));
4018 nsCOMPtr<nsIDocShell> currentDocShell;
4019 nsCOMPtr<nsISupports> currentContainer;
4020 PRBool hasMoreDocShells;
4021 while (NS_SUCCEEDED(docShellEnumerator->HasMoreElements(&hasMoreDocShells))
4022 && hasMoreDocShells) {
4023 docShellEnumerator->GetNext(getter_AddRefs(currentContainer));
4024 currentDocShell = do_QueryInterface(currentContainer);
4025 if (!currentDocShell) {
4026 break;
4028 nsCOMPtr<nsPresContext> presContext;
4029 currentDocShell->GetPresContext(getter_AddRefs(presContext));
4030 nsIEventStateManager* esm =
4031 presContext ? presContext->EventStateManager() : nsnull;
4032 if (esm) {
4033 esm->SetContentState(nsnull, NS_EVENT_STATE_FOCUS);
4034 esm->SetFocusedContent(nsnull);
4039 //------------------------------------------------------------
4040 // This called ONLY when printing has completed and the DV
4041 // is being notified that it should get rid of the PrintEngine.
4043 // BUT, if we are in Print Preview then we want to ignore the
4044 // notification (we do not get rid of the PrintEngine)
4046 // One small caveat:
4047 // This IS called from two places in this module for cleaning
4048 // up when an error occurred during the start up printing
4049 // and print preview
4051 void
4052 DocumentViewerImpl::OnDonePrinting()
4054 #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
4055 if (mPrintEngine) {
4056 if (GetIsPrintPreview()) {
4057 mPrintEngine->DestroyPrintingData();
4058 } else {
4059 mPrintEngine->Destroy();
4060 mPrintEngine = nsnull;
4063 // We are done printing, now cleanup
4064 if (mDeferredWindowClose) {
4065 mDeferredWindowClose = PR_FALSE;
4066 nsCOMPtr<nsISupports> container = do_QueryReferent(mContainer);
4067 nsCOMPtr<nsIDOMWindowInternal> win = do_GetInterface(container);
4068 if (win)
4069 win->Close();
4070 } else if (mClosingWhilePrinting) {
4071 if (mDocument) {
4072 mDocument->SetScriptGlobalObject(nsnull);
4073 mDocument->Destroy();
4074 mDocument = nsnull;
4076 mClosingWhilePrinting = PR_FALSE;
4077 NS_RELEASE_THIS();
4079 if (mPresContext)
4080 mPresContext->RestoreImageAnimationMode();
4082 #endif // NS_PRINTING && NS_PRINT_PREVIEW
4085 NS_IMETHODIMP DocumentViewerImpl::SetPageMode(PRBool aPageMode, nsIPrintSettings* aPrintSettings)
4087 // XXX Page mode is only partially working; it's currently used for
4088 // reftests that require a paginated context
4089 mIsPageMode = aPageMode;
4090 // Get the current size of what is being viewed
4091 nsRect bounds;
4092 mWindow->GetBounds(bounds);
4094 if (mPresShell) {
4095 // Break circular reference (or something)
4096 mPresShell->EndObservingDocument();
4097 nsCOMPtr<nsISelection> selection;
4098 nsresult rv = GetDocumentSelection(getter_AddRefs(selection));
4099 nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(selection));
4100 if (NS_SUCCEEDED(rv) && selPrivate && mSelectionListener)
4101 selPrivate->RemoveSelectionListener(mSelectionListener);
4102 mPresShell->Destroy();
4105 if (mPresContext) {
4106 mPresContext->SetContainer(nsnull);
4107 mPresContext->SetLinkHandler(nsnull);
4110 mPresShell = nsnull;
4111 mPresContext = nsnull;
4112 mViewManager = nsnull;
4113 mWindow = nsnull;
4115 NS_ENSURE_STATE(mDocument);
4116 if (aPageMode)
4118 mPresContext =
4119 new nsPresContext(mDocument, nsPresContext::eContext_PageLayout);
4120 NS_ENSURE_TRUE(mPresContext, NS_ERROR_OUT_OF_MEMORY);
4121 mPresContext->SetPaginatedScrolling(PR_TRUE);
4122 mPresContext->SetPrintSettings(aPrintSettings);
4123 nsresult rv = mPresContext->Init(mDeviceContext);
4124 NS_ENSURE_SUCCESS(rv, rv);
4126 InitInternal(mParentWidget, nsnull, bounds, PR_TRUE, PR_FALSE, PR_FALSE);
4127 mViewManager->EnableRefresh(NS_VMREFRESH_NO_SYNC);
4129 Show();
4130 return NS_OK;
4133 NS_IMETHODIMP
4134 DocumentViewerImpl::GetHistoryEntry(nsISHEntry **aHistoryEntry)
4136 NS_IF_ADDREF(*aHistoryEntry = mSHEntry);
4137 return NS_OK;