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 */
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"
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"
37 #include "mozilla/a11y/DocAccessible.h"
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"
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"
64 #include "nsIXULDocument.h"
65 #include "nsXULPopupManager.h"
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 //--------------------------
87 //---------------------------
90 #include "nsIWebBrowserPrint.h"
92 #include "nsPrintEngine.h"
95 #include "nsIPrintSettings.h"
96 #include "nsIPrintOptions.h"
97 #include "nsISimpleEnumerator.h"
100 // PrintOptions is now implemented by PrintSettingsService
101 static const char sPrintOptionsContractID
[] =
102 "@mozilla.org/gfx/printsettings-service;1";
105 #include "nsIPluginDocument.h"
107 #endif // NS_PRINTING
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"
124 #include "mozilla/dom/Element.h"
126 using namespace mozilla
;
127 using namespace mozilla::dom
;
129 #define BEFOREUNLOAD_DISABLED_PREFNAME "dom.disable_beforeunload"
131 //-----------------------------------------------------
134 #define FORCE_PR_LOG /* Allow logging in the release build */
142 static PRLogModuleInfo
*
145 static PRLogModuleInfo
*sLog
;
147 sLog
= PR_NewLogModule("printing");
150 #define PR_PL(_p1) PR_LOG(GetPrintingLog(), PR_LOG_DEBUG, _p1);
151 #endif // NS_PRINTING
153 #define PRT_YESNO(_p) ((_p)?"YES":"NO")
155 #define PRT_YESNO(_p)
158 //-----------------------------------------------------
160 class nsDocumentViewer
;
161 class nsPrintEventDispatcher
;
163 // a small delegate class used to avoid circular references
165 class nsDocViewerSelectionListener
: public nsISelectionListener
169 // nsISupports interface...
172 // nsISelectionListerner interface
173 NS_DECL_NSISELECTIONLISTENER
175 nsDocViewerSelectionListener()
176 : mDocViewer(nullptr)
177 , mGotSelectionState(false)
178 , mSelectionWasCollapsed(false)
182 nsresult
Init(nsDocumentViewer
*aDocViewer
);
186 virtual ~nsDocViewerSelectionListener() {}
188 nsDocumentViewer
* mDocViewer
;
189 bool mGotSelectionState
;
190 bool mSelectionWasCollapsed
;
195 /** editor Implementation of the FocusListener interface
197 class nsDocViewerFocusListener
: public nsIDOMEventListener
200 /** default constructor
202 nsDocViewerFocusListener();
205 NS_DECL_NSIDOMEVENTLISTENER
207 nsresult
Init(nsDocumentViewer
*aDocViewer
);
210 /** default destructor
212 virtual ~nsDocViewerFocusListener();
215 nsDocumentViewer
* mDocViewer
;
219 //-------------------------------------------------------------
220 class nsDocumentViewer
: public nsIContentViewer
,
221 public nsIContentViewerEdit
,
222 public nsIContentViewerFile
,
223 public nsIDocumentViewerPrint
226 , public nsIWebBrowserPrint
230 friend class nsDocViewerSelectionListener
;
231 friend class nsPagePrintTimer
;
232 friend class nsPrintEngine
;
237 NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
239 // nsISupports interface...
242 // nsIContentViewer interface...
243 NS_DECL_NSICONTENTVIEWER
245 // nsIContentViewerEdit
246 NS_DECL_NSICONTENTVIEWEREDIT
248 // nsIContentViewerFile
249 NS_DECL_NSICONTENTVIEWERFILE
252 // nsIWebBrowserPrint
253 NS_DECL_NSIWEBBROWSERPRINT
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
);
275 virtual ~nsDocumentViewer();
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
,
301 const nsIntRect
& aBounds
,
303 bool aNeedMakeCX
= true,
304 bool aForceSetNewDocument
= true);
306 * @param aDoInitialReflow set to true if you want to kick off the initial
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();
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
,
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
335 bool ShouldAttachToTopLevel();
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
374 // mTextZoom/mPageZoom record the textzoom/pagezoom of the first (galley)
376 float mTextZoom
; // Text zoom, defaults to 1.0
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;
394 unsigned mClosingWhilePrinting
: 1;
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
414 #endif // NS_PRINTING
416 /* character set member data */
417 int32_t mHintCharsetSource
;
418 nsCString mHintCharset
;
419 nsCString mForceCharacterSet
;
422 bool mCallerIsClosingWindow
;
423 bool mInitializedForPrintPreview
;
427 class nsPrintEventDispatcher
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
445 explicit nsDocumentShownDispatcher(nsCOMPtr
<nsIDocument
> aDocument
)
446 : mDocument(aDocument
) {}
448 NS_IMETHOD
Run() MOZ_OVERRIDE
;
451 nsCOMPtr
<nsIDocument
> mDocument
;
455 //------------------------------------------------------------------
457 //------------------------------------------------------------------
459 //------------------------------------------------------------------
460 already_AddRefed
<nsIContentViewer
>
461 NS_NewContentViewer()
463 nsRefPtr
<nsDocumentViewer
> viewer
= new nsDocumentViewer();
464 return viewer
.forget();
467 void nsDocumentViewer::PrepareToStartLoad()
471 mAttachedToParent
= false;
472 mDeferredWindowClose
= false;
473 mCallerIsClosingWindow
= false;
476 mPrintIsPending
= false;
477 mPrintDocIsFullyLoaded
= false;
478 mClosingWhilePrinting
= false;
480 // Make sure we have destroyed it and cleared the data member
482 mPrintEngine
->Destroy();
483 mPrintEngine
= nullptr;
484 #ifdef NS_PRINT_PREVIEW
485 SetIsPrintPreview(false);
490 mDebugFile
= nullptr;
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),
500 #ifdef NS_PRINT_PREVIEW
501 mPrintPreviewZoom(1.0),
503 mHintCharsetSource(kCharsetUninitialized
),
504 mInitializedForPrintPreview(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
)
520 NS_INTERFACE_MAP_ENTRY(nsIWebBrowserPrint
)
524 nsDocumentViewer::~nsDocumentViewer()
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
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.
553 nsDocumentViewer::LoadStart(nsIDocument
* aDocument
)
555 MOZ_ASSERT(aDocument
);
558 mDocument
= aDocument
;
563 nsDocumentViewer::SyncParentSubDocMap()
565 nsCOMPtr
<nsIDocShell
> docShell(mContainer
);
570 nsCOMPtr
<nsPIDOMWindow
> pwin(docShell
->GetWindow());
571 if (!mDocument
|| !pwin
) {
575 nsCOMPtr
<Element
> element
= pwin
->GetFrameElementInternal();
580 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
581 docShell
->GetParent(getter_AddRefs(parent
));
583 nsCOMPtr
<nsPIDOMWindow
> parent_win
= parent
? parent
->GetWindow() : nullptr;
588 nsCOMPtr
<nsIDocument
> parent_doc
= parent_win
->GetDoc();
593 if (mDocument
&& parent_doc
->GetSubDocumentFor(element
) != mDocument
) {
594 mDocument
->SuppressEventHandling(nsIDocument::eEvents
,
595 parent_doc
->EventHandlingSuppressed());
597 return parent_doc
->SetSubDocumentFor(element
, mDocument
);
601 nsDocumentViewer::SetContainer(nsIDocShell
* aContainer
)
603 mContainer
= static_cast<nsDocShell
*>(aContainer
);
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
612 return SyncParentSubDocMap();
616 nsDocumentViewer::GetContainer(nsIDocShell
** aResult
)
618 NS_ENSURE_ARG_POINTER(aResult
);
620 nsCOMPtr
<nsIDocShell
> container(mContainer
);
621 container
.swap(*aResult
);
626 nsDocumentViewer::Init(nsIWidget
* aParentWidget
,
627 const nsIntRect
& aBounds
)
629 return InitInternal(aParentWidget
, nullptr, aBounds
, true);
633 nsDocumentViewer::InitPresentationStuff(bool aDoInitialReflow
)
635 if (GetIsPrintPreview())
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
);
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
;
688 mPresShell
->Initialize(width
, height
);
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
);
716 nsRefPtr
<SelectionCarets
> selectionCaret
= mPresShell
->GetSelectionCarets();
717 if (selectionCaret
) {
718 nsCOMPtr
<nsIDocShell
> docShell(mContainer
);
720 docShell
->AddWeakScrollObserver(selectionCaret
);
724 // Save old listener so we can unregister it
725 nsRefPtr
<nsDocViewerFocusListener
> oldFocusListener
= mFocusListener
;
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
;
739 mDocument
->AddEventListener(NS_LITERAL_STRING("focus"),
742 mDocument
->AddEventListener(NS_LITERAL_STRING("blur"),
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();
761 static nsPresContext
*
762 CreatePresContext(nsIDocument
* aDocument
,
763 nsPresContext::nsPresContextType aType
,
764 nsView
* 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
776 nsDocumentViewer::InitInternal(nsIWidget
* aParentWidget
,
778 const nsIntRect
& aBounds
,
780 bool aNeedMakeCX
/*= true*/,
781 bool aForceSetNewDocument
/* = true*/)
784 // XXXbz should the InitInternal in SetPageMode just pass false
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
798 NS_ENSURE_TRUE(mDocument
, NS_ERROR_NULL_POINTER
);
800 nsView
* containerView
= FindContainerView();
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.
812 (aParentWidget
|| containerView
|| mDocument
->IsBeingUsedAsImage() ||
813 (mDocument
->GetDisplayDocument() &&
814 mDocument
->GetDisplayDocument()->GetShell()))) {
815 // Create presentation context
817 //Presentation context already created in SetPageMode which is calling this method
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
);
826 mPresContext
= nullptr;
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.
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
)),
848 NS_ENSURE_SUCCESS(rv
, rv
);
851 #ifdef NS_PRINT_PREVIEW
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
,
860 mPresContext
->SetPageSize(
861 nsSize(mPresContext
->CSSTwipsToAppUnits(NSToIntFloor(pageWidth
)),
862 mPresContext
->CSSTwipsToAppUnits(NSToIntFloor(pageHeight
))));
863 mPresContext
->SetIsRootPaginatedDocument(true);
864 mPresContext
->SetPageScale(1.0f
);
868 // Avoid leaking the old viewer.
869 if (mPreviousViewer
) {
870 mPreviousViewer
->Destroy();
871 mPreviousViewer
= nullptr;
876 nsCOMPtr
<nsIInterfaceRequestor
> requestor(mContainer
);
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
));
894 nsCOMPtr
<nsIDocument
> curDoc
= window
->GetExtantDoc();
895 if (aForceSetNewDocument
|| curDoc
!= mDocument
) {
896 rv
= window
->SetNewDocument(mDocument
, aState
, false);
901 nsJSContext::LoadStart();
906 if (aDoCreation
&& mPresContext
) {
907 // The ViewManager and Root View was created above (in
910 rv
= InitPresentationStuff(!makeCX
);
916 void nsDocumentViewer::SetNavigationTiming(nsDOMNavigationTiming
* timing
)
918 NS_ASSERTION(mDocument
, "Must have a document to set navigation timing.");
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.
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
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
);
952 NS_ENSURE_TRUE(mDocument
, NS_ERROR_NOT_AVAILABLE
);
954 // First, get the window from the document...
955 nsCOMPtr
<nsPIDOMWindow
> window
= mDocument
->GetWindow();
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!
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
978 nsIDocShell
*docShell
= window
->GetDocShell();
979 NS_ENSURE_TRUE(docShell
, NS_ERROR_UNEXPECTED
);
981 docShell
->GetRestoringDocument(&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())),
992 nsCOMPtr
<nsIDocument
> d
= mDocument
;
993 mDocument
->SetReadyStateInternal(nsIDocument::READYSTATE_COMPLETE
);
995 nsRefPtr
<nsDOMNavigationTiming
> timing(d
->GetNavigationTiming());
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",
1009 EventDispatcher::Dispatch(window
, mPresContext
, &event
, nullptr, &status
);
1011 timing
->NotifyLoadEventEnd();
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.
1022 // Re-get window, since it might have changed during above firing of onload
1023 window
= mDocument
->GetWindow();
1025 nsIDocShell
*docShell
= window
->GetDocShell();
1027 if (docShell
&& NS_SUCCEEDED(docShell
->GetIsInUnload(&isInUnload
)) &&
1029 mDocument
->OnPageShow(restoring
, nullptr);
1036 mDocument
->ScrollToRef();
1039 // Now that the document has loaded, we can tell the presshell
1040 // to unsuppress painting.
1042 nsCOMPtr
<nsIPresShell
> shellDeathGrip(mPresShell
);
1043 mPresShell
->UnsuppressPainting();
1044 // mPresShell could have been removed now, see bug 378682/421432
1046 mPresShell
->LoadComplete();
1051 nsJSContext::LoadEnd();
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;
1068 nsDocumentViewer::PermitUnload(bool aCallerClosesWindow
,
1069 bool *aPermitUnload
)
1071 bool shouldPrompt
= true;
1072 return PermitUnloadInternal(aCallerClosesWindow
, &shouldPrompt
,
1078 nsDocumentViewer::PermitUnloadInternal(bool aCallerClosesWindow
,
1079 bool *aShouldPrompt
,
1080 bool *aPermitUnload
)
1082 AutoDontWarnAboutSyncXHR disableSyncXHRWarning
;
1084 *aPermitUnload
= true;
1088 || mCallerIsClosingWindow
1089 || mInPermitUnloadPrompt
) {
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
) {
1107 // First, get the script global object from the document...
1108 nsPIDOMWindow
*window
= mDocument
->GetWindow();
1111 // This is odd, but not fatal
1112 NS_WARNING("window not set for document!");
1116 NS_ASSERTION(nsContentUtils::IsSafeToRunScript(), "This is unsafe");
1118 // Now, fire an BeforeUnload event to the document and see if it's ok
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"),
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
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
,
1152 mInPermitUnload
= false;
1153 if (dialogsWereEnabled
) {
1154 utils
->EnableDialogs();
1158 nsCOMPtr
<nsIDocShell
> docShell(mContainer
);
1160 beforeUnload
->GetReturnValue(text
);
1161 if (*aShouldPrompt
&& (event
->GetInternalNSEvent()->mFlags
.mDefaultPrevented
||
1163 // Ask the user if it's ok to unload the current page
1165 nsCOMPtr
<nsIPrompt
> prompt
= do_GetInterface(docShell
);
1168 nsCOMPtr
<nsIWritablePropertyBag2
> promptBag
= do_QueryInterface(prompt
);
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",
1180 nsresult tmp
= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
1181 "OnBeforeUnloadMessage",
1183 if (NS_FAILED(tmp
)) {
1186 tmp
= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
1187 "OnBeforeUnloadLeaveButton",
1189 if (NS_FAILED(tmp
)) {
1192 tmp
= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
1193 "OnBeforeUnloadStayButton",
1195 if (NS_FAILED(tmp
)) {
1199 if (NS_FAILED(rv
) || !title
|| !message
|| !stayLabel
|| !leaveLabel
) {
1200 NS_ERROR("Failed to get strings from dom.properties!");
1204 // Although the exact value is ignored, we must not pass invalid
1205 // bool values through XPConnect.
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
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;
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;
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
));
1253 nsCOMPtr
<nsIContentViewer
> cv
;
1254 docShell
->GetContentViewer(getter_AddRefs(cv
));
1257 cv
->PermitUnloadInternal(aCallerClosesWindow
, aShouldPrompt
,
1264 if (aCallerClosesWindow
&& *aPermitUnload
)
1265 mCallerIsClosingWindow
= true;
1271 nsDocumentViewer::GetBeforeUnloadFiring(bool* aInEvent
)
1273 *aInEvent
= mInPermitUnload
;
1278 nsDocumentViewer::GetInPermitUnload(bool* aInEvent
)
1280 *aInEvent
= mInPermitUnloadPrompt
;
1285 nsDocumentViewer::ResetCloseWindow()
1287 mCallerIsClosingWindow
= false;
1289 nsCOMPtr
<nsIDocShell
> docShell(mContainer
);
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
));
1301 nsCOMPtr
<nsIContentViewer
> cv
;
1302 docShell
->GetContentViewer(getter_AddRefs(cv
));
1305 cv
->ResetCloseWindow();
1314 nsDocumentViewer::PageHide(bool aIsUnload
)
1316 AutoDontWarnAboutSyncXHR disableSyncXHRWarning
;
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();
1330 window
->PageHidden();
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();
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
1357 nsAutoPopupStatePusher
popupStatePusher(openAbused
, true);
1359 EventDispatcher::Dispatch(window
, mPresContext
, &event
, nullptr, &status
);
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
);
1372 AttachContainerRecurse(nsIDocShell
* aShell
)
1374 nsCOMPtr
<nsIContentViewer
> viewer
;
1375 aShell
->GetContentViewer(getter_AddRefs(viewer
));
1377 viewer
->SetIsHidden(false);
1378 nsIDocument
* doc
= viewer
->GetDocument();
1380 doc
->SetContainer(static_cast<nsDocShell
*>(aShell
));
1382 nsRefPtr
<nsPresContext
> pc
;
1383 viewer
->GetPresContext(getter_AddRefs(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
));
1391 presShell
->SetForwardingContainer(WeakPtr
<nsDocShell
>());
1395 // Now recurse through the children
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
)));
1406 nsDocumentViewer::Open(nsISupports
*aState
, nsISHEntry
*aSHEntry
)
1408 NS_ENSURE_TRUE(mPresShell
, NS_ERROR_NOT_INITIALIZED
);
1411 mDocument
->SetContainer(mContainer
);
1413 nsresult rv
= InitInternal(mParentWidget
, aState
, mBounds
, false);
1414 NS_ENSURE_SUCCESS(rv
, rv
);
1419 mPresShell
->SetForwardingContainer(WeakPtr
<nsDocShell
>());
1421 // Rehook the child presentations. The child shells are still in
1422 // session history, so get them from there.
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
,
1438 mDocument
->AddEventListener(NS_LITERAL_STRING("blur"), mFocusListener
,
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;
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
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.
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);
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;
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
,
1518 mDocument
->RemoveEventListener(NS_LITERAL_STRING("blur"), mFocusListener
,
1526 DetachContainerRecurse(nsIDocShell
*aShell
)
1528 // Unhook this docshell's presentation
1529 nsCOMPtr
<nsIContentViewer
> viewer
;
1530 aShell
->GetContentViewer(getter_AddRefs(viewer
));
1532 nsIDocument
* doc
= viewer
->GetDocument();
1534 doc
->SetContainer(nullptr);
1536 nsRefPtr
<nsPresContext
> pc
;
1537 viewer
->GetPresContext(getter_AddRefs(pc
));
1541 nsCOMPtr
<nsIPresShell
> presShell
;
1542 viewer
->GetPresShell(getter_AddRefs(presShell
));
1544 auto weakShell
= static_cast<nsDocShell
*>(aShell
);
1545 presShell
->SetForwardingContainer(weakShell
);
1549 // Now recurse through the children
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
)));
1560 nsDocumentViewer::Destroy()
1562 NS_ASSERTION(mDocument
, "No document in Destroy()!");
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
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
1573 if (mPrintEngine
->CheckBeforeDestroy()) {
1577 mBeforeAndAfterPrint
= nullptr;
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) {
1589 // If we were told to put ourselves into session history instead of destroy
1590 // the presentation, do that now.
1593 mPresShell
->Freeze();
1595 // Make sure the presentation isn't torn down by Hide().
1596 mSHEntry
->SetSticky(mIsSticky
);
1599 bool savePresentation
= mDocument
? mDocument
->IsBFCachingAllowed() : true;
1601 // Remove our root view from the view hierarchy.
1603 nsViewManager
*vm
= mPresShell
->GetViewManager();
1605 nsView
*rootView
= vm
->GetRootView();
1608 nsView
*rootViewParent
= rootView
->GetParent();
1609 if (rootViewParent
) {
1610 nsViewManager
*parentVM
= rootViewParent
->GetViewManager();
1612 parentVM
->RemoveChild(rootView
);
1621 // This is after Hide() so that the user doesn't see the inputs clear.
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
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
1641 shEntry
->SyncPresentationState();
1643 // Shut down accessibility for the document before we start to tear it down.
1644 #ifdef ACCESSIBILITY
1646 a11y::DocAccessible
* docAcc
= mPresShell
->GetDocAccessible();
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.
1659 mDocument
->SetContainer(nullptr);
1662 mPresContext
->Detach();
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
)));
1680 // The document was not put in the bfcache
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
1697 #ifdef NS_PRINT_PREVIEW
1698 bool doingPrintPreview
;
1699 mPrintEngine
->GetDoingPrintPreview(&doingPrintPreview
);
1700 if (doingPrintPreview
) {
1701 mPrintEngine
->FinishPrintPreview();
1705 mPrintEngine
->Destroy();
1706 mPrintEngine
= nullptr;
1710 // Avoid leaking the old viewer.
1711 if (mPreviousViewer
) {
1712 mPreviousViewer
->Destroy();
1713 mPreviousViewer
= nullptr;
1716 mDeviceContext
= nullptr;
1719 DestroyPresContext();
1723 mViewManager
= nullptr;
1724 mContainer
= WeakPtr
<nsDocShell
>();
1730 nsDocumentViewer::Stop(void)
1732 NS_ASSERTION(mDocument
, "Stop called too early or too late");
1734 mDocument
->StopDocumentLoad();
1737 if (!mHidden
&& (mLoaded
|| mStopped
) && mPresContext
&& !mSHEntry
)
1738 mPresContext
->SetImageAnimationMode(imgIContainer::kDontAnimMode
);
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();
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()
1765 nsDocumentViewer::SetDOMDocument(nsIDOMDocument
*aDocument
)
1769 // 1) this document viewer has been initialized with a call to Init().
1770 // 2) the stylesheets associated with the document have been added
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.
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);
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
);
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;
1826 nsresult rv
= window
->SetNewDocument(aDocument
, nullptr,
1827 aForceReuseInnerWindow
);
1828 if (NS_FAILED(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
1845 DestroyPresContext();
1848 rv
= InitInternal(mParentWidget
, nullptr, mBounds
, true, true, false);
1855 nsDocumentViewer::GetPresShell()
1861 nsDocumentViewer::GetPresContext()
1863 return mPresContext
;
1867 nsDocumentViewer::GetViewManager()
1869 return mViewManager
;
1873 nsDocumentViewer::GetPresShell(nsIPresShell
** aResult
)
1875 nsIPresShell
* shell
= GetPresShell();
1876 NS_IF_ADDREF(*aResult
= shell
);
1881 nsDocumentViewer::GetPresContext(nsPresContext
** aResult
)
1883 nsPresContext
* pc
= GetPresContext();
1884 NS_IF_ADDREF(*aResult
= pc
);
1889 nsDocumentViewer::GetBounds(nsIntRect
& aResult
)
1891 NS_ENSURE_TRUE(mDocument
, NS_ERROR_NOT_AVAILABLE
);
1897 nsDocumentViewer::GetPreviousViewer(nsIContentViewer
** aViewer
)
1899 *aViewer
= mPreviousViewer
;
1900 NS_IF_ADDREF(*aViewer
);
1905 nsDocumentViewer::SetPreviousViewer(nsIContentViewer
* aViewer
)
1907 // NOTE: |Show| sets |mPreviousViewer| to null without calling this
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
));
1927 aViewer
->SetPreviousViewer(nullptr);
1929 return SetPreviousViewer(prevViewer
);
1933 mPreviousViewer
= aViewer
;
1938 nsDocumentViewer::SetBounds(const nsIntRect
& aBounds
)
1940 NS_ENSURE_TRUE(mDocument
, NS_ERROR_NOT_AVAILABLE
);
1944 if (!mAttachedToParent
) {
1945 // Don't have the widget repaint. Layout will generate repaint requests
1947 mWindow
->Resize(aBounds
.x
, aBounds
.y
,
1948 aBounds
.width
, aBounds
.height
,
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
);
1973 nsDocumentViewer::Move(int32_t aX
, int32_t aY
)
1975 NS_ENSURE_TRUE(mDocument
, NS_ERROR_NOT_AVAILABLE
);
1976 mBounds
.MoveTo(aX
, aY
);
1978 mWindow
->Move(aX
, aY
);
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
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
);
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
);
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
);
2017 historyInt
->EvictOutOfRangeContentViewers(loadedIndex
);
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
);
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;
2059 rv
= MakeWindow(nsSize(mPresContext
->DevPixelsToAppUnits(mBounds
.width
),
2060 mPresContext
->DevPixelsToAppUnits(mBounds
.height
)),
2065 if (mPresContext
&& base_win
) {
2066 nsCOMPtr
<nsILinkHandler
> linkHandler(do_GetInterface(base_win
));
2069 mPresContext
->SetLinkHandler(linkHandler
);
2072 mPresContext
->SetContainer(mContainer
);
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
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
));
2099 nsDocumentViewer::Hide(void)
2101 if (!mAttachedToParent
&& mWindow
) {
2102 mWindow
->Show(false);
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;
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.
2124 nsCOMPtr
<nsIDocShell
> docShell(mContainer
);
2126 nsCOMPtr
<nsILayoutHistoryState
> layoutState
;
2127 mPresShell
->CaptureHistoryState(getter_AddRefs(layoutState
));
2132 DestroyPresContext();
2134 mViewManager
= nullptr;
2136 mDeviceContext
= nullptr;
2137 mParentWidget
= nullptr;
2139 nsCOMPtr
<nsIBaseWindow
> base_win(mContainer
);
2141 if (base_win
&& !mAttachedToParent
) {
2142 base_win
->SetParentWidget(nullptr);
2149 nsDocumentViewer::GetSticky(bool *aSticky
)
2151 *aSticky
= mIsSticky
;
2157 nsDocumentViewer::SetSticky(bool aSticky
)
2159 mIsSticky
= aSticky
;
2165 nsDocumentViewer::RequestWindowClose(bool* aCanClose
)
2168 if (mPrintIsPending
|| (mPrintEngine
&& mPrintEngine
->GetIsPrinting())) {
2170 mDeferredWindowClose
= true;
2179 AppendAgentSheet(nsIStyleSheet
*aSheet
, void *aData
)
2181 nsStyleSet
*styleSet
= static_cast<nsStyleSet
*>(aData
);
2182 styleSet
->AppendStyleSheet(nsStyleSet::eAgentSheet
, aSheet
);
2187 PrependUserSheet(nsIStyleSheet
*aSheet
, void *aData
)
2189 nsStyleSet
*styleSet
= static_cast<nsStyleSet
*>(aData
);
2190 styleSet
->PrependStyleSheet(nsStyleSet::eUserSheet
, aSheet
);
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
;
2223 // Handle the user sheets.
2224 CSSStyleSheet
* sheet
= nullptr;
2225 if (nsContentUtils::IsInChromeDocshell(aDocument
)) {
2226 sheet
= nsLayoutStylesheetCache::UserChromeSheet();
2229 sheet
= nsLayoutStylesheetCache::UserContentSheet();
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
;
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
);
2261 while ( (token
= nsCRT::strtok(newStr
, ", ", &newStr
)) ) {
2262 NS_NewURI(getter_AddRefs(uri
), nsDependentCString(token
), nullptr,
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();
2280 styleSet
->PrependStyleSheet(nsStyleSet::eAgentSheet
, sheet
);
2284 sheet
= nsLayoutStylesheetCache::FullScreenOverrideSheet();
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();
2301 styleSet
->PrependStyleSheet(nsStyleSet::eAgentSheet
, sheet
);
2304 sheet
= nsLayoutStylesheetCache::FormsSheet();
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)) ||
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
2328 sheet
= nsLayoutStylesheetCache::XULSheet();
2330 styleSet
->PrependStyleSheet(nsStyleSet::eAgentSheet
, sheet
);
2334 sheet
= nsLayoutStylesheetCache::MinimalXULSheet();
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();
2343 styleSet
->PrependStyleSheet(nsStyleSet::eAgentSheet
, sheet
);
2346 sheet
= nsLayoutStylesheetCache::HTMLSheet();
2348 styleSet
->PrependStyleSheet(nsStyleSet::eAgentSheet
, sheet
);
2351 styleSet
->PrependStyleSheet(nsStyleSet::eAgentSheet
,
2352 nsLayoutStylesheetCache::UASheet());
2354 // SVG documents may have scrollbars and need the scrollbar styling.
2355 sheet
= nsLayoutStylesheetCache::MinimalXULSheet();
2357 styleSet
->PrependStyleSheet(nsStyleSet::eAgentSheet
, sheet
);
2361 nsStyleSheetService
*sheetService
= nsStyleSheetService::GetInstance();
2363 sheetService
->AgentStyleSheets()->EnumerateForwards(AppendAgentSheet
,
2365 sheetService
->UserStyleSheets()->EnumerateBackwards(PrependUserSheet
,
2369 // Caller will handle calling EndUpdate, per contract.
2370 *aStyleSet
= styleSet
;
2375 nsDocumentViewer::ClearHistoryEntry()
2381 //-------------------------------------------------------
2384 nsDocumentViewer::MakeWindow(const nsSize
& aSize
, nsView
* aContainerView
)
2386 if (GetIsPrintPreview())
2389 bool shouldAttach
= ShouldAttachToTopLevel();
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
);
2404 // The root view is always at 0,0.
2405 nsRect
tbounds(nsPoint(0, 0), aSize
);
2407 nsView
* view
= mViewManager
->CreateView(tbounds
, aContainerView
);
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
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
;
2427 initDataPtr
= nullptr;
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
,
2440 rv
= view
->CreateWidget(initDataPtr
, true, false);
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();
2460 nsDocumentViewer::DetachFromTopLevelWidget()
2463 nsView
* oldView
= mViewManager
->GetRootView();
2464 if (oldView
&& oldView
->IsAttachedToTopLevel()) {
2465 oldView
->DetachFromTopLevelWidget();
2468 mAttachedToParent
= false;
2472 nsDocumentViewer::FindContainerView()
2474 nsView
* containerView
= nullptr;
2477 nsCOMPtr
<nsIDocShell
> docShell(mContainer
);
2478 nsCOMPtr
<nsPIDOMWindow
> pwin(docShell
->GetWindow());
2480 nsCOMPtr
<Element
> containerElement
= pwin
->GetFrameElementInternal();
2481 if (!containerElement
) {
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();
2494 parentPresShell
= parentDoc
->GetShell();
2497 if (!parentPresShell
) {
2498 NS_WARNING("Subdocument container has no presshell");
2500 nsIFrame
* subdocFrame
= parentPresShell
->GetRealPrimaryFrameFor(containerElement
);
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
2506 if (subdocFrame
->GetType() == nsGkAtoms::subDocumentFrame
) {
2507 NS_ASSERTION(subdocFrame
->GetView(), "Subdoc frames must have views");
2509 static_cast<nsSubDocumentFrame
*>(subdocFrame
)->EnsureInnerView();
2510 containerView
= innerView
;
2512 NS_WARNING("Subdocument container has non-subdocument frame");
2515 NS_WARNING("Subdocument container has no frame");
2521 return containerView
;
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();
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();
2537 nsPresContext
* ctx
= shell
->GetPresContext();
2539 mDeviceContext
= ctx
->DeviceContext();
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);
2552 widget
= mParentWidget
;
2555 widget
= widget
->GetTopLevelWidget();
2558 mDeviceContext
= new nsDeviceContext();
2559 mDeviceContext
->Init(widget
);
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
);
2569 return NS_ERROR_NOT_INITIALIZED
;
2572 nsCOMPtr
<nsISelectionController
> selcon
;
2573 selcon
= do_QueryInterface(mPresShell
);
2575 return selcon
->GetSelection(nsISelectionController::SELECTION_NORMAL
,
2577 return NS_ERROR_FAILURE
;
2580 /* ========================================================================================
2581 * nsIContentViewerEdit
2582 * ======================================================================================== */
2584 NS_IMETHODIMP
nsDocumentViewer::ClearSelection()
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
;
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
;
2613 nsCOMPtr
<nsIDOMHTMLElement
>bodyElement
;
2614 rv
= htmldoc
->GetBody(getter_AddRefs(bodyElement
));
2615 if (NS_FAILED(rv
) || !bodyElement
) return rv
;
2617 bodyNode
= do_QueryInterface(bodyElement
);
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
);
2632 NS_IMETHODIMP
nsDocumentViewer::CopySelection()
2634 nsCopySupport::FireClipboardEvent(NS_COPY
, nsIClipboard::kGlobalClipboard
, mPresShell
, nullptr);
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
);
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
);
2698 sel
->GetIsCollapsed(&isCollapsed
);
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
);
2719 /* ========================================================================================
2720 * nsIContentViewerFile
2721 * ======================================================================================== */
2722 /** ---------------------------------------------------
2723 * See documentation above in the nsIContentViewerfile class definition
2724 * @update 01/24/00 dwc
2727 nsDocumentViewer::Print(bool aSilent
,
2729 nsIPrintSettings
* aPrintSettings
)
2732 nsCOMPtr
<nsIPrintSettings
> printSettings
;
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);
2754 return Print(printSettings
, nullptr);
2756 return NS_ERROR_FAILURE
;
2760 // nsIContentViewerFile interface
2762 nsDocumentViewer::GetPrintable(bool *aPrintable
)
2764 NS_ENSURE_ARG_POINTER(aPrintable
);
2766 *aPrintable
= !GetIsPrinting();
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.
2786 presShell
->ScrollContentIntoView(content
,
2787 nsIPresShell::ScrollAxis(
2788 nsIPresShell::SCROLL_TOP
,
2789 nsIPresShell::SCROLL_ALWAYS
),
2790 nsIPresShell::ScrollAxis(),
2791 nsIPresShell::SCROLL_OVERFLOW_HIDDEN
),
2797 nsDocumentViewer::CallChildren(CallChildFunc aFunc
, void* aClosure
)
2799 nsCOMPtr
<nsIDocShell
> docShell(mContainer
);
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");
2813 nsCOMPtr
<nsIContentViewer
> childCV
;
2814 childAsShell
->GetContentViewer(getter_AddRefs(childCV
));
2817 (*aFunc
)(childCV
, aClosure
);
2826 nscoord mMaxLineBoxWidth
;
2830 ChangeChildPaintingEnabled(nsIContentViewer
* aChild
, void* aClosure
)
2832 bool* enablePainting
= (bool*) aClosure
;
2833 if (*enablePainting
) {
2834 aChild
->ResumePainting();
2836 aChild
->PausePainting();
2841 ChangeChildMaxLineBoxWidth(nsIContentViewer
* aChild
, void* aClosure
)
2843 struct LineBoxInfo
* lbi
= (struct LineBoxInfo
*) aClosure
;
2844 aChild
->ChangeMaxLineBoxWidth(lbi
->mMaxLineBoxWidth
);
2853 SetChildTextZoom(nsIContentViewer
* aChild
, void* aClosure
)
2855 struct ZoomInfo
* ZoomInfo
= (struct ZoomInfo
*) aClosure
;
2856 aChild
->SetTextZoom(ZoomInfo
->mZoom
);
2860 SetChildMinFontSize(nsIContentViewer
* aChild
, void* aClosure
)
2862 aChild
->SetMinFontSize(NS_PTR_TO_INT32(aClosure
));
2866 SetChildFullZoom(nsIContentViewer
* aChild
, void* aClosure
)
2868 struct ZoomInfo
* ZoomInfo
= (struct ZoomInfo
*) aClosure
;
2869 aChild
->SetFullZoom(ZoomInfo
->mZoom
);
2873 SetExtResourceTextZoom(nsIDocument
* aDocument
, void* aClosure
)
2875 // Would it be better to enumerate external resource viewers instead?
2876 nsIPresShell
* shell
= aDocument
->GetShell();
2878 nsPresContext
* ctxt
= shell
->GetPresContext();
2880 struct ZoomInfo
* ZoomInfo
= static_cast<struct ZoomInfo
*>(aClosure
);
2881 ctxt
->SetTextZoom(ZoomInfo
->mZoom
);
2889 SetExtResourceMinFontSize(nsIDocument
* aDocument
, void* aClosure
)
2891 nsIPresShell
* shell
= aDocument
->GetShell();
2893 nsPresContext
* ctxt
= shell
->GetPresContext();
2895 ctxt
->SetBaseMinFontSize(NS_PTR_TO_INT32(aClosure
));
2903 SetExtResourceFullZoom(nsIDocument
* aDocument
, void* aClosure
)
2905 // Would it be better to enumerate external resource viewers instead?
2906 nsIPresShell
* shell
= aDocument
->GetShell();
2908 nsPresContext
* ctxt
= shell
->GetPresContext();
2910 struct ZoomInfo
* ZoomInfo
= static_cast<struct ZoomInfo
*>(aClosure
);
2911 ctxt
->SetFullZoom(ZoomInfo
->mZoom
);
2919 nsDocumentViewer::SetTextZoom(float aTextZoom
)
2921 // If we don't have a document, then we need to bail.
2923 return NS_ERROR_FAILURE
;
2926 if (GetIsPrintPreview()) {
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"),
2956 nsDocumentViewer::GetTextZoom(float* aTextZoom
)
2958 NS_ENSURE_ARG_POINTER(aTextZoom
);
2959 nsPresContext
* pc
= GetPresContext();
2960 *aTextZoom
= pc
? pc
->TextZoom() : 1.0f
;
2965 nsDocumentViewer::SetMinFontSize(int32_t aMinFontSize
)
2967 // If we don't have a document, then we need to bail.
2969 return NS_ERROR_FAILURE
;
2972 if (GetIsPrintPreview()) {
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
));
2998 nsDocumentViewer::GetMinFontSize(int32_t* aMinFontSize
)
3000 NS_ENSURE_ARG_POINTER(aMinFontSize
);
3001 nsPresContext
* pc
= GetPresContext();
3002 *aMinFontSize
= pc
? pc
->BaseMinFontSize() : 0;
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();
3025 nsIFrame
* f
= do_QueryFrame(pf
);
3026 shell
->FrameNeedsReflow(f
, nsIPresShell::eResize
, NS_FRAME_IS_DIRTY
);
3029 nsIFrame
* rootFrame
= shell
->GetRootFrame();
3031 rootFrame
->InvalidateFrame();
3037 // If we don't have a document, then we need to bail.
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();
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"),
3067 nsDocumentViewer::GetFullZoom(float* aFullZoom
)
3069 NS_ENSURE_ARG_POINTER(aFullZoom
);
3070 #ifdef NS_PRINT_PREVIEW
3071 if (GetIsPrintPreview()) {
3072 *aFullZoom
= mPrintPreviewZoom
;
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
;
3084 SetChildAuthorStyleDisabled(nsIContentViewer
* aChild
, void* aClosure
)
3086 bool styleDisabled
= *static_cast<bool*>(aClosure
);
3087 aChild
->SetAuthorStyleDisabled(styleDisabled
);
3092 nsDocumentViewer::SetAuthorStyleDisabled(bool aStyleDisabled
)
3095 mPresShell
->SetAuthorStyleDisabled(aStyleDisabled
);
3097 CallChildren(SetChildAuthorStyleDisabled
, &aStyleDisabled
);
3102 nsDocumentViewer::GetAuthorStyleDisabled(bool* aStyleDisabled
)
3105 *aStyleDisabled
= mPresShell
->GetAuthorStyleDisabled();
3107 *aStyleDisabled
= false;
3113 ExtResourceEmulateMedium(nsIDocument
* aDocument
, void* aClosure
)
3115 nsIPresShell
* shell
= aDocument
->GetShell();
3117 nsPresContext
* ctxt
= shell
->GetPresContext();
3119 const nsAString
* mediaType
= static_cast<nsAString
*>(aClosure
);
3120 ctxt
->EmulateMedium(*mediaType
);
3128 ChildEmulateMedium(nsIContentViewer
* aChild
, void* aClosure
)
3130 const nsAString
* mediaType
= static_cast<nsAString
*>(aClosure
);
3131 aChild
->EmulateMedium(*mediaType
);
3135 nsDocumentViewer::EmulateMedium(const nsAString
& aMediaType
)
3138 mPresContext
->EmulateMedium(aMediaType
);
3140 CallChildren(ChildEmulateMedium
, const_cast<nsAString
*>(&aMediaType
));
3143 mDocument
->EnumerateExternalResources(ExtResourceEmulateMedium
,
3144 const_cast<nsAString
*>(&aMediaType
));
3151 ExtResourceStopEmulatingMedium(nsIDocument
* aDocument
, void* aClosure
)
3153 nsIPresShell
* shell
= aDocument
->GetShell();
3155 nsPresContext
* ctxt
= shell
->GetPresContext();
3157 ctxt
->StopEmulatingMedium();
3165 ChildStopEmulatingMedium(nsIContentViewer
* aChild
, void* aClosure
)
3167 aChild
->StopEmulatingMedium();
3171 nsDocumentViewer::StopEmulatingMedium()
3174 mPresContext
->StopEmulatingMedium();
3176 CallChildren(ChildStopEmulatingMedium
, nullptr);
3179 mDocument
->EnumerateExternalResources(ExtResourceStopEmulatingMedium
,
3186 NS_IMETHODIMP
nsDocumentViewer::GetForceCharacterSet(nsACString
& aForceCharacterSet
)
3188 aForceCharacterSet
= mForceCharacterSet
;
3193 SetChildForceCharacterSet(nsIContentViewer
* aChild
, void* aClosure
)
3195 const nsACString
* charset
= static_cast<nsACString
*>(aClosure
);
3196 aChild
->SetForceCharacterSet(*charset
);
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
);
3208 NS_IMETHODIMP
nsDocumentViewer::GetHintCharacterSet(nsACString
& aHintCharacterSet
)
3211 if(kCharsetUninitialized
== mHintCharsetSource
) {
3212 aHintCharacterSet
.Truncate();
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;
3221 NS_IMETHODIMP
nsDocumentViewer::GetHintCharacterSetSource(int32_t *aHintCharacterSetSource
)
3223 NS_ENSURE_ARG_POINTER(aHintCharacterSetSource
);
3225 *aHintCharacterSetSource
= mHintCharsetSource
;
3230 SetChildHintCharacterSetSource(nsIContentViewer
* aChild
, void* aClosure
)
3232 aChild
->SetHintCharacterSetSource(NS_PTR_TO_INT32(aClosure
));
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
));
3246 SetChildHintCharacterSet(nsIContentViewer
* aChild
, void* aClosure
)
3248 const nsACString
* charset
= static_cast<nsACString
*>(aClosure
);
3249 aChild
->SetHintCharacterSet(*charset
);
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
);
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
);
3277 nsDocumentViewer::PausePainting()
3279 bool enablePaint
= false;
3280 CallChildren(ChangeChildPaintingEnabled
, &enablePaint
);
3282 nsIPresShell
* presShell
= GetPresShell();
3284 presShell
->PausePainting();
3291 nsDocumentViewer::ResumePainting()
3293 bool enablePaint
= true;
3294 CallChildren(ChangeChildPaintingEnabled
, &enablePaint
);
3296 nsIPresShell
* presShell
= GetPresShell();
3298 presShell
->ResumePainting();
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();
3316 presShell
->SetMaxLineBoxWidth(mlbw
);
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
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
);
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
,
3370 *aWidth
= presContext
->AppUnitsToDevPixels(shellArea
.width
);
3371 *aHeight
= presContext
->AppUnitsToDevPixels(shellArea
.height
);
3377 NS_IMPL_ISUPPORTS(nsDocViewerSelectionListener
, nsISelectionListener
)
3379 nsresult
nsDocViewerSelectionListener::Init(nsDocumentViewer
*aDocViewer
)
3381 mDocViewer
= aDocViewer
;
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.
3395 nsDocumentViewer::GetPopupNode(nsIDOMNode
** aNode
)
3397 NS_ENSURE_ARG_POINTER(aNode
);
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
);
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();
3416 nsPIDOMWindow
* rootWindow
= root
->GetWindow();
3418 nsCOMPtr
<nsIDocument
> rootDoc
= rootWindow
->GetExtantDoc();
3420 nsXULPopupManager
* pm
= nsXULPopupManager::GetInstance();
3422 node
= pm
->GetLastTriggerPopupNode(rootDoc
);
3434 // GetPopupLinkNode: return popup link node or fail
3436 nsDocumentViewer::GetPopupLinkNode(nsIDOMNode
** aNode
)
3438 NS_ENSURE_ARG_POINTER(aNode
);
3440 // you get null unless i say so
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
3451 nsCOMPtr
<nsIContent
> content(do_QueryInterface(node
));
3453 nsCOMPtr
<nsIURI
> hrefURI
= content
->GetHrefURI();
3456 NS_IF_ADDREF(*aNode
); // addref
3461 // get our parent and keep trying...
3462 nsCOMPtr
<nsIDOMNode
> parentNode
;
3463 node
->GetParentNode(getter_AddRefs(parentNode
));
3467 // if we have no node, fail
3468 return NS_ERROR_FAILURE
;
3471 // GetPopupLinkNode: return popup image node or fail
3473 nsDocumentViewer::GetPopupImageNode(nsIImageLoadingContent
** aNode
)
3475 NS_ENSURE_ARG_POINTER(aNode
);
3477 // you get null unless i say so
3481 nsCOMPtr
<nsIDOMNode
> node
;
3482 nsresult rv
= GetPopupNode(getter_AddRefs(node
));
3483 NS_ENSURE_SUCCESS(rv
, rv
);
3486 CallQueryInterface(node
, aNode
);
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
3502 NS_IMETHODIMP
nsDocumentViewer::GetInLink(bool* aInLink
)
3505 printf("dr :: nsDocumentViewer::GetInLink\n");
3508 NS_ENSURE_ARG_POINTER(aInLink
);
3510 // we're not in a link unless i say so
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
3524 NS_IMETHODIMP
nsDocumentViewer::GetInImage(bool* aInImage
)
3527 printf("dr :: nsDocumentViewer::GetInImage\n");
3530 NS_ENSURE_ARG_POINTER(aInImage
);
3532 // we're not in an image unless i say so
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
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
);
3578 //nsDocViewerFocusListener
3579 NS_IMPL_ISUPPORTS(nsDocViewerFocusListener
,
3580 nsIDOMEventListener
)
3582 nsDocViewerFocusListener::nsDocViewerFocusListener()
3583 :mDocViewer(nullptr)
3587 nsDocViewerFocusListener::~nsDocViewerFocusListener(){}
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
);
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
);
3626 nsDocViewerFocusListener::Init(nsDocumentViewer
*aDocViewer
)
3628 mDocViewer
= aDocViewer
;
3632 /** ---------------------------------------------------
3633 * From nsIWebBrowserPrint
3639 nsDocumentViewer::Print(nsIPrintSettings
* aPrintSettings
,
3640 nsIWebProgressListener
* aWebProgressListener
)
3642 // Printing XUL documents is not supported.
3643 nsCOMPtr
<nsIXULDocument
> xulDoc(do_QueryInterface(mDocument
));
3645 return NS_ERROR_FAILURE
;
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
;
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
);
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
));
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()) /
3713 if (NS_FAILED(rv
)) {
3714 mPrintEngine
->Destroy();
3715 mPrintEngine
= nullptr;
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
)) {
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
));
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()) /
3787 if (NS_FAILED(rv
)) {
3788 mPrintEngine
->Destroy();
3789 mPrintEngine
= nullptr;
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
)) {
3812 return NS_ERROR_FAILURE
;
3816 //----------------------------------------------------------------------
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();
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
);
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
;
3870 pageFrame
= pageFrame
->GetNextSibling();
3873 if (aType
== nsIWebBrowserPrint::PRINTPREVIEW_PREV_PAGE
) {
3875 fndPageFrame
= currentPage
->GetPrevInFlow();
3876 if (!fndPageFrame
) {
3882 } else if (aType
== nsIWebBrowserPrint::PRINTPREVIEW_NEXT_PAGE
) {
3884 fndPageFrame
= currentPage
->GetNextInFlow();
3885 if (!fndPageFrame
) {
3891 } else { // If we get here we are doing "GoTo"
3892 if (aPageNum
< 0 || aPageNum
> pageCount
) {
3899 nscoord(mPrintEngine
->GetPrintPreviewScale() * fndPageFrame
->GetPosition().y
);
3900 sf
->ScrollTo(nsPoint(pt
.x
, newYPosn
), nsIScrollableFrame::INSTANT
);
3906 /* readonly attribute nsIPrintSettings globalPrintSettings; */
3908 nsDocumentViewer::GetGlobalPrintSettings(nsIPrintSettings
* *aGlobalPrintSettings
)
3910 return nsPrintEngine::GetGlobalPrintSettings(aGlobalPrintSettings
);
3913 /* readonly attribute boolean doingPrint; */
3914 // XXX This always returns false for subdocuments
3916 nsDocumentViewer::GetDoingPrint(bool *aDoingPrint
)
3918 NS_ENSURE_ARG_POINTER(aDoingPrint
);
3920 *aDoingPrint
= false;
3922 // XXX shouldn't this be GetDoingPrint() ?
3923 return mPrintEngine
->GetDoingPrintPreview(aDoingPrint
);
3928 /* readonly attribute boolean doingPrintPreview; */
3929 // XXX This always returns false for subdocuments
3931 nsDocumentViewer::GetDoingPrintPreview(bool *aDoingPrintPreview
)
3933 NS_ENSURE_ARG_POINTER(aDoingPrintPreview
);
3935 *aDoingPrintPreview
= false;
3937 return mPrintEngine
->GetDoingPrintPreview(aDoingPrintPreview
);
3942 /* readonly attribute nsIPrintSettings currentPrintSettings; */
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; */
3957 nsDocumentViewer::GetCurrentChildDOMWindow(nsIDOMWindow
* *aCurrentChildDOMWindow
)
3959 NS_ENSURE_ARG_POINTER(aCurrentChildDOMWindow
);
3960 *aCurrentChildDOMWindow
= nullptr;
3961 return NS_ERROR_NOT_IMPLEMENTED
;
3964 /* void cancel (); */
3966 nsDocumentViewer::Cancel()
3968 NS_ENSURE_TRUE(mPrintEngine
, NS_ERROR_FAILURE
);
3969 return mPrintEngine
->Cancelled();
3972 /* void exitPrintPreview (); */
3974 nsDocumentViewer::ExitPrintPreview()
3976 if (GetIsPrinting())
3977 return NS_ERROR_FAILURE
;
3978 NS_ENSURE_TRUE(mPrintEngine
, NS_ERROR_FAILURE
);
3980 if (GetIsPrintPreview()) {
3981 ReturnToGalleyPresentation();
3986 //----------------------------------------------------------------------------------
3987 // Enumerate all the documents for their titles
3989 nsDocumentViewer::EnumerateDocumentNames(uint32_t* aCount
,
3990 char16_t
*** aResult
)
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
);
3999 return NS_ERROR_FAILURE
;
4003 /* readonly attribute boolean isFramesetFrameSelected; */
4005 nsDocumentViewer::GetIsFramesetFrameSelected(bool *aIsFramesetFrameSelected
)
4008 *aIsFramesetFrameSelected
= false;
4009 NS_ENSURE_TRUE(mPrintEngine
, NS_ERROR_FAILURE
);
4011 return mPrintEngine
->GetIsFramesetFrameSelected(aIsFramesetFrameSelected
);
4013 return NS_ERROR_FAILURE
;
4017 /* readonly attribute long printPreviewNumPages; */
4019 nsDocumentViewer::GetPrintPreviewNumPages(int32_t *aPrintPreviewNumPages
)
4022 NS_ENSURE_ARG_POINTER(aPrintPreviewNumPages
);
4023 NS_ENSURE_TRUE(mPrintEngine
, NS_ERROR_FAILURE
);
4025 return mPrintEngine
->GetPrintPreviewNumPages(aPrintPreviewNumPages
);
4027 return NS_ERROR_FAILURE
;
4031 /* readonly attribute boolean isFramesetDocument; */
4033 nsDocumentViewer::GetIsFramesetDocument(bool *aIsFramesetDocument
)
4036 *aIsFramesetDocument
= false;
4037 NS_ENSURE_TRUE(mPrintEngine
, NS_ERROR_FAILURE
);
4039 return mPrintEngine
->GetIsFramesetDocument(aIsFramesetDocument
);
4041 return NS_ERROR_FAILURE
;
4045 /* readonly attribute boolean isIFrameSelected; */
4047 nsDocumentViewer::GetIsIFrameSelected(bool *aIsIFrameSelected
)
4050 *aIsIFrameSelected
= false;
4051 NS_ENSURE_TRUE(mPrintEngine
, NS_ERROR_FAILURE
);
4053 return mPrintEngine
->GetIsIFrameSelected(aIsIFrameSelected
);
4055 return NS_ERROR_FAILURE
;
4059 /* readonly attribute boolean isRangeSelection; */
4061 nsDocumentViewer::GetIsRangeSelection(bool *aIsRangeSelection
)
4064 *aIsRangeSelection
= false;
4065 NS_ENSURE_TRUE(mPrintEngine
, NS_ERROR_FAILURE
);
4067 return mPrintEngine
->GetIsRangeSelection(aIsRangeSelection
);
4069 return NS_ERROR_FAILURE
;
4073 //----------------------------------------------------------------------------------
4074 // Printing/Print Preview Helpers
4075 //----------------------------------------------------------------------------------
4077 //----------------------------------------------------------------------------------
4078 // Walks the document tree and tells each DocShell whether Printing/PP is happening
4080 nsDocumentViewer::SetIsPrintingInDocShellTree(nsIDocShellTreeItem
* aParentNode
,
4081 bool aIsPrintingOrPP
,
4084 nsCOMPtr
<nsIDocShellTreeItem
> parentItem(do_QueryInterface(aParentNode
));
4086 // find top of "same parent" tree
4088 if (aIsPrintingOrPP
) {
4089 while (parentItem
) {
4090 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
4091 parentItem
->GetSameTypeParent(getter_AddRefs(parent
));
4095 parentItem
= do_QueryInterface(parent
);
4097 mTopContainerWhilePrinting
= do_GetWeakReference(parentItem
);
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
);
4113 // Traverse children to see if any of them are printing.
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");
4121 SetIsPrintingInDocShellTree(child
, aIsPrintingOrPP
, false);
4126 #endif // NS_PRINTING
4129 nsDocumentViewer::ShouldAttachToTopLevel()
4134 nsCOMPtr
<nsIDocShellTreeItem
> containerItem(mContainer
);
4138 // We always attach when using puppet widgets
4139 if (nsIWidget::UsePuppetWidgets())
4142 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
4143 // On windows, in the parent process we also attach, but just to
4145 nsWindowType winType
= mParentWidget
->WindowType();
4146 if ((winType
== eWindowType_toplevel
||
4147 winType
== eWindowType_dialog
||
4148 winType
== eWindowType_invisible
) &&
4149 containerItem
->ItemType() == nsIDocShellTreeItem::typeChrome
) {
4157 bool CollectDocuments(nsIDocument
* aDocument
, void* aData
)
4160 static_cast<nsCOMArray
<nsIDocument
>*>(aData
)->AppendObject(aDocument
);
4161 aDocument
->EnumerateSubDocuments(CollectDocuments
, aData
);
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
4182 nsDocumentViewer::GetIsPrinting()
4186 return mPrintEngine
->GetIsPrinting();
4192 //------------------------------------------------------------
4193 // Notification from the PrintEngine of the current Printing status
4195 nsDocumentViewer::SetIsPrinting(bool aIsPrinting
)
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);
4204 NS_WARNING("Did you close a window before printing?");
4208 mBeforeAndAfterPrint
= nullptr;
4213 //------------------------------------------------------------
4214 // The PrintEngine holds the current value
4215 // this called from inside the DocViewer.
4216 // XXX it always returns false for subdocuments
4218 nsDocumentViewer::GetIsPrintPreview()
4222 return mPrintEngine
->GetIsPrintPreview();
4228 //------------------------------------------------------------
4229 // Notification from the PrintEngine of the current PP status
4231 nsDocumentViewer::SetIsPrintPreview(bool aIsPrintPreview
)
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;
4244 if (!aIsPrintPreview
) {
4249 mViewManager
= nullptr;
4250 mPresContext
= nullptr;
4251 mPresShell
= nullptr;
4255 //----------------------------------------------------------------------------------
4256 // nsIDocumentViewerPrint IFace
4257 //----------------------------------------------------------------------------------
4259 //------------------------------------------------------------
4261 nsDocumentViewer::IncrementDestroyRefCount()
4266 //------------------------------------------------------------
4268 #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
4269 //------------------------------------------------------------
4270 // Reset ESM focus for all descendent doc shells.
4272 ResetFocusState(nsIDocShell
* aDocShell
)
4274 nsIFocusManager
* fm
= nsFocusManager::GetFocusManager();
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
);
4290 fm
->ClearFocus(win
);
4293 #endif // NS_PRINTING && NS_PRINT_PREVIEW
4296 nsDocumentViewer::ReturnToGalleyPresentation()
4298 #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
4299 if (!GetIsPrintPreview()) {
4300 NS_ERROR("Wow, we should never get here!");
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
);
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
4334 nsDocumentViewer::OnDonePrinting()
4336 #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
4338 nsRefPtr
<nsPrintEngine
> pe
= mPrintEngine
;
4339 if (GetIsPrintPreview()) {
4340 pe
->DestroyPrintingData();
4342 mPrintEngine
= nullptr;
4346 // We are done printing, now cleanup
4347 if (mDeferredWindowClose
) {
4348 mDeferredWindowClose
= false;
4350 nsCOMPtr
<nsIDOMWindow
> win
= mContainer
->GetWindow();
4354 } else if (mClosingWhilePrinting
) {
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
;
4377 DestroyPresContext();
4380 mViewManager
= nullptr;
4383 NS_ENSURE_STATE(mDocument
);
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),
4402 nsDocumentViewer::GetHistoryEntry(nsISHEntry
**aHistoryEntry
)
4404 NS_IF_ADDREF(*aHistoryEntry
= mSHEntry
);
4409 nsDocumentViewer::GetIsTabModalPromptAllowed(bool *aAllowed
)
4411 *aAllowed
= !mHidden
;
4416 nsDocumentViewer::GetIsHidden(bool *aHidden
)
4423 nsDocumentViewer::SetIsHidden(bool aHidden
)
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
);
4445 docShell
->RemoveWeakScrollObserver(selectionCaret
);
4449 nsAutoScriptBlocker scriptBlocker
;
4450 mPresShell
->Destroy();
4451 mPresShell
= nullptr;
4455 nsDocumentViewer::DestroyPresContext()
4457 mPresContext
->Detach();
4458 mPresContext
= nullptr;
4462 nsDocumentViewer::IsInitializedForPrintPreview()
4464 return mInitializedForPrintPreview
;
4468 nsDocumentViewer::InitializeForPrintPreview()
4470 mInitializedForPrintPreview
= true;
4474 nsDocumentViewer::SetPrintPreviewPresentation(nsViewManager
* aViewManager
,
4475 nsPresContext
* aPresContext
,
4476 nsIPresShell
* aPresShell
)
4483 mViewManager
= aViewManager
;
4484 mPresContext
= aPresContext
;
4485 mPresShell
= aPresShell
;
4488 // Fires the "document-shown" event so that interested parties are aware of it.
4490 nsDocumentShownDispatcher::Run()
4492 nsCOMPtr
<nsIObserverService
> observerService
=
4493 mozilla::services::GetObserverService();
4494 if (observerService
) {
4495 observerService
->NotifyObservers(mDocument
, "document-shown", nullptr);