Bumping manifests a=b2g-bump
[gecko.git] / layout / base / nsDocumentViewer.cpp
blob068def476dd123a53e6d7ffb0d897a61784a50a8
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 sw=2 et tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* container for a document and its presentation */
9 #include "nscore.h"
10 #include "nsCOMPtr.h"
11 #include "nsCRT.h"
12 #include "nsString.h"
13 #include "nsReadableUtils.h"
14 #include "nsIContent.h"
15 #include "nsIContentViewerContainer.h"
16 #include "nsIContentViewer.h"
17 #include "nsIDocumentViewerPrint.h"
18 #include "nsIDOMBeforeUnloadEvent.h"
19 #include "nsIDocument.h"
20 #include "nsIDOMWindowUtils.h"
21 #include "nsPresContext.h"
22 #include "nsIPresShell.h"
23 #include "nsStyleSet.h"
24 #include "nsIFrame.h"
25 #include "nsIWritablePropertyBag2.h"
26 #include "nsSubDocumentFrame.h"
28 #include "nsILinkHandler.h"
29 #include "nsIDOMDocument.h"
30 #include "nsISelectionListener.h"
31 #include "nsISelectionPrivate.h"
32 #include "nsIDOMHTMLDocument.h"
33 #include "nsIDOMHTMLElement.h"
34 #include "nsContentUtils.h"
35 #include "nsLayoutStylesheetCache.h"
36 #ifdef ACCESSIBILITY
37 #include "mozilla/a11y/DocAccessible.h"
38 #endif
39 #include "mozilla/BasicEvents.h"
40 #include "mozilla/Preferences.h"
41 #include "mozilla/dom/EncodingUtils.h"
42 #include "mozilla/WeakPtr.h"
44 #include "nsViewManager.h"
45 #include "nsView.h"
47 #include "nsIPageSequenceFrame.h"
48 #include "nsNetUtil.h"
49 #include "nsIContentViewerEdit.h"
50 #include "nsIContentViewerFile.h"
51 #include "mozilla/CSSStyleSheet.h"
52 #include "mozilla/css/Loader.h"
53 #include "nsIInterfaceRequestor.h"
54 #include "nsIInterfaceRequestorUtils.h"
55 #include "nsDocShell.h"
56 #include "nsIBaseWindow.h"
57 #include "nsILayoutHistoryState.h"
58 #include "nsCharsetSource.h"
59 #include "nsHTMLReflowState.h"
60 #include "nsIImageLoadingContent.h"
61 #include "nsCopySupport.h"
62 #include "nsIDOMHTMLFrameSetElement.h"
63 #ifdef MOZ_XUL
64 #include "nsIXULDocument.h"
65 #include "nsXULPopupManager.h"
66 #endif
68 #include "nsIClipboardHelper.h"
70 #include "nsPIDOMWindow.h"
71 #include "nsDOMNavigationTiming.h"
72 #include "nsPIWindowRoot.h"
73 #include "nsJSEnvironment.h"
74 #include "nsFocusManager.h"
76 #include "nsIScrollableFrame.h"
77 #include "nsStyleSheetService.h"
78 #include "nsRenderingContext.h"
79 #include "nsILoadContext.h"
81 #include "nsIPrompt.h"
82 #include "imgIContainer.h" // image animation mode constants
83 #include "SelectionCarets.h"
85 //--------------------------
86 // Printing Include
87 //---------------------------
88 #ifdef NS_PRINTING
90 #include "nsIWebBrowserPrint.h"
92 #include "nsPrintEngine.h"
94 // Print Options
95 #include "nsIPrintSettings.h"
96 #include "nsIPrintOptions.h"
97 #include "nsISimpleEnumerator.h"
99 #ifdef DEBUG
100 // PrintOptions is now implemented by PrintSettingsService
101 static const char sPrintOptionsContractID[] =
102 "@mozilla.org/gfx/printsettings-service;1";
103 #endif // DEBUG
105 #include "nsIPluginDocument.h"
107 #endif // NS_PRINTING
109 //focus
110 #include "nsIDOMEventTarget.h"
111 #include "nsIDOMEventListener.h"
112 #include "nsISelectionController.h"
114 #include "mozilla/EventDispatcher.h"
115 #include "nsISHEntry.h"
116 #include "nsISHistory.h"
117 #include "nsISHistoryInternal.h"
118 #include "nsIWebNavigation.h"
119 #include "nsXMLHttpRequest.h"
121 //paint forcing
122 #include <stdio.h>
124 #include "mozilla/dom/Element.h"
126 using namespace mozilla;
127 using namespace mozilla::dom;
129 #define BEFOREUNLOAD_DISABLED_PREFNAME "dom.disable_beforeunload"
131 //-----------------------------------------------------
132 // PR LOGGING
133 #ifdef MOZ_LOGGING
134 #define FORCE_PR_LOG /* Allow logging in the release build */
135 #endif
137 #include "prlog.h"
139 #ifdef PR_LOGGING
141 #ifdef NS_PRINTING
142 static PRLogModuleInfo *
143 GetPrintingLog()
145 static PRLogModuleInfo *sLog;
146 if (!sLog)
147 sLog = PR_NewLogModule("printing");
148 return sLog;
150 #define PR_PL(_p1) PR_LOG(GetPrintingLog(), PR_LOG_DEBUG, _p1);
151 #endif // NS_PRINTING
153 #define PRT_YESNO(_p) ((_p)?"YES":"NO")
154 #else
155 #define PRT_YESNO(_p)
156 #define PR_PL(_p1)
157 #endif
158 //-----------------------------------------------------
160 class nsDocumentViewer;
161 class nsPrintEventDispatcher;
163 // a small delegate class used to avoid circular references
165 class nsDocViewerSelectionListener : public nsISelectionListener
167 public:
169 // nsISupports interface...
170 NS_DECL_ISUPPORTS
172 // nsISelectionListerner interface
173 NS_DECL_NSISELECTIONLISTENER
175 nsDocViewerSelectionListener()
176 : mDocViewer(nullptr)
177 , mGotSelectionState(false)
178 , mSelectionWasCollapsed(false)
182 nsresult Init(nsDocumentViewer *aDocViewer);
184 protected:
186 virtual ~nsDocViewerSelectionListener() {}
188 nsDocumentViewer* mDocViewer;
189 bool mGotSelectionState;
190 bool mSelectionWasCollapsed;
195 /** editor Implementation of the FocusListener interface
197 class nsDocViewerFocusListener : public nsIDOMEventListener
199 public:
200 /** default constructor
202 nsDocViewerFocusListener();
204 NS_DECL_ISUPPORTS
205 NS_DECL_NSIDOMEVENTLISTENER
207 nsresult Init(nsDocumentViewer *aDocViewer);
209 protected:
210 /** default destructor
212 virtual ~nsDocViewerFocusListener();
214 private:
215 nsDocumentViewer* mDocViewer;
219 //-------------------------------------------------------------
220 class nsDocumentViewer : public nsIContentViewer,
221 public nsIContentViewerEdit,
222 public nsIContentViewerFile,
223 public nsIDocumentViewerPrint
225 #ifdef NS_PRINTING
226 , public nsIWebBrowserPrint
227 #endif
230 friend class nsDocViewerSelectionListener;
231 friend class nsPagePrintTimer;
232 friend class nsPrintEngine;
234 public:
235 nsDocumentViewer();
237 NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
239 // nsISupports interface...
240 NS_DECL_ISUPPORTS
242 // nsIContentViewer interface...
243 NS_DECL_NSICONTENTVIEWER
245 // nsIContentViewerEdit
246 NS_DECL_NSICONTENTVIEWEREDIT
248 // nsIContentViewerFile
249 NS_DECL_NSICONTENTVIEWERFILE
251 #ifdef NS_PRINTING
252 // nsIWebBrowserPrint
253 NS_DECL_NSIWEBBROWSERPRINT
254 #endif
256 typedef void (*CallChildFunc)(nsIContentViewer* aViewer, void* aClosure);
257 void CallChildren(CallChildFunc aFunc, void* aClosure);
259 // nsIDocumentViewerPrint Printing Methods
260 NS_DECL_NSIDOCUMENTVIEWERPRINT
263 static void DispatchBeforePrint(nsIDocument* aTop)
265 DispatchEventToWindowTree(aTop, NS_LITERAL_STRING("beforeprint"));
267 static void DispatchAfterPrint(nsIDocument* aTop)
269 DispatchEventToWindowTree(aTop, NS_LITERAL_STRING("afterprint"));
271 static void DispatchEventToWindowTree(nsIDocument* aTop,
272 const nsAString& aEvent);
274 protected:
275 virtual ~nsDocumentViewer();
277 private:
279 * Creates a view manager, root view, and widget for the root view, setting
280 * mViewManager and mWindow.
281 * @param aSize the initial size in appunits
282 * @param aContainerView the container view to hook our root view up
283 * to as a child, or null if this will be the root view manager
285 nsresult MakeWindow(const nsSize& aSize, nsView* aContainerView);
288 * Create our device context
290 nsresult CreateDeviceContext(nsView* aContainerView);
293 * If aDoCreation is true, this creates the device context, creates a
294 * prescontext if necessary, and calls MakeWindow.
296 * If aForceSetNewDocument is false, then SetNewDocument won't be
297 * called if the window's current document is already mDocument.
299 nsresult InitInternal(nsIWidget* aParentWidget,
300 nsISupports *aState,
301 const nsIntRect& aBounds,
302 bool aDoCreation,
303 bool aNeedMakeCX = true,
304 bool aForceSetNewDocument = true);
306 * @param aDoInitialReflow set to true if you want to kick off the initial
307 * reflow
309 nsresult InitPresentationStuff(bool aDoInitialReflow);
311 nsresult GetPopupNode(nsIDOMNode** aNode);
312 nsresult GetPopupLinkNode(nsIDOMNode** aNode);
313 nsresult GetPopupImageNode(nsIImageLoadingContent** aNode);
315 void PrepareToStartLoad(void);
317 nsresult SyncParentSubDocMap();
319 nsresult GetDocumentSelection(nsISelection **aSelection);
321 void DestroyPresShell();
322 void DestroyPresContext();
324 #ifdef NS_PRINTING
325 // Called when the DocViewer is notified that the state
326 // of Printing or PP has changed
327 void SetIsPrintingInDocShellTree(nsIDocShellTreeItem* aParentNode,
328 bool aIsPrintingOrPP,
329 bool aStartAtTop);
330 #endif // NS_PRINTING
332 // Whether we should attach to the top level widget. This is true if we
333 // are sharing/recycling a single base widget and not creating multiple
334 // child widgets.
335 bool ShouldAttachToTopLevel();
337 protected:
338 // These return the current shell/prescontext etc.
339 nsIPresShell* GetPresShell();
340 nsPresContext* GetPresContext();
341 nsViewManager* GetViewManager();
343 void DetachFromTopLevelWidget();
345 // IMPORTANT: The ownership implicit in the following member
346 // variables has been explicitly checked and set using nsCOMPtr
347 // for owning pointers and raw COM interface pointers for weak
348 // (ie, non owning) references. If you add any members to this
349 // class, please make the ownership explicit (pinkerton, scc).
351 WeakPtr<nsDocShell> mContainer; // it owns me!
352 nsWeakPtr mTopContainerWhilePrinting;
353 nsRefPtr<nsDeviceContext> mDeviceContext; // We create and own this baby
355 // the following six items are explicitly in this order
356 // so they will be destroyed in the reverse order (pinkerton, scc)
357 nsCOMPtr<nsIDocument> mDocument;
358 nsCOMPtr<nsIWidget> mWindow; // may be null
359 nsRefPtr<nsViewManager> mViewManager;
360 nsRefPtr<nsPresContext> mPresContext;
361 nsCOMPtr<nsIPresShell> mPresShell;
363 nsCOMPtr<nsISelectionListener> mSelectionListener;
364 nsRefPtr<nsDocViewerFocusListener> mFocusListener;
366 nsCOMPtr<nsIContentViewer> mPreviousViewer;
367 nsCOMPtr<nsISHEntry> mSHEntry;
369 nsIWidget* mParentWidget; // purposely won't be ref counted. May be null
370 bool mAttachedToParent; // view is attached to the parent widget
372 nsIntRect mBounds;
374 // mTextZoom/mPageZoom record the textzoom/pagezoom of the first (galley)
375 // presshell only.
376 float mTextZoom; // Text zoom, defaults to 1.0
377 float mPageZoom;
378 int mMinFontSize;
380 int16_t mNumURLStarts;
381 int16_t mDestroyRefCount; // a second "refcount" for the document viewer's "destroy"
383 unsigned mStopped : 1;
384 unsigned mLoaded : 1;
385 unsigned mDeferredWindowClose : 1;
386 // document management data
387 // these items are specific to markup documents (html and xml)
388 // may consider splitting these out into a subclass
389 unsigned mIsSticky : 1;
390 unsigned mInPermitUnload : 1;
391 unsigned mInPermitUnloadPrompt: 1;
393 #ifdef NS_PRINTING
394 unsigned mClosingWhilePrinting : 1;
396 #if NS_PRINT_PREVIEW
397 unsigned mPrintPreviewZoomed : 1;
399 // These data members support delayed printing when the document is loading
400 unsigned mPrintIsPending : 1;
401 unsigned mPrintDocIsFullyLoaded : 1;
402 nsCOMPtr<nsIPrintSettings> mCachedPrintSettings;
403 nsCOMPtr<nsIWebProgressListener> mCachedPrintWebProgressListner;
405 nsRefPtr<nsPrintEngine> mPrintEngine;
406 float mOriginalPrintPreviewScale;
407 float mPrintPreviewZoom;
408 nsAutoPtr<nsPrintEventDispatcher> mBeforeAndAfterPrint;
409 #endif // NS_PRINT_PREVIEW
411 #ifdef DEBUG
412 FILE* mDebugFile;
413 #endif // DEBUG
414 #endif // NS_PRINTING
416 /* character set member data */
417 int32_t mHintCharsetSource;
418 nsCString mHintCharset;
419 nsCString mForceCharacterSet;
421 bool mIsPageMode;
422 bool mCallerIsClosingWindow;
423 bool mInitializedForPrintPreview;
424 bool mHidden;
427 class nsPrintEventDispatcher
429 public:
430 explicit nsPrintEventDispatcher(nsIDocument* aTop) : mTop(aTop)
432 nsDocumentViewer::DispatchBeforePrint(mTop);
434 ~nsPrintEventDispatcher()
436 nsDocumentViewer::DispatchAfterPrint(mTop);
439 nsCOMPtr<nsIDocument> mTop;
442 class nsDocumentShownDispatcher : public nsRunnable
444 public:
445 explicit nsDocumentShownDispatcher(nsCOMPtr<nsIDocument> aDocument)
446 : mDocument(aDocument) {}
448 NS_IMETHOD Run() MOZ_OVERRIDE;
450 private:
451 nsCOMPtr<nsIDocument> mDocument;
455 //------------------------------------------------------------------
456 // nsDocumentViewer
457 //------------------------------------------------------------------
459 //------------------------------------------------------------------
460 already_AddRefed<nsIContentViewer>
461 NS_NewContentViewer()
463 nsRefPtr<nsDocumentViewer> viewer = new nsDocumentViewer();
464 return viewer.forget();
467 void nsDocumentViewer::PrepareToStartLoad()
469 mStopped = false;
470 mLoaded = false;
471 mAttachedToParent = false;
472 mDeferredWindowClose = false;
473 mCallerIsClosingWindow = false;
475 #ifdef NS_PRINTING
476 mPrintIsPending = false;
477 mPrintDocIsFullyLoaded = false;
478 mClosingWhilePrinting = false;
480 // Make sure we have destroyed it and cleared the data member
481 if (mPrintEngine) {
482 mPrintEngine->Destroy();
483 mPrintEngine = nullptr;
484 #ifdef NS_PRINT_PREVIEW
485 SetIsPrintPreview(false);
486 #endif
489 #ifdef DEBUG
490 mDebugFile = nullptr;
491 #endif
493 #endif // NS_PRINTING
496 // Note: operator new zeros our memory, so no need to init things to null.
497 nsDocumentViewer::nsDocumentViewer()
498 : mTextZoom(1.0), mPageZoom(1.0), mMinFontSize(0),
499 mIsSticky(true),
500 #ifdef NS_PRINT_PREVIEW
501 mPrintPreviewZoom(1.0),
502 #endif
503 mHintCharsetSource(kCharsetUninitialized),
504 mInitializedForPrintPreview(false),
505 mHidden(false)
507 PrepareToStartLoad();
510 NS_IMPL_ADDREF(nsDocumentViewer)
511 NS_IMPL_RELEASE(nsDocumentViewer)
513 NS_INTERFACE_MAP_BEGIN(nsDocumentViewer)
514 NS_INTERFACE_MAP_ENTRY(nsIContentViewer)
515 NS_INTERFACE_MAP_ENTRY(nsIContentViewerFile)
516 NS_INTERFACE_MAP_ENTRY(nsIContentViewerEdit)
517 NS_INTERFACE_MAP_ENTRY(nsIDocumentViewerPrint)
518 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentViewer)
519 #ifdef NS_PRINTING
520 NS_INTERFACE_MAP_ENTRY(nsIWebBrowserPrint)
521 #endif
522 NS_INTERFACE_MAP_END
524 nsDocumentViewer::~nsDocumentViewer()
526 if (mDocument) {
527 Close(nullptr);
528 mDocument->Destroy();
531 NS_ASSERTION(!mPresShell && !mPresContext,
532 "User did not call nsIContentViewer::Destroy");
533 if (mPresShell || mPresContext) {
534 // Make sure we don't hand out a reference to the content viewer to
535 // the SHEntry!
536 mSHEntry = nullptr;
538 Destroy();
541 // XXX(?) Revoke pending invalidate events
545 * This method is called by the Document Loader once a document has
546 * been created for a particular data stream... The content viewer
547 * must cache this document for later use when Init(...) is called.
549 * This method is also called when an out of band document.write() happens.
550 * In that case, the document passed in is the same as the previous document.
552 /* virtual */ void
553 nsDocumentViewer::LoadStart(nsIDocument* aDocument)
555 MOZ_ASSERT(aDocument);
557 if (!mDocument) {
558 mDocument = aDocument;
562 nsresult
563 nsDocumentViewer::SyncParentSubDocMap()
565 nsCOMPtr<nsIDocShell> docShell(mContainer);
566 if (!docShell) {
567 return NS_OK;
570 nsCOMPtr<nsPIDOMWindow> pwin(docShell->GetWindow());
571 if (!mDocument || !pwin) {
572 return NS_OK;
575 nsCOMPtr<Element> element = pwin->GetFrameElementInternal();
576 if (!element) {
577 return NS_OK;
580 nsCOMPtr<nsIDocShellTreeItem> parent;
581 docShell->GetParent(getter_AddRefs(parent));
583 nsCOMPtr<nsPIDOMWindow> parent_win = parent ? parent->GetWindow() : nullptr;
584 if (!parent_win) {
585 return NS_OK;
588 nsCOMPtr<nsIDocument> parent_doc = parent_win->GetDoc();
589 if (!parent_doc) {
590 return NS_OK;
593 if (mDocument && parent_doc->GetSubDocumentFor(element) != mDocument) {
594 mDocument->SuppressEventHandling(nsIDocument::eEvents,
595 parent_doc->EventHandlingSuppressed());
597 return parent_doc->SetSubDocumentFor(element, mDocument);
600 NS_IMETHODIMP
601 nsDocumentViewer::SetContainer(nsIDocShell* aContainer)
603 mContainer = static_cast<nsDocShell*>(aContainer);
604 if (mPresContext) {
605 mPresContext->SetContainer(mContainer);
608 // We're loading a new document into the window where this document
609 // viewer lives, sync the parent document's frame element -> sub
610 // document map
612 return SyncParentSubDocMap();
615 NS_IMETHODIMP
616 nsDocumentViewer::GetContainer(nsIDocShell** aResult)
618 NS_ENSURE_ARG_POINTER(aResult);
620 nsCOMPtr<nsIDocShell> container(mContainer);
621 container.swap(*aResult);
622 return NS_OK;
625 NS_IMETHODIMP
626 nsDocumentViewer::Init(nsIWidget* aParentWidget,
627 const nsIntRect& aBounds)
629 return InitInternal(aParentWidget, nullptr, aBounds, true);
632 nsresult
633 nsDocumentViewer::InitPresentationStuff(bool aDoInitialReflow)
635 if (GetIsPrintPreview())
636 return NS_OK;
638 NS_ASSERTION(!mPresShell,
639 "Someone should have destroyed the presshell!");
641 // Create the style set...
642 nsStyleSet *styleSet;
643 nsresult rv = CreateStyleSet(mDocument, &styleSet);
644 NS_ENSURE_SUCCESS(rv, rv);
646 // Now make the shell for the document
647 mPresShell = mDocument->CreateShell(mPresContext, mViewManager, styleSet);
648 if (!mPresShell) {
649 delete styleSet;
650 return NS_ERROR_FAILURE;
653 // We're done creating the style set
654 styleSet->EndUpdate();
656 if (aDoInitialReflow) {
657 // Since Initialize() will create frames for *all* items
658 // that are currently in the document tree, we need to flush
659 // any pending notifications to prevent the content sink from
660 // duplicating layout frames for content it has added to the tree
661 // but hasn't notified the document about. (Bug 154018)
663 // Note that we are flushing before we add mPresShell as an observer
664 // to avoid bogus notifications.
666 mDocument->FlushPendingNotifications(Flush_ContentAndNotify);
669 mPresShell->BeginObservingDocument();
671 // Initialize our view manager
672 int32_t p2a = mPresContext->AppUnitsPerDevPixel();
673 MOZ_ASSERT(p2a == mPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel());
674 nscoord width = p2a * mBounds.width;
675 nscoord height = p2a * mBounds.height;
677 mViewManager->SetWindowDimensions(width, height);
678 mPresContext->SetTextZoom(mTextZoom);
679 mPresContext->SetFullZoom(mPageZoom);
680 mPresContext->SetBaseMinFontSize(mMinFontSize);
682 p2a = mPresContext->AppUnitsPerDevPixel(); // zoom may have changed it
683 width = p2a * mBounds.width;
684 height = p2a * mBounds.height;
685 if (aDoInitialReflow) {
686 nsCOMPtr<nsIPresShell> shellGrip = mPresShell;
687 // Initial reflow
688 mPresShell->Initialize(width, height);
689 } else {
690 // Store the visible area so it's available for other callers of
691 // Initialize, like nsContentSink::StartLayout.
692 mPresContext->SetVisibleArea(nsRect(0, 0, width, height));
695 // now register ourselves as a selection listener, so that we get
696 // called when the selection changes in the window
697 if (!mSelectionListener) {
698 nsDocViewerSelectionListener *selectionListener =
699 new nsDocViewerSelectionListener();
701 selectionListener->Init(this);
703 // mSelectionListener is a owning reference
704 mSelectionListener = selectionListener;
707 nsCOMPtr<nsISelection> selection;
708 rv = GetDocumentSelection(getter_AddRefs(selection));
709 NS_ENSURE_SUCCESS(rv, rv);
711 nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(selection));
712 rv = selPrivate->AddSelectionListener(mSelectionListener);
713 if (NS_FAILED(rv))
714 return rv;
716 nsRefPtr<SelectionCarets> selectionCaret = mPresShell->GetSelectionCarets();
717 if (selectionCaret) {
718 nsCOMPtr<nsIDocShell> docShell(mContainer);
719 if (docShell) {
720 docShell->AddWeakScrollObserver(selectionCaret);
724 // Save old listener so we can unregister it
725 nsRefPtr<nsDocViewerFocusListener> oldFocusListener = mFocusListener;
727 // focus listener
729 // now register ourselves as a focus listener, so that we get called
730 // when the focus changes in the window
731 nsDocViewerFocusListener *focusListener = new nsDocViewerFocusListener();
733 focusListener->Init(this);
735 // mFocusListener is a strong reference
736 mFocusListener = focusListener;
738 if (mDocument) {
739 mDocument->AddEventListener(NS_LITERAL_STRING("focus"),
740 mFocusListener,
741 false, false);
742 mDocument->AddEventListener(NS_LITERAL_STRING("blur"),
743 mFocusListener,
744 false, false);
746 if (oldFocusListener) {
747 mDocument->RemoveEventListener(NS_LITERAL_STRING("focus"),
748 oldFocusListener, false);
749 mDocument->RemoveEventListener(NS_LITERAL_STRING("blur"),
750 oldFocusListener, false);
754 if (aDoInitialReflow && mDocument) {
755 mDocument->ScrollToRef();
758 return NS_OK;
761 static nsPresContext*
762 CreatePresContext(nsIDocument* aDocument,
763 nsPresContext::nsPresContextType aType,
764 nsView* aContainerView)
766 if (aContainerView)
767 return new nsPresContext(aDocument, aType);
768 return new nsRootPresContext(aDocument, aType);
771 //-----------------------------------------------
772 // This method can be used to initial the "presentation"
773 // The aDoCreation indicates whether it should create
774 // all the new objects or just initialize the existing ones
775 nsresult
776 nsDocumentViewer::InitInternal(nsIWidget* aParentWidget,
777 nsISupports *aState,
778 const nsIntRect& aBounds,
779 bool aDoCreation,
780 bool aNeedMakeCX /*= true*/,
781 bool aForceSetNewDocument /* = true*/)
783 if (mIsPageMode) {
784 // XXXbz should the InitInternal in SetPageMode just pass false
785 // here itself?
786 aForceSetNewDocument = false;
789 // We don't want any scripts to run here. That can cause flushing,
790 // which can cause reentry into initialization of this document viewer,
791 // which would be disastrous.
792 nsAutoScriptBlocker blockScripts;
794 mParentWidget = aParentWidget; // not ref counted
795 mBounds = aBounds;
797 nsresult rv = NS_OK;
798 NS_ENSURE_TRUE(mDocument, NS_ERROR_NULL_POINTER);
800 nsView* containerView = FindContainerView();
802 bool makeCX = false;
803 if (aDoCreation) {
804 nsresult rv = CreateDeviceContext(containerView);
805 NS_ENSURE_SUCCESS(rv, rv);
807 // XXXbz this is a nasty hack to do with the fact that we create
808 // presentations both in Init() and in Show()... Ideally we would only do
809 // it in one place (Show()) and require that callers call init(), open(),
810 // show() in that order or something.
811 if (!mPresContext &&
812 (aParentWidget || containerView || mDocument->IsBeingUsedAsImage() ||
813 (mDocument->GetDisplayDocument() &&
814 mDocument->GetDisplayDocument()->GetShell()))) {
815 // Create presentation context
816 if (mIsPageMode) {
817 //Presentation context already created in SetPageMode which is calling this method
818 } else {
819 mPresContext = CreatePresContext(mDocument,
820 nsPresContext::eContext_Galley, containerView);
822 NS_ENSURE_TRUE(mPresContext, NS_ERROR_OUT_OF_MEMORY);
824 nsresult rv = mPresContext->Init(mDeviceContext);
825 if (NS_FAILED(rv)) {
826 mPresContext = nullptr;
827 return rv;
830 #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
831 makeCX = !GetIsPrintPreview() && aNeedMakeCX; // needs to be true except when we are already in PP or we are enabling/disabling paginated mode.
832 #else
833 makeCX = true;
834 #endif
837 if (mPresContext) {
838 // Create the ViewManager and Root View...
840 // We must do this before we tell the script global object about
841 // this new document since doing that will cause us to re-enter
842 // into nsSubDocumentFrame code through reflows caused by
843 // FlushPendingNotifications() calls down the road...
845 rv = MakeWindow(nsSize(mPresContext->DevPixelsToAppUnits(aBounds.width),
846 mPresContext->DevPixelsToAppUnits(aBounds.height)),
847 containerView);
848 NS_ENSURE_SUCCESS(rv, rv);
849 Hide();
851 #ifdef NS_PRINT_PREVIEW
852 if (mIsPageMode) {
853 // I'm leaving this in a broken state for the moment; we should
854 // be measuring/scaling with the print device context, not the
855 // screen device context, but this is good enough to allow
856 // printing reftests to work.
857 double pageWidth = 0, pageHeight = 0;
858 mPresContext->GetPrintSettings()->GetEffectivePageSize(&pageWidth,
859 &pageHeight);
860 mPresContext->SetPageSize(
861 nsSize(mPresContext->CSSTwipsToAppUnits(NSToIntFloor(pageWidth)),
862 mPresContext->CSSTwipsToAppUnits(NSToIntFloor(pageHeight))));
863 mPresContext->SetIsRootPaginatedDocument(true);
864 mPresContext->SetPageScale(1.0f);
866 #endif
867 } else {
868 // Avoid leaking the old viewer.
869 if (mPreviousViewer) {
870 mPreviousViewer->Destroy();
871 mPreviousViewer = nullptr;
876 nsCOMPtr<nsIInterfaceRequestor> requestor(mContainer);
877 if (requestor) {
878 if (mPresContext) {
879 nsCOMPtr<nsILinkHandler> linkHandler;
880 requestor->GetInterface(NS_GET_IID(nsILinkHandler),
881 getter_AddRefs(linkHandler));
883 mPresContext->SetContainer(mContainer);
884 mPresContext->SetLinkHandler(linkHandler);
887 // Set script-context-owner in the document
889 nsCOMPtr<nsPIDOMWindow> window;
890 requestor->GetInterface(NS_GET_IID(nsPIDOMWindow),
891 getter_AddRefs(window));
893 if (window) {
894 nsCOMPtr<nsIDocument> curDoc = window->GetExtantDoc();
895 if (aForceSetNewDocument || curDoc != mDocument) {
896 rv = window->SetNewDocument(mDocument, aState, false);
897 if (NS_FAILED(rv)) {
898 Destroy();
899 return rv;
901 nsJSContext::LoadStart();
906 if (aDoCreation && mPresContext) {
907 // The ViewManager and Root View was created above (in
908 // MakeWindow())...
910 rv = InitPresentationStuff(!makeCX);
913 return rv;
916 void nsDocumentViewer::SetNavigationTiming(nsDOMNavigationTiming* timing)
918 NS_ASSERTION(mDocument, "Must have a document to set navigation timing.");
919 if (mDocument) {
920 mDocument->SetNavigationTiming(timing);
925 // LoadComplete(aStatus)
927 // aStatus - The status returned from loading the document.
929 // This method is called by the container when the document has been
930 // completely loaded.
932 NS_IMETHODIMP
933 nsDocumentViewer::LoadComplete(nsresult aStatus)
935 /* We need to protect ourself against auto-destruction in case the
936 window is closed while processing the OnLoad event. See bug
937 http://bugzilla.mozilla.org/show_bug.cgi?id=78445 for more
938 explanation.
940 nsRefPtr<nsDocumentViewer> kungFuDeathGrip(this);
942 // Flush out layout so it's up-to-date by the time onload is called.
943 // Note that this could destroy the window, so do this before
944 // checking for our mDocument and its window.
945 if (mPresShell && !mStopped) {
946 // Hold strong ref because this could conceivably run script
947 nsCOMPtr<nsIPresShell> shell = mPresShell;
948 shell->FlushPendingNotifications(Flush_Layout);
951 nsresult rv = NS_OK;
952 NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
954 // First, get the window from the document...
955 nsCOMPtr<nsPIDOMWindow> window = mDocument->GetWindow();
957 mLoaded = true;
959 // Now, fire either an OnLoad or OnError event to the document...
960 bool restoring = false;
961 // XXXbz imagelib kills off the document load for a full-page image with
962 // NS_ERROR_PARSED_DATA_CACHED if it's in the cache. So we want to treat
963 // that one as a success code; otherwise whether we fire onload for the image
964 // will depend on whether it's cached!
965 if(window &&
966 (NS_SUCCEEDED(aStatus) || aStatus == NS_ERROR_PARSED_DATA_CACHED)) {
967 nsEventStatus status = nsEventStatus_eIgnore;
968 WidgetEvent event(true, NS_LOAD);
969 event.mFlags.mBubbles = false;
970 event.mFlags.mCancelable = false;
971 // XXX Dispatching to |window|, but using |document| as the target.
972 event.target = mDocument;
974 // If the document presentation is being restored, we don't want to fire
975 // onload to the document content since that would likely confuse scripts
976 // on the page.
978 nsIDocShell *docShell = window->GetDocShell();
979 NS_ENSURE_TRUE(docShell, NS_ERROR_UNEXPECTED);
981 docShell->GetRestoringDocument(&restoring);
982 if (!restoring) {
983 NS_ASSERTION(mDocument->IsXUL() || // readyState for XUL is bogus
984 mDocument->GetReadyStateEnum() ==
985 nsIDocument::READYSTATE_INTERACTIVE ||
986 // test_stricttransportsecurity.html has old-style
987 // docshell-generated about:blank docs reach this code!
988 (mDocument->GetReadyStateEnum() ==
989 nsIDocument::READYSTATE_UNINITIALIZED &&
990 NS_IsAboutBlank(mDocument->GetDocumentURI())),
991 "Bad readystate");
992 nsCOMPtr<nsIDocument> d = mDocument;
993 mDocument->SetReadyStateInternal(nsIDocument::READYSTATE_COMPLETE);
995 nsRefPtr<nsDOMNavigationTiming> timing(d->GetNavigationTiming());
996 if (timing) {
997 timing->NotifyLoadEventStart();
1000 // Dispatch observer notification to notify observers document load is complete.
1001 nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
1002 nsIPrincipal *principal = d->NodePrincipal();
1003 os->NotifyObservers(d,
1004 nsContentUtils::IsSystemPrincipal(principal) ?
1005 "chrome-document-loaded" :
1006 "content-document-loaded",
1007 nullptr);
1009 EventDispatcher::Dispatch(window, mPresContext, &event, nullptr, &status);
1010 if (timing) {
1011 timing->NotifyLoadEventEnd();
1014 } else {
1015 // XXX: Should fire error event to the document...
1018 // Notify the document that it has been shown (regardless of whether
1019 // it was just loaded). Note: mDocument may be null now if the above
1020 // firing of onload caused the document to unload.
1021 if (mDocument) {
1022 // Re-get window, since it might have changed during above firing of onload
1023 window = mDocument->GetWindow();
1024 if (window) {
1025 nsIDocShell *docShell = window->GetDocShell();
1026 bool isInUnload;
1027 if (docShell && NS_SUCCEEDED(docShell->GetIsInUnload(&isInUnload)) &&
1028 !isInUnload) {
1029 mDocument->OnPageShow(restoring, nullptr);
1034 if (!mStopped) {
1035 if (mDocument) {
1036 mDocument->ScrollToRef();
1039 // Now that the document has loaded, we can tell the presshell
1040 // to unsuppress painting.
1041 if (mPresShell) {
1042 nsCOMPtr<nsIPresShell> shellDeathGrip(mPresShell);
1043 mPresShell->UnsuppressPainting();
1044 // mPresShell could have been removed now, see bug 378682/421432
1045 if (mPresShell) {
1046 mPresShell->LoadComplete();
1051 nsJSContext::LoadEnd();
1053 #ifdef NS_PRINTING
1054 // Check to see if someone tried to print during the load
1055 if (mPrintIsPending) {
1056 mPrintIsPending = false;
1057 mPrintDocIsFullyLoaded = true;
1058 Print(mCachedPrintSettings, mCachedPrintWebProgressListner);
1059 mCachedPrintSettings = nullptr;
1060 mCachedPrintWebProgressListner = nullptr;
1062 #endif
1064 return rv;
1067 NS_IMETHODIMP
1068 nsDocumentViewer::PermitUnload(bool aCallerClosesWindow,
1069 bool *aPermitUnload)
1071 bool shouldPrompt = true;
1072 return PermitUnloadInternal(aCallerClosesWindow, &shouldPrompt,
1073 aPermitUnload);
1077 nsresult
1078 nsDocumentViewer::PermitUnloadInternal(bool aCallerClosesWindow,
1079 bool *aShouldPrompt,
1080 bool *aPermitUnload)
1082 AutoDontWarnAboutSyncXHR disableSyncXHRWarning;
1084 *aPermitUnload = true;
1086 if (!mDocument
1087 || mInPermitUnload
1088 || mCallerIsClosingWindow
1089 || mInPermitUnloadPrompt) {
1090 return NS_OK;
1093 static bool sIsBeforeUnloadDisabled;
1094 static bool sBeforeUnloadPrefCached = false;
1096 if (!sBeforeUnloadPrefCached ) {
1097 sBeforeUnloadPrefCached = true;
1098 Preferences::AddBoolVarCache(&sIsBeforeUnloadDisabled,
1099 BEFOREUNLOAD_DISABLED_PREFNAME);
1102 // If the user has turned off onbeforeunload warnings, no need to check.
1103 if (sIsBeforeUnloadDisabled) {
1104 return NS_OK;
1107 // First, get the script global object from the document...
1108 nsPIDOMWindow *window = mDocument->GetWindow();
1110 if (!window) {
1111 // This is odd, but not fatal
1112 NS_WARNING("window not set for document!");
1113 return NS_OK;
1116 NS_ASSERTION(nsContentUtils::IsSafeToRunScript(), "This is unsafe");
1118 // Now, fire an BeforeUnload event to the document and see if it's ok
1119 // to unload...
1120 nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(mDocument);
1121 nsCOMPtr<nsIDOMEvent> event;
1122 domDoc->CreateEvent(NS_LITERAL_STRING("beforeunloadevent"),
1123 getter_AddRefs(event));
1124 nsCOMPtr<nsIDOMBeforeUnloadEvent> beforeUnload = do_QueryInterface(event);
1125 NS_ENSURE_STATE(beforeUnload);
1126 nsresult rv = event->InitEvent(NS_LITERAL_STRING("beforeunload"),
1127 false, true);
1128 NS_ENSURE_SUCCESS(rv, rv);
1130 // Dispatching to |window|, but using |document| as the target.
1131 event->SetTarget(mDocument);
1132 event->SetTrusted(true);
1134 // In evil cases we might be destroyed while handling the
1135 // onbeforeunload event, don't let that happen. (see also bug#331040)
1136 nsRefPtr<nsDocumentViewer> kungFuDeathGrip(this);
1139 // Never permit popups from the beforeunload handler, no matter
1140 // how we get here.
1141 nsAutoPopupStatePusher popupStatePusher(openAbused, true);
1143 // Never permit dialogs from the beforeunload handler
1144 nsCOMPtr<nsIDOMWindowUtils> utils = do_GetInterface(window);
1145 bool dialogsWereEnabled = false;
1146 utils->AreDialogsEnabled(&dialogsWereEnabled);
1147 utils->DisableDialogs();
1149 mInPermitUnload = true;
1150 EventDispatcher::DispatchDOMEvent(window, nullptr, event, mPresContext,
1151 nullptr);
1152 mInPermitUnload = false;
1153 if (dialogsWereEnabled) {
1154 utils->EnableDialogs();
1158 nsCOMPtr<nsIDocShell> docShell(mContainer);
1159 nsAutoString text;
1160 beforeUnload->GetReturnValue(text);
1161 if (*aShouldPrompt && (event->GetInternalNSEvent()->mFlags.mDefaultPrevented ||
1162 !text.IsEmpty())) {
1163 // Ask the user if it's ok to unload the current page
1165 nsCOMPtr<nsIPrompt> prompt = do_GetInterface(docShell);
1167 if (prompt) {
1168 nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt);
1169 if (promptBag) {
1170 bool isTabModalPromptAllowed;
1171 GetIsTabModalPromptAllowed(&isTabModalPromptAllowed);
1172 promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"),
1173 isTabModalPromptAllowed);
1176 nsXPIDLString title, message, stayLabel, leaveLabel;
1177 rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
1178 "OnBeforeUnloadTitle",
1179 title);
1180 nsresult tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
1181 "OnBeforeUnloadMessage",
1182 message);
1183 if (NS_FAILED(tmp)) {
1184 rv = tmp;
1186 tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
1187 "OnBeforeUnloadLeaveButton",
1188 leaveLabel);
1189 if (NS_FAILED(tmp)) {
1190 rv = tmp;
1192 tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
1193 "OnBeforeUnloadStayButton",
1194 stayLabel);
1195 if (NS_FAILED(tmp)) {
1196 rv = tmp;
1199 if (NS_FAILED(rv) || !title || !message || !stayLabel || !leaveLabel) {
1200 NS_ERROR("Failed to get strings from dom.properties!");
1201 return NS_OK;
1204 // Although the exact value is ignored, we must not pass invalid
1205 // bool values through XPConnect.
1206 bool dummy = false;
1207 int32_t buttonPressed = 0;
1208 uint32_t buttonFlags = (nsIPrompt::BUTTON_POS_0_DEFAULT |
1209 (nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_0) |
1210 (nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_1));
1212 nsAutoSyncOperation sync(mDocument);
1213 mInPermitUnloadPrompt = true;
1214 rv = prompt->ConfirmEx(title, message, buttonFlags,
1215 leaveLabel, stayLabel, nullptr, nullptr,
1216 &dummy, &buttonPressed);
1217 mInPermitUnloadPrompt = false;
1219 // If the prompt aborted, we tell our consumer that it is not allowed
1220 // to unload the page. One reason that prompts abort is that the user
1221 // performed some action that caused the page to unload while our prompt
1222 // was active. In those cases we don't want our consumer to also unload
1223 // the page.
1225 // XXX: Are there other cases where prompts can abort? Is it ok to
1226 // prevent unloading the page in those cases?
1227 if (NS_FAILED(rv)) {
1228 *aPermitUnload = false;
1229 return NS_OK;
1232 // Button 0 == leave, button 1 == stay
1233 *aPermitUnload = (buttonPressed == 0);
1234 // If the user decided to go ahead, make sure not to prompt the user again
1235 // by toggling the internal prompting bool to false:
1236 if (*aPermitUnload) {
1237 *aShouldPrompt = false;
1242 if (docShell) {
1243 int32_t childCount;
1244 docShell->GetChildCount(&childCount);
1246 for (int32_t i = 0; i < childCount && *aPermitUnload; ++i) {
1247 nsCOMPtr<nsIDocShellTreeItem> item;
1248 docShell->GetChildAt(i, getter_AddRefs(item));
1250 nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(item));
1252 if (docShell) {
1253 nsCOMPtr<nsIContentViewer> cv;
1254 docShell->GetContentViewer(getter_AddRefs(cv));
1256 if (cv) {
1257 cv->PermitUnloadInternal(aCallerClosesWindow, aShouldPrompt,
1258 aPermitUnload);
1264 if (aCallerClosesWindow && *aPermitUnload)
1265 mCallerIsClosingWindow = true;
1267 return NS_OK;
1270 NS_IMETHODIMP
1271 nsDocumentViewer::GetBeforeUnloadFiring(bool* aInEvent)
1273 *aInEvent = mInPermitUnload;
1274 return NS_OK;
1277 NS_IMETHODIMP
1278 nsDocumentViewer::GetInPermitUnload(bool* aInEvent)
1280 *aInEvent = mInPermitUnloadPrompt;
1281 return NS_OK;
1284 NS_IMETHODIMP
1285 nsDocumentViewer::ResetCloseWindow()
1287 mCallerIsClosingWindow = false;
1289 nsCOMPtr<nsIDocShell> docShell(mContainer);
1290 if (docShell) {
1291 int32_t childCount;
1292 docShell->GetChildCount(&childCount);
1294 for (int32_t i = 0; i < childCount; ++i) {
1295 nsCOMPtr<nsIDocShellTreeItem> item;
1296 docShell->GetChildAt(i, getter_AddRefs(item));
1298 nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(item));
1300 if (docShell) {
1301 nsCOMPtr<nsIContentViewer> cv;
1302 docShell->GetContentViewer(getter_AddRefs(cv));
1304 if (cv) {
1305 cv->ResetCloseWindow();
1310 return NS_OK;
1313 NS_IMETHODIMP
1314 nsDocumentViewer::PageHide(bool aIsUnload)
1316 AutoDontWarnAboutSyncXHR disableSyncXHRWarning;
1318 mHidden = true;
1320 if (!mDocument) {
1321 return NS_ERROR_NULL_POINTER;
1324 mDocument->OnPageHide(!aIsUnload, nullptr);
1326 // inform the window so that the focus state is reset.
1327 NS_ENSURE_STATE(mDocument);
1328 nsPIDOMWindow *window = mDocument->GetWindow();
1329 if (window)
1330 window->PageHidden();
1332 if (aIsUnload) {
1333 // Poke the GC. The window might be collectable garbage now.
1334 nsJSContext::PokeGC(JS::gcreason::PAGE_HIDE, NS_GC_DELAY * 2);
1336 // if Destroy() was called during OnPageHide(), mDocument is nullptr.
1337 NS_ENSURE_STATE(mDocument);
1339 // First, get the window from the document...
1340 nsPIDOMWindow *window = mDocument->GetWindow();
1342 if (!window) {
1343 // Fail if no window is available...
1344 NS_WARNING("window not set for document!");
1345 return NS_ERROR_NULL_POINTER;
1348 // Now, fire an Unload event to the document...
1349 nsEventStatus status = nsEventStatus_eIgnore;
1350 WidgetEvent event(true, NS_PAGE_UNLOAD);
1351 event.mFlags.mBubbles = false;
1352 // XXX Dispatching to |window|, but using |document| as the target.
1353 event.target = mDocument;
1355 // Never permit popups from the unload handler, no matter how we get
1356 // here.
1357 nsAutoPopupStatePusher popupStatePusher(openAbused, true);
1359 EventDispatcher::Dispatch(window, mPresContext, &event, nullptr, &status);
1362 #ifdef MOZ_XUL
1363 // look for open menupopups and close them after the unload event, in case
1364 // the unload event listeners open any new popups
1365 nsContentUtils::HidePopupsInDocument(mDocument);
1366 #endif
1368 return NS_OK;
1371 static void
1372 AttachContainerRecurse(nsIDocShell* aShell)
1374 nsCOMPtr<nsIContentViewer> viewer;
1375 aShell->GetContentViewer(getter_AddRefs(viewer));
1376 if (viewer) {
1377 viewer->SetIsHidden(false);
1378 nsIDocument* doc = viewer->GetDocument();
1379 if (doc) {
1380 doc->SetContainer(static_cast<nsDocShell*>(aShell));
1382 nsRefPtr<nsPresContext> pc;
1383 viewer->GetPresContext(getter_AddRefs(pc));
1384 if (pc) {
1385 pc->SetContainer(static_cast<nsDocShell*>(aShell));
1386 pc->SetLinkHandler(nsCOMPtr<nsILinkHandler>(do_QueryInterface(aShell)));
1388 nsCOMPtr<nsIPresShell> presShell;
1389 viewer->GetPresShell(getter_AddRefs(presShell));
1390 if (presShell) {
1391 presShell->SetForwardingContainer(WeakPtr<nsDocShell>());
1395 // Now recurse through the children
1396 int32_t childCount;
1397 aShell->GetChildCount(&childCount);
1398 for (int32_t i = 0; i < childCount; ++i) {
1399 nsCOMPtr<nsIDocShellTreeItem> childItem;
1400 aShell->GetChildAt(i, getter_AddRefs(childItem));
1401 AttachContainerRecurse(nsCOMPtr<nsIDocShell>(do_QueryInterface(childItem)));
1405 NS_IMETHODIMP
1406 nsDocumentViewer::Open(nsISupports *aState, nsISHEntry *aSHEntry)
1408 NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);
1410 if (mDocument)
1411 mDocument->SetContainer(mContainer);
1413 nsresult rv = InitInternal(mParentWidget, aState, mBounds, false);
1414 NS_ENSURE_SUCCESS(rv, rv);
1416 mHidden = false;
1418 if (mPresShell)
1419 mPresShell->SetForwardingContainer(WeakPtr<nsDocShell>());
1421 // Rehook the child presentations. The child shells are still in
1422 // session history, so get them from there.
1424 if (aSHEntry) {
1425 nsCOMPtr<nsIDocShellTreeItem> item;
1426 int32_t itemIndex = 0;
1427 while (NS_SUCCEEDED(aSHEntry->ChildShellAt(itemIndex++,
1428 getter_AddRefs(item))) && item) {
1429 AttachContainerRecurse(nsCOMPtr<nsIDocShell>(do_QueryInterface(item)));
1433 SyncParentSubDocMap();
1435 if (mFocusListener && mDocument) {
1436 mDocument->AddEventListener(NS_LITERAL_STRING("focus"), mFocusListener,
1437 false, false);
1438 mDocument->AddEventListener(NS_LITERAL_STRING("blur"), mFocusListener,
1439 false, false);
1442 // XXX re-enable image animations once that works correctly
1444 PrepareToStartLoad();
1446 // When loading a page from the bfcache with puppet widgets, we do the
1447 // widget attachment here (it is otherwise done in MakeWindow, which is
1448 // called for non-bfcache pages in the history, but not bfcache pages).
1449 // Attachment is necessary, since we get detached when another page
1450 // is browsed to. That is, if we are one page A, then when we go to
1451 // page B, we detach. So page A's view has no widget. If we then go
1452 // back to it, and it is in the bfcache, we will use that view, which
1453 // doesn't have a widget. The attach call here will properly attach us.
1454 if (nsIWidget::UsePuppetWidgets() && mPresContext &&
1455 ShouldAttachToTopLevel()) {
1456 // If the old view is already attached to our parent, detach
1457 DetachFromTopLevelWidget();
1459 nsViewManager *vm = GetViewManager();
1460 NS_ABORT_IF_FALSE(vm, "no view manager");
1461 nsView* v = vm->GetRootView();
1462 NS_ABORT_IF_FALSE(v, "no root view");
1463 NS_ABORT_IF_FALSE(mParentWidget, "no mParentWidget to set");
1464 v->AttachToTopLevelWidget(mParentWidget);
1466 mAttachedToParent = true;
1469 return NS_OK;
1472 NS_IMETHODIMP
1473 nsDocumentViewer::Close(nsISHEntry *aSHEntry)
1475 // All callers are supposed to call close to break circular
1476 // references. If we do this stuff in the destructor, the
1477 // destructor might never be called (especially if we're being
1478 // used from JS.
1480 mSHEntry = aSHEntry;
1482 // Close is also needed to disable scripts during paint suppression,
1483 // since we transfer the existing global object to the new document
1484 // that is loaded. In the future, the global object may become a proxy
1485 // for an object that can be switched in and out so that we don't need
1486 // to disable scripts during paint suppression.
1488 if (!mDocument)
1489 return NS_OK;
1491 #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
1492 // Turn scripting back on
1493 // after PrintPreview had turned it off
1494 if (GetIsPrintPreview() && mPrintEngine) {
1495 mPrintEngine->TurnScriptingOn(true);
1497 #endif
1499 #ifdef NS_PRINTING
1500 // A Close was called while we were printing
1501 // so don't clear the ScriptGlobalObject
1502 // or clear the mDocument below
1503 if (mPrintEngine && !mClosingWhilePrinting) {
1504 mClosingWhilePrinting = true;
1505 } else
1506 #endif
1508 // out of band cleanup of docshell
1509 mDocument->SetScriptGlobalObject(nullptr);
1511 if (!mSHEntry && mDocument)
1512 mDocument->RemovedFromDocShell();
1515 if (mFocusListener && mDocument) {
1516 mDocument->RemoveEventListener(NS_LITERAL_STRING("focus"), mFocusListener,
1517 false);
1518 mDocument->RemoveEventListener(NS_LITERAL_STRING("blur"), mFocusListener,
1519 false);
1522 return NS_OK;
1525 static void
1526 DetachContainerRecurse(nsIDocShell *aShell)
1528 // Unhook this docshell's presentation
1529 nsCOMPtr<nsIContentViewer> viewer;
1530 aShell->GetContentViewer(getter_AddRefs(viewer));
1531 if (viewer) {
1532 nsIDocument* doc = viewer->GetDocument();
1533 if (doc) {
1534 doc->SetContainer(nullptr);
1536 nsRefPtr<nsPresContext> pc;
1537 viewer->GetPresContext(getter_AddRefs(pc));
1538 if (pc) {
1539 pc->Detach();
1541 nsCOMPtr<nsIPresShell> presShell;
1542 viewer->GetPresShell(getter_AddRefs(presShell));
1543 if (presShell) {
1544 auto weakShell = static_cast<nsDocShell*>(aShell);
1545 presShell->SetForwardingContainer(weakShell);
1549 // Now recurse through the children
1550 int32_t childCount;
1551 aShell->GetChildCount(&childCount);
1552 for (int32_t i = 0; i < childCount; ++i) {
1553 nsCOMPtr<nsIDocShellTreeItem> childItem;
1554 aShell->GetChildAt(i, getter_AddRefs(childItem));
1555 DetachContainerRecurse(nsCOMPtr<nsIDocShell>(do_QueryInterface(childItem)));
1559 NS_IMETHODIMP
1560 nsDocumentViewer::Destroy()
1562 NS_ASSERTION(mDocument, "No document in Destroy()!");
1564 #ifdef NS_PRINTING
1565 // Here is where we check to see if the document was still being prepared
1566 // for printing when it was asked to be destroy from someone externally
1567 // This usually happens if the document is unloaded while the user is in the
1568 // Print Dialog
1570 // So we flip the bool to remember that the document is going away
1571 // and we can clean up and abort later after returning from the Print Dialog
1572 if (mPrintEngine) {
1573 if (mPrintEngine->CheckBeforeDestroy()) {
1574 return NS_OK;
1577 mBeforeAndAfterPrint = nullptr;
1578 #endif
1580 // Don't let the document get unloaded while we are printing.
1581 // this could happen if we hit the back button during printing.
1582 // We also keep the viewer from being cached in session history, since
1583 // we require all documents there to be sanitized.
1584 if (mDestroyRefCount != 0) {
1585 --mDestroyRefCount;
1586 return NS_OK;
1589 // If we were told to put ourselves into session history instead of destroy
1590 // the presentation, do that now.
1591 if (mSHEntry) {
1592 if (mPresShell)
1593 mPresShell->Freeze();
1595 // Make sure the presentation isn't torn down by Hide().
1596 mSHEntry->SetSticky(mIsSticky);
1597 mIsSticky = true;
1599 bool savePresentation = mDocument ? mDocument->IsBFCachingAllowed() : true;
1601 // Remove our root view from the view hierarchy.
1602 if (mPresShell) {
1603 nsViewManager *vm = mPresShell->GetViewManager();
1604 if (vm) {
1605 nsView *rootView = vm->GetRootView();
1607 if (rootView) {
1608 nsView *rootViewParent = rootView->GetParent();
1609 if (rootViewParent) {
1610 nsViewManager *parentVM = rootViewParent->GetViewManager();
1611 if (parentVM) {
1612 parentVM->RemoveChild(rootView);
1619 Hide();
1621 // This is after Hide() so that the user doesn't see the inputs clear.
1622 if (mDocument) {
1623 mDocument->Sanitize();
1626 // Reverse ownership. Do this *after* calling sanitize so that sanitize
1627 // doesn't cause mutations that make the SHEntry drop the presentation
1629 // Grab a reference to mSHEntry before calling into things like
1630 // SyncPresentationState that might mess with our members.
1631 nsCOMPtr<nsISHEntry> shEntry = mSHEntry; // we'll need this below
1632 mSHEntry = nullptr;
1634 if (savePresentation) {
1635 shEntry->SetContentViewer(this);
1638 // Always sync the presentation state. That way even if someone screws up
1639 // and shEntry has no window state at this point we'll be ok; we just won't
1640 // cache ourselves.
1641 shEntry->SyncPresentationState();
1643 // Shut down accessibility for the document before we start to tear it down.
1644 #ifdef ACCESSIBILITY
1645 if (mPresShell) {
1646 a11y::DocAccessible* docAcc = mPresShell->GetDocAccessible();
1647 if (docAcc) {
1648 docAcc->Shutdown();
1651 #endif
1653 // Break the link from the document/presentation to the docshell, so that
1654 // link traversals cannot affect the currently-loaded document.
1655 // When the presentation is restored, Open() and InitInternal() will reset
1656 // these pointers to their original values.
1658 if (mDocument) {
1659 mDocument->SetContainer(nullptr);
1661 if (mPresContext) {
1662 mPresContext->Detach();
1664 if (mPresShell) {
1665 mPresShell->SetForwardingContainer(mContainer);
1668 // Do the same for our children. Note that we need to get the child
1669 // docshells from the SHEntry now; the docshell will have cleared them.
1670 nsCOMPtr<nsIDocShellTreeItem> item;
1671 int32_t itemIndex = 0;
1672 while (NS_SUCCEEDED(shEntry->ChildShellAt(itemIndex++,
1673 getter_AddRefs(item))) && item) {
1674 DetachContainerRecurse(nsCOMPtr<nsIDocShell>(do_QueryInterface(item)));
1677 return NS_OK;
1680 // The document was not put in the bfcache
1682 if (mPresShell) {
1683 DestroyPresShell();
1685 if (mDocument) {
1686 mDocument->Destroy();
1687 mDocument = nullptr;
1690 // All callers are supposed to call destroy to break circular
1691 // references. If we do this stuff in the destructor, the
1692 // destructor might never be called (especially if we're being
1693 // used from JS.
1695 #ifdef NS_PRINTING
1696 if (mPrintEngine) {
1697 #ifdef NS_PRINT_PREVIEW
1698 bool doingPrintPreview;
1699 mPrintEngine->GetDoingPrintPreview(&doingPrintPreview);
1700 if (doingPrintPreview) {
1701 mPrintEngine->FinishPrintPreview();
1703 #endif
1705 mPrintEngine->Destroy();
1706 mPrintEngine = nullptr;
1708 #endif
1710 // Avoid leaking the old viewer.
1711 if (mPreviousViewer) {
1712 mPreviousViewer->Destroy();
1713 mPreviousViewer = nullptr;
1716 mDeviceContext = nullptr;
1718 if (mPresContext) {
1719 DestroyPresContext();
1722 mWindow = nullptr;
1723 mViewManager = nullptr;
1724 mContainer = WeakPtr<nsDocShell>();
1726 return NS_OK;
1729 NS_IMETHODIMP
1730 nsDocumentViewer::Stop(void)
1732 NS_ASSERTION(mDocument, "Stop called too early or too late");
1733 if (mDocument) {
1734 mDocument->StopDocumentLoad();
1737 if (!mHidden && (mLoaded || mStopped) && mPresContext && !mSHEntry)
1738 mPresContext->SetImageAnimationMode(imgIContainer::kDontAnimMode);
1740 mStopped = true;
1742 if (!mLoaded && mPresShell) {
1743 // Well, we might as well paint what we have so far.
1744 nsCOMPtr<nsIPresShell> shellDeathGrip(mPresShell); // bug 378682
1745 mPresShell->UnsuppressPainting();
1748 return NS_OK;
1751 NS_IMETHODIMP
1752 nsDocumentViewer::GetDOMDocument(nsIDOMDocument **aResult)
1754 NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
1755 return CallQueryInterface(mDocument, aResult);
1758 NS_IMETHODIMP_(nsIDocument *)
1759 nsDocumentViewer::GetDocument()
1761 return mDocument;
1764 NS_IMETHODIMP
1765 nsDocumentViewer::SetDOMDocument(nsIDOMDocument *aDocument)
1767 // Assumptions:
1769 // 1) this document viewer has been initialized with a call to Init().
1770 // 2) the stylesheets associated with the document have been added
1771 // to the document.
1773 // XXX Right now, this method assumes that the layout of the current
1774 // document hasn't started yet. More cleanup will probably be
1775 // necessary to make this method work for the case when layout *has*
1776 // occurred for the current document.
1777 // That work can happen when and if it is needed.
1779 if (!aDocument)
1780 return NS_ERROR_NULL_POINTER;
1782 nsCOMPtr<nsIDocument> newDoc = do_QueryInterface(aDocument);
1783 NS_ENSURE_TRUE(newDoc, NS_ERROR_UNEXPECTED);
1785 return SetDocumentInternal(newDoc, false);
1788 NS_IMETHODIMP
1789 nsDocumentViewer::SetDocumentInternal(nsIDocument* aDocument,
1790 bool aForceReuseInnerWindow)
1792 MOZ_ASSERT(aDocument);
1794 // Set new container
1795 aDocument->SetContainer(mContainer);
1797 if (mDocument != aDocument) {
1798 if (mDocument->IsStaticDocument()) {
1799 mDocument->SetScriptGlobalObject(nullptr);
1800 mDocument->Destroy();
1803 // Clear the list of old child docshells. Child docshells for the new
1804 // document will be constructed as frames are created.
1805 if (!aDocument->IsStaticDocument()) {
1806 nsCOMPtr<nsIDocShell> node(mContainer);
1807 if (node) {
1808 int32_t count;
1809 node->GetChildCount(&count);
1810 for (int32_t i = 0; i < count; ++i) {
1811 nsCOMPtr<nsIDocShellTreeItem> child;
1812 node->GetChildAt(0, getter_AddRefs(child));
1813 node->RemoveChild(child);
1818 // Replace the old document with the new one. Do this only when
1819 // the new document really is a new document.
1820 mDocument = aDocument;
1822 // Set the script global object on the new document
1823 nsCOMPtr<nsPIDOMWindow> window =
1824 mContainer ? mContainer->GetWindow() : nullptr;
1825 if (window) {
1826 nsresult rv = window->SetNewDocument(aDocument, nullptr,
1827 aForceReuseInnerWindow);
1828 if (NS_FAILED(rv)) {
1829 Destroy();
1830 return rv;
1835 nsresult rv = SyncParentSubDocMap();
1836 NS_ENSURE_SUCCESS(rv, rv);
1838 // Replace the current pres shell with a new shell for the new document
1840 if (mPresShell) {
1841 DestroyPresShell();
1844 if (mPresContext) {
1845 DestroyPresContext();
1847 mWindow = nullptr;
1848 rv = InitInternal(mParentWidget, nullptr, mBounds, true, true, false);
1851 return rv;
1854 nsIPresShell*
1855 nsDocumentViewer::GetPresShell()
1857 return mPresShell;
1860 nsPresContext*
1861 nsDocumentViewer::GetPresContext()
1863 return mPresContext;
1866 nsViewManager*
1867 nsDocumentViewer::GetViewManager()
1869 return mViewManager;
1872 NS_IMETHODIMP
1873 nsDocumentViewer::GetPresShell(nsIPresShell** aResult)
1875 nsIPresShell* shell = GetPresShell();
1876 NS_IF_ADDREF(*aResult = shell);
1877 return NS_OK;
1880 NS_IMETHODIMP
1881 nsDocumentViewer::GetPresContext(nsPresContext** aResult)
1883 nsPresContext* pc = GetPresContext();
1884 NS_IF_ADDREF(*aResult = pc);
1885 return NS_OK;
1888 NS_IMETHODIMP
1889 nsDocumentViewer::GetBounds(nsIntRect& aResult)
1891 NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
1892 aResult = mBounds;
1893 return NS_OK;
1896 NS_IMETHODIMP
1897 nsDocumentViewer::GetPreviousViewer(nsIContentViewer** aViewer)
1899 *aViewer = mPreviousViewer;
1900 NS_IF_ADDREF(*aViewer);
1901 return NS_OK;
1904 NS_IMETHODIMP
1905 nsDocumentViewer::SetPreviousViewer(nsIContentViewer* aViewer)
1907 // NOTE: |Show| sets |mPreviousViewer| to null without calling this
1908 // function.
1910 if (aViewer) {
1911 NS_ASSERTION(!mPreviousViewer,
1912 "can't set previous viewer when there already is one");
1914 // In a multiple chaining situation (which occurs when running a thrashing
1915 // test like i-bench or jrgm's tests with no delay), we can build up a
1916 // whole chain of viewers. In order to avoid this, we always set our previous
1917 // viewer to the MOST previous viewer in the chain, and then dump the intermediate
1918 // link from the chain. This ensures that at most only 2 documents are alive
1919 // and undestroyed at any given time (the one that is showing and the one that
1920 // is loading with painting suppressed).
1921 // It's very important that if this ever gets changed the code
1922 // before the RestorePresentation call in nsDocShell::InternalLoad
1923 // be changed accordingly.
1924 nsCOMPtr<nsIContentViewer> prevViewer;
1925 aViewer->GetPreviousViewer(getter_AddRefs(prevViewer));
1926 if (prevViewer) {
1927 aViewer->SetPreviousViewer(nullptr);
1928 aViewer->Destroy();
1929 return SetPreviousViewer(prevViewer);
1933 mPreviousViewer = aViewer;
1934 return NS_OK;
1937 NS_IMETHODIMP
1938 nsDocumentViewer::SetBounds(const nsIntRect& aBounds)
1940 NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
1942 mBounds = aBounds;
1943 if (mWindow) {
1944 if (!mAttachedToParent) {
1945 // Don't have the widget repaint. Layout will generate repaint requests
1946 // during reflow.
1947 mWindow->Resize(aBounds.x, aBounds.y,
1948 aBounds.width, aBounds.height,
1949 false);
1951 } else if (mPresContext && mViewManager) {
1952 int32_t p2a = mPresContext->AppUnitsPerDevPixel();
1953 mViewManager->SetWindowDimensions(NSIntPixelsToAppUnits(mBounds.width, p2a),
1954 NSIntPixelsToAppUnits(mBounds.height, p2a));
1957 // If there's a previous viewer, it's the one that's actually showing,
1958 // so be sure to resize it as well so it paints over the right area.
1959 // This may slow down the performance of the new page load, but resize
1960 // during load is also probably a relatively unusual condition
1961 // relating to things being hidden while something is loaded. It so
1962 // happens that Firefox does this a good bit with its infobar, and it
1963 // looks ugly if we don't do this.
1964 if (mPreviousViewer) {
1965 nsCOMPtr<nsIContentViewer> previousViewer = mPreviousViewer;
1966 previousViewer->SetBounds(aBounds);
1969 return NS_OK;
1972 NS_IMETHODIMP
1973 nsDocumentViewer::Move(int32_t aX, int32_t aY)
1975 NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
1976 mBounds.MoveTo(aX, aY);
1977 if (mWindow) {
1978 mWindow->Move(aX, aY);
1980 return NS_OK;
1983 NS_IMETHODIMP
1984 nsDocumentViewer::Show(void)
1986 NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
1988 // We don't need the previous viewer anymore since we're not
1989 // displaying it.
1990 if (mPreviousViewer) {
1991 // This little dance *may* only be to keep
1992 // PresShell::EndObservingDocument happy, but I'm not sure.
1993 nsCOMPtr<nsIContentViewer> prevViewer(mPreviousViewer);
1994 mPreviousViewer = nullptr;
1995 prevViewer->Destroy();
1997 // Make sure we don't have too many cached ContentViewers
1998 nsCOMPtr<nsIDocShellTreeItem> treeItem(mContainer);
1999 if (treeItem) {
2000 // We need to find the root DocShell since only that object has an
2001 // SHistory and we need the SHistory to evict content viewers
2002 nsCOMPtr<nsIDocShellTreeItem> root;
2003 treeItem->GetSameTypeRootTreeItem(getter_AddRefs(root));
2004 nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(root);
2005 nsCOMPtr<nsISHistory> history;
2006 webNav->GetSessionHistory(getter_AddRefs(history));
2007 nsCOMPtr<nsISHistoryInternal> historyInt = do_QueryInterface(history);
2008 if (historyInt) {
2009 int32_t prevIndex,loadedIndex;
2010 nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(treeItem);
2011 docShell->GetPreviousTransIndex(&prevIndex);
2012 docShell->GetLoadedTransIndex(&loadedIndex);
2013 #ifdef DEBUG_PAGE_CACHE
2014 printf("About to evict content viewers: prev=%d, loaded=%d\n",
2015 prevIndex, loadedIndex);
2016 #endif
2017 historyInt->EvictOutOfRangeContentViewers(loadedIndex);
2022 if (mWindow) {
2023 // When attached to a top level xul window, we do not need to call
2024 // Show on the widget. Underlying window management code handles
2025 // this when the window is initialized.
2026 if (!mAttachedToParent) {
2027 mWindow->Show(true);
2031 if (mDocument && !mPresShell) {
2032 NS_ASSERTION(!mWindow, "Window already created but no presshell?");
2034 nsCOMPtr<nsIBaseWindow> base_win(mContainer);
2035 if (base_win) {
2036 base_win->GetParentWidget(&mParentWidget);
2037 if (mParentWidget) {
2038 mParentWidget->Release(); // GetParentWidget AddRefs, but mParentWidget is weak
2042 nsView* containerView = FindContainerView();
2044 nsresult rv = CreateDeviceContext(containerView);
2045 NS_ENSURE_SUCCESS(rv, rv);
2047 // Create presentation context
2048 NS_ASSERTION(!mPresContext, "Shouldn't have a prescontext if we have no shell!");
2049 mPresContext = CreatePresContext(mDocument,
2050 nsPresContext::eContext_Galley, containerView);
2051 NS_ENSURE_TRUE(mPresContext, NS_ERROR_OUT_OF_MEMORY);
2053 rv = mPresContext->Init(mDeviceContext);
2054 if (NS_FAILED(rv)) {
2055 mPresContext = nullptr;
2056 return rv;
2059 rv = MakeWindow(nsSize(mPresContext->DevPixelsToAppUnits(mBounds.width),
2060 mPresContext->DevPixelsToAppUnits(mBounds.height)),
2061 containerView);
2062 if (NS_FAILED(rv))
2063 return rv;
2065 if (mPresContext && base_win) {
2066 nsCOMPtr<nsILinkHandler> linkHandler(do_GetInterface(base_win));
2068 if (linkHandler) {
2069 mPresContext->SetLinkHandler(linkHandler);
2072 mPresContext->SetContainer(mContainer);
2075 if (mPresContext) {
2076 Hide();
2078 rv = InitPresentationStuff(mDocument->MayStartLayout());
2081 // If we get here the document load has already started and the
2082 // window is shown because some JS on the page caused it to be
2083 // shown...
2085 if (mPresShell) {
2086 nsCOMPtr<nsIPresShell> shellDeathGrip(mPresShell); // bug 378682
2087 mPresShell->UnsuppressPainting();
2091 // Notify observers that a new page has been shown. This will get run
2092 // from the event loop after we actually draw the page.
2093 NS_DispatchToMainThread(new nsDocumentShownDispatcher(mDocument));
2095 return NS_OK;
2098 NS_IMETHODIMP
2099 nsDocumentViewer::Hide(void)
2101 if (!mAttachedToParent && mWindow) {
2102 mWindow->Show(false);
2105 if (!mPresShell)
2106 return NS_OK;
2108 NS_ASSERTION(mPresContext, "Can't have a presshell and no prescontext!");
2110 // Avoid leaking the old viewer.
2111 if (mPreviousViewer) {
2112 mPreviousViewer->Destroy();
2113 mPreviousViewer = nullptr;
2116 if (mIsSticky) {
2117 // This window is sticky, that means that it might be shown again
2118 // and we don't want the presshell n' all that to be thrown away
2119 // just because the window is hidden.
2121 return NS_OK;
2124 nsCOMPtr<nsIDocShell> docShell(mContainer);
2125 if (docShell) {
2126 nsCOMPtr<nsILayoutHistoryState> layoutState;
2127 mPresShell->CaptureHistoryState(getter_AddRefs(layoutState));
2130 DestroyPresShell();
2132 DestroyPresContext();
2134 mViewManager = nullptr;
2135 mWindow = nullptr;
2136 mDeviceContext = nullptr;
2137 mParentWidget = nullptr;
2139 nsCOMPtr<nsIBaseWindow> base_win(mContainer);
2141 if (base_win && !mAttachedToParent) {
2142 base_win->SetParentWidget(nullptr);
2145 return NS_OK;
2148 NS_IMETHODIMP
2149 nsDocumentViewer::GetSticky(bool *aSticky)
2151 *aSticky = mIsSticky;
2153 return NS_OK;
2156 NS_IMETHODIMP
2157 nsDocumentViewer::SetSticky(bool aSticky)
2159 mIsSticky = aSticky;
2161 return NS_OK;
2164 NS_IMETHODIMP
2165 nsDocumentViewer::RequestWindowClose(bool* aCanClose)
2167 #ifdef NS_PRINTING
2168 if (mPrintIsPending || (mPrintEngine && mPrintEngine->GetIsPrinting())) {
2169 *aCanClose = false;
2170 mDeferredWindowClose = true;
2171 } else
2172 #endif
2173 *aCanClose = true;
2175 return NS_OK;
2178 static bool
2179 AppendAgentSheet(nsIStyleSheet *aSheet, void *aData)
2181 nsStyleSet *styleSet = static_cast<nsStyleSet*>(aData);
2182 styleSet->AppendStyleSheet(nsStyleSet::eAgentSheet, aSheet);
2183 return true;
2186 static bool
2187 PrependUserSheet(nsIStyleSheet *aSheet, void *aData)
2189 nsStyleSet *styleSet = static_cast<nsStyleSet*>(aData);
2190 styleSet->PrependStyleSheet(nsStyleSet::eUserSheet, aSheet);
2191 return true;
2194 nsresult
2195 nsDocumentViewer::CreateStyleSet(nsIDocument* aDocument,
2196 nsStyleSet** aStyleSet)
2198 // Make sure this does the same thing as PresShell::AddSheet wrt ordering.
2200 // this should eventually get expanded to allow for creating
2201 // different sets for different media
2202 nsStyleSet *styleSet = new nsStyleSet();
2204 styleSet->BeginUpdate();
2206 // The document will fill in the document sheets when we create the presshell
2208 if (aDocument->IsBeingUsedAsImage()) {
2209 MOZ_ASSERT(aDocument->IsSVG(),
2210 "Do we want to skip most sheets for this new image type?");
2212 // SVG-as-an-image must be kept as light and small as possible. We
2213 // deliberately skip loading everything and leave svg.css (and html.css and
2214 // xul.css) to be loaded on-demand.
2215 // XXXjwatt Nothing else is loaded on-demand, but I don't think that
2216 // should matter for SVG-as-an-image. If it does, I want to know why!
2218 // Caller will handle calling EndUpdate, per contract.
2219 *aStyleSet = styleSet;
2220 return NS_OK;
2223 // Handle the user sheets.
2224 CSSStyleSheet* sheet = nullptr;
2225 if (nsContentUtils::IsInChromeDocshell(aDocument)) {
2226 sheet = nsLayoutStylesheetCache::UserChromeSheet();
2228 else {
2229 sheet = nsLayoutStylesheetCache::UserContentSheet();
2232 if (sheet)
2233 styleSet->AppendStyleSheet(nsStyleSet::eUserSheet, sheet);
2235 // Append chrome sheets (scrollbars + forms).
2236 bool shouldOverride = false;
2237 // We don't want a docshell here for external resource docs, so just
2238 // look at mContainer.
2239 nsCOMPtr<nsIDocShell> ds(mContainer);
2240 nsCOMPtr<nsIDOMEventTarget> chromeHandler;
2241 nsCOMPtr<nsIURI> uri;
2242 nsRefPtr<CSSStyleSheet> csssheet;
2244 if (ds) {
2245 ds->GetChromeEventHandler(getter_AddRefs(chromeHandler));
2247 if (chromeHandler) {
2248 nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(chromeHandler));
2249 nsCOMPtr<nsIContent> content(do_QueryInterface(elt));
2250 if (elt && content) {
2251 nsCOMPtr<nsIURI> baseURI = content->GetBaseURI();
2253 nsAutoString sheets;
2254 elt->GetAttribute(NS_LITERAL_STRING("usechromesheets"), sheets);
2255 if (!sheets.IsEmpty() && baseURI) {
2256 nsRefPtr<mozilla::css::Loader> cssLoader = new mozilla::css::Loader();
2258 char *str = ToNewCString(sheets);
2259 char *newStr = str;
2260 char *token;
2261 while ( (token = nsCRT::strtok(newStr, ", ", &newStr)) ) {
2262 NS_NewURI(getter_AddRefs(uri), nsDependentCString(token), nullptr,
2263 baseURI);
2264 if (!uri) continue;
2266 cssLoader->LoadSheetSync(uri, getter_AddRefs(csssheet));
2267 if (!csssheet) continue;
2269 styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, csssheet);
2270 shouldOverride = true;
2272 nsMemory::Free(str);
2277 if (!shouldOverride) {
2278 sheet = nsLayoutStylesheetCache::ScrollbarsSheet();
2279 if (sheet) {
2280 styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet);
2284 sheet = nsLayoutStylesheetCache::FullScreenOverrideSheet();
2285 if (sheet) {
2286 styleSet->PrependStyleSheet(nsStyleSet::eOverrideSheet, sheet);
2289 if (!aDocument->IsSVG()) {
2290 // !!! IMPORTANT - KEEP THIS BLOCK IN SYNC WITH
2291 // !!! SVGDocument::EnsureNonSVGUserAgentStyleSheetsLoaded.
2293 // SVGForeignObjectElement::BindToTree calls SVGDocument::
2294 // EnsureNonSVGUserAgentStyleSheetsLoaded to loads these UA sheet
2295 // on-demand. (Excluding the quirks sheet, which should never be loaded for
2296 // an SVG document, and excluding xul.css which will be loaded on demand by
2297 // nsXULElement::BindToTree.)
2299 sheet = nsLayoutStylesheetCache::NumberControlSheet();
2300 if (sheet) {
2301 styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet);
2304 sheet = nsLayoutStylesheetCache::FormsSheet();
2305 if (sheet) {
2306 styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet);
2309 // Make sure to clone the quirk sheet so that it can be usefully
2310 // enabled/disabled as needed.
2311 nsRefPtr<CSSStyleSheet> quirkClone;
2312 CSSStyleSheet* quirkSheet;
2313 if (!nsLayoutStylesheetCache::UASheet() ||
2314 !(quirkSheet = nsLayoutStylesheetCache::QuirkSheet()) ||
2315 !(quirkClone = quirkSheet->Clone(nullptr, nullptr, nullptr, nullptr)) ||
2316 !sheet) {
2317 delete styleSet;
2318 return NS_ERROR_OUT_OF_MEMORY;
2320 // quirk.css needs to come after the regular UA sheet (or more precisely,
2321 // after the html.css and so forth that the UA sheet imports).
2322 styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, quirkClone);
2323 styleSet->SetQuirkStyleSheet(quirkClone);
2325 if (aDocument->LoadsFullXULStyleSheetUpFront()) {
2326 // nsXULElement::BindToTree loads xul.css on-demand if we don't load it
2327 // up-front here.
2328 sheet = nsLayoutStylesheetCache::XULSheet();
2329 if (sheet) {
2330 styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet);
2334 sheet = nsLayoutStylesheetCache::MinimalXULSheet();
2335 if (sheet) {
2336 // Load the minimal XUL rules for scrollbars and a few other XUL things
2337 // that non-XUL (typically HTML) documents commonly use.
2338 styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet);
2341 sheet = nsLayoutStylesheetCache::CounterStylesSheet();
2342 if (sheet) {
2343 styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet);
2346 sheet = nsLayoutStylesheetCache::HTMLSheet();
2347 if (sheet) {
2348 styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet);
2351 styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet,
2352 nsLayoutStylesheetCache::UASheet());
2353 } else {
2354 // SVG documents may have scrollbars and need the scrollbar styling.
2355 sheet = nsLayoutStylesheetCache::MinimalXULSheet();
2356 if (sheet) {
2357 styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet);
2361 nsStyleSheetService *sheetService = nsStyleSheetService::GetInstance();
2362 if (sheetService) {
2363 sheetService->AgentStyleSheets()->EnumerateForwards(AppendAgentSheet,
2364 styleSet);
2365 sheetService->UserStyleSheets()->EnumerateBackwards(PrependUserSheet,
2366 styleSet);
2369 // Caller will handle calling EndUpdate, per contract.
2370 *aStyleSet = styleSet;
2371 return NS_OK;
2374 NS_IMETHODIMP
2375 nsDocumentViewer::ClearHistoryEntry()
2377 mSHEntry = nullptr;
2378 return NS_OK;
2381 //-------------------------------------------------------
2383 nsresult
2384 nsDocumentViewer::MakeWindow(const nsSize& aSize, nsView* aContainerView)
2386 if (GetIsPrintPreview())
2387 return NS_OK;
2389 bool shouldAttach = ShouldAttachToTopLevel();
2391 if (shouldAttach) {
2392 // If the old view is already attached to our parent, detach
2393 DetachFromTopLevelWidget();
2396 mViewManager = new nsViewManager();
2398 nsDeviceContext *dx = mPresContext->DeviceContext();
2400 nsresult rv = mViewManager->Init(dx);
2401 if (NS_FAILED(rv))
2402 return rv;
2404 // The root view is always at 0,0.
2405 nsRect tbounds(nsPoint(0, 0), aSize);
2406 // Create a view
2407 nsView* view = mViewManager->CreateView(tbounds, aContainerView);
2408 if (!view)
2409 return NS_ERROR_OUT_OF_MEMORY;
2411 // Create a widget if we were given a parent widget or don't have a
2412 // container view that we can hook up to without a widget.
2413 // Don't create widgets for ResourceDocs (external resources & svg images),
2414 // because when they're displayed, they're painted into *another* document's
2415 // widget.
2416 if (!mDocument->IsResourceDoc() &&
2417 (mParentWidget || !aContainerView)) {
2418 // pass in a native widget to be the parent widget ONLY if the view hierarchy will stand alone.
2419 // otherwise the view will find its own parent widget and "do the right thing" to
2420 // establish a parent/child widget relationship
2421 nsWidgetInitData initData;
2422 nsWidgetInitData* initDataPtr;
2423 if (!mParentWidget) {
2424 initDataPtr = &initData;
2425 initData.mWindowType = eWindowType_invisible;
2426 } else {
2427 initDataPtr = nullptr;
2430 if (shouldAttach) {
2431 // Reuse the top level parent widget.
2432 rv = view->AttachToTopLevelWidget(mParentWidget);
2433 mAttachedToParent = true;
2435 else if (!aContainerView && mParentWidget) {
2436 rv = view->CreateWidgetForParent(mParentWidget, initDataPtr,
2437 true, false);
2439 else {
2440 rv = view->CreateWidget(initDataPtr, true, false);
2442 if (NS_FAILED(rv))
2443 return rv;
2446 // Setup hierarchical relationship in view manager
2447 mViewManager->SetRootView(view);
2449 mWindow = view->GetWidget();
2451 // This SetFocus is necessary so the Arrow Key and Page Key events
2452 // go to the scrolled view as soon as the Window is created instead of going to
2453 // the browser window (this enables keyboard scrolling of the document)
2454 // mWindow->SetFocus();
2456 return rv;
2459 void
2460 nsDocumentViewer::DetachFromTopLevelWidget()
2462 if (mViewManager) {
2463 nsView* oldView = mViewManager->GetRootView();
2464 if (oldView && oldView->IsAttachedToTopLevel()) {
2465 oldView->DetachFromTopLevelWidget();
2468 mAttachedToParent = false;
2471 nsView*
2472 nsDocumentViewer::FindContainerView()
2474 nsView* containerView = nullptr;
2476 if (mContainer) {
2477 nsCOMPtr<nsIDocShell> docShell(mContainer);
2478 nsCOMPtr<nsPIDOMWindow> pwin(docShell->GetWindow());
2479 if (pwin) {
2480 nsCOMPtr<Element> containerElement = pwin->GetFrameElementInternal();
2481 if (!containerElement) {
2482 return nullptr;
2484 nsCOMPtr<nsIPresShell> parentPresShell;
2485 nsCOMPtr<nsIDocShellTreeItem> parentDocShellItem;
2486 docShell->GetParent(getter_AddRefs(parentDocShellItem));
2487 if (parentDocShellItem) {
2488 nsCOMPtr<nsIDocShell> parentDocShell = do_QueryInterface(parentDocShellItem);
2489 parentPresShell = parentDocShell->GetPresShell();
2491 if (!parentPresShell) {
2492 nsCOMPtr<nsIDocument> parentDoc = containerElement->GetCurrentDoc();
2493 if (parentDoc) {
2494 parentPresShell = parentDoc->GetShell();
2497 if (!parentPresShell) {
2498 NS_WARNING("Subdocument container has no presshell");
2499 } else {
2500 nsIFrame* subdocFrame = parentPresShell->GetRealPrimaryFrameFor(containerElement);
2501 if (subdocFrame) {
2502 // subdocFrame might not be a subdocument frame; the frame
2503 // constructor can treat a <frame> as an inline in some XBL
2504 // cases. Treat that as display:none, the document is not
2505 // displayed.
2506 if (subdocFrame->GetType() == nsGkAtoms::subDocumentFrame) {
2507 NS_ASSERTION(subdocFrame->GetView(), "Subdoc frames must have views");
2508 nsView* innerView =
2509 static_cast<nsSubDocumentFrame*>(subdocFrame)->EnsureInnerView();
2510 containerView = innerView;
2511 } else {
2512 NS_WARNING("Subdocument container has non-subdocument frame");
2514 } else {
2515 NS_WARNING("Subdocument container has no frame");
2521 return containerView;
2524 nsresult
2525 nsDocumentViewer::CreateDeviceContext(nsView* aContainerView)
2527 NS_PRECONDITION(!mPresShell && !mWindow,
2528 "This will screw up our existing presentation");
2529 NS_PRECONDITION(mDocument, "Gotta have a document here");
2531 nsIDocument* doc = mDocument->GetDisplayDocument();
2532 if (doc) {
2533 NS_ASSERTION(!aContainerView, "External resource document embedded somewhere?");
2534 // We want to use our display document's device context if possible
2535 nsIPresShell* shell = doc->GetShell();
2536 if (shell) {
2537 nsPresContext* ctx = shell->GetPresContext();
2538 if (ctx) {
2539 mDeviceContext = ctx->DeviceContext();
2540 return NS_OK;
2545 // Create a device context even if we already have one, since our widget
2546 // might have changed.
2547 nsIWidget* widget = nullptr;
2548 if (aContainerView) {
2549 widget = aContainerView->GetNearestWidget(nullptr);
2551 if (!widget) {
2552 widget = mParentWidget;
2554 if (widget) {
2555 widget = widget->GetTopLevelWidget();
2558 mDeviceContext = new nsDeviceContext();
2559 mDeviceContext->Init(widget);
2560 return NS_OK;
2563 // Return the selection for the document. Note that text fields have their
2564 // own selection, which cannot be accessed with this method.
2565 nsresult nsDocumentViewer::GetDocumentSelection(nsISelection **aSelection)
2567 NS_ENSURE_ARG_POINTER(aSelection);
2568 if (!mPresShell) {
2569 return NS_ERROR_NOT_INITIALIZED;
2572 nsCOMPtr<nsISelectionController> selcon;
2573 selcon = do_QueryInterface(mPresShell);
2574 if (selcon)
2575 return selcon->GetSelection(nsISelectionController::SELECTION_NORMAL,
2576 aSelection);
2577 return NS_ERROR_FAILURE;
2580 /* ========================================================================================
2581 * nsIContentViewerEdit
2582 * ======================================================================================== */
2584 NS_IMETHODIMP nsDocumentViewer::ClearSelection()
2586 nsresult rv;
2587 nsCOMPtr<nsISelection> selection;
2589 // use nsCopySupport::GetSelectionForCopy() ?
2590 rv = GetDocumentSelection(getter_AddRefs(selection));
2591 if (NS_FAILED(rv)) return rv;
2593 return selection->CollapseToStart();
2596 NS_IMETHODIMP nsDocumentViewer::SelectAll()
2598 // XXX this is a temporary implementation copied from nsWebShell
2599 // for now. I think nsDocument and friends should have some helper
2600 // functions to make this easier.
2601 nsCOMPtr<nsISelection> selection;
2602 nsresult rv;
2604 // use nsCopySupport::GetSelectionForCopy() ?
2605 rv = GetDocumentSelection(getter_AddRefs(selection));
2606 if (NS_FAILED(rv)) return rv;
2608 nsCOMPtr<nsIDOMHTMLDocument> htmldoc = do_QueryInterface(mDocument);
2609 nsCOMPtr<nsIDOMNode> bodyNode;
2611 if (htmldoc)
2613 nsCOMPtr<nsIDOMHTMLElement>bodyElement;
2614 rv = htmldoc->GetBody(getter_AddRefs(bodyElement));
2615 if (NS_FAILED(rv) || !bodyElement) return rv;
2617 bodyNode = do_QueryInterface(bodyElement);
2619 else if (mDocument)
2621 bodyNode = do_QueryInterface(mDocument->GetRootElement());
2623 if (!bodyNode) return NS_ERROR_FAILURE;
2625 rv = selection->RemoveAllRanges();
2626 if (NS_FAILED(rv)) return rv;
2628 rv = selection->SelectAllChildren(bodyNode);
2629 return rv;
2632 NS_IMETHODIMP nsDocumentViewer::CopySelection()
2634 nsCopySupport::FireClipboardEvent(NS_COPY, nsIClipboard::kGlobalClipboard, mPresShell, nullptr);
2635 return NS_OK;
2638 NS_IMETHODIMP nsDocumentViewer::CopyLinkLocation()
2640 NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);
2641 nsCOMPtr<nsIDOMNode> node;
2642 GetPopupLinkNode(getter_AddRefs(node));
2643 // make noise if we're not in a link
2644 NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
2646 nsCOMPtr<dom::Element> elm(do_QueryInterface(node));
2647 NS_ENSURE_TRUE(elm, NS_ERROR_FAILURE);
2649 nsAutoString locationText;
2650 nsContentUtils::GetLinkLocation(elm, locationText);
2651 if (locationText.IsEmpty())
2652 return NS_ERROR_FAILURE;
2654 nsresult rv = NS_OK;
2655 nsCOMPtr<nsIClipboardHelper> clipboard(do_GetService("@mozilla.org/widget/clipboardhelper;1", &rv));
2656 NS_ENSURE_SUCCESS(rv, rv);
2658 // copy the href onto the clipboard
2659 nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(mDocument);
2660 return clipboard->CopyString(locationText, doc);
2663 NS_IMETHODIMP nsDocumentViewer::CopyImage(int32_t aCopyFlags)
2665 NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);
2666 nsCOMPtr<nsIImageLoadingContent> node;
2667 GetPopupImageNode(getter_AddRefs(node));
2668 // make noise if we're not in an image
2669 NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
2671 nsCOMPtr<nsILoadContext> loadContext(mContainer);
2672 return nsCopySupport::ImageCopy(node, loadContext, aCopyFlags);
2676 NS_IMETHODIMP nsDocumentViewer::GetCopyable(bool *aCopyable)
2678 NS_ENSURE_ARG_POINTER(aCopyable);
2679 *aCopyable = nsCopySupport::CanCopy(mDocument);
2680 return NS_OK;
2683 /* AString getContents (in string mimeType, in boolean selectionOnly); */
2684 NS_IMETHODIMP nsDocumentViewer::GetContents(const char *mimeType, bool selectionOnly, nsAString& aOutValue)
2686 aOutValue.Truncate();
2688 NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);
2689 NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_INITIALIZED);
2691 // Now we have the selection. Make sure it's nonzero:
2692 nsCOMPtr<nsISelection> sel;
2693 if (selectionOnly) {
2694 nsCopySupport::GetSelectionForCopy(mDocument, getter_AddRefs(sel));
2695 NS_ENSURE_TRUE(sel, NS_ERROR_FAILURE);
2697 bool isCollapsed;
2698 sel->GetIsCollapsed(&isCollapsed);
2699 if (isCollapsed)
2700 return NS_OK;
2703 // call the copy code
2704 return nsCopySupport::GetContents(nsDependentCString(mimeType), 0, sel,
2705 mDocument, aOutValue);
2708 /* readonly attribute boolean canGetContents; */
2709 NS_IMETHODIMP nsDocumentViewer::GetCanGetContents(bool *aCanGetContents)
2711 NS_ENSURE_ARG_POINTER(aCanGetContents);
2712 *aCanGetContents = false;
2713 NS_ENSURE_STATE(mDocument);
2714 *aCanGetContents = nsCopySupport::CanCopy(mDocument);
2715 return NS_OK;
2719 /* ========================================================================================
2720 * nsIContentViewerFile
2721 * ======================================================================================== */
2722 /** ---------------------------------------------------
2723 * See documentation above in the nsIContentViewerfile class definition
2724 * @update 01/24/00 dwc
2726 NS_IMETHODIMP
2727 nsDocumentViewer::Print(bool aSilent,
2728 FILE * aDebugFile,
2729 nsIPrintSettings* aPrintSettings)
2731 #ifdef NS_PRINTING
2732 nsCOMPtr<nsIPrintSettings> printSettings;
2734 #ifdef DEBUG
2735 nsresult rv = NS_ERROR_FAILURE;
2737 mDebugFile = aDebugFile;
2738 // if they don't pass in a PrintSettings, then make one
2739 // it will have all the default values
2740 printSettings = aPrintSettings;
2741 nsCOMPtr<nsIPrintOptions> printOptions = do_GetService(sPrintOptionsContractID, &rv);
2742 if (NS_SUCCEEDED(rv)) {
2743 // if they don't pass in a PrintSettings, then make one
2744 if (printSettings == nullptr) {
2745 printOptions->CreatePrintSettings(getter_AddRefs(printSettings));
2747 NS_ASSERTION(printSettings, "You can't PrintPreview without a PrintSettings!");
2749 if (printSettings) printSettings->SetPrintSilent(aSilent);
2750 if (printSettings) printSettings->SetShowPrintProgress(false);
2751 #endif
2754 return Print(printSettings, nullptr);
2755 #else
2756 return NS_ERROR_FAILURE;
2757 #endif
2760 // nsIContentViewerFile interface
2761 NS_IMETHODIMP
2762 nsDocumentViewer::GetPrintable(bool *aPrintable)
2764 NS_ENSURE_ARG_POINTER(aPrintable);
2766 *aPrintable = !GetIsPrinting();
2768 return NS_OK;
2771 NS_IMETHODIMP nsDocumentViewer::ScrollToNode(nsIDOMNode* aNode)
2773 NS_ENSURE_ARG(aNode);
2774 NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
2775 nsCOMPtr<nsIPresShell> presShell;
2776 NS_ENSURE_SUCCESS(GetPresShell(getter_AddRefs(presShell)), NS_ERROR_FAILURE);
2778 // Get the nsIContent interface, because that's what we need to
2779 // get the primary frame
2781 nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
2782 NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
2784 // Tell the PresShell to scroll to the primary frame of the content.
2785 NS_ENSURE_SUCCESS(
2786 presShell->ScrollContentIntoView(content,
2787 nsIPresShell::ScrollAxis(
2788 nsIPresShell::SCROLL_TOP,
2789 nsIPresShell::SCROLL_ALWAYS),
2790 nsIPresShell::ScrollAxis(),
2791 nsIPresShell::SCROLL_OVERFLOW_HIDDEN),
2792 NS_ERROR_FAILURE);
2793 return NS_OK;
2796 void
2797 nsDocumentViewer::CallChildren(CallChildFunc aFunc, void* aClosure)
2799 nsCOMPtr<nsIDocShell> docShell(mContainer);
2800 if (docShell)
2802 int32_t i;
2803 int32_t n;
2804 docShell->GetChildCount(&n);
2805 for (i=0; i < n; i++)
2807 nsCOMPtr<nsIDocShellTreeItem> child;
2808 docShell->GetChildAt(i, getter_AddRefs(child));
2809 nsCOMPtr<nsIDocShell> childAsShell(do_QueryInterface(child));
2810 NS_ASSERTION(childAsShell, "null child in docshell");
2811 if (childAsShell)
2813 nsCOMPtr<nsIContentViewer> childCV;
2814 childAsShell->GetContentViewer(getter_AddRefs(childCV));
2815 if (childCV)
2817 (*aFunc)(childCV, aClosure);
2824 struct LineBoxInfo
2826 nscoord mMaxLineBoxWidth;
2829 static void
2830 ChangeChildPaintingEnabled(nsIContentViewer* aChild, void* aClosure)
2832 bool* enablePainting = (bool*) aClosure;
2833 if (*enablePainting) {
2834 aChild->ResumePainting();
2835 } else {
2836 aChild->PausePainting();
2840 static void
2841 ChangeChildMaxLineBoxWidth(nsIContentViewer* aChild, void* aClosure)
2843 struct LineBoxInfo* lbi = (struct LineBoxInfo*) aClosure;
2844 aChild->ChangeMaxLineBoxWidth(lbi->mMaxLineBoxWidth);
2847 struct ZoomInfo
2849 float mZoom;
2852 static void
2853 SetChildTextZoom(nsIContentViewer* aChild, void* aClosure)
2855 struct ZoomInfo* ZoomInfo = (struct ZoomInfo*) aClosure;
2856 aChild->SetTextZoom(ZoomInfo->mZoom);
2859 static void
2860 SetChildMinFontSize(nsIContentViewer* aChild, void* aClosure)
2862 aChild->SetMinFontSize(NS_PTR_TO_INT32(aClosure));
2865 static void
2866 SetChildFullZoom(nsIContentViewer* aChild, void* aClosure)
2868 struct ZoomInfo* ZoomInfo = (struct ZoomInfo*) aClosure;
2869 aChild->SetFullZoom(ZoomInfo->mZoom);
2872 static bool
2873 SetExtResourceTextZoom(nsIDocument* aDocument, void* aClosure)
2875 // Would it be better to enumerate external resource viewers instead?
2876 nsIPresShell* shell = aDocument->GetShell();
2877 if (shell) {
2878 nsPresContext* ctxt = shell->GetPresContext();
2879 if (ctxt) {
2880 struct ZoomInfo* ZoomInfo = static_cast<struct ZoomInfo*>(aClosure);
2881 ctxt->SetTextZoom(ZoomInfo->mZoom);
2885 return true;
2888 static bool
2889 SetExtResourceMinFontSize(nsIDocument* aDocument, void* aClosure)
2891 nsIPresShell* shell = aDocument->GetShell();
2892 if (shell) {
2893 nsPresContext* ctxt = shell->GetPresContext();
2894 if (ctxt) {
2895 ctxt->SetBaseMinFontSize(NS_PTR_TO_INT32(aClosure));
2899 return true;
2902 static bool
2903 SetExtResourceFullZoom(nsIDocument* aDocument, void* aClosure)
2905 // Would it be better to enumerate external resource viewers instead?
2906 nsIPresShell* shell = aDocument->GetShell();
2907 if (shell) {
2908 nsPresContext* ctxt = shell->GetPresContext();
2909 if (ctxt) {
2910 struct ZoomInfo* ZoomInfo = static_cast<struct ZoomInfo*>(aClosure);
2911 ctxt->SetFullZoom(ZoomInfo->mZoom);
2915 return true;
2918 NS_IMETHODIMP
2919 nsDocumentViewer::SetTextZoom(float aTextZoom)
2921 // If we don't have a document, then we need to bail.
2922 if (!mDocument) {
2923 return NS_ERROR_FAILURE;
2926 if (GetIsPrintPreview()) {
2927 return NS_OK;
2930 mTextZoom = aTextZoom;
2932 // Set the text zoom on all children of mContainer (even if our zoom didn't
2933 // change, our children's zoom may be different, though it would be unusual).
2934 // Do this first, in case kids are auto-sizing and post reflow commands on
2935 // our presshell (which should be subsumed into our own style change reflow).
2936 struct ZoomInfo ZoomInfo = { aTextZoom };
2937 CallChildren(SetChildTextZoom, &ZoomInfo);
2939 // Now change our own zoom
2940 nsPresContext* pc = GetPresContext();
2941 if (pc && aTextZoom != mPresContext->TextZoom()) {
2942 pc->SetTextZoom(aTextZoom);
2945 // And do the external resources
2946 mDocument->EnumerateExternalResources(SetExtResourceTextZoom, &ZoomInfo);
2948 nsContentUtils::DispatchChromeEvent(mDocument, static_cast<nsIDocument*>(mDocument),
2949 NS_LITERAL_STRING("TextZoomChange"),
2950 true, true);
2952 return NS_OK;
2955 NS_IMETHODIMP
2956 nsDocumentViewer::GetTextZoom(float* aTextZoom)
2958 NS_ENSURE_ARG_POINTER(aTextZoom);
2959 nsPresContext* pc = GetPresContext();
2960 *aTextZoom = pc ? pc->TextZoom() : 1.0f;
2961 return NS_OK;
2964 NS_IMETHODIMP
2965 nsDocumentViewer::SetMinFontSize(int32_t aMinFontSize)
2967 // If we don't have a document, then we need to bail.
2968 if (!mDocument) {
2969 return NS_ERROR_FAILURE;
2972 if (GetIsPrintPreview()) {
2973 return NS_OK;
2976 mMinFontSize = aMinFontSize;
2978 // Set the min font on all children of mContainer (even if our min font didn't
2979 // change, our children's min font may be different, though it would be unusual).
2980 // Do this first, in case kids are auto-sizing and post reflow commands on
2981 // our presshell (which should be subsumed into our own style change reflow).
2982 CallChildren(SetChildMinFontSize, NS_INT32_TO_PTR(aMinFontSize));
2984 // Now change our own min font
2985 nsPresContext* pc = GetPresContext();
2986 if (pc && aMinFontSize != mPresContext->MinFontSize(nullptr)) {
2987 pc->SetBaseMinFontSize(aMinFontSize);
2990 // And do the external resources
2991 mDocument->EnumerateExternalResources(SetExtResourceMinFontSize,
2992 NS_INT32_TO_PTR(aMinFontSize));
2994 return NS_OK;
2997 NS_IMETHODIMP
2998 nsDocumentViewer::GetMinFontSize(int32_t* aMinFontSize)
3000 NS_ENSURE_ARG_POINTER(aMinFontSize);
3001 nsPresContext* pc = GetPresContext();
3002 *aMinFontSize = pc ? pc->BaseMinFontSize() : 0;
3003 return NS_OK;
3006 NS_IMETHODIMP
3007 nsDocumentViewer::SetFullZoom(float aFullZoom)
3009 #ifdef NS_PRINT_PREVIEW
3010 if (GetIsPrintPreview()) {
3011 nsPresContext* pc = GetPresContext();
3012 NS_ENSURE_TRUE(pc, NS_OK);
3013 nsCOMPtr<nsIPresShell> shell = pc->GetPresShell();
3014 NS_ENSURE_TRUE(shell, NS_OK);
3016 if (!mPrintPreviewZoomed) {
3017 mOriginalPrintPreviewScale = pc->GetPrintPreviewScale();
3018 mPrintPreviewZoomed = true;
3021 mPrintPreviewZoom = aFullZoom;
3022 pc->SetPrintPreviewScale(aFullZoom * mOriginalPrintPreviewScale);
3023 nsIPageSequenceFrame* pf = shell->GetPageSequenceFrame();
3024 if (pf) {
3025 nsIFrame* f = do_QueryFrame(pf);
3026 shell->FrameNeedsReflow(f, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
3029 nsIFrame* rootFrame = shell->GetRootFrame();
3030 if (rootFrame) {
3031 rootFrame->InvalidateFrame();
3033 return NS_OK;
3035 #endif
3037 // If we don't have a document, then we need to bail.
3038 if (!mDocument) {
3039 return NS_ERROR_FAILURE;
3042 bool fullZoomChange = (mPageZoom != aFullZoom);
3043 mPageZoom = aFullZoom;
3045 struct ZoomInfo ZoomInfo = { aFullZoom };
3046 CallChildren(SetChildFullZoom, &ZoomInfo);
3048 nsPresContext* pc = GetPresContext();
3049 if (pc) {
3050 pc->SetFullZoom(aFullZoom);
3053 // And do the external resources
3054 mDocument->EnumerateExternalResources(SetExtResourceFullZoom, &ZoomInfo);
3056 // Dispatch FullZoomChange event only if fullzoom value really was been changed
3057 if (fullZoomChange) {
3058 nsContentUtils::DispatchChromeEvent(mDocument, static_cast<nsIDocument*>(mDocument),
3059 NS_LITERAL_STRING("FullZoomChange"),
3060 true, true);
3063 return NS_OK;
3066 NS_IMETHODIMP
3067 nsDocumentViewer::GetFullZoom(float* aFullZoom)
3069 NS_ENSURE_ARG_POINTER(aFullZoom);
3070 #ifdef NS_PRINT_PREVIEW
3071 if (GetIsPrintPreview()) {
3072 *aFullZoom = mPrintPreviewZoom;
3073 return NS_OK;
3075 #endif
3076 // Check the prescontext first because it might have a temporary
3077 // setting for print-preview
3078 nsPresContext* pc = GetPresContext();
3079 *aFullZoom = pc ? pc->GetFullZoom() : mPageZoom;
3080 return NS_OK;
3083 static void
3084 SetChildAuthorStyleDisabled(nsIContentViewer* aChild, void* aClosure)
3086 bool styleDisabled = *static_cast<bool*>(aClosure);
3087 aChild->SetAuthorStyleDisabled(styleDisabled);
3091 NS_IMETHODIMP
3092 nsDocumentViewer::SetAuthorStyleDisabled(bool aStyleDisabled)
3094 if (mPresShell) {
3095 mPresShell->SetAuthorStyleDisabled(aStyleDisabled);
3097 CallChildren(SetChildAuthorStyleDisabled, &aStyleDisabled);
3098 return NS_OK;
3101 NS_IMETHODIMP
3102 nsDocumentViewer::GetAuthorStyleDisabled(bool* aStyleDisabled)
3104 if (mPresShell) {
3105 *aStyleDisabled = mPresShell->GetAuthorStyleDisabled();
3106 } else {
3107 *aStyleDisabled = false;
3109 return NS_OK;
3112 static bool
3113 ExtResourceEmulateMedium(nsIDocument* aDocument, void* aClosure)
3115 nsIPresShell* shell = aDocument->GetShell();
3116 if (shell) {
3117 nsPresContext* ctxt = shell->GetPresContext();
3118 if (ctxt) {
3119 const nsAString* mediaType = static_cast<nsAString*>(aClosure);
3120 ctxt->EmulateMedium(*mediaType);
3124 return true;
3127 static void
3128 ChildEmulateMedium(nsIContentViewer* aChild, void* aClosure)
3130 const nsAString* mediaType = static_cast<nsAString*>(aClosure);
3131 aChild->EmulateMedium(*mediaType);
3134 NS_IMETHODIMP
3135 nsDocumentViewer::EmulateMedium(const nsAString& aMediaType)
3137 if (mPresContext) {
3138 mPresContext->EmulateMedium(aMediaType);
3140 CallChildren(ChildEmulateMedium, const_cast<nsAString*>(&aMediaType));
3142 if (mDocument) {
3143 mDocument->EnumerateExternalResources(ExtResourceEmulateMedium,
3144 const_cast<nsAString*>(&aMediaType));
3147 return NS_OK;
3150 static bool
3151 ExtResourceStopEmulatingMedium(nsIDocument* aDocument, void* aClosure)
3153 nsIPresShell* shell = aDocument->GetShell();
3154 if (shell) {
3155 nsPresContext* ctxt = shell->GetPresContext();
3156 if (ctxt) {
3157 ctxt->StopEmulatingMedium();
3161 return true;
3164 static void
3165 ChildStopEmulatingMedium(nsIContentViewer* aChild, void* aClosure)
3167 aChild->StopEmulatingMedium();
3170 NS_IMETHODIMP
3171 nsDocumentViewer::StopEmulatingMedium()
3173 if (mPresContext) {
3174 mPresContext->StopEmulatingMedium();
3176 CallChildren(ChildStopEmulatingMedium, nullptr);
3178 if (mDocument) {
3179 mDocument->EnumerateExternalResources(ExtResourceStopEmulatingMedium,
3180 nullptr);
3183 return NS_OK;
3186 NS_IMETHODIMP nsDocumentViewer::GetForceCharacterSet(nsACString& aForceCharacterSet)
3188 aForceCharacterSet = mForceCharacterSet;
3189 return NS_OK;
3192 static void
3193 SetChildForceCharacterSet(nsIContentViewer* aChild, void* aClosure)
3195 const nsACString* charset = static_cast<nsACString*>(aClosure);
3196 aChild->SetForceCharacterSet(*charset);
3199 NS_IMETHODIMP
3200 nsDocumentViewer::SetForceCharacterSet(const nsACString& aForceCharacterSet)
3202 mForceCharacterSet = aForceCharacterSet;
3203 // now set the force char set on all children of mContainer
3204 CallChildren(SetChildForceCharacterSet, (void*) &aForceCharacterSet);
3205 return NS_OK;
3208 NS_IMETHODIMP nsDocumentViewer::GetHintCharacterSet(nsACString& aHintCharacterSet)
3211 if(kCharsetUninitialized == mHintCharsetSource) {
3212 aHintCharacterSet.Truncate();
3213 } else {
3214 aHintCharacterSet = mHintCharset;
3215 // this can't possibly be right. we can't set a value just because somebody got a related value!
3216 //mHintCharsetSource = kCharsetUninitialized;
3218 return NS_OK;
3221 NS_IMETHODIMP nsDocumentViewer::GetHintCharacterSetSource(int32_t *aHintCharacterSetSource)
3223 NS_ENSURE_ARG_POINTER(aHintCharacterSetSource);
3225 *aHintCharacterSetSource = mHintCharsetSource;
3226 return NS_OK;
3229 static void
3230 SetChildHintCharacterSetSource(nsIContentViewer* aChild, void* aClosure)
3232 aChild->SetHintCharacterSetSource(NS_PTR_TO_INT32(aClosure));
3235 NS_IMETHODIMP
3236 nsDocumentViewer::SetHintCharacterSetSource(int32_t aHintCharacterSetSource)
3238 mHintCharsetSource = aHintCharacterSetSource;
3239 // now set the hint char set source on all children of mContainer
3240 CallChildren(SetChildHintCharacterSetSource,
3241 NS_INT32_TO_PTR(aHintCharacterSetSource));
3242 return NS_OK;
3245 static void
3246 SetChildHintCharacterSet(nsIContentViewer* aChild, void* aClosure)
3248 const nsACString* charset = static_cast<nsACString*>(aClosure);
3249 aChild->SetHintCharacterSet(*charset);
3252 NS_IMETHODIMP
3253 nsDocumentViewer::SetHintCharacterSet(const nsACString& aHintCharacterSet)
3255 mHintCharset = aHintCharacterSet;
3256 // now set the hint char set on all children of mContainer
3257 CallChildren(SetChildHintCharacterSet, (void*) &aHintCharacterSet);
3258 return NS_OK;
3261 static void
3262 AppendChildSubtree(nsIContentViewer* aChild, void* aClosure)
3264 nsTArray<nsCOMPtr<nsIContentViewer> >& array =
3265 *static_cast<nsTArray<nsCOMPtr<nsIContentViewer> >*>(aClosure);
3266 aChild->AppendSubtree(array);
3269 NS_IMETHODIMP nsDocumentViewer::AppendSubtree(nsTArray<nsCOMPtr<nsIContentViewer> >& aArray)
3271 aArray.AppendElement(this);
3272 CallChildren(AppendChildSubtree, &aArray);
3273 return NS_OK;
3276 NS_IMETHODIMP
3277 nsDocumentViewer::PausePainting()
3279 bool enablePaint = false;
3280 CallChildren(ChangeChildPaintingEnabled, &enablePaint);
3282 nsIPresShell* presShell = GetPresShell();
3283 if (presShell) {
3284 presShell->PausePainting();
3287 return NS_OK;
3290 NS_IMETHODIMP
3291 nsDocumentViewer::ResumePainting()
3293 bool enablePaint = true;
3294 CallChildren(ChangeChildPaintingEnabled, &enablePaint);
3296 nsIPresShell* presShell = GetPresShell();
3297 if (presShell) {
3298 presShell->ResumePainting();
3301 return NS_OK;
3304 NS_IMETHODIMP
3305 nsDocumentViewer::ChangeMaxLineBoxWidth(int32_t aMaxLineBoxWidth)
3307 // Change the max line box width for all children.
3308 struct LineBoxInfo lbi = { aMaxLineBoxWidth };
3309 CallChildren(ChangeChildMaxLineBoxWidth, &lbi);
3311 // Now, change our max line box width.
3312 // Convert to app units, since our input is in CSS pixels.
3313 nscoord mlbw = nsPresContext::CSSPixelsToAppUnits(aMaxLineBoxWidth);
3314 nsIPresShell* presShell = GetPresShell();
3315 if (presShell) {
3316 presShell->SetMaxLineBoxWidth(mlbw);
3319 return NS_OK;
3322 NS_IMETHODIMP
3323 nsDocumentViewer::GetContentSize(int32_t* aWidth, int32_t* aHeight)
3325 NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
3327 // Skip doing this on docshell-less documents for now
3328 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(mContainer);
3329 NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_NOT_AVAILABLE);
3331 nsCOMPtr<nsIDocShellTreeItem> docShellParent;
3332 docShellAsItem->GetSameTypeParent(getter_AddRefs(docShellParent));
3334 // It's only valid to access this from a top frame. Doesn't work from
3335 // sub-frames.
3336 NS_ENSURE_TRUE(!docShellParent, NS_ERROR_FAILURE);
3338 nsCOMPtr<nsIPresShell> presShell;
3339 GetPresShell(getter_AddRefs(presShell));
3340 NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
3342 // Flush out all content and style updates. We can't use a resize reflow
3343 // because it won't change some sizes that a style change reflow will.
3344 mDocument->FlushPendingNotifications(Flush_Layout);
3346 nsIFrame *root = presShell->GetRootFrame();
3347 NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
3349 nscoord prefWidth;
3351 nsRefPtr<nsRenderingContext> rcx =
3352 presShell->CreateReferenceRenderingContext();
3353 prefWidth = root->GetPrefISize(rcx);
3356 nsresult rv = presShell->ResizeReflow(prefWidth, NS_UNCONSTRAINEDSIZE);
3357 NS_ENSURE_SUCCESS(rv, rv);
3359 nsRefPtr<nsPresContext> presContext;
3360 GetPresContext(getter_AddRefs(presContext));
3361 NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
3363 // so how big is it?
3364 nsRect shellArea = presContext->GetVisibleArea();
3365 // Protect against bogus returns here
3366 NS_ENSURE_TRUE(shellArea.width != NS_UNCONSTRAINEDSIZE &&
3367 shellArea.height != NS_UNCONSTRAINEDSIZE,
3368 NS_ERROR_FAILURE);
3370 *aWidth = presContext->AppUnitsToDevPixels(shellArea.width);
3371 *aHeight = presContext->AppUnitsToDevPixels(shellArea.height);
3373 return NS_OK;
3377 NS_IMPL_ISUPPORTS(nsDocViewerSelectionListener, nsISelectionListener)
3379 nsresult nsDocViewerSelectionListener::Init(nsDocumentViewer *aDocViewer)
3381 mDocViewer = aDocViewer;
3382 return NS_OK;
3386 * GetPopupNode, GetPopupLinkNode and GetPopupImageNode are helpers
3387 * for the cmd_copyLink / cmd_copyImageLocation / cmd_copyImageContents family
3388 * of commands. The focus controller stores the popup node, these retrieve
3389 * them and munge appropriately. Note that we have to store the popup node
3390 * rather than retrieving it from EventStateManager::GetFocusedContent because
3391 * not all content (images included) can receive focus.
3394 nsresult
3395 nsDocumentViewer::GetPopupNode(nsIDOMNode** aNode)
3397 NS_ENSURE_ARG_POINTER(aNode);
3399 *aNode = nullptr;
3401 // get the document
3402 nsIDocument* document = GetDocument();
3403 NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
3405 // get the private dom window
3406 nsCOMPtr<nsPIDOMWindow> window(document->GetWindow());
3407 NS_ENSURE_TRUE(window, NS_ERROR_NOT_AVAILABLE);
3408 if (window) {
3409 nsCOMPtr<nsPIWindowRoot> root = window->GetTopWindowRoot();
3410 NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
3412 // get the popup node
3413 nsCOMPtr<nsIDOMNode> node = root->GetPopupNode();
3414 #ifdef MOZ_XUL
3415 if (!node) {
3416 nsPIDOMWindow* rootWindow = root->GetWindow();
3417 if (rootWindow) {
3418 nsCOMPtr<nsIDocument> rootDoc = rootWindow->GetExtantDoc();
3419 if (rootDoc) {
3420 nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
3421 if (pm) {
3422 node = pm->GetLastTriggerPopupNode(rootDoc);
3427 #endif
3428 node.swap(*aNode);
3431 return NS_OK;
3434 // GetPopupLinkNode: return popup link node or fail
3435 nsresult
3436 nsDocumentViewer::GetPopupLinkNode(nsIDOMNode** aNode)
3438 NS_ENSURE_ARG_POINTER(aNode);
3440 // you get null unless i say so
3441 *aNode = nullptr;
3443 // find popup node
3444 nsCOMPtr<nsIDOMNode> node;
3445 nsresult rv = GetPopupNode(getter_AddRefs(node));
3446 NS_ENSURE_SUCCESS(rv, rv);
3448 // find out if we have a link in our ancestry
3449 while (node) {
3451 nsCOMPtr<nsIContent> content(do_QueryInterface(node));
3452 if (content) {
3453 nsCOMPtr<nsIURI> hrefURI = content->GetHrefURI();
3454 if (hrefURI) {
3455 *aNode = node;
3456 NS_IF_ADDREF(*aNode); // addref
3457 return NS_OK;
3461 // get our parent and keep trying...
3462 nsCOMPtr<nsIDOMNode> parentNode;
3463 node->GetParentNode(getter_AddRefs(parentNode));
3464 node = parentNode;
3467 // if we have no node, fail
3468 return NS_ERROR_FAILURE;
3471 // GetPopupLinkNode: return popup image node or fail
3472 nsresult
3473 nsDocumentViewer::GetPopupImageNode(nsIImageLoadingContent** aNode)
3475 NS_ENSURE_ARG_POINTER(aNode);
3477 // you get null unless i say so
3478 *aNode = nullptr;
3480 // find popup node
3481 nsCOMPtr<nsIDOMNode> node;
3482 nsresult rv = GetPopupNode(getter_AddRefs(node));
3483 NS_ENSURE_SUCCESS(rv, rv);
3485 if (node)
3486 CallQueryInterface(node, aNode);
3488 return NS_OK;
3492 * XXX dr
3493 * ------
3494 * These two functions -- GetInLink and GetInImage -- are kind of annoying
3495 * in that they only get called from the controller (in
3496 * nsDOMWindowController::IsCommandEnabled). The actual construction of the
3497 * context menus in communicator (nsContextMenu.js) has its own, redundant
3498 * tests. No big deal, but good to keep in mind if we ever clean context
3499 * menus.
3502 NS_IMETHODIMP nsDocumentViewer::GetInLink(bool* aInLink)
3504 #ifdef DEBUG_dr
3505 printf("dr :: nsDocumentViewer::GetInLink\n");
3506 #endif
3508 NS_ENSURE_ARG_POINTER(aInLink);
3510 // we're not in a link unless i say so
3511 *aInLink = false;
3513 // get the popup link
3514 nsCOMPtr<nsIDOMNode> node;
3515 nsresult rv = GetPopupLinkNode(getter_AddRefs(node));
3516 if (NS_FAILED(rv)) return rv;
3517 NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
3519 // if we made it here, we're in a link
3520 *aInLink = true;
3521 return NS_OK;
3524 NS_IMETHODIMP nsDocumentViewer::GetInImage(bool* aInImage)
3526 #ifdef DEBUG_dr
3527 printf("dr :: nsDocumentViewer::GetInImage\n");
3528 #endif
3530 NS_ENSURE_ARG_POINTER(aInImage);
3532 // we're not in an image unless i say so
3533 *aInImage = false;
3535 // get the popup image
3536 nsCOMPtr<nsIImageLoadingContent> node;
3537 nsresult rv = GetPopupImageNode(getter_AddRefs(node));
3538 if (NS_FAILED(rv)) return rv;
3539 NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
3541 // if we made it here, we're in an image
3542 *aInImage = true;
3543 return NS_OK;
3546 NS_IMETHODIMP nsDocViewerSelectionListener::NotifySelectionChanged(nsIDOMDocument *, nsISelection *, int16_t aReason)
3548 NS_ASSERTION(mDocViewer, "Should have doc viewer!");
3550 // get the selection state
3551 nsCOMPtr<nsISelection> selection;
3552 nsresult rv = mDocViewer->GetDocumentSelection(getter_AddRefs(selection));
3553 if (NS_FAILED(rv)) return rv;
3555 nsIDocument* theDoc = mDocViewer->GetDocument();
3556 if (!theDoc) return NS_ERROR_FAILURE;
3558 nsCOMPtr<nsPIDOMWindow> domWindow = theDoc->GetWindow();
3559 if (!domWindow) return NS_ERROR_FAILURE;
3561 bool selectionCollapsed;
3562 selection->GetIsCollapsed(&selectionCollapsed);
3563 // we only call UpdateCommands when the selection changes from collapsed
3564 // to non-collapsed or vice versa. We might need another update string
3565 // for simple selection changes, but that would be expenseive.
3566 if (!mGotSelectionState || mSelectionWasCollapsed != selectionCollapsed)
3568 domWindow->UpdateCommands(NS_LITERAL_STRING("select"), selection, aReason);
3569 mGotSelectionState = true;
3570 mSelectionWasCollapsed = selectionCollapsed;
3573 domWindow->UpdateCommands(NS_LITERAL_STRING("selectionchange"), selection, aReason);
3575 return NS_OK;
3578 //nsDocViewerFocusListener
3579 NS_IMPL_ISUPPORTS(nsDocViewerFocusListener,
3580 nsIDOMEventListener)
3582 nsDocViewerFocusListener::nsDocViewerFocusListener()
3583 :mDocViewer(nullptr)
3587 nsDocViewerFocusListener::~nsDocViewerFocusListener(){}
3589 nsresult
3590 nsDocViewerFocusListener::HandleEvent(nsIDOMEvent* aEvent)
3592 NS_ENSURE_STATE(mDocViewer);
3594 nsCOMPtr<nsIPresShell> shell;
3595 mDocViewer->GetPresShell(getter_AddRefs(shell));
3596 NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE);
3598 nsCOMPtr<nsISelectionController> selCon = do_QueryInterface(shell);
3599 int16_t selectionStatus;
3600 selCon->GetDisplaySelection(&selectionStatus);
3602 nsAutoString eventType;
3603 aEvent->GetType(eventType);
3604 if (eventType.EqualsLiteral("focus")) {
3605 // If selection was disabled, re-enable it.
3606 if(selectionStatus == nsISelectionController::SELECTION_DISABLED ||
3607 selectionStatus == nsISelectionController::SELECTION_HIDDEN) {
3608 selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
3609 selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL);
3611 } else {
3612 NS_ABORT_IF_FALSE(eventType.EqualsLiteral("blur"),
3613 "Unexpected event type");
3614 // If selection was on, disable it.
3615 if(selectionStatus == nsISelectionController::SELECTION_ON ||
3616 selectionStatus == nsISelectionController::SELECTION_ATTENTION) {
3617 selCon->SetDisplaySelection(nsISelectionController::SELECTION_DISABLED);
3618 selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL);
3622 return NS_OK;
3625 nsresult
3626 nsDocViewerFocusListener::Init(nsDocumentViewer *aDocViewer)
3628 mDocViewer = aDocViewer;
3629 return NS_OK;
3632 /** ---------------------------------------------------
3633 * From nsIWebBrowserPrint
3636 #ifdef NS_PRINTING
3638 NS_IMETHODIMP
3639 nsDocumentViewer::Print(nsIPrintSettings* aPrintSettings,
3640 nsIWebProgressListener* aWebProgressListener)
3642 // Printing XUL documents is not supported.
3643 nsCOMPtr<nsIXULDocument> xulDoc(do_QueryInterface(mDocument));
3644 if (xulDoc) {
3645 return NS_ERROR_FAILURE;
3648 if (!mContainer) {
3649 PR_PL(("Container was destroyed yet we are still trying to use it!"));
3650 return NS_ERROR_FAILURE;
3653 nsCOMPtr<nsIDocShell> docShell(mContainer);
3654 NS_ENSURE_STATE(docShell);
3656 // Check to see if this document is still busy
3657 // If it is busy and we aren't already "queued" up to print then
3658 // Indicate there is a print pending and cache the args for later
3659 uint32_t busyFlags = nsIDocShell::BUSY_FLAGS_NONE;
3660 if ((NS_FAILED(docShell->GetBusyFlags(&busyFlags)) ||
3661 (busyFlags != nsIDocShell::BUSY_FLAGS_NONE && busyFlags & nsIDocShell::BUSY_FLAGS_PAGE_LOADING)) &&
3662 !mPrintDocIsFullyLoaded) {
3663 if (!mPrintIsPending) {
3664 mCachedPrintSettings = aPrintSettings;
3665 mCachedPrintWebProgressListner = aWebProgressListener;
3666 mPrintIsPending = true;
3668 PR_PL(("Printing Stopped - document is still busy!"));
3669 return NS_ERROR_GFX_PRINTER_DOC_IS_BUSY;
3672 if (!mDocument || !mDeviceContext) {
3673 PR_PL(("Can't Print without a document and a device context"));
3674 return NS_ERROR_FAILURE;
3677 nsresult rv;
3679 // if we are printing another URL, then exit
3680 // the reason we check here is because this method can be called while
3681 // another is still in here (the printing dialog is a good example).
3682 // the only time we can print more than one job at a time is the regression tests
3683 if (GetIsPrinting()) {
3684 // Let the user know we are not ready to print.
3685 rv = NS_ERROR_NOT_AVAILABLE;
3686 nsPrintEngine::ShowPrintErrorDialog(rv);
3687 return rv;
3690 nsAutoPtr<nsPrintEventDispatcher> beforeAndAfterPrint(
3691 new nsPrintEventDispatcher(mDocument));
3692 NS_ENSURE_STATE(!GetIsPrinting());
3693 // If we are hosting a full-page plugin, tell it to print
3694 // first. It shows its own native print UI.
3695 nsCOMPtr<nsIPluginDocument> pDoc(do_QueryInterface(mDocument));
3696 if (pDoc)
3697 return pDoc->Print();
3699 if (!mPrintEngine) {
3700 NS_ENSURE_STATE(mDeviceContext);
3701 mPrintEngine = new nsPrintEngine();
3703 rv = mPrintEngine->Initialize(this, mContainer, mDocument,
3704 float(mDeviceContext->AppUnitsPerCSSInch()) /
3705 float(mDeviceContext->AppUnitsPerDevPixel()) /
3706 mPageZoom,
3707 #ifdef DEBUG
3708 mDebugFile
3709 #else
3710 nullptr
3711 #endif
3713 if (NS_FAILED(rv)) {
3714 mPrintEngine->Destroy();
3715 mPrintEngine = nullptr;
3716 return rv;
3719 if (mPrintEngine->HasPrintCallbackCanvas()) {
3720 mBeforeAndAfterPrint = beforeAndAfterPrint;
3722 dom::Element* root = mDocument->GetRootElement();
3723 if (root && root->HasAttr(kNameSpaceID_None, nsGkAtoms::mozdisallowselectionprint)) {
3724 mPrintEngine->SetDisallowSelectionPrint(true);
3726 if (root && root->HasAttr(kNameSpaceID_None, nsGkAtoms::moznomarginboxes)) {
3727 mPrintEngine->SetNoMarginBoxes(true);
3729 rv = mPrintEngine->Print(aPrintSettings, aWebProgressListener);
3730 if (NS_FAILED(rv)) {
3731 OnDonePrinting();
3733 return rv;
3736 NS_IMETHODIMP
3737 nsDocumentViewer::PrintPreview(nsIPrintSettings* aPrintSettings,
3738 nsIDOMWindow *aChildDOMWin,
3739 nsIWebProgressListener* aWebProgressListener)
3741 #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
3742 NS_WARN_IF_FALSE(IsInitializedForPrintPreview(),
3743 "Using docshell.printPreview is the preferred way for print previewing!");
3745 NS_ENSURE_ARG_POINTER(aChildDOMWin);
3746 nsresult rv = NS_OK;
3748 if (GetIsPrinting()) {
3749 nsPrintEngine::CloseProgressDialog(aWebProgressListener);
3750 return NS_ERROR_FAILURE;
3753 // Printing XUL documents is not supported.
3754 nsCOMPtr<nsIXULDocument> xulDoc(do_QueryInterface(mDocument));
3755 if (xulDoc) {
3756 nsPrintEngine::CloseProgressDialog(aWebProgressListener);
3757 return NS_ERROR_FAILURE;
3760 nsCOMPtr<nsIDocShell> docShell(mContainer);
3761 if (!docShell || !mDeviceContext) {
3762 PR_PL(("Can't Print Preview without device context and docshell"));
3763 return NS_ERROR_FAILURE;
3766 nsCOMPtr<nsIDOMDocument> domDoc;
3767 aChildDOMWin->GetDocument(getter_AddRefs(domDoc));
3768 nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
3769 NS_ENSURE_STATE(doc);
3771 nsAutoPtr<nsPrintEventDispatcher> beforeAndAfterPrint(
3772 new nsPrintEventDispatcher(doc));
3773 NS_ENSURE_STATE(!GetIsPrinting());
3774 if (!mPrintEngine) {
3775 mPrintEngine = new nsPrintEngine();
3777 rv = mPrintEngine->Initialize(this, mContainer, doc,
3778 float(mDeviceContext->AppUnitsPerCSSInch()) /
3779 float(mDeviceContext->AppUnitsPerDevPixel()) /
3780 mPageZoom,
3781 #ifdef DEBUG
3782 mDebugFile
3783 #else
3784 nullptr
3785 #endif
3787 if (NS_FAILED(rv)) {
3788 mPrintEngine->Destroy();
3789 mPrintEngine = nullptr;
3790 return rv;
3793 if (mPrintEngine->HasPrintCallbackCanvas()) {
3794 mBeforeAndAfterPrint = beforeAndAfterPrint;
3796 dom::Element* root = doc->GetRootElement();
3797 if (root && root->HasAttr(kNameSpaceID_None, nsGkAtoms::mozdisallowselectionprint)) {
3798 PR_PL(("PrintPreview: found mozdisallowselectionprint"));
3799 mPrintEngine->SetDisallowSelectionPrint(true);
3801 if (root && root->HasAttr(kNameSpaceID_None, nsGkAtoms::moznomarginboxes)) {
3802 PR_PL(("PrintPreview: found moznomarginboxes"));
3803 mPrintEngine->SetNoMarginBoxes(true);
3805 rv = mPrintEngine->PrintPreview(aPrintSettings, aChildDOMWin, aWebProgressListener);
3806 mPrintPreviewZoomed = false;
3807 if (NS_FAILED(rv)) {
3808 OnDonePrinting();
3810 return rv;
3811 #else
3812 return NS_ERROR_FAILURE;
3813 #endif
3816 //----------------------------------------------------------------------
3817 NS_IMETHODIMP
3818 nsDocumentViewer::PrintPreviewNavigate(int16_t aType, int32_t aPageNum)
3820 if (!GetIsPrintPreview() ||
3821 mPrintEngine->GetIsCreatingPrintPreview())
3822 return NS_ERROR_FAILURE;
3824 nsIScrollableFrame* sf =
3825 mPrintEngine->GetPrintPreviewPresShell()->GetRootScrollFrameAsScrollable();
3826 if (!sf)
3827 return NS_OK;
3829 // Check to see if we can short circut scrolling to the top
3830 if (aType == nsIWebBrowserPrint::PRINTPREVIEW_HOME ||
3831 (aType == nsIWebBrowserPrint::PRINTPREVIEW_GOTO_PAGENUM && aPageNum == 1)) {
3832 sf->ScrollTo(nsPoint(0, 0), nsIScrollableFrame::INSTANT);
3833 return NS_OK;
3836 // Finds the SimplePageSequencer frame
3837 // in PP mPrtPreview->mPrintObject->mSeqFrame is null
3838 nsIFrame* seqFrame = nullptr;
3839 int32_t pageCount = 0;
3840 if (NS_FAILED(mPrintEngine->GetSeqFrameAndCountPages(seqFrame, pageCount))) {
3841 return NS_ERROR_FAILURE;
3844 // Figure where we are currently scrolled to
3845 nsPoint pt = sf->GetScrollPosition();
3847 int32_t pageNum = 1;
3848 nsIFrame * fndPageFrame = nullptr;
3849 nsIFrame * currentPage = nullptr;
3851 // If it is "End" then just do a "goto" to the last page
3852 if (aType == nsIWebBrowserPrint::PRINTPREVIEW_END) {
3853 aType = nsIWebBrowserPrint::PRINTPREVIEW_GOTO_PAGENUM;
3854 aPageNum = pageCount;
3857 // Now, locate the current page we are on and
3858 // and the page of the page number
3859 nsIFrame* pageFrame = seqFrame->GetFirstPrincipalChild();
3860 while (pageFrame != nullptr) {
3861 nsRect pageRect = pageFrame->GetRect();
3862 if (pageRect.Contains(pageRect.x, pt.y)) {
3863 currentPage = pageFrame;
3865 if (pageNum == aPageNum) {
3866 fndPageFrame = pageFrame;
3867 break;
3869 pageNum++;
3870 pageFrame = pageFrame->GetNextSibling();
3873 if (aType == nsIWebBrowserPrint::PRINTPREVIEW_PREV_PAGE) {
3874 if (currentPage) {
3875 fndPageFrame = currentPage->GetPrevInFlow();
3876 if (!fndPageFrame) {
3877 return NS_OK;
3879 } else {
3880 return NS_OK;
3882 } else if (aType == nsIWebBrowserPrint::PRINTPREVIEW_NEXT_PAGE) {
3883 if (currentPage) {
3884 fndPageFrame = currentPage->GetNextInFlow();
3885 if (!fndPageFrame) {
3886 return NS_OK;
3888 } else {
3889 return NS_OK;
3891 } else { // If we get here we are doing "GoTo"
3892 if (aPageNum < 0 || aPageNum > pageCount) {
3893 return NS_OK;
3897 if (fndPageFrame) {
3898 nscoord newYPosn =
3899 nscoord(mPrintEngine->GetPrintPreviewScale() * fndPageFrame->GetPosition().y);
3900 sf->ScrollTo(nsPoint(pt.x, newYPosn), nsIScrollableFrame::INSTANT);
3902 return NS_OK;
3906 /* readonly attribute nsIPrintSettings globalPrintSettings; */
3907 NS_IMETHODIMP
3908 nsDocumentViewer::GetGlobalPrintSettings(nsIPrintSettings * *aGlobalPrintSettings)
3910 return nsPrintEngine::GetGlobalPrintSettings(aGlobalPrintSettings);
3913 /* readonly attribute boolean doingPrint; */
3914 // XXX This always returns false for subdocuments
3915 NS_IMETHODIMP
3916 nsDocumentViewer::GetDoingPrint(bool *aDoingPrint)
3918 NS_ENSURE_ARG_POINTER(aDoingPrint);
3920 *aDoingPrint = false;
3921 if (mPrintEngine) {
3922 // XXX shouldn't this be GetDoingPrint() ?
3923 return mPrintEngine->GetDoingPrintPreview(aDoingPrint);
3925 return NS_OK;
3928 /* readonly attribute boolean doingPrintPreview; */
3929 // XXX This always returns false for subdocuments
3930 NS_IMETHODIMP
3931 nsDocumentViewer::GetDoingPrintPreview(bool *aDoingPrintPreview)
3933 NS_ENSURE_ARG_POINTER(aDoingPrintPreview);
3935 *aDoingPrintPreview = false;
3936 if (mPrintEngine) {
3937 return mPrintEngine->GetDoingPrintPreview(aDoingPrintPreview);
3939 return NS_OK;
3942 /* readonly attribute nsIPrintSettings currentPrintSettings; */
3943 NS_IMETHODIMP
3944 nsDocumentViewer::GetCurrentPrintSettings(nsIPrintSettings * *aCurrentPrintSettings)
3946 NS_ENSURE_ARG_POINTER(aCurrentPrintSettings);
3948 *aCurrentPrintSettings = nullptr;
3949 NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
3951 return mPrintEngine->GetCurrentPrintSettings(aCurrentPrintSettings);
3955 /* readonly attribute nsIDOMWindow currentChildDOMWindow; */
3956 NS_IMETHODIMP
3957 nsDocumentViewer::GetCurrentChildDOMWindow(nsIDOMWindow * *aCurrentChildDOMWindow)
3959 NS_ENSURE_ARG_POINTER(aCurrentChildDOMWindow);
3960 *aCurrentChildDOMWindow = nullptr;
3961 return NS_ERROR_NOT_IMPLEMENTED;
3964 /* void cancel (); */
3965 NS_IMETHODIMP
3966 nsDocumentViewer::Cancel()
3968 NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
3969 return mPrintEngine->Cancelled();
3972 /* void exitPrintPreview (); */
3973 NS_IMETHODIMP
3974 nsDocumentViewer::ExitPrintPreview()
3976 if (GetIsPrinting())
3977 return NS_ERROR_FAILURE;
3978 NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
3980 if (GetIsPrintPreview()) {
3981 ReturnToGalleyPresentation();
3983 return NS_OK;
3986 //----------------------------------------------------------------------------------
3987 // Enumerate all the documents for their titles
3988 NS_IMETHODIMP
3989 nsDocumentViewer::EnumerateDocumentNames(uint32_t* aCount,
3990 char16_t*** aResult)
3992 #ifdef NS_PRINTING
3993 NS_ENSURE_ARG(aCount);
3994 NS_ENSURE_ARG_POINTER(aResult);
3995 NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
3997 return mPrintEngine->EnumerateDocumentNames(aCount, aResult);
3998 #else
3999 return NS_ERROR_FAILURE;
4000 #endif
4003 /* readonly attribute boolean isFramesetFrameSelected; */
4004 NS_IMETHODIMP
4005 nsDocumentViewer::GetIsFramesetFrameSelected(bool *aIsFramesetFrameSelected)
4007 #ifdef NS_PRINTING
4008 *aIsFramesetFrameSelected = false;
4009 NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
4011 return mPrintEngine->GetIsFramesetFrameSelected(aIsFramesetFrameSelected);
4012 #else
4013 return NS_ERROR_FAILURE;
4014 #endif
4017 /* readonly attribute long printPreviewNumPages; */
4018 NS_IMETHODIMP
4019 nsDocumentViewer::GetPrintPreviewNumPages(int32_t *aPrintPreviewNumPages)
4021 #ifdef NS_PRINTING
4022 NS_ENSURE_ARG_POINTER(aPrintPreviewNumPages);
4023 NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
4025 return mPrintEngine->GetPrintPreviewNumPages(aPrintPreviewNumPages);
4026 #else
4027 return NS_ERROR_FAILURE;
4028 #endif
4031 /* readonly attribute boolean isFramesetDocument; */
4032 NS_IMETHODIMP
4033 nsDocumentViewer::GetIsFramesetDocument(bool *aIsFramesetDocument)
4035 #ifdef NS_PRINTING
4036 *aIsFramesetDocument = false;
4037 NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
4039 return mPrintEngine->GetIsFramesetDocument(aIsFramesetDocument);
4040 #else
4041 return NS_ERROR_FAILURE;
4042 #endif
4045 /* readonly attribute boolean isIFrameSelected; */
4046 NS_IMETHODIMP
4047 nsDocumentViewer::GetIsIFrameSelected(bool *aIsIFrameSelected)
4049 #ifdef NS_PRINTING
4050 *aIsIFrameSelected = false;
4051 NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
4053 return mPrintEngine->GetIsIFrameSelected(aIsIFrameSelected);
4054 #else
4055 return NS_ERROR_FAILURE;
4056 #endif
4059 /* readonly attribute boolean isRangeSelection; */
4060 NS_IMETHODIMP
4061 nsDocumentViewer::GetIsRangeSelection(bool *aIsRangeSelection)
4063 #ifdef NS_PRINTING
4064 *aIsRangeSelection = false;
4065 NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
4067 return mPrintEngine->GetIsRangeSelection(aIsRangeSelection);
4068 #else
4069 return NS_ERROR_FAILURE;
4070 #endif
4073 //----------------------------------------------------------------------------------
4074 // Printing/Print Preview Helpers
4075 //----------------------------------------------------------------------------------
4077 //----------------------------------------------------------------------------------
4078 // Walks the document tree and tells each DocShell whether Printing/PP is happening
4079 void
4080 nsDocumentViewer::SetIsPrintingInDocShellTree(nsIDocShellTreeItem* aParentNode,
4081 bool aIsPrintingOrPP,
4082 bool aStartAtTop)
4084 nsCOMPtr<nsIDocShellTreeItem> parentItem(do_QueryInterface(aParentNode));
4086 // find top of "same parent" tree
4087 if (aStartAtTop) {
4088 if (aIsPrintingOrPP) {
4089 while (parentItem) {
4090 nsCOMPtr<nsIDocShellTreeItem> parent;
4091 parentItem->GetSameTypeParent(getter_AddRefs(parent));
4092 if (!parent) {
4093 break;
4095 parentItem = do_QueryInterface(parent);
4097 mTopContainerWhilePrinting = do_GetWeakReference(parentItem);
4098 } else {
4099 parentItem = do_QueryReferent(mTopContainerWhilePrinting);
4103 // Check to see if the DocShell's ContentViewer is printing/PP
4104 nsCOMPtr<nsIContentViewerContainer> viewerContainer(do_QueryInterface(parentItem));
4105 if (viewerContainer) {
4106 viewerContainer->SetIsPrinting(aIsPrintingOrPP);
4109 if (!aParentNode) {
4110 return;
4113 // Traverse children to see if any of them are printing.
4114 int32_t n;
4115 aParentNode->GetChildCount(&n);
4116 for (int32_t i=0; i < n; i++) {
4117 nsCOMPtr<nsIDocShellTreeItem> child;
4118 aParentNode->GetChildAt(i, getter_AddRefs(child));
4119 NS_ASSERTION(child, "child isn't nsIDocShell");
4120 if (child) {
4121 SetIsPrintingInDocShellTree(child, aIsPrintingOrPP, false);
4126 #endif // NS_PRINTING
4128 bool
4129 nsDocumentViewer::ShouldAttachToTopLevel()
4131 if (!mParentWidget)
4132 return false;
4134 nsCOMPtr<nsIDocShellTreeItem> containerItem(mContainer);
4135 if (!containerItem)
4136 return false;
4138 // We always attach when using puppet widgets
4139 if (nsIWidget::UsePuppetWidgets())
4140 return true;
4142 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
4143 // On windows, in the parent process we also attach, but just to
4144 // chrome items
4145 nsWindowType winType = mParentWidget->WindowType();
4146 if ((winType == eWindowType_toplevel ||
4147 winType == eWindowType_dialog ||
4148 winType == eWindowType_invisible) &&
4149 containerItem->ItemType() == nsIDocShellTreeItem::typeChrome) {
4150 return true;
4152 #endif
4154 return false;
4157 bool CollectDocuments(nsIDocument* aDocument, void* aData)
4159 if (aDocument) {
4160 static_cast<nsCOMArray<nsIDocument>*>(aData)->AppendObject(aDocument);
4161 aDocument->EnumerateSubDocuments(CollectDocuments, aData);
4163 return true;
4166 void
4167 nsDocumentViewer::DispatchEventToWindowTree(nsIDocument* aDoc,
4168 const nsAString& aEvent)
4170 nsCOMArray<nsIDocument> targets;
4171 CollectDocuments(aDoc, &targets);
4172 for (int32_t i = 0; i < targets.Count(); ++i) {
4173 nsIDocument* d = targets[i];
4174 nsContentUtils::DispatchTrustedEvent(d, d->GetWindow(),
4175 aEvent, false, false, nullptr);
4179 //------------------------------------------------------------
4180 // XXX this always returns false for subdocuments
4181 bool
4182 nsDocumentViewer::GetIsPrinting()
4184 #ifdef NS_PRINTING
4185 if (mPrintEngine) {
4186 return mPrintEngine->GetIsPrinting();
4188 #endif
4189 return false;
4192 //------------------------------------------------------------
4193 // Notification from the PrintEngine of the current Printing status
4194 void
4195 nsDocumentViewer::SetIsPrinting(bool aIsPrinting)
4197 #ifdef NS_PRINTING
4198 // Set all the docShells in the docshell tree to be printing.
4199 // that way if anyone of them tries to "navigate" it can't
4200 nsCOMPtr<nsIDocShell> docShell(mContainer);
4201 if (docShell || !aIsPrinting) {
4202 SetIsPrintingInDocShellTree(docShell, aIsPrinting, true);
4203 } else {
4204 NS_WARNING("Did you close a window before printing?");
4207 if (!aIsPrinting) {
4208 mBeforeAndAfterPrint = nullptr;
4210 #endif
4213 //------------------------------------------------------------
4214 // The PrintEngine holds the current value
4215 // this called from inside the DocViewer.
4216 // XXX it always returns false for subdocuments
4217 bool
4218 nsDocumentViewer::GetIsPrintPreview()
4220 #ifdef NS_PRINTING
4221 if (mPrintEngine) {
4222 return mPrintEngine->GetIsPrintPreview();
4224 #endif
4225 return false;
4228 //------------------------------------------------------------
4229 // Notification from the PrintEngine of the current PP status
4230 void
4231 nsDocumentViewer::SetIsPrintPreview(bool aIsPrintPreview)
4233 #ifdef NS_PRINTING
4234 // Set all the docShells in the docshell tree to be printing.
4235 // that way if anyone of them tries to "navigate" it can't
4236 nsCOMPtr<nsIDocShell> docShell(mContainer);
4237 if (docShell || !aIsPrintPreview) {
4238 SetIsPrintingInDocShellTree(docShell, aIsPrintPreview, true);
4240 if (!aIsPrintPreview) {
4241 mBeforeAndAfterPrint = nullptr;
4243 #endif
4244 if (!aIsPrintPreview) {
4245 if (mPresShell) {
4246 DestroyPresShell();
4248 mWindow = nullptr;
4249 mViewManager = nullptr;
4250 mPresContext = nullptr;
4251 mPresShell = nullptr;
4255 //----------------------------------------------------------------------------------
4256 // nsIDocumentViewerPrint IFace
4257 //----------------------------------------------------------------------------------
4259 //------------------------------------------------------------
4260 void
4261 nsDocumentViewer::IncrementDestroyRefCount()
4263 ++mDestroyRefCount;
4266 //------------------------------------------------------------
4268 #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
4269 //------------------------------------------------------------
4270 // Reset ESM focus for all descendent doc shells.
4271 static void
4272 ResetFocusState(nsIDocShell* aDocShell)
4274 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
4275 if (!fm)
4276 return;
4278 nsCOMPtr<nsISimpleEnumerator> docShellEnumerator;
4279 aDocShell->GetDocShellEnumerator(nsIDocShellTreeItem::typeContent,
4280 nsIDocShell::ENUMERATE_FORWARDS,
4281 getter_AddRefs(docShellEnumerator));
4283 nsCOMPtr<nsISupports> currentContainer;
4284 bool hasMoreDocShells;
4285 while (NS_SUCCEEDED(docShellEnumerator->HasMoreElements(&hasMoreDocShells))
4286 && hasMoreDocShells) {
4287 docShellEnumerator->GetNext(getter_AddRefs(currentContainer));
4288 nsCOMPtr<nsIDOMWindow> win = do_GetInterface(currentContainer);
4289 if (win)
4290 fm->ClearFocus(win);
4293 #endif // NS_PRINTING && NS_PRINT_PREVIEW
4295 void
4296 nsDocumentViewer::ReturnToGalleyPresentation()
4298 #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
4299 if (!GetIsPrintPreview()) {
4300 NS_ERROR("Wow, we should never get here!");
4301 return;
4304 SetIsPrintPreview(false);
4306 mPrintEngine->TurnScriptingOn(true);
4307 mPrintEngine->Destroy();
4308 mPrintEngine = nullptr;
4310 nsCOMPtr<nsIDocShell> docShell(mContainer);
4311 ResetFocusState(docShell);
4313 SetTextZoom(mTextZoom);
4314 SetFullZoom(mPageZoom);
4315 SetMinFontSize(mMinFontSize);
4316 Show();
4318 #endif // NS_PRINTING && NS_PRINT_PREVIEW
4321 //------------------------------------------------------------
4322 // This called ONLY when printing has completed and the DV
4323 // is being notified that it should get rid of the PrintEngine.
4325 // BUT, if we are in Print Preview then we want to ignore the
4326 // notification (we do not get rid of the PrintEngine)
4328 // One small caveat:
4329 // This IS called from two places in this module for cleaning
4330 // up when an error occurred during the start up printing
4331 // and print preview
4333 void
4334 nsDocumentViewer::OnDonePrinting()
4336 #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
4337 if (mPrintEngine) {
4338 nsRefPtr<nsPrintEngine> pe = mPrintEngine;
4339 if (GetIsPrintPreview()) {
4340 pe->DestroyPrintingData();
4341 } else {
4342 mPrintEngine = nullptr;
4343 pe->Destroy();
4346 // We are done printing, now cleanup
4347 if (mDeferredWindowClose) {
4348 mDeferredWindowClose = false;
4349 if (mContainer) {
4350 nsCOMPtr<nsIDOMWindow> win = mContainer->GetWindow();
4351 if (win)
4352 win->Close();
4354 } else if (mClosingWhilePrinting) {
4355 if (mDocument) {
4356 mDocument->SetScriptGlobalObject(nullptr);
4357 mDocument->Destroy();
4358 mDocument = nullptr;
4360 mClosingWhilePrinting = false;
4363 #endif // NS_PRINTING && NS_PRINT_PREVIEW
4366 NS_IMETHODIMP nsDocumentViewer::SetPageMode(bool aPageMode, nsIPrintSettings* aPrintSettings)
4368 // XXX Page mode is only partially working; it's currently used for
4369 // reftests that require a paginated context
4370 mIsPageMode = aPageMode;
4372 if (mPresShell) {
4373 DestroyPresShell();
4376 if (mPresContext) {
4377 DestroyPresContext();
4380 mViewManager = nullptr;
4381 mWindow = nullptr;
4383 NS_ENSURE_STATE(mDocument);
4384 if (aPageMode)
4386 mPresContext = CreatePresContext(mDocument,
4387 nsPresContext::eContext_PageLayout, FindContainerView());
4388 NS_ENSURE_TRUE(mPresContext, NS_ERROR_OUT_OF_MEMORY);
4389 mPresContext->SetPaginatedScrolling(true);
4390 mPresContext->SetPrintSettings(aPrintSettings);
4391 nsresult rv = mPresContext->Init(mDeviceContext);
4392 NS_ENSURE_SUCCESS(rv, rv);
4394 NS_ENSURE_SUCCESS(InitInternal(mParentWidget, nullptr, mBounds, true, false),
4395 NS_ERROR_FAILURE);
4397 Show();
4398 return NS_OK;
4401 NS_IMETHODIMP
4402 nsDocumentViewer::GetHistoryEntry(nsISHEntry **aHistoryEntry)
4404 NS_IF_ADDREF(*aHistoryEntry = mSHEntry);
4405 return NS_OK;
4408 NS_IMETHODIMP
4409 nsDocumentViewer::GetIsTabModalPromptAllowed(bool *aAllowed)
4411 *aAllowed = !mHidden;
4412 return NS_OK;
4415 NS_IMETHODIMP
4416 nsDocumentViewer::GetIsHidden(bool *aHidden)
4418 *aHidden = mHidden;
4419 return NS_OK;
4422 NS_IMETHODIMP
4423 nsDocumentViewer::SetIsHidden(bool aHidden)
4425 mHidden = aHidden;
4426 return NS_OK;
4429 void
4430 nsDocumentViewer::DestroyPresShell()
4432 // Break circular reference (or something)
4433 mPresShell->EndObservingDocument();
4435 nsCOMPtr<nsISelection> selection;
4436 GetDocumentSelection(getter_AddRefs(selection));
4437 nsCOMPtr<nsISelectionPrivate> selPrivate = do_QueryInterface(selection);
4438 if (selPrivate && mSelectionListener)
4439 selPrivate->RemoveSelectionListener(mSelectionListener);
4441 nsRefPtr<SelectionCarets> selectionCaret = mPresShell->GetSelectionCarets();
4442 if (selectionCaret) {
4443 nsCOMPtr<nsIDocShell> docShell(mContainer);
4444 if (docShell) {
4445 docShell->RemoveWeakScrollObserver(selectionCaret);
4449 nsAutoScriptBlocker scriptBlocker;
4450 mPresShell->Destroy();
4451 mPresShell = nullptr;
4454 void
4455 nsDocumentViewer::DestroyPresContext()
4457 mPresContext->Detach();
4458 mPresContext = nullptr;
4461 bool
4462 nsDocumentViewer::IsInitializedForPrintPreview()
4464 return mInitializedForPrintPreview;
4467 void
4468 nsDocumentViewer::InitializeForPrintPreview()
4470 mInitializedForPrintPreview = true;
4473 void
4474 nsDocumentViewer::SetPrintPreviewPresentation(nsViewManager* aViewManager,
4475 nsPresContext* aPresContext,
4476 nsIPresShell* aPresShell)
4478 if (mPresShell) {
4479 DestroyPresShell();
4482 mWindow = nullptr;
4483 mViewManager = aViewManager;
4484 mPresContext = aPresContext;
4485 mPresShell = aPresShell;
4488 // Fires the "document-shown" event so that interested parties are aware of it.
4489 NS_IMETHODIMP
4490 nsDocumentShownDispatcher::Run()
4492 nsCOMPtr<nsIObserverService> observerService =
4493 mozilla::services::GetObserverService();
4494 if (observerService) {
4495 observerService->NotifyObservers(mDocument, "document-shown", nullptr);
4497 return NS_OK;