Line data Source code
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/. */
6 :
7 : /* container for a document and its presentation */
8 :
9 : #include "gfxContext.h"
10 : #include "mozilla/ServoRestyleManager.h"
11 : #include "mozilla/ServoStyleSet.h"
12 : #include "nsAutoPtr.h"
13 : #include "nscore.h"
14 : #include "nsCOMPtr.h"
15 : #include "nsCRT.h"
16 : #include "nsString.h"
17 : #include "nsReadableUtils.h"
18 : #include "nsIContent.h"
19 : #include "nsIContentViewerContainer.h"
20 : #include "nsIContentViewer.h"
21 : #include "nsIDocumentViewerPrint.h"
22 : #include "mozilla/dom/BeforeUnloadEvent.h"
23 : #include "nsIDocument.h"
24 : #include "nsPresContext.h"
25 : #include "nsIPresShell.h"
26 : #include "mozilla/StyleSetHandle.h"
27 : #include "mozilla/StyleSetHandleInlines.h"
28 : #include "nsIFrame.h"
29 : #include "nsIWritablePropertyBag2.h"
30 : #include "nsSubDocumentFrame.h"
31 :
32 : #include "nsILinkHandler.h"
33 : #include "nsIDOMDocument.h"
34 : #include "nsISelectionListener.h"
35 : #include "mozilla/dom/Selection.h"
36 : #include "nsIDOMHTMLDocument.h"
37 : #include "nsIDOMHTMLElement.h"
38 : #include "nsContentUtils.h"
39 : #include "nsLayoutStylesheetCache.h"
40 : #ifdef ACCESSIBILITY
41 : #include "mozilla/a11y/DocAccessible.h"
42 : #endif
43 : #include "mozilla/BasicEvents.h"
44 : #include "mozilla/Encoding.h"
45 : #include "mozilla/Preferences.h"
46 : #include "mozilla/WeakPtr.h"
47 : #include "mozilla/StyleSheet.h"
48 : #include "mozilla/StyleSheetInlines.h"
49 :
50 : #include "nsViewManager.h"
51 : #include "nsView.h"
52 :
53 : #include "nsIPageSequenceFrame.h"
54 : #include "nsNetUtil.h"
55 : #include "nsIContentViewerEdit.h"
56 : #include "nsIContentViewerFile.h"
57 : #include "mozilla/StyleSheetInlines.h"
58 : #include "mozilla/css/Loader.h"
59 : #include "nsIInterfaceRequestor.h"
60 : #include "nsIInterfaceRequestorUtils.h"
61 : #include "nsDocShell.h"
62 : #include "nsIBaseWindow.h"
63 : #include "nsILayoutHistoryState.h"
64 : #include "nsCharsetSource.h"
65 : #include "mozilla/ReflowInput.h"
66 : #include "nsIImageLoadingContent.h"
67 : #include "nsCopySupport.h"
68 : #include "nsIDOMHTMLFrameSetElement.h"
69 : #include "nsIDOMHTMLImageElement.h"
70 : #ifdef MOZ_XUL
71 : #include "nsIXULDocument.h"
72 : #include "nsXULPopupManager.h"
73 : #endif
74 :
75 : #include "nsIClipboardHelper.h"
76 :
77 : #include "nsPIDOMWindow.h"
78 : #include "nsGlobalWindow.h"
79 : #include "nsDOMNavigationTiming.h"
80 : #include "nsPIWindowRoot.h"
81 : #include "nsJSEnvironment.h"
82 : #include "nsFocusManager.h"
83 :
84 : #include "nsIScrollableFrame.h"
85 : #include "nsStyleSheetService.h"
86 : #include "nsILoadContext.h"
87 :
88 : #include "nsIPrompt.h"
89 : #include "imgIContainer.h" // image animation mode constants
90 :
91 : #include "nsSandboxFlags.h"
92 :
93 : #include "mozilla/DocLoadingTimelineMarker.h"
94 :
95 : //--------------------------
96 : // Printing Include
97 : //---------------------------
98 : #ifdef NS_PRINTING
99 :
100 : #include "nsIWebBrowserPrint.h"
101 :
102 : #include "nsPrintEngine.h"
103 :
104 : // Print Options
105 : #include "nsIPrintSettings.h"
106 : #include "nsIPrintSettingsService.h"
107 : #include "nsISimpleEnumerator.h"
108 :
109 : #include "nsIPluginDocument.h"
110 :
111 : #endif // NS_PRINTING
112 :
113 : //focus
114 : #include "nsIDOMEventTarget.h"
115 : #include "nsIDOMEventListener.h"
116 : #include "nsISelectionController.h"
117 :
118 : #include "mozilla/EventDispatcher.h"
119 : #include "nsISHEntry.h"
120 : #include "nsISHistory.h"
121 : #include "nsISHistoryInternal.h"
122 : #include "nsIWebNavigation.h"
123 : #include "mozilla/dom/XMLHttpRequestMainThread.h"
124 :
125 : //paint forcing
126 : #include <stdio.h>
127 :
128 : #include "mozilla/dom/Element.h"
129 : #include "mozilla/Telemetry.h"
130 :
131 : using namespace mozilla;
132 : using namespace mozilla::dom;
133 :
134 : #define BEFOREUNLOAD_DISABLED_PREFNAME "dom.disable_beforeunload"
135 : #define BEFOREUNLOAD_REQUIRES_INTERACTION_PREFNAME "dom.require_user_interaction_for_beforeunload"
136 :
137 : //-----------------------------------------------------
138 : // LOGGING
139 : #include "LayoutLogging.h"
140 : #include "mozilla/Logging.h"
141 :
142 : #ifdef NS_PRINTING
143 : static mozilla::LazyLogModule gPrintingLog("printing");
144 :
145 : #define PR_PL(_p1) MOZ_LOG(gPrintingLog, mozilla::LogLevel::Debug, _p1);
146 : #endif // NS_PRINTING
147 :
148 : #define PRT_YESNO(_p) ((_p)?"YES":"NO")
149 : //-----------------------------------------------------
150 :
151 : class nsDocumentViewer;
152 : namespace mozilla {
153 : class AutoPrintEventDispatcher;
154 : }
155 :
156 : // a small delegate class used to avoid circular references
157 :
158 : class nsDocViewerSelectionListener : public nsISelectionListener
159 : {
160 : public:
161 :
162 : // nsISupports interface...
163 : NS_DECL_ISUPPORTS
164 :
165 : // nsISelectionListerner interface
166 : NS_DECL_NSISELECTIONLISTENER
167 :
168 28 : nsDocViewerSelectionListener()
169 28 : : mDocViewer(nullptr)
170 28 : , mSelectionWasCollapsed(true)
171 : {
172 28 : }
173 :
174 : nsresult Init(nsDocumentViewer *aDocViewer);
175 :
176 3 : void Disconnect() { mDocViewer = nullptr; }
177 :
178 : protected:
179 :
180 9 : virtual ~nsDocViewerSelectionListener() {}
181 :
182 : nsDocumentViewer* mDocViewer;
183 : bool mSelectionWasCollapsed;
184 :
185 : };
186 :
187 :
188 : /** editor Implementation of the FocusListener interface
189 : */
190 : class nsDocViewerFocusListener : public nsIDOMEventListener
191 : {
192 : public:
193 : /** default constructor
194 : */
195 : nsDocViewerFocusListener();
196 :
197 : NS_DECL_ISUPPORTS
198 : NS_DECL_NSIDOMEVENTLISTENER
199 :
200 : nsresult Init(nsDocumentViewer *aDocViewer);
201 :
202 7 : void Disconnect() { mDocViewer = nullptr; }
203 :
204 : protected:
205 : /** default destructor
206 : */
207 : virtual ~nsDocViewerFocusListener();
208 :
209 : private:
210 : nsDocumentViewer* mDocViewer;
211 : };
212 :
213 :
214 : //-------------------------------------------------------------
215 : class nsDocumentViewer final : public nsIContentViewer,
216 : public nsIContentViewerEdit,
217 : public nsIContentViewerFile,
218 : public nsIDocumentViewerPrint
219 :
220 : #ifdef NS_PRINTING
221 : , public nsIWebBrowserPrint
222 : #endif
223 :
224 : {
225 : friend class nsDocViewerSelectionListener;
226 : friend class nsPagePrintTimer;
227 : friend class nsPrintEngine;
228 :
229 : public:
230 : nsDocumentViewer();
231 :
232 : // nsISupports interface...
233 : NS_DECL_ISUPPORTS
234 :
235 : // nsIContentViewer interface...
236 : NS_DECL_NSICONTENTVIEWER
237 :
238 : // nsIContentViewerEdit
239 : NS_DECL_NSICONTENTVIEWEREDIT
240 :
241 : // nsIContentViewerFile
242 : NS_DECL_NSICONTENTVIEWERFILE
243 :
244 : #ifdef NS_PRINTING
245 : // nsIWebBrowserPrint
246 : NS_DECL_NSIWEBBROWSERPRINT
247 : #endif
248 :
249 : typedef void (*CallChildFunc)(nsIContentViewer* aViewer, void* aClosure);
250 : void CallChildren(CallChildFunc aFunc, void* aClosure);
251 :
252 : // nsIDocumentViewerPrint Printing Methods
253 : NS_DECL_NSIDOCUMENTVIEWERPRINT
254 :
255 : protected:
256 : virtual ~nsDocumentViewer();
257 :
258 : private:
259 : /**
260 : * Creates a view manager, root view, and widget for the root view, setting
261 : * mViewManager and mWindow.
262 : * @param aSize the initial size in appunits
263 : * @param aContainerView the container view to hook our root view up
264 : * to as a child, or null if this will be the root view manager
265 : */
266 : nsresult MakeWindow(const nsSize& aSize, nsView* aContainerView);
267 :
268 : /**
269 : * Create our device context
270 : */
271 : nsresult CreateDeviceContext(nsView* aContainerView);
272 :
273 : /**
274 : * If aDoCreation is true, this creates the device context, creates a
275 : * prescontext if necessary, and calls MakeWindow.
276 : *
277 : * If aForceSetNewDocument is false, then SetNewDocument won't be
278 : * called if the window's current document is already mDocument.
279 : */
280 : nsresult InitInternal(nsIWidget* aParentWidget,
281 : nsISupports *aState,
282 : const nsIntRect& aBounds,
283 : bool aDoCreation,
284 : bool aNeedMakeCX = true,
285 : bool aForceSetNewDocument = true);
286 : /**
287 : * @param aDoInitialReflow set to true if you want to kick off the initial
288 : * reflow
289 : */
290 : nsresult InitPresentationStuff(bool aDoInitialReflow);
291 :
292 : nsresult GetPopupNode(nsIDOMNode** aNode);
293 : nsresult GetPopupLinkNode(nsIDOMNode** aNode);
294 : nsresult GetPopupImageNode(nsIImageLoadingContent** aNode);
295 :
296 : nsresult GetContentSizeInternal(int32_t* aWidth, int32_t* aHeight,
297 : nscoord aMaxWidth, nscoord aMaxHeight);
298 :
299 : void PrepareToStartLoad(void);
300 :
301 : nsresult SyncParentSubDocMap();
302 :
303 : mozilla::dom::Selection* GetDocumentSelection();
304 :
305 : void DestroyPresShell();
306 : void DestroyPresContext();
307 :
308 : #ifdef NS_PRINTING
309 : // Called when the DocViewer is notified that the state
310 : // of Printing or PP has changed
311 : void SetIsPrintingInDocShellTree(nsIDocShellTreeItem* aParentNode,
312 : bool aIsPrintingOrPP,
313 : bool aStartAtTop);
314 : #endif // NS_PRINTING
315 :
316 : // Whether we should attach to the top level widget. This is true if we
317 : // are sharing/recycling a single base widget and not creating multiple
318 : // child widgets.
319 : bool ShouldAttachToTopLevel();
320 :
321 : protected:
322 : // These return the current shell/prescontext etc.
323 : nsIPresShell* GetPresShell();
324 : nsPresContext* GetPresContext();
325 : nsViewManager* GetViewManager();
326 :
327 : void DetachFromTopLevelWidget();
328 :
329 : void SetPrintRelated();
330 :
331 : // IMPORTANT: The ownership implicit in the following member
332 : // variables has been explicitly checked and set using nsCOMPtr
333 : // for owning pointers and raw COM interface pointers for weak
334 : // (ie, non owning) references. If you add any members to this
335 : // class, please make the ownership explicit (pinkerton, scc).
336 :
337 : WeakPtr<nsDocShell> mContainer; // it owns me!
338 : nsWeakPtr mTopContainerWhilePrinting;
339 : RefPtr<nsDeviceContext> mDeviceContext; // We create and own this baby
340 :
341 : // the following six items are explicitly in this order
342 : // so they will be destroyed in the reverse order (pinkerton, scc)
343 : nsCOMPtr<nsIDocument> mDocument;
344 : nsCOMPtr<nsIWidget> mWindow; // may be null
345 : RefPtr<nsViewManager> mViewManager;
346 : RefPtr<nsPresContext> mPresContext;
347 : nsCOMPtr<nsIPresShell> mPresShell;
348 :
349 : RefPtr<nsDocViewerSelectionListener> mSelectionListener;
350 : RefPtr<nsDocViewerFocusListener> mFocusListener;
351 :
352 : nsCOMPtr<nsIContentViewer> mPreviousViewer;
353 : nsCOMPtr<nsISHEntry> mSHEntry;
354 :
355 : nsIWidget* mParentWidget; // purposely won't be ref counted. May be null
356 : bool mAttachedToParent; // view is attached to the parent widget
357 :
358 : nsIntRect mBounds;
359 :
360 : // mTextZoom/mPageZoom record the textzoom/pagezoom of the first (galley)
361 : // presshell only.
362 : float mTextZoom; // Text zoom, defaults to 1.0
363 : float mPageZoom;
364 : float mOverrideDPPX; // DPPX overrided, defaults to 0.0
365 : int mMinFontSize;
366 :
367 : int16_t mNumURLStarts;
368 : int16_t mDestroyRefCount; // a second "refcount" for the document viewer's "destroy"
369 :
370 : unsigned mStopped : 1;
371 : unsigned mLoaded : 1;
372 : unsigned mDeferredWindowClose : 1;
373 : // document management data
374 : // these items are specific to markup documents (html and xml)
375 : // may consider splitting these out into a subclass
376 : unsigned mIsSticky : 1;
377 : unsigned mInPermitUnload : 1;
378 : unsigned mInPermitUnloadPrompt: 1;
379 :
380 : #ifdef NS_PRINTING
381 : unsigned mClosingWhilePrinting : 1;
382 :
383 : #if NS_PRINT_PREVIEW
384 : unsigned mPrintPreviewZoomed : 1;
385 :
386 : // These data members support delayed printing when the document is loading
387 : unsigned mPrintIsPending : 1;
388 : unsigned mPrintDocIsFullyLoaded : 1;
389 : nsCOMPtr<nsIPrintSettings> mCachedPrintSettings;
390 : nsCOMPtr<nsIWebProgressListener> mCachedPrintWebProgressListner;
391 :
392 : RefPtr<nsPrintEngine> mPrintEngine;
393 : float mOriginalPrintPreviewScale;
394 : float mPrintPreviewZoom;
395 : nsAutoPtr<AutoPrintEventDispatcher> mAutoBeforeAndAfterPrint;
396 : #endif // NS_PRINT_PREVIEW
397 :
398 : #ifdef DEBUG
399 : FILE* mDebugFile;
400 : #endif // DEBUG
401 : #endif // NS_PRINTING
402 :
403 : /* character set member data */
404 : int32_t mHintCharsetSource;
405 : const Encoding* mHintCharset;
406 : const Encoding* mForceCharacterSet;
407 :
408 : bool mIsPageMode;
409 : bool mInitializedForPrintPreview;
410 : bool mHidden;
411 : bool mPrintRelated; // Only use for asserts.
412 : bool mPresShellDestroyed; // Only use for asserts.
413 : bool mDestroyWasFull; // Only use for asserts.
414 : };
415 :
416 : namespace mozilla {
417 :
418 : /**
419 : * A RAII class for automatic dispatch of the 'beforeprint' and 'afterprint'
420 : * events ('beforeprint' on construction, 'afterprint' on destruction).
421 : *
422 : * https://developer.mozilla.org/en-US/docs/Web/Events/beforeprint
423 : * https://developer.mozilla.org/en-US/docs/Web/Events/afterprint
424 : */
425 : class AutoPrintEventDispatcher
426 : {
427 : public:
428 0 : explicit AutoPrintEventDispatcher(nsIDocument* aTop) : mTop(aTop)
429 : {
430 0 : DispatchEventToWindowTree(NS_LITERAL_STRING("beforeprint"));
431 0 : }
432 0 : ~AutoPrintEventDispatcher()
433 0 : {
434 0 : DispatchEventToWindowTree(NS_LITERAL_STRING("afterprint"));
435 0 : }
436 :
437 : private:
438 0 : void DispatchEventToWindowTree(const nsAString& aEvent)
439 : {
440 0 : nsCOMArray<nsIDocument> targets;
441 0 : CollectDocuments(mTop, &targets);
442 0 : for (int32_t i = 0; i < targets.Count(); ++i) {
443 0 : nsIDocument* d = targets[i];
444 0 : nsContentUtils::DispatchTrustedEvent(d, d->GetWindow(),
445 0 : aEvent, false, false, nullptr);
446 : }
447 0 : }
448 :
449 0 : static bool CollectDocuments(nsIDocument* aDocument, void* aData)
450 : {
451 0 : if (aDocument) {
452 0 : static_cast<nsCOMArray<nsIDocument>*>(aData)->AppendObject(aDocument);
453 0 : aDocument->EnumerateSubDocuments(CollectDocuments, aData);
454 : }
455 0 : return true;
456 : }
457 :
458 : nsCOMPtr<nsIDocument> mTop;
459 : };
460 :
461 : }
462 :
463 15 : class nsDocumentShownDispatcher : public Runnable
464 : {
465 : public:
466 5 : explicit nsDocumentShownDispatcher(nsCOMPtr<nsIDocument> aDocument)
467 5 : : Runnable("nsDocumentShownDispatcher"), mDocument(aDocument) {}
468 :
469 : NS_IMETHOD Run() override;
470 :
471 : private:
472 : nsCOMPtr<nsIDocument> mDocument;
473 : };
474 :
475 :
476 : //------------------------------------------------------------------
477 : // nsDocumentViewer
478 : //------------------------------------------------------------------
479 :
480 : //------------------------------------------------------------------
481 : already_AddRefed<nsIContentViewer>
482 29 : NS_NewContentViewer()
483 : {
484 58 : RefPtr<nsDocumentViewer> viewer = new nsDocumentViewer();
485 58 : return viewer.forget();
486 : }
487 :
488 50 : void nsDocumentViewer::PrepareToStartLoad()
489 : {
490 50 : mStopped = false;
491 50 : mLoaded = false;
492 50 : mAttachedToParent = false;
493 50 : mDeferredWindowClose = false;
494 :
495 : #ifdef NS_PRINTING
496 50 : mPrintIsPending = false;
497 50 : mPrintDocIsFullyLoaded = false;
498 50 : mClosingWhilePrinting = false;
499 :
500 : // Make sure we have destroyed it and cleared the data member
501 50 : if (mPrintEngine) {
502 0 : mPrintEngine->Destroy();
503 0 : mPrintEngine = nullptr;
504 : #ifdef NS_PRINT_PREVIEW
505 0 : SetIsPrintPreview(false);
506 : #endif
507 : }
508 :
509 : #ifdef DEBUG
510 50 : mDebugFile = nullptr;
511 : #endif
512 :
513 : #endif // NS_PRINTING
514 50 : }
515 :
516 29 : nsDocumentViewer::nsDocumentViewer()
517 : : mParentWidget(nullptr),
518 : mAttachedToParent(false),
519 : mTextZoom(1.0),
520 : mPageZoom(1.0),
521 : mOverrideDPPX(0.0),
522 : mMinFontSize(0),
523 : mNumURLStarts(0),
524 : mDestroyRefCount(0),
525 : mStopped(false),
526 : mLoaded(false),
527 : mDeferredWindowClose(false),
528 : mIsSticky(true),
529 : mInPermitUnload(false),
530 : mInPermitUnloadPrompt(false),
531 : #ifdef NS_PRINTING
532 : mClosingWhilePrinting(false),
533 : #if NS_PRINT_PREVIEW
534 : mPrintPreviewZoomed(false),
535 : mPrintIsPending(false),
536 : mPrintDocIsFullyLoaded(false),
537 : mOriginalPrintPreviewScale(0.0),
538 : mPrintPreviewZoom(1.0),
539 : #endif // NS_PRINT_PREVIEW
540 : #ifdef DEBUG
541 : mDebugFile(nullptr),
542 : #endif // DEBUG
543 : #endif // NS_PRINTING
544 : mHintCharsetSource(kCharsetUninitialized),
545 : mHintCharset(nullptr),
546 : mForceCharacterSet(nullptr),
547 : mIsPageMode(false),
548 : mInitializedForPrintPreview(false),
549 : mHidden(false),
550 : mPrintRelated(false),
551 : mPresShellDestroyed(true),
552 29 : mDestroyWasFull(false)
553 : {
554 29 : PrepareToStartLoad();
555 29 : }
556 :
557 : void
558 0 : nsDocumentViewer::SetPrintRelated()
559 : {
560 0 : if (!mPrintRelated) {
561 0 : if (mViewManager) {
562 0 : mViewManager->SetPrintRelated();
563 : }
564 : }
565 0 : mPrintRelated = true;
566 0 : }
567 :
568 323 : NS_IMPL_ADDREF(nsDocumentViewer)
569 292 : NS_IMPL_RELEASE(nsDocumentViewer)
570 :
571 217 : NS_INTERFACE_MAP_BEGIN(nsDocumentViewer)
572 217 : NS_INTERFACE_MAP_ENTRY(nsIContentViewer)
573 72 : NS_INTERFACE_MAP_ENTRY(nsIContentViewerFile)
574 72 : NS_INTERFACE_MAP_ENTRY(nsIContentViewerEdit)
575 42 : NS_INTERFACE_MAP_ENTRY(nsIDocumentViewerPrint)
576 42 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentViewer)
577 : #ifdef NS_PRINTING
578 32 : NS_INTERFACE_MAP_ENTRY(nsIWebBrowserPrint)
579 : #endif
580 32 : NS_INTERFACE_MAP_END
581 :
582 9 : nsDocumentViewer::~nsDocumentViewer()
583 : {
584 3 : if (mDocument) {
585 0 : Close(nullptr);
586 0 : mDocument->Destroy();
587 : }
588 :
589 : nsIFrame* vmRootFrame =
590 3 : mViewManager && mViewManager->GetRootView()
591 3 : ? mViewManager->GetRootView()->GetFrame()
592 3 : : nullptr;
593 3 : nsIFrame* psRootFrame = mPresShell ? mPresShell->GetRootFrame() : nullptr;
594 3 : MOZ_RELEASE_ASSERT(vmRootFrame == psRootFrame);
595 :
596 3 : NS_ASSERTION(!mPresShell && !mPresContext,
597 : "User did not call nsIContentViewer::Destroy");
598 3 : if (mPresShell || mPresContext) {
599 : // Make sure we don't hand out a reference to the content viewer to
600 : // the SHEntry!
601 0 : mSHEntry = nullptr;
602 0 : mDestroyWasFull = false;
603 0 : Destroy();
604 0 : MOZ_RELEASE_ASSERT(mDestroyWasFull);
605 : }
606 :
607 3 : MOZ_RELEASE_ASSERT(mPresShellDestroyed);
608 :
609 3 : MOZ_RELEASE_ASSERT(!mPresShell || !mPresShell->GetRootFrame());
610 3 : MOZ_RELEASE_ASSERT(!mViewManager || !mViewManager->GetRootView() ||
611 : (!mViewManager->GetRootView()->GetFrame() &&
612 : !mViewManager->GetRootView()->GetFirstChild()));
613 :
614 3 : if (mSelectionListener) {
615 3 : mSelectionListener->Disconnect();
616 : }
617 :
618 3 : if (mFocusListener) {
619 3 : mFocusListener->Disconnect();
620 : }
621 :
622 : // XXX(?) Revoke pending invalidate events
623 9 : }
624 :
625 : /*
626 : * This method is called by the Document Loader once a document has
627 : * been created for a particular data stream... The content viewer
628 : * must cache this document for later use when Init(...) is called.
629 : *
630 : * This method is also called when an out of band document.write() happens.
631 : * In that case, the document passed in is the same as the previous document.
632 : */
633 : /* virtual */ void
634 29 : nsDocumentViewer::LoadStart(nsIDocument* aDocument)
635 : {
636 29 : MOZ_ASSERT(aDocument);
637 :
638 29 : if (!mDocument) {
639 29 : mDocument = aDocument;
640 : }
641 29 : }
642 :
643 : nsresult
644 29 : nsDocumentViewer::SyncParentSubDocMap()
645 : {
646 58 : nsCOMPtr<nsIDocShell> docShell(mContainer);
647 29 : if (!docShell) {
648 21 : return NS_OK;
649 : }
650 :
651 16 : nsCOMPtr<nsPIDOMWindowOuter> pwin(docShell->GetWindow());
652 8 : if (!mDocument || !pwin) {
653 0 : return NS_OK;
654 : }
655 :
656 16 : nsCOMPtr<Element> element = pwin->GetFrameElementInternal();
657 8 : if (!element) {
658 6 : return NS_OK;
659 : }
660 :
661 4 : nsCOMPtr<nsIDocShellTreeItem> parent;
662 2 : docShell->GetParent(getter_AddRefs(parent));
663 :
664 4 : nsCOMPtr<nsPIDOMWindowOuter> parent_win = parent ? parent->GetWindow() : nullptr;
665 2 : if (!parent_win) {
666 0 : return NS_OK;
667 : }
668 :
669 4 : nsCOMPtr<nsIDocument> parent_doc = parent_win->GetDoc();
670 2 : if (!parent_doc) {
671 0 : return NS_OK;
672 : }
673 :
674 4 : if (mDocument &&
675 4 : parent_doc->GetSubDocumentFor(element) != mDocument &&
676 2 : parent_doc->EventHandlingSuppressed()) {
677 0 : mDocument->SuppressEventHandling(parent_doc->EventHandlingSuppressed());
678 : }
679 2 : return parent_doc->SetSubDocumentFor(element, mDocument);
680 : }
681 :
682 : NS_IMETHODIMP
683 8 : nsDocumentViewer::SetContainer(nsIDocShell* aContainer)
684 : {
685 8 : mContainer = static_cast<nsDocShell*>(aContainer);
686 8 : if (mPresContext) {
687 0 : mPresContext->SetContainer(mContainer);
688 : }
689 :
690 : // We're loading a new document into the window where this document
691 : // viewer lives, sync the parent document's frame element -> sub
692 : // document map
693 :
694 8 : return SyncParentSubDocMap();
695 : }
696 :
697 : NS_IMETHODIMP
698 0 : nsDocumentViewer::GetContainer(nsIDocShell** aResult)
699 : {
700 0 : NS_ENSURE_ARG_POINTER(aResult);
701 :
702 0 : nsCOMPtr<nsIDocShell> container(mContainer);
703 0 : container.swap(*aResult);
704 0 : return NS_OK;
705 : }
706 :
707 : NS_IMETHODIMP
708 29 : nsDocumentViewer::Init(nsIWidget* aParentWidget,
709 : const nsIntRect& aBounds)
710 : {
711 29 : return InitInternal(aParentWidget, nullptr, aBounds, true);
712 : }
713 :
714 : nsresult
715 28 : nsDocumentViewer::InitPresentationStuff(bool aDoInitialReflow)
716 : {
717 : // We assert this because initializing the pres shell could otherwise cause
718 : // re-entrancy into nsDocumentViewer methods, which might cause a different
719 : // pres shell to be created. Callers of InitPresentationStuff should ensure
720 : // the call is appropriately bounded by an nsAutoScriptBlocker to decide
721 : // when it is safe for these re-entrant calls to be made.
722 28 : MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(),
723 : "InitPresentationStuff must only be called when scripts are "
724 : "blocked");
725 :
726 28 : if (GetIsPrintPreview())
727 0 : return NS_OK;
728 :
729 28 : NS_ASSERTION(!mPresShell,
730 : "Someone should have destroyed the presshell!");
731 :
732 : // Create the style set...
733 28 : StyleSetHandle styleSet = CreateStyleSet(mDocument);
734 :
735 : // Now make the shell for the document
736 28 : mPresShell = mDocument->CreateShell(mPresContext, mViewManager, styleSet);
737 28 : if (!mPresShell) {
738 0 : styleSet->Delete();
739 0 : return NS_ERROR_FAILURE;
740 : }
741 28 : mPresShellDestroyed = false;
742 :
743 : // We're done creating the style set
744 28 : styleSet->EndUpdate();
745 :
746 28 : if (aDoInitialReflow) {
747 : // Since Initialize() will create frames for *all* items
748 : // that are currently in the document tree, we need to flush
749 : // any pending notifications to prevent the content sink from
750 : // duplicating layout frames for content it has added to the tree
751 : // but hasn't notified the document about. (Bug 154018)
752 : //
753 : // Note that we are flushing before we add mPresShell as an observer
754 : // to avoid bogus notifications.
755 :
756 0 : mDocument->FlushPendingNotifications(FlushType::ContentAndNotify);
757 : }
758 :
759 28 : mPresShell->BeginObservingDocument();
760 :
761 : // Initialize our view manager
762 28 : int32_t p2a = mPresContext->AppUnitsPerDevPixel();
763 28 : MOZ_ASSERT(p2a ==
764 : mPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom());
765 28 : nscoord width = p2a * mBounds.width;
766 28 : nscoord height = p2a * mBounds.height;
767 :
768 28 : mViewManager->SetWindowDimensions(width, height);
769 28 : mPresContext->SetTextZoom(mTextZoom);
770 28 : mPresContext->SetFullZoom(mPageZoom);
771 28 : mPresContext->SetOverrideDPPX(mOverrideDPPX);
772 28 : mPresContext->SetBaseMinFontSize(mMinFontSize);
773 :
774 28 : p2a = mPresContext->AppUnitsPerDevPixel(); // zoom may have changed it
775 28 : width = p2a * mBounds.width;
776 28 : height = p2a * mBounds.height;
777 28 : if (aDoInitialReflow) {
778 0 : nsCOMPtr<nsIPresShell> shell = mPresShell;
779 : // Initial reflow
780 0 : shell->Initialize(width, height);
781 : } else {
782 : // Store the visible area so it's available for other callers of
783 : // Initialize, like nsContentSink::StartLayout.
784 28 : mPresContext->SetVisibleArea(nsRect(0, 0, width, height));
785 : }
786 :
787 : // now register ourselves as a selection listener, so that we get
788 : // called when the selection changes in the window
789 28 : if (!mSelectionListener) {
790 : nsDocViewerSelectionListener *selectionListener =
791 28 : new nsDocViewerSelectionListener();
792 :
793 28 : selectionListener->Init(this);
794 :
795 : // mSelectionListener is a owning reference
796 28 : mSelectionListener = selectionListener;
797 : }
798 :
799 56 : RefPtr<mozilla::dom::Selection> selection = GetDocumentSelection();
800 28 : if (!selection) {
801 0 : return NS_ERROR_FAILURE;
802 : }
803 :
804 28 : nsresult rv = selection->AddSelectionListener(mSelectionListener);
805 28 : if (NS_FAILED(rv))
806 0 : return rv;
807 :
808 : // Save old listener so we can unregister it
809 56 : RefPtr<nsDocViewerFocusListener> oldFocusListener = mFocusListener;
810 28 : if (oldFocusListener) {
811 0 : oldFocusListener->Disconnect();
812 : }
813 :
814 : // focus listener
815 : //
816 : // now register ourselves as a focus listener, so that we get called
817 : // when the focus changes in the window
818 28 : nsDocViewerFocusListener *focusListener = new nsDocViewerFocusListener();
819 :
820 28 : focusListener->Init(this);
821 :
822 : // mFocusListener is a strong reference
823 28 : mFocusListener = focusListener;
824 :
825 28 : if (mDocument) {
826 84 : mDocument->AddEventListener(NS_LITERAL_STRING("focus"),
827 : mFocusListener,
828 84 : false, false);
829 84 : mDocument->AddEventListener(NS_LITERAL_STRING("blur"),
830 : mFocusListener,
831 84 : false, false);
832 :
833 28 : if (oldFocusListener) {
834 0 : mDocument->RemoveEventListener(NS_LITERAL_STRING("focus"),
835 0 : oldFocusListener, false);
836 0 : mDocument->RemoveEventListener(NS_LITERAL_STRING("blur"),
837 0 : oldFocusListener, false);
838 : }
839 : }
840 :
841 28 : if (aDoInitialReflow && mDocument) {
842 0 : mDocument->ScrollToRef();
843 : }
844 :
845 28 : return NS_OK;
846 : }
847 :
848 : static nsPresContext*
849 28 : CreatePresContext(nsIDocument* aDocument,
850 : nsPresContext::nsPresContextType aType,
851 : nsView* aContainerView)
852 : {
853 28 : if (aContainerView)
854 1 : return new nsPresContext(aDocument, aType);
855 27 : return new nsRootPresContext(aDocument, aType);
856 : }
857 :
858 : //-----------------------------------------------
859 : // This method can be used to initial the "presentation"
860 : // The aDoCreation indicates whether it should create
861 : // all the new objects or just initialize the existing ones
862 : nsresult
863 50 : nsDocumentViewer::InitInternal(nsIWidget* aParentWidget,
864 : nsISupports *aState,
865 : const nsIntRect& aBounds,
866 : bool aDoCreation,
867 : bool aNeedMakeCX /*= true*/,
868 : bool aForceSetNewDocument /* = true*/)
869 : {
870 50 : if (mIsPageMode) {
871 : // XXXbz should the InitInternal in SetPageMode just pass false
872 : // here itself?
873 0 : aForceSetNewDocument = false;
874 : }
875 :
876 : // We don't want any scripts to run here. That can cause flushing,
877 : // which can cause reentry into initialization of this document viewer,
878 : // which would be disastrous.
879 100 : nsAutoScriptBlocker blockScripts;
880 :
881 50 : mParentWidget = aParentWidget; // not ref counted
882 50 : mBounds = aBounds;
883 :
884 50 : nsresult rv = NS_OK;
885 50 : NS_ENSURE_TRUE(mDocument, NS_ERROR_NULL_POINTER);
886 :
887 50 : nsView* containerView = FindContainerView();
888 :
889 50 : bool makeCX = false;
890 50 : if (aDoCreation) {
891 29 : nsresult rv = CreateDeviceContext(containerView);
892 29 : NS_ENSURE_SUCCESS(rv, rv);
893 :
894 : // XXXbz this is a nasty hack to do with the fact that we create
895 : // presentations both in Init() and in Show()... Ideally we would only do
896 : // it in one place (Show()) and require that callers call init(), open(),
897 : // show() in that order or something.
898 57 : if (!mPresContext &&
899 24 : (aParentWidget || containerView || mDocument->IsBeingUsedAsImage() ||
900 1 : (mDocument->GetDisplayDocument() &&
901 0 : mDocument->GetDisplayDocument()->GetShell()))) {
902 : // Create presentation context
903 28 : if (mIsPageMode) {
904 : //Presentation context already created in SetPageMode which is calling this method
905 : } else {
906 : mPresContext = CreatePresContext(mDocument,
907 28 : nsPresContext::eContext_Galley, containerView);
908 : }
909 28 : NS_ENSURE_TRUE(mPresContext, NS_ERROR_OUT_OF_MEMORY);
910 :
911 28 : nsresult rv = mPresContext->Init(mDeviceContext);
912 28 : if (NS_FAILED(rv)) {
913 0 : mPresContext = nullptr;
914 0 : return rv;
915 : }
916 :
917 : #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
918 28 : makeCX = !GetIsPrintPreview() && aNeedMakeCX; // needs to be true except when we are already in PP or we are enabling/disabling paginated mode.
919 : #else
920 : makeCX = true;
921 : #endif
922 : }
923 :
924 29 : if (mPresContext) {
925 : // Create the ViewManager and Root View...
926 :
927 : // We must do this before we tell the script global object about
928 : // this new document since doing that will cause us to re-enter
929 : // into nsSubDocumentFrame code through reflows caused by
930 : // FlushPendingNotifications() calls down the road...
931 :
932 56 : rv = MakeWindow(nsSize(mPresContext->DevPixelsToAppUnits(aBounds.width),
933 28 : mPresContext->DevPixelsToAppUnits(aBounds.height)),
934 28 : containerView);
935 28 : NS_ENSURE_SUCCESS(rv, rv);
936 28 : Hide();
937 :
938 : #ifdef NS_PRINT_PREVIEW
939 28 : if (mIsPageMode) {
940 : // I'm leaving this in a broken state for the moment; we should
941 : // be measuring/scaling with the print device context, not the
942 : // screen device context, but this is good enough to allow
943 : // printing reftests to work.
944 0 : double pageWidth = 0, pageHeight = 0;
945 0 : mPresContext->GetPrintSettings()->GetEffectivePageSize(&pageWidth,
946 0 : &pageHeight);
947 0 : mPresContext->SetPageSize(
948 0 : nsSize(mPresContext->CSSTwipsToAppUnits(NSToIntFloor(pageWidth)),
949 0 : mPresContext->CSSTwipsToAppUnits(NSToIntFloor(pageHeight))));
950 0 : mPresContext->SetIsRootPaginatedDocument(true);
951 0 : mPresContext->SetPageScale(1.0f);
952 : }
953 : #endif
954 : } else {
955 : // Avoid leaking the old viewer.
956 1 : if (mPreviousViewer) {
957 0 : mPreviousViewer->Destroy();
958 0 : mPreviousViewer = nullptr;
959 : }
960 : }
961 : }
962 :
963 100 : nsCOMPtr<nsIInterfaceRequestor> requestor(mContainer);
964 50 : if (requestor) {
965 8 : if (mPresContext) {
966 14 : nsCOMPtr<nsILinkHandler> linkHandler;
967 14 : requestor->GetInterface(NS_GET_IID(nsILinkHandler),
968 14 : getter_AddRefs(linkHandler));
969 :
970 7 : mPresContext->SetContainer(mContainer);
971 7 : mPresContext->SetLinkHandler(linkHandler);
972 : }
973 :
974 : // Set script-context-owner in the document
975 :
976 16 : nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(requestor);
977 :
978 8 : if (window) {
979 16 : nsCOMPtr<nsIDocument> curDoc = window->GetExtantDoc();
980 8 : if (aForceSetNewDocument || curDoc != mDocument) {
981 8 : rv = window->SetNewDocument(mDocument, aState, false);
982 8 : if (NS_FAILED(rv)) {
983 0 : Destroy();
984 0 : return rv;
985 : }
986 8 : nsJSContext::LoadStart();
987 : }
988 : }
989 : }
990 :
991 50 : if (aDoCreation && mPresContext) {
992 : // The ViewManager and Root View was created above (in
993 : // MakeWindow())...
994 :
995 28 : rv = InitPresentationStuff(!makeCX);
996 : }
997 :
998 50 : return rv;
999 : }
1000 :
1001 29 : void nsDocumentViewer::SetNavigationTiming(nsDOMNavigationTiming* timing)
1002 : {
1003 29 : NS_ASSERTION(mDocument, "Must have a document to set navigation timing.");
1004 29 : if (mDocument) {
1005 29 : mDocument->SetNavigationTiming(timing);
1006 : }
1007 29 : }
1008 :
1009 : //
1010 : // LoadComplete(aStatus)
1011 : //
1012 : // aStatus - The status returned from loading the document.
1013 : //
1014 : // This method is called by the container when the document has been
1015 : // completely loaded.
1016 : //
1017 : NS_IMETHODIMP
1018 6 : nsDocumentViewer::LoadComplete(nsresult aStatus)
1019 : {
1020 : /* We need to protect ourself against auto-destruction in case the
1021 : window is closed while processing the OnLoad event. See bug
1022 : http://bugzilla.mozilla.org/show_bug.cgi?id=78445 for more
1023 : explanation.
1024 : */
1025 12 : RefPtr<nsDocumentViewer> kungFuDeathGrip(this);
1026 :
1027 : // Flush out layout so it's up-to-date by the time onload is called.
1028 : // Note that this could destroy the window, so do this before
1029 : // checking for our mDocument and its window.
1030 6 : if (mPresShell && !mStopped) {
1031 : // Hold strong ref because this could conceivably run script
1032 8 : nsCOMPtr<nsIPresShell> shell = mPresShell;
1033 4 : shell->FlushPendingNotifications(FlushType::Layout);
1034 : }
1035 :
1036 6 : nsresult rv = NS_OK;
1037 6 : NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
1038 :
1039 : // First, get the window from the document...
1040 12 : nsCOMPtr<nsPIDOMWindowOuter> window = mDocument->GetWindow();
1041 :
1042 6 : mLoaded = true;
1043 :
1044 : // Now, fire either an OnLoad or OnError event to the document...
1045 6 : bool restoring = false;
1046 : // XXXbz imagelib kills off the document load for a full-page image with
1047 : // NS_ERROR_PARSED_DATA_CACHED if it's in the cache. So we want to treat
1048 : // that one as a success code; otherwise whether we fire onload for the image
1049 : // will depend on whether it's cached!
1050 16 : if(window &&
1051 15 : (NS_SUCCEEDED(aStatus) || aStatus == NS_ERROR_PARSED_DATA_CACHED)) {
1052 4 : nsEventStatus status = nsEventStatus_eIgnore;
1053 8 : WidgetEvent event(true, eLoad);
1054 4 : event.mFlags.mBubbles = false;
1055 4 : event.mFlags.mCancelable = false;
1056 : // XXX Dispatching to |window|, but using |document| as the target.
1057 4 : event.mTarget = mDocument;
1058 :
1059 : // If the document presentation is being restored, we don't want to fire
1060 : // onload to the document content since that would likely confuse scripts
1061 : // on the page.
1062 :
1063 4 : nsIDocShell *docShell = window->GetDocShell();
1064 4 : NS_ENSURE_TRUE(docShell, NS_ERROR_UNEXPECTED);
1065 :
1066 4 : docShell->GetRestoringDocument(&restoring);
1067 4 : if (!restoring) {
1068 4 : NS_ASSERTION(mDocument->IsXULDocument() || // readyState for XUL is bogus
1069 : mDocument->GetReadyStateEnum() ==
1070 : nsIDocument::READYSTATE_INTERACTIVE ||
1071 : // test_stricttransportsecurity.html has old-style
1072 : // docshell-generated about:blank docs reach this code!
1073 : (mDocument->GetReadyStateEnum() ==
1074 : nsIDocument::READYSTATE_UNINITIALIZED &&
1075 : NS_IsAboutBlank(mDocument->GetDocumentURI())),
1076 : "Bad readystate");
1077 8 : nsCOMPtr<nsIDocument> d = mDocument;
1078 4 : mDocument->SetReadyStateInternal(nsIDocument::READYSTATE_COMPLETE);
1079 :
1080 8 : RefPtr<nsDOMNavigationTiming> timing(d->GetNavigationTiming());
1081 4 : if (timing) {
1082 4 : timing->NotifyLoadEventStart();
1083 : }
1084 :
1085 : // Dispatch observer notification to notify observers document load is complete.
1086 8 : nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
1087 4 : if (os) {
1088 4 : nsIPrincipal *principal = d->NodePrincipal();
1089 8 : os->NotifyObservers(d,
1090 4 : nsContentUtils::IsSystemPrincipal(principal) ?
1091 : "chrome-document-loaded" :
1092 : "content-document-loaded",
1093 8 : nullptr);
1094 : }
1095 :
1096 : // Notify any devtools about the load.
1097 8 : RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
1098 :
1099 4 : if (timelines && timelines->HasConsumer(docShell)) {
1100 0 : timelines->AddMarkerForDocShell(docShell,
1101 0 : MakeUnique<DocLoadingTimelineMarker>("document::Load"));
1102 : }
1103 :
1104 4 : EventDispatcher::Dispatch(window, mPresContext, &event, nullptr, &status);
1105 4 : if (timing) {
1106 4 : timing->NotifyLoadEventEnd();
1107 : }
1108 : }
1109 : } else {
1110 : // XXX: Should fire error event to the document...
1111 : }
1112 :
1113 : // Notify the document that it has been shown (regardless of whether
1114 : // it was just loaded). Note: mDocument may be null now if the above
1115 : // firing of onload caused the document to unload.
1116 6 : if (mDocument) {
1117 : // Re-get window, since it might have changed during above firing of onload
1118 6 : window = mDocument->GetWindow();
1119 6 : if (window) {
1120 6 : nsIDocShell *docShell = window->GetDocShell();
1121 : bool isInUnload;
1122 12 : if (docShell && NS_SUCCEEDED(docShell->GetIsInUnload(&isInUnload)) &&
1123 6 : !isInUnload) {
1124 5 : mDocument->OnPageShow(restoring, nullptr);
1125 : }
1126 : }
1127 : }
1128 :
1129 6 : if (!mStopped) {
1130 5 : if (mDocument) {
1131 5 : mDocument->ScrollToRef();
1132 : }
1133 :
1134 : // Now that the document has loaded, we can tell the presshell
1135 : // to unsuppress painting.
1136 5 : if (mPresShell) {
1137 8 : nsCOMPtr<nsIPresShell> shell(mPresShell);
1138 4 : shell->UnsuppressPainting();
1139 : // mPresShell could have been removed now, see bug 378682/421432
1140 4 : if (mPresShell) {
1141 4 : mPresShell->LoadComplete();
1142 : }
1143 : }
1144 : }
1145 :
1146 : // Release the JS bytecode cache from its wait on the load event, and
1147 : // potentially dispatch the encoding of the bytecode.
1148 6 : if (mDocument && mDocument->ScriptLoader()) {
1149 6 : mDocument->ScriptLoader()->LoadEventFired();
1150 : }
1151 :
1152 6 : nsJSContext::LoadEnd();
1153 :
1154 : // It's probably a good idea to GC soon since we have finished loading.
1155 12 : nsJSContext::PokeGC(JS::gcreason::LOAD_END,
1156 18 : mDocument ? mDocument->GetWrapperPreserveColor() : nullptr);
1157 :
1158 : #ifdef NS_PRINTING
1159 : // Check to see if someone tried to print during the load
1160 6 : if (mPrintIsPending) {
1161 0 : mPrintIsPending = false;
1162 0 : mPrintDocIsFullyLoaded = true;
1163 0 : Print(mCachedPrintSettings, mCachedPrintWebProgressListner);
1164 0 : mCachedPrintSettings = nullptr;
1165 0 : mCachedPrintWebProgressListner = nullptr;
1166 : }
1167 : #endif
1168 :
1169 6 : return rv;
1170 : }
1171 :
1172 : NS_IMETHODIMP
1173 0 : nsDocumentViewer::GetLoadCompleted(bool *aOutLoadCompleted)
1174 : {
1175 0 : *aOutLoadCompleted = mLoaded;
1176 0 : return NS_OK;
1177 : }
1178 :
1179 : NS_IMETHODIMP
1180 0 : nsDocumentViewer::GetIsStopped(bool* aOutIsStopped)
1181 : {
1182 0 : *aOutIsStopped = mStopped;
1183 0 : return NS_OK;
1184 : }
1185 :
1186 : NS_IMETHODIMP
1187 5 : nsDocumentViewer::PermitUnload(bool *aPermitUnload)
1188 : {
1189 5 : bool shouldPrompt = true;
1190 5 : return PermitUnloadInternal(&shouldPrompt, aPermitUnload);
1191 : }
1192 :
1193 :
1194 : nsresult
1195 5 : nsDocumentViewer::PermitUnloadInternal(bool *aShouldPrompt,
1196 : bool *aPermitUnload)
1197 : {
1198 10 : AutoDontWarnAboutSyncXHR disableSyncXHRWarning;
1199 :
1200 5 : nsresult rv = NS_OK;
1201 5 : *aPermitUnload = true;
1202 :
1203 10 : if (!mDocument
1204 5 : || mInPermitUnload
1205 10 : || mInPermitUnloadPrompt) {
1206 0 : return NS_OK;
1207 : }
1208 :
1209 : static bool sIsBeforeUnloadDisabled;
1210 : static bool sBeforeUnloadRequiresInteraction;
1211 : static bool sBeforeUnloadPrefsCached = false;
1212 :
1213 5 : if (!sBeforeUnloadPrefsCached) {
1214 2 : sBeforeUnloadPrefsCached = true;
1215 : Preferences::AddBoolVarCache(&sIsBeforeUnloadDisabled,
1216 2 : BEFOREUNLOAD_DISABLED_PREFNAME);
1217 : Preferences::AddBoolVarCache(&sBeforeUnloadRequiresInteraction,
1218 2 : BEFOREUNLOAD_REQUIRES_INTERACTION_PREFNAME);
1219 : }
1220 :
1221 : // First, get the script global object from the document...
1222 5 : nsPIDOMWindowOuter* window = mDocument->GetWindow();
1223 :
1224 5 : if (!window) {
1225 : // This is odd, but not fatal
1226 0 : NS_WARNING("window not set for document!");
1227 0 : return NS_OK;
1228 : }
1229 :
1230 5 : NS_ASSERTION(nsContentUtils::IsSafeToRunScript(), "This is unsafe");
1231 :
1232 : // Now, fire an BeforeUnload event to the document and see if it's ok
1233 : // to unload...
1234 5 : nsIPresShell* shell = mDocument->GetShell();
1235 5 : nsPresContext* presContext = nullptr;
1236 5 : if (shell) {
1237 5 : presContext = shell->GetPresContext();
1238 : }
1239 : RefPtr<BeforeUnloadEvent> event =
1240 15 : new BeforeUnloadEvent(mDocument, presContext, nullptr);
1241 5 : event->InitEvent(NS_LITERAL_STRING("beforeunload"), false, true);
1242 :
1243 : // Dispatching to |window|, but using |document| as the target.
1244 5 : event->SetTarget(mDocument);
1245 5 : event->SetTrusted(true);
1246 :
1247 : // In evil cases we might be destroyed while handling the
1248 : // onbeforeunload event, don't let that happen. (see also bug#331040)
1249 10 : RefPtr<nsDocumentViewer> kungFuDeathGrip(this);
1250 :
1251 5 : bool dialogsAreEnabled = false;
1252 : {
1253 : // Never permit popups from the beforeunload handler, no matter
1254 : // how we get here.
1255 10 : nsAutoPopupStatePusher popupStatePusher(openAbused, true);
1256 :
1257 : // Never permit dialogs from the beforeunload handler
1258 5 : nsGlobalWindow* globalWindow = nsGlobalWindow::Cast(window);
1259 5 : dialogsAreEnabled = globalWindow->AreDialogsEnabled();
1260 10 : nsGlobalWindow::TemporarilyDisableDialogs disableDialogs(globalWindow);
1261 :
1262 10 : nsIDocument::PageUnloadingEventTimeStamp timestamp(mDocument);
1263 :
1264 5 : mInPermitUnload = true;
1265 5 : EventDispatcher::DispatchDOMEvent(window, nullptr, event, mPresContext,
1266 5 : nullptr);
1267 5 : mInPermitUnload = false;
1268 : }
1269 :
1270 10 : nsCOMPtr<nsIDocShell> docShell(mContainer);
1271 10 : nsAutoString text;
1272 5 : event->GetReturnValue(text);
1273 :
1274 : // NB: we nullcheck mDocument because it might now be dead as a result of
1275 : // the event being dispatched.
1276 20 : if (!sIsBeforeUnloadDisabled && *aShouldPrompt && dialogsAreEnabled &&
1277 15 : mDocument && !(mDocument->GetSandboxFlags() & SANDBOXED_MODALS) &&
1278 15 : (!sBeforeUnloadRequiresInteraction || mDocument->UserHasInteracted()) &&
1279 0 : (event->WidgetEventPtr()->DefaultPrevented() || !text.IsEmpty())) {
1280 : // Ask the user if it's ok to unload the current page
1281 :
1282 0 : nsCOMPtr<nsIPrompt> prompt = do_GetInterface(docShell);
1283 :
1284 0 : if (prompt) {
1285 0 : nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt);
1286 0 : if (promptBag) {
1287 : bool isTabModalPromptAllowed;
1288 0 : GetIsTabModalPromptAllowed(&isTabModalPromptAllowed);
1289 0 : promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"),
1290 0 : isTabModalPromptAllowed);
1291 : }
1292 :
1293 0 : nsXPIDLString title, message, stayLabel, leaveLabel;
1294 : rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
1295 : "OnBeforeUnloadTitle",
1296 0 : title);
1297 : nsresult tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
1298 : "OnBeforeUnloadMessage",
1299 0 : message);
1300 0 : if (NS_FAILED(tmp)) {
1301 0 : rv = tmp;
1302 : }
1303 : tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
1304 : "OnBeforeUnloadLeaveButton",
1305 0 : leaveLabel);
1306 0 : if (NS_FAILED(tmp)) {
1307 0 : rv = tmp;
1308 : }
1309 : tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
1310 : "OnBeforeUnloadStayButton",
1311 0 : stayLabel);
1312 0 : if (NS_FAILED(tmp)) {
1313 0 : rv = tmp;
1314 : }
1315 :
1316 0 : if (NS_FAILED(rv) || !title || !message || !stayLabel || !leaveLabel) {
1317 0 : NS_ERROR("Failed to get strings from dom.properties!");
1318 0 : return NS_OK;
1319 : }
1320 :
1321 : // Although the exact value is ignored, we must not pass invalid
1322 : // bool values through XPConnect.
1323 0 : bool dummy = false;
1324 0 : int32_t buttonPressed = 0;
1325 : uint32_t buttonFlags = (nsIPrompt::BUTTON_POS_0_DEFAULT |
1326 : (nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_0) |
1327 0 : (nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_1));
1328 :
1329 0 : nsAutoSyncOperation sync(mDocument);
1330 0 : mInPermitUnloadPrompt = true;
1331 0 : mozilla::Telemetry::Accumulate(mozilla::Telemetry::ONBEFOREUNLOAD_PROMPT_COUNT, 1);
1332 0 : rv = prompt->ConfirmEx(title, message, buttonFlags,
1333 : leaveLabel, stayLabel, nullptr, nullptr,
1334 0 : &dummy, &buttonPressed);
1335 0 : mInPermitUnloadPrompt = false;
1336 :
1337 : // If the prompt aborted, we tell our consumer that it is not allowed
1338 : // to unload the page. One reason that prompts abort is that the user
1339 : // performed some action that caused the page to unload while our prompt
1340 : // was active. In those cases we don't want our consumer to also unload
1341 : // the page.
1342 : //
1343 : // XXX: Are there other cases where prompts can abort? Is it ok to
1344 : // prevent unloading the page in those cases?
1345 0 : if (NS_FAILED(rv)) {
1346 0 : mozilla::Telemetry::Accumulate(mozilla::Telemetry::ONBEFOREUNLOAD_PROMPT_ACTION, 2);
1347 0 : *aPermitUnload = false;
1348 0 : return NS_OK;
1349 : }
1350 :
1351 : // Button 0 == leave, button 1 == stay
1352 0 : *aPermitUnload = (buttonPressed == 0);
1353 0 : mozilla::Telemetry::Accumulate(mozilla::Telemetry::ONBEFOREUNLOAD_PROMPT_ACTION,
1354 0 : (*aPermitUnload ? 1 : 0));
1355 : // If the user decided to go ahead, make sure not to prompt the user again
1356 : // by toggling the internal prompting bool to false:
1357 0 : if (*aPermitUnload) {
1358 0 : *aShouldPrompt = false;
1359 : }
1360 : }
1361 : }
1362 :
1363 5 : if (docShell) {
1364 : int32_t childCount;
1365 5 : docShell->GetChildCount(&childCount);
1366 :
1367 5 : for (int32_t i = 0; i < childCount && *aPermitUnload; ++i) {
1368 0 : nsCOMPtr<nsIDocShellTreeItem> item;
1369 0 : docShell->GetChildAt(i, getter_AddRefs(item));
1370 :
1371 0 : nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(item));
1372 :
1373 0 : if (docShell) {
1374 0 : nsCOMPtr<nsIContentViewer> cv;
1375 0 : docShell->GetContentViewer(getter_AddRefs(cv));
1376 :
1377 0 : if (cv) {
1378 0 : cv->PermitUnloadInternal(aShouldPrompt, aPermitUnload);
1379 : }
1380 : }
1381 : }
1382 : }
1383 :
1384 5 : return NS_OK;
1385 : }
1386 :
1387 : NS_IMETHODIMP
1388 10 : nsDocumentViewer::GetBeforeUnloadFiring(bool* aInEvent)
1389 : {
1390 10 : *aInEvent = mInPermitUnload;
1391 10 : return NS_OK;
1392 : }
1393 :
1394 : NS_IMETHODIMP
1395 0 : nsDocumentViewer::GetInPermitUnload(bool* aInEvent)
1396 : {
1397 0 : *aInEvent = mInPermitUnloadPrompt;
1398 0 : return NS_OK;
1399 : }
1400 :
1401 : NS_IMETHODIMP
1402 4 : nsDocumentViewer::PageHide(bool aIsUnload)
1403 : {
1404 8 : AutoDontWarnAboutSyncXHR disableSyncXHRWarning;
1405 :
1406 4 : mHidden = true;
1407 :
1408 4 : if (!mDocument) {
1409 0 : return NS_ERROR_NULL_POINTER;
1410 : }
1411 :
1412 4 : if (aIsUnload) {
1413 : // Poke the GC. The window might be collectable garbage now.
1414 4 : nsJSContext::PokeGC(JS::gcreason::PAGE_HIDE,
1415 4 : mDocument->GetWrapperPreserveColor(),
1416 4 : NS_GC_DELAY * 2);
1417 : }
1418 :
1419 4 : mDocument->OnPageHide(!aIsUnload, nullptr);
1420 :
1421 : // inform the window so that the focus state is reset.
1422 4 : NS_ENSURE_STATE(mDocument);
1423 4 : nsPIDOMWindowOuter* window = mDocument->GetWindow();
1424 4 : if (window)
1425 4 : window->PageHidden();
1426 :
1427 4 : if (aIsUnload) {
1428 : // if Destroy() was called during OnPageHide(), mDocument is nullptr.
1429 4 : NS_ENSURE_STATE(mDocument);
1430 :
1431 : // First, get the window from the document...
1432 4 : nsPIDOMWindowOuter* window = mDocument->GetWindow();
1433 :
1434 4 : if (!window) {
1435 : // Fail if no window is available...
1436 0 : NS_WARNING("window not set for document!");
1437 0 : return NS_ERROR_NULL_POINTER;
1438 : }
1439 :
1440 : // Now, fire an Unload event to the document...
1441 4 : nsEventStatus status = nsEventStatus_eIgnore;
1442 8 : WidgetEvent event(true, eUnload);
1443 4 : event.mFlags.mBubbles = false;
1444 : // XXX Dispatching to |window|, but using |document| as the target.
1445 4 : event.mTarget = mDocument;
1446 :
1447 : // Never permit popups from the unload handler, no matter how we get
1448 : // here.
1449 8 : nsAutoPopupStatePusher popupStatePusher(openAbused, true);
1450 :
1451 8 : nsIDocument::PageUnloadingEventTimeStamp timestamp(mDocument);
1452 :
1453 4 : EventDispatcher::Dispatch(window, mPresContext, &event, nullptr, &status);
1454 : }
1455 :
1456 : #ifdef MOZ_XUL
1457 : // look for open menupopups and close them after the unload event, in case
1458 : // the unload event listeners open any new popups
1459 4 : nsContentUtils::HidePopupsInDocument(mDocument);
1460 : #endif
1461 :
1462 4 : return NS_OK;
1463 : }
1464 :
1465 : static void
1466 0 : AttachContainerRecurse(nsIDocShell* aShell)
1467 : {
1468 0 : nsCOMPtr<nsIContentViewer> viewer;
1469 0 : aShell->GetContentViewer(getter_AddRefs(viewer));
1470 0 : if (viewer) {
1471 0 : viewer->SetIsHidden(false);
1472 0 : nsIDocument* doc = viewer->GetDocument();
1473 0 : if (doc) {
1474 0 : doc->SetContainer(static_cast<nsDocShell*>(aShell));
1475 : }
1476 0 : RefPtr<nsPresContext> pc;
1477 0 : viewer->GetPresContext(getter_AddRefs(pc));
1478 0 : if (pc) {
1479 0 : pc->SetContainer(static_cast<nsDocShell*>(aShell));
1480 0 : nsCOMPtr<nsILinkHandler> handler = do_QueryInterface(aShell);
1481 0 : pc->SetLinkHandler(handler);
1482 : }
1483 0 : nsCOMPtr<nsIPresShell> presShell;
1484 0 : viewer->GetPresShell(getter_AddRefs(presShell));
1485 0 : if (presShell) {
1486 0 : presShell->SetForwardingContainer(WeakPtr<nsDocShell>());
1487 : }
1488 : }
1489 :
1490 : // Now recurse through the children
1491 : int32_t childCount;
1492 0 : aShell->GetChildCount(&childCount);
1493 0 : for (int32_t i = 0; i < childCount; ++i) {
1494 0 : nsCOMPtr<nsIDocShellTreeItem> childItem;
1495 0 : aShell->GetChildAt(i, getter_AddRefs(childItem));
1496 0 : nsCOMPtr<nsIDocShell> shell = do_QueryInterface(childItem);
1497 0 : AttachContainerRecurse(shell);
1498 : }
1499 0 : }
1500 :
1501 : NS_IMETHODIMP
1502 21 : nsDocumentViewer::Open(nsISupports *aState, nsISHEntry *aSHEntry)
1503 : {
1504 21 : NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);
1505 :
1506 21 : if (mDocument)
1507 21 : mDocument->SetContainer(mContainer);
1508 :
1509 21 : nsresult rv = InitInternal(mParentWidget, aState, mBounds, false);
1510 21 : NS_ENSURE_SUCCESS(rv, rv);
1511 :
1512 21 : mHidden = false;
1513 :
1514 21 : if (mPresShell)
1515 21 : mPresShell->SetForwardingContainer(WeakPtr<nsDocShell>());
1516 :
1517 : // Rehook the child presentations. The child shells are still in
1518 : // session history, so get them from there.
1519 :
1520 21 : if (aSHEntry) {
1521 0 : nsCOMPtr<nsIDocShellTreeItem> item;
1522 0 : int32_t itemIndex = 0;
1523 0 : while (NS_SUCCEEDED(aSHEntry->ChildShellAt(itemIndex++,
1524 0 : getter_AddRefs(item))) && item) {
1525 0 : nsCOMPtr<nsIDocShell> shell = do_QueryInterface(item);
1526 0 : AttachContainerRecurse(shell);
1527 : }
1528 : }
1529 :
1530 21 : SyncParentSubDocMap();
1531 :
1532 21 : if (mFocusListener && mDocument) {
1533 63 : mDocument->AddEventListener(NS_LITERAL_STRING("focus"), mFocusListener,
1534 63 : false, false);
1535 63 : mDocument->AddEventListener(NS_LITERAL_STRING("blur"), mFocusListener,
1536 63 : false, false);
1537 : }
1538 :
1539 : // XXX re-enable image animations once that works correctly
1540 :
1541 21 : PrepareToStartLoad();
1542 :
1543 : // When loading a page from the bfcache with puppet widgets, we do the
1544 : // widget attachment here (it is otherwise done in MakeWindow, which is
1545 : // called for non-bfcache pages in the history, but not bfcache pages).
1546 : // Attachment is necessary, since we get detached when another page
1547 : // is browsed to. That is, if we are one page A, then when we go to
1548 : // page B, we detach. So page A's view has no widget. If we then go
1549 : // back to it, and it is in the bfcache, we will use that view, which
1550 : // doesn't have a widget. The attach call here will properly attach us.
1551 21 : if (nsIWidget::UsePuppetWidgets() && mPresContext &&
1552 0 : ShouldAttachToTopLevel()) {
1553 : // If the old view is already attached to our parent, detach
1554 0 : DetachFromTopLevelWidget();
1555 :
1556 0 : nsViewManager *vm = GetViewManager();
1557 0 : MOZ_ASSERT(vm, "no view manager");
1558 0 : nsView* v = vm->GetRootView();
1559 0 : MOZ_ASSERT(v, "no root view");
1560 0 : MOZ_ASSERT(mParentWidget, "no mParentWidget to set");
1561 0 : v->AttachToTopLevelWidget(mParentWidget);
1562 :
1563 0 : mAttachedToParent = true;
1564 : }
1565 :
1566 21 : return NS_OK;
1567 : }
1568 :
1569 : NS_IMETHODIMP
1570 4 : nsDocumentViewer::Close(nsISHEntry *aSHEntry)
1571 : {
1572 : // All callers are supposed to call close to break circular
1573 : // references. If we do this stuff in the destructor, the
1574 : // destructor might never be called (especially if we're being
1575 : // used from JS.
1576 :
1577 4 : mSHEntry = aSHEntry;
1578 :
1579 : // Close is also needed to disable scripts during paint suppression,
1580 : // since we transfer the existing global object to the new document
1581 : // that is loaded. In the future, the global object may become a proxy
1582 : // for an object that can be switched in and out so that we don't need
1583 : // to disable scripts during paint suppression.
1584 :
1585 4 : if (!mDocument)
1586 0 : return NS_OK;
1587 :
1588 : #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
1589 : // Turn scripting back on
1590 : // after PrintPreview had turned it off
1591 4 : if (GetIsPrintPreview() && mPrintEngine) {
1592 0 : mPrintEngine->TurnScriptingOn(true);
1593 : }
1594 : #endif
1595 :
1596 : #ifdef NS_PRINTING
1597 : // A Close was called while we were printing
1598 : // so don't clear the ScriptGlobalObject
1599 : // or clear the mDocument below
1600 4 : if (mPrintEngine && !mClosingWhilePrinting) {
1601 0 : mClosingWhilePrinting = true;
1602 : } else
1603 : #endif
1604 : {
1605 : // out of band cleanup of docshell
1606 4 : mDocument->SetScriptGlobalObject(nullptr);
1607 :
1608 4 : if (!mSHEntry && mDocument)
1609 4 : mDocument->RemovedFromDocShell();
1610 : }
1611 :
1612 4 : if (mFocusListener) {
1613 4 : mFocusListener->Disconnect();
1614 4 : if (mDocument) {
1615 16 : mDocument->RemoveEventListener(NS_LITERAL_STRING("focus"), mFocusListener,
1616 12 : false);
1617 16 : mDocument->RemoveEventListener(NS_LITERAL_STRING("blur"), mFocusListener,
1618 12 : false);
1619 : }
1620 : }
1621 :
1622 4 : return NS_OK;
1623 : }
1624 :
1625 : static void
1626 0 : DetachContainerRecurse(nsIDocShell *aShell)
1627 : {
1628 : // Unhook this docshell's presentation
1629 0 : nsCOMPtr<nsIContentViewer> viewer;
1630 0 : aShell->GetContentViewer(getter_AddRefs(viewer));
1631 0 : if (viewer) {
1632 0 : nsIDocument* doc = viewer->GetDocument();
1633 0 : if (doc) {
1634 0 : doc->SetContainer(nullptr);
1635 : }
1636 0 : RefPtr<nsPresContext> pc;
1637 0 : viewer->GetPresContext(getter_AddRefs(pc));
1638 0 : if (pc) {
1639 0 : pc->Detach();
1640 : }
1641 0 : nsCOMPtr<nsIPresShell> presShell;
1642 0 : viewer->GetPresShell(getter_AddRefs(presShell));
1643 0 : if (presShell) {
1644 0 : auto weakShell = static_cast<nsDocShell*>(aShell);
1645 0 : presShell->SetForwardingContainer(weakShell);
1646 : }
1647 : }
1648 :
1649 : // Now recurse through the children
1650 : int32_t childCount;
1651 0 : aShell->GetChildCount(&childCount);
1652 0 : for (int32_t i = 0; i < childCount; ++i) {
1653 0 : nsCOMPtr<nsIDocShellTreeItem> childItem;
1654 0 : aShell->GetChildAt(i, getter_AddRefs(childItem));
1655 0 : nsCOMPtr<nsIDocShell> shell = do_QueryInterface(childItem);
1656 0 : DetachContainerRecurse(shell);
1657 : }
1658 0 : }
1659 :
1660 : NS_IMETHODIMP
1661 4 : nsDocumentViewer::Destroy()
1662 : {
1663 4 : NS_ASSERTION(mDocument, "No document in Destroy()!");
1664 :
1665 : #ifdef NS_PRINTING
1666 : // Here is where we check to see if the document was still being prepared
1667 : // for printing when it was asked to be destroy from someone externally
1668 : // This usually happens if the document is unloaded while the user is in the
1669 : // Print Dialog
1670 : //
1671 : // So we flip the bool to remember that the document is going away
1672 : // and we can clean up and abort later after returning from the Print Dialog
1673 4 : if (mPrintEngine) {
1674 0 : if (mPrintEngine->CheckBeforeDestroy()) {
1675 0 : return NS_OK;
1676 : }
1677 : }
1678 : // Dispatch the 'afterprint' event now, if pending:
1679 4 : mAutoBeforeAndAfterPrint = nullptr;
1680 : #endif
1681 :
1682 : // Don't let the document get unloaded while we are printing.
1683 : // this could happen if we hit the back button during printing.
1684 : // We also keep the viewer from being cached in session history, since
1685 : // we require all documents there to be sanitized.
1686 4 : if (mDestroyRefCount != 0) {
1687 0 : --mDestroyRefCount;
1688 0 : return NS_OK;
1689 : }
1690 :
1691 : // If we were told to put ourselves into session history instead of destroy
1692 : // the presentation, do that now.
1693 4 : if (mSHEntry) {
1694 0 : if (mPresShell)
1695 0 : mPresShell->Freeze();
1696 :
1697 : // Make sure the presentation isn't torn down by Hide().
1698 0 : mSHEntry->SetSticky(mIsSticky);
1699 0 : mIsSticky = true;
1700 :
1701 0 : bool savePresentation = mDocument ? mDocument->IsBFCachingAllowed() : true;
1702 :
1703 : // Remove our root view from the view hierarchy.
1704 0 : if (mPresShell) {
1705 0 : nsViewManager *vm = mPresShell->GetViewManager();
1706 0 : if (vm) {
1707 0 : nsView *rootView = vm->GetRootView();
1708 :
1709 0 : if (rootView) {
1710 0 : nsView *rootViewParent = rootView->GetParent();
1711 0 : if (rootViewParent) {
1712 0 : nsViewManager *parentVM = rootViewParent->GetViewManager();
1713 0 : if (parentVM) {
1714 0 : parentVM->RemoveChild(rootView);
1715 : }
1716 : }
1717 : }
1718 : }
1719 : }
1720 :
1721 0 : Hide();
1722 :
1723 : // This is after Hide() so that the user doesn't see the inputs clear.
1724 0 : if (mDocument) {
1725 0 : mDocument->Sanitize();
1726 : }
1727 :
1728 : // Reverse ownership. Do this *after* calling sanitize so that sanitize
1729 : // doesn't cause mutations that make the SHEntry drop the presentation
1730 :
1731 : // Grab a reference to mSHEntry before calling into things like
1732 : // SyncPresentationState that might mess with our members.
1733 0 : nsCOMPtr<nsISHEntry> shEntry = mSHEntry; // we'll need this below
1734 0 : mSHEntry = nullptr;
1735 :
1736 0 : if (savePresentation) {
1737 0 : shEntry->SetContentViewer(this);
1738 : }
1739 :
1740 : // Always sync the presentation state. That way even if someone screws up
1741 : // and shEntry has no window state at this point we'll be ok; we just won't
1742 : // cache ourselves.
1743 0 : shEntry->SyncPresentationState();
1744 :
1745 : // Shut down accessibility for the document before we start to tear it down.
1746 : #ifdef ACCESSIBILITY
1747 0 : if (mPresShell) {
1748 0 : a11y::DocAccessible* docAcc = mPresShell->GetDocAccessible();
1749 0 : if (docAcc) {
1750 0 : docAcc->Shutdown();
1751 : }
1752 : }
1753 : #endif
1754 :
1755 : // Break the link from the document/presentation to the docshell, so that
1756 : // link traversals cannot affect the currently-loaded document.
1757 : // When the presentation is restored, Open() and InitInternal() will reset
1758 : // these pointers to their original values.
1759 :
1760 0 : if (mDocument) {
1761 0 : mDocument->SetContainer(nullptr);
1762 : }
1763 0 : if (mPresContext) {
1764 0 : mPresContext->Detach();
1765 : }
1766 0 : if (mPresShell) {
1767 0 : mPresShell->SetForwardingContainer(mContainer);
1768 : }
1769 :
1770 : // Do the same for our children. Note that we need to get the child
1771 : // docshells from the SHEntry now; the docshell will have cleared them.
1772 0 : nsCOMPtr<nsIDocShellTreeItem> item;
1773 0 : int32_t itemIndex = 0;
1774 0 : while (NS_SUCCEEDED(shEntry->ChildShellAt(itemIndex++,
1775 0 : getter_AddRefs(item))) && item) {
1776 0 : nsCOMPtr<nsIDocShell> shell = do_QueryInterface(item);
1777 0 : DetachContainerRecurse(shell);
1778 : }
1779 :
1780 0 : return NS_OK;
1781 : }
1782 :
1783 : // The document was not put in the bfcache
1784 :
1785 : // Protect against pres shell destruction running scripts and re-entrantly
1786 : // creating a new presentation.
1787 8 : nsAutoScriptBlocker scriptBlocker;
1788 :
1789 4 : if (mPresShell) {
1790 3 : DestroyPresShell();
1791 : }
1792 4 : if (mDocument) {
1793 4 : mDocument->Destroy();
1794 4 : mDocument = nullptr;
1795 : }
1796 :
1797 : // All callers are supposed to call destroy to break circular
1798 : // references. If we do this stuff in the destructor, the
1799 : // destructor might never be called (especially if we're being
1800 : // used from JS.
1801 :
1802 : #ifdef NS_PRINTING
1803 4 : if (mPrintEngine) {
1804 0 : RefPtr<nsPrintEngine> printEngine = mozilla::Move(mPrintEngine);
1805 : #ifdef NS_PRINT_PREVIEW
1806 : bool doingPrintPreview;
1807 0 : printEngine->GetDoingPrintPreview(&doingPrintPreview);
1808 0 : if (doingPrintPreview) {
1809 0 : printEngine->FinishPrintPreview();
1810 : }
1811 : #endif
1812 0 : printEngine->Destroy();
1813 0 : MOZ_ASSERT(!mPrintEngine,
1814 : "mPrintEngine shouldn't be recreated while destroying it");
1815 : }
1816 : #endif
1817 :
1818 : // Avoid leaking the old viewer.
1819 4 : if (mPreviousViewer) {
1820 0 : mPreviousViewer->Destroy();
1821 0 : mPreviousViewer = nullptr;
1822 : }
1823 :
1824 4 : mDeviceContext = nullptr;
1825 :
1826 4 : if (mPresContext) {
1827 3 : DestroyPresContext();
1828 : }
1829 :
1830 4 : mWindow = nullptr;
1831 4 : mViewManager = nullptr;
1832 4 : mContainer = WeakPtr<nsDocShell>();
1833 :
1834 4 : mDestroyWasFull = true;
1835 :
1836 4 : return NS_OK;
1837 : }
1838 :
1839 : NS_IMETHODIMP
1840 4 : nsDocumentViewer::Stop(void)
1841 : {
1842 4 : NS_ASSERTION(mDocument, "Stop called too early or too late");
1843 4 : if (mDocument) {
1844 4 : mDocument->StopDocumentLoad();
1845 : }
1846 :
1847 4 : if (!mHidden && (mLoaded || mStopped) && mPresContext && !mSHEntry)
1848 0 : mPresContext->SetImageAnimationMode(imgIContainer::kDontAnimMode);
1849 :
1850 4 : mStopped = true;
1851 :
1852 4 : if (!mLoaded && mPresShell) {
1853 : // Well, we might as well paint what we have so far.
1854 4 : nsCOMPtr<nsIPresShell> shell(mPresShell); // bug 378682
1855 2 : shell->UnsuppressPainting();
1856 : }
1857 :
1858 4 : return NS_OK;
1859 : }
1860 :
1861 : NS_IMETHODIMP
1862 403 : nsDocumentViewer::GetDOMDocument(nsIDOMDocument **aResult)
1863 : {
1864 403 : NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
1865 403 : return CallQueryInterface(mDocument, aResult);
1866 : }
1867 :
1868 : NS_IMETHODIMP_(nsIDocument *)
1869 2573 : nsDocumentViewer::GetDocument()
1870 : {
1871 2573 : return mDocument;
1872 : }
1873 :
1874 : NS_IMETHODIMP
1875 0 : nsDocumentViewer::SetDOMDocument(nsIDOMDocument *aDocument)
1876 : {
1877 : // Assumptions:
1878 : //
1879 : // 1) this document viewer has been initialized with a call to Init().
1880 : // 2) the stylesheets associated with the document have been added
1881 : // to the document.
1882 :
1883 : // XXX Right now, this method assumes that the layout of the current
1884 : // document hasn't started yet. More cleanup will probably be
1885 : // necessary to make this method work for the case when layout *has*
1886 : // occurred for the current document.
1887 : // That work can happen when and if it is needed.
1888 :
1889 0 : if (!aDocument)
1890 0 : return NS_ERROR_NULL_POINTER;
1891 :
1892 0 : nsCOMPtr<nsIDocument> newDoc = do_QueryInterface(aDocument);
1893 0 : NS_ENSURE_TRUE(newDoc, NS_ERROR_UNEXPECTED);
1894 :
1895 0 : return SetDocumentInternal(newDoc, false);
1896 : }
1897 :
1898 : NS_IMETHODIMP
1899 0 : nsDocumentViewer::SetDocumentInternal(nsIDocument* aDocument,
1900 : bool aForceReuseInnerWindow)
1901 : {
1902 0 : MOZ_ASSERT(aDocument);
1903 :
1904 : // Set new container
1905 0 : aDocument->SetContainer(mContainer);
1906 :
1907 0 : if (mDocument != aDocument) {
1908 0 : if (aForceReuseInnerWindow) {
1909 : // Transfer the navigation timing information to the new document, since
1910 : // we're keeping the same inner and hence should really have the same
1911 : // timing information.
1912 0 : aDocument->SetNavigationTiming(mDocument->GetNavigationTiming());
1913 : }
1914 :
1915 0 : if (mDocument->IsStaticDocument()) {
1916 0 : mDocument->Destroy();
1917 : }
1918 :
1919 : // Clear the list of old child docshells. Child docshells for the new
1920 : // document will be constructed as frames are created.
1921 0 : if (!aDocument->IsStaticDocument()) {
1922 0 : nsCOMPtr<nsIDocShell> node(mContainer);
1923 0 : if (node) {
1924 : int32_t count;
1925 0 : node->GetChildCount(&count);
1926 0 : for (int32_t i = 0; i < count; ++i) {
1927 0 : nsCOMPtr<nsIDocShellTreeItem> child;
1928 0 : node->GetChildAt(0, getter_AddRefs(child));
1929 0 : node->RemoveChild(child);
1930 : }
1931 : }
1932 : }
1933 :
1934 : // Replace the old document with the new one. Do this only when
1935 : // the new document really is a new document.
1936 0 : mDocument = aDocument;
1937 :
1938 : // Set the script global object on the new document
1939 : nsCOMPtr<nsPIDOMWindowOuter> window =
1940 0 : mContainer ? mContainer->GetWindow() : nullptr;
1941 0 : if (window) {
1942 0 : nsresult rv = window->SetNewDocument(aDocument, nullptr,
1943 0 : aForceReuseInnerWindow);
1944 0 : if (NS_FAILED(rv)) {
1945 0 : Destroy();
1946 0 : return rv;
1947 : }
1948 : }
1949 : }
1950 :
1951 0 : nsresult rv = SyncParentSubDocMap();
1952 0 : NS_ENSURE_SUCCESS(rv, rv);
1953 :
1954 : // Replace the current pres shell with a new shell for the new document
1955 :
1956 : // Protect against pres shell destruction running scripts and re-entrantly
1957 : // creating a new presentation.
1958 0 : nsAutoScriptBlocker scriptBlocker;
1959 :
1960 0 : if (mPresShell) {
1961 0 : DestroyPresShell();
1962 : }
1963 :
1964 0 : if (mPresContext) {
1965 0 : DestroyPresContext();
1966 :
1967 0 : mWindow = nullptr;
1968 0 : rv = InitInternal(mParentWidget, nullptr, mBounds, true, true, false);
1969 : }
1970 :
1971 0 : return rv;
1972 : }
1973 :
1974 : nsIPresShell*
1975 89 : nsDocumentViewer::GetPresShell()
1976 : {
1977 89 : return mPresShell;
1978 : }
1979 :
1980 : nsPresContext*
1981 89 : nsDocumentViewer::GetPresContext()
1982 : {
1983 89 : return mPresContext;
1984 : }
1985 :
1986 : nsViewManager*
1987 0 : nsDocumentViewer::GetViewManager()
1988 : {
1989 0 : return mViewManager;
1990 : }
1991 :
1992 : NS_IMETHODIMP
1993 89 : nsDocumentViewer::GetPresShell(nsIPresShell** aResult)
1994 : {
1995 89 : nsIPresShell* shell = GetPresShell();
1996 89 : NS_IF_ADDREF(*aResult = shell);
1997 89 : return NS_OK;
1998 : }
1999 :
2000 : NS_IMETHODIMP
2001 50 : nsDocumentViewer::GetPresContext(nsPresContext** aResult)
2002 : {
2003 50 : nsPresContext* pc = GetPresContext();
2004 50 : NS_IF_ADDREF(*aResult = pc);
2005 50 : return NS_OK;
2006 : }
2007 :
2008 : NS_IMETHODIMP
2009 19 : nsDocumentViewer::GetBounds(nsIntRect& aResult)
2010 : {
2011 19 : NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
2012 19 : aResult = mBounds;
2013 19 : return NS_OK;
2014 : }
2015 :
2016 : NS_IMETHODIMP
2017 8 : nsDocumentViewer::GetPreviousViewer(nsIContentViewer** aViewer)
2018 : {
2019 8 : *aViewer = mPreviousViewer;
2020 8 : NS_IF_ADDREF(*aViewer);
2021 8 : return NS_OK;
2022 : }
2023 :
2024 : NS_IMETHODIMP
2025 3 : nsDocumentViewer::SetPreviousViewer(nsIContentViewer* aViewer)
2026 : {
2027 : // NOTE: |Show| sets |mPreviousViewer| to null without calling this
2028 : // function.
2029 :
2030 3 : if (aViewer) {
2031 3 : NS_ASSERTION(!mPreviousViewer,
2032 : "can't set previous viewer when there already is one");
2033 :
2034 : // In a multiple chaining situation (which occurs when running a thrashing
2035 : // test like i-bench or jrgm's tests with no delay), we can build up a
2036 : // whole chain of viewers. In order to avoid this, we always set our previous
2037 : // viewer to the MOST previous viewer in the chain, and then dump the intermediate
2038 : // link from the chain. This ensures that at most only 2 documents are alive
2039 : // and undestroyed at any given time (the one that is showing and the one that
2040 : // is loading with painting suppressed).
2041 : // It's very important that if this ever gets changed the code
2042 : // before the RestorePresentation call in nsDocShell::InternalLoad
2043 : // be changed accordingly.
2044 6 : nsCOMPtr<nsIContentViewer> prevViewer;
2045 3 : aViewer->GetPreviousViewer(getter_AddRefs(prevViewer));
2046 3 : if (prevViewer) {
2047 0 : aViewer->SetPreviousViewer(nullptr);
2048 0 : aViewer->Destroy();
2049 0 : return SetPreviousViewer(prevViewer);
2050 : }
2051 : }
2052 :
2053 3 : mPreviousViewer = aViewer;
2054 3 : return NS_OK;
2055 : }
2056 :
2057 : NS_IMETHODIMP
2058 24 : nsDocumentViewer::SetBoundsWithFlags(const nsIntRect& aBounds, uint32_t aFlags)
2059 : {
2060 24 : NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
2061 :
2062 24 : mBounds = aBounds;
2063 :
2064 24 : if (mWindow && !mAttachedToParent) {
2065 : // Resize the widget, but don't trigger repaint. Layout will generate
2066 : // repaint requests during reflow.
2067 0 : mWindow->Resize(aBounds.x, aBounds.y,
2068 0 : aBounds.width, aBounds.height,
2069 0 : false);
2070 24 : } else if (mPresContext && mViewManager) {
2071 : // Ensure presContext's deviceContext is up to date, as we sometimes get
2072 : // here before a resolution-change notification has been fully handled
2073 : // during display configuration changes, especially when there are lots
2074 : // of windows/widgets competing to handle the notifications.
2075 : // (See bug 1154125.)
2076 24 : if (mPresContext->DeviceContext()->CheckDPIChange()) {
2077 1 : mPresContext->UIResolutionChanged();
2078 : }
2079 24 : int32_t p2a = mPresContext->AppUnitsPerDevPixel();
2080 24 : mViewManager->SetWindowDimensions(NSIntPixelsToAppUnits(mBounds.width, p2a),
2081 : NSIntPixelsToAppUnits(mBounds.height, p2a),
2082 48 : !!(aFlags & nsIContentViewer::eDelayResize));
2083 : }
2084 :
2085 : // If there's a previous viewer, it's the one that's actually showing,
2086 : // so be sure to resize it as well so it paints over the right area.
2087 : // This may slow down the performance of the new page load, but resize
2088 : // during load is also probably a relatively unusual condition
2089 : // relating to things being hidden while something is loaded. It so
2090 : // happens that Firefox does this a good bit with its infobar, and it
2091 : // looks ugly if we don't do this.
2092 24 : if (mPreviousViewer) {
2093 0 : nsCOMPtr<nsIContentViewer> previousViewer = mPreviousViewer;
2094 0 : previousViewer->SetBounds(aBounds);
2095 : }
2096 :
2097 24 : return NS_OK;
2098 : }
2099 :
2100 : NS_IMETHODIMP
2101 18 : nsDocumentViewer::SetBounds(const nsIntRect& aBounds)
2102 : {
2103 18 : return SetBoundsWithFlags(aBounds, 0);
2104 : }
2105 :
2106 : NS_IMETHODIMP
2107 0 : nsDocumentViewer::Move(int32_t aX, int32_t aY)
2108 : {
2109 0 : NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
2110 0 : mBounds.MoveTo(aX, aY);
2111 0 : if (mWindow) {
2112 0 : mWindow->Move(aX, aY);
2113 : }
2114 0 : return NS_OK;
2115 : }
2116 :
2117 : NS_IMETHODIMP
2118 5 : nsDocumentViewer::Show(void)
2119 : {
2120 5 : NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
2121 :
2122 : // We don't need the previous viewer anymore since we're not
2123 : // displaying it.
2124 5 : if (mPreviousViewer) {
2125 : // This little dance *may* only be to keep
2126 : // PresShell::EndObservingDocument happy, but I'm not sure.
2127 6 : nsCOMPtr<nsIContentViewer> prevViewer(mPreviousViewer);
2128 3 : mPreviousViewer = nullptr;
2129 3 : prevViewer->Destroy();
2130 :
2131 : // Make sure we don't have too many cached ContentViewers
2132 6 : nsCOMPtr<nsIDocShellTreeItem> treeItem(mContainer);
2133 3 : if (treeItem) {
2134 : // We need to find the root DocShell since only that object has an
2135 : // SHistory and we need the SHistory to evict content viewers
2136 6 : nsCOMPtr<nsIDocShellTreeItem> root;
2137 3 : treeItem->GetSameTypeRootTreeItem(getter_AddRefs(root));
2138 6 : nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(root);
2139 6 : nsCOMPtr<nsISHistory> history;
2140 3 : webNav->GetSessionHistory(getter_AddRefs(history));
2141 6 : nsCOMPtr<nsISHistoryInternal> historyInt = do_QueryInterface(history);
2142 3 : if (historyInt) {
2143 : int32_t prevIndex,loadedIndex;
2144 2 : nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(treeItem);
2145 1 : docShell->GetPreviousTransIndex(&prevIndex);
2146 1 : docShell->GetLoadedTransIndex(&loadedIndex);
2147 : #ifdef DEBUG_PAGE_CACHE
2148 : printf("About to evict content viewers: prev=%d, loaded=%d\n",
2149 : prevIndex, loadedIndex);
2150 : #endif
2151 1 : historyInt->EvictOutOfRangeContentViewers(loadedIndex);
2152 : }
2153 : }
2154 : }
2155 :
2156 5 : if (mWindow) {
2157 : // When attached to a top level xul window, we do not need to call
2158 : // Show on the widget. Underlying window management code handles
2159 : // this when the window is initialized.
2160 5 : if (!mAttachedToParent) {
2161 0 : mWindow->Show(true);
2162 : }
2163 : }
2164 :
2165 : // Hold on to the document so we can use it after the script blocker below
2166 : // has been released (which might re-entrantly call into other
2167 : // nsDocumentViewer methods).
2168 10 : nsCOMPtr<nsIDocument> document = mDocument;
2169 :
2170 5 : if (mDocument && !mPresShell) {
2171 : // The InitPresentationStuff call below requires a script blocker, because
2172 : // its PresShell::Initialize call can cause scripts to run and therefore
2173 : // re-entrant calls to nsDocumentViewer methods to be made.
2174 0 : nsAutoScriptBlocker scriptBlocker;
2175 :
2176 0 : NS_ASSERTION(!mWindow, "Window already created but no presshell?");
2177 :
2178 0 : nsCOMPtr<nsIBaseWindow> base_win(mContainer);
2179 0 : if (base_win) {
2180 0 : base_win->GetParentWidget(&mParentWidget);
2181 0 : if (mParentWidget) {
2182 0 : mParentWidget->Release(); // GetParentWidget AddRefs, but mParentWidget is weak
2183 : }
2184 : }
2185 :
2186 0 : nsView* containerView = FindContainerView();
2187 :
2188 0 : nsresult rv = CreateDeviceContext(containerView);
2189 0 : NS_ENSURE_SUCCESS(rv, rv);
2190 :
2191 : // Create presentation context
2192 0 : NS_ASSERTION(!mPresContext, "Shouldn't have a prescontext if we have no shell!");
2193 : mPresContext = CreatePresContext(mDocument,
2194 0 : nsPresContext::eContext_Galley, containerView);
2195 0 : NS_ENSURE_TRUE(mPresContext, NS_ERROR_OUT_OF_MEMORY);
2196 :
2197 0 : rv = mPresContext->Init(mDeviceContext);
2198 0 : if (NS_FAILED(rv)) {
2199 0 : mPresContext = nullptr;
2200 0 : return rv;
2201 : }
2202 :
2203 0 : rv = MakeWindow(nsSize(mPresContext->DevPixelsToAppUnits(mBounds.width),
2204 : mPresContext->DevPixelsToAppUnits(mBounds.height)),
2205 0 : containerView);
2206 0 : if (NS_FAILED(rv))
2207 0 : return rv;
2208 :
2209 0 : if (mPresContext && base_win) {
2210 0 : nsCOMPtr<nsILinkHandler> linkHandler(do_GetInterface(base_win));
2211 :
2212 0 : if (linkHandler) {
2213 0 : mPresContext->SetLinkHandler(linkHandler);
2214 : }
2215 :
2216 0 : mPresContext->SetContainer(mContainer);
2217 : }
2218 :
2219 0 : if (mPresContext) {
2220 0 : Hide();
2221 :
2222 0 : rv = InitPresentationStuff(mDocument->MayStartLayout());
2223 : }
2224 :
2225 : // If we get here the document load has already started and the
2226 : // window is shown because some JS on the page caused it to be
2227 : // shown...
2228 :
2229 0 : if (mPresShell) {
2230 0 : nsCOMPtr<nsIPresShell> shell(mPresShell); // bug 378682
2231 0 : shell->UnsuppressPainting();
2232 : }
2233 : }
2234 :
2235 : // Notify observers that a new page has been shown. This will get run
2236 : // from the event loop after we actually draw the page.
2237 : RefPtr<nsDocumentShownDispatcher> event =
2238 15 : new nsDocumentShownDispatcher(document);
2239 15 : document->Dispatch("nsDocumentShownDispatcher",
2240 : TaskCategory::Other,
2241 15 : event.forget());
2242 :
2243 5 : return NS_OK;
2244 : }
2245 :
2246 : NS_IMETHODIMP
2247 29 : nsDocumentViewer::Hide(void)
2248 : {
2249 29 : if (!mAttachedToParent && mWindow) {
2250 0 : mWindow->Show(false);
2251 : }
2252 :
2253 29 : if (!mPresShell)
2254 28 : return NS_OK;
2255 :
2256 1 : NS_ASSERTION(mPresContext, "Can't have a presshell and no prescontext!");
2257 :
2258 : // Avoid leaking the old viewer.
2259 1 : if (mPreviousViewer) {
2260 0 : mPreviousViewer->Destroy();
2261 0 : mPreviousViewer = nullptr;
2262 : }
2263 :
2264 1 : if (mIsSticky) {
2265 : // This window is sticky, that means that it might be shown again
2266 : // and we don't want the presshell n' all that to be thrown away
2267 : // just because the window is hidden.
2268 :
2269 0 : return NS_OK;
2270 : }
2271 :
2272 2 : nsCOMPtr<nsIDocShell> docShell(mContainer);
2273 1 : if (docShell) {
2274 : #ifdef DEBUG
2275 2 : nsCOMPtr<nsIContentViewer> currentViewer;
2276 1 : docShell->GetContentViewer(getter_AddRefs(currentViewer));
2277 1 : MOZ_ASSERT(currentViewer == this);
2278 : #endif
2279 2 : nsCOMPtr<nsILayoutHistoryState> layoutState;
2280 1 : mPresShell->CaptureHistoryState(getter_AddRefs(layoutState));
2281 : }
2282 :
2283 : // Do not run ScriptRunners queued by DestroyPresShell() in the intermediate
2284 : // state before we're done destroying PresShell, PresContext, ViewManager, etc.
2285 2 : nsAutoScriptBlocker scriptBlocker;
2286 :
2287 1 : DestroyPresShell();
2288 :
2289 1 : DestroyPresContext();
2290 :
2291 1 : mViewManager = nullptr;
2292 1 : mWindow = nullptr;
2293 1 : mDeviceContext = nullptr;
2294 1 : mParentWidget = nullptr;
2295 :
2296 2 : nsCOMPtr<nsIBaseWindow> base_win(mContainer);
2297 :
2298 1 : if (base_win && !mAttachedToParent) {
2299 1 : base_win->SetParentWidget(nullptr);
2300 : }
2301 :
2302 1 : return NS_OK;
2303 : }
2304 :
2305 : NS_IMETHODIMP
2306 0 : nsDocumentViewer::GetSticky(bool *aSticky)
2307 : {
2308 0 : *aSticky = mIsSticky;
2309 :
2310 0 : return NS_OK;
2311 : }
2312 :
2313 : NS_IMETHODIMP
2314 1 : nsDocumentViewer::SetSticky(bool aSticky)
2315 : {
2316 1 : mIsSticky = aSticky;
2317 :
2318 1 : return NS_OK;
2319 : }
2320 :
2321 : NS_IMETHODIMP
2322 0 : nsDocumentViewer::RequestWindowClose(bool* aCanClose)
2323 : {
2324 : #ifdef NS_PRINTING
2325 0 : if (mPrintIsPending || (mPrintEngine && mPrintEngine->GetIsPrinting())) {
2326 0 : *aCanClose = false;
2327 0 : mDeferredWindowClose = true;
2328 : } else
2329 : #endif
2330 0 : *aCanClose = true;
2331 :
2332 0 : return NS_OK;
2333 : }
2334 :
2335 : StyleSetHandle
2336 28 : nsDocumentViewer::CreateStyleSet(nsIDocument* aDocument)
2337 : {
2338 : // Make sure this does the same thing as PresShell::AddSheet wrt ordering.
2339 :
2340 : // this should eventually get expanded to allow for creating
2341 : // different sets for different media
2342 :
2343 28 : StyleBackendType backendType = aDocument->GetStyleBackendType();
2344 :
2345 28 : StyleSetHandle styleSet;
2346 28 : if (backendType == StyleBackendType::Gecko) {
2347 28 : styleSet = new nsStyleSet();
2348 : } else {
2349 0 : styleSet = new ServoStyleSet();
2350 : }
2351 :
2352 28 : styleSet->BeginUpdate();
2353 :
2354 : // The document will fill in the document sheets when we create the presshell
2355 :
2356 28 : if (aDocument->IsBeingUsedAsImage()) {
2357 21 : MOZ_ASSERT(aDocument->IsSVGDocument(),
2358 : "Do we want to skip most sheets for this new image type?");
2359 :
2360 : // SVG-as-an-image must be kept as light and small as possible. We
2361 : // deliberately skip loading everything and leave svg.css (and html.css and
2362 : // xul.css) to be loaded on-demand.
2363 : // XXXjwatt Nothing else is loaded on-demand, but I don't think that
2364 : // should matter for SVG-as-an-image. If it does, I want to know why!
2365 :
2366 : // Caller will handle calling EndUpdate, per contract.
2367 21 : return styleSet;
2368 : }
2369 :
2370 7 : auto cache = nsLayoutStylesheetCache::For(backendType);
2371 :
2372 : // Handle the user sheets.
2373 7 : StyleSheet* sheet = nullptr;
2374 7 : if (nsContentUtils::IsInChromeDocshell(aDocument)) {
2375 4 : sheet = cache->UserChromeSheet();
2376 : } else {
2377 3 : sheet = cache->UserContentSheet();
2378 : }
2379 :
2380 7 : if (sheet)
2381 0 : styleSet->AppendStyleSheet(SheetType::User, sheet);
2382 :
2383 : // Append chrome sheets (scrollbars + forms).
2384 7 : bool shouldOverride = false;
2385 : // We don't want a docshell here for external resource docs, so just
2386 : // look at mContainer.
2387 14 : nsCOMPtr<nsIDocShell> ds(mContainer);
2388 14 : nsCOMPtr<nsIDOMEventTarget> chromeHandler;
2389 14 : nsCOMPtr<nsIURI> uri;
2390 14 : RefPtr<StyleSheet> chromeSheet;
2391 :
2392 7 : if (ds) {
2393 7 : ds->GetChromeEventHandler(getter_AddRefs(chromeHandler));
2394 : }
2395 7 : if (chromeHandler) {
2396 6 : nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(chromeHandler));
2397 6 : nsCOMPtr<nsIContent> content(do_QueryInterface(elt));
2398 3 : if (elt && content) {
2399 2 : nsCOMPtr<nsIURI> baseURI = content->GetBaseURI();
2400 :
2401 2 : nsAutoString sheets;
2402 1 : elt->GetAttribute(NS_LITERAL_STRING("usechromesheets"), sheets);
2403 1 : if (!sheets.IsEmpty() && baseURI) {
2404 : RefPtr<css::Loader> cssLoader =
2405 0 : new css::Loader(backendType, aDocument->GetDocGroup());
2406 :
2407 0 : char *str = ToNewCString(sheets);
2408 0 : char *newStr = str;
2409 : char *token;
2410 0 : while ( (token = nsCRT::strtok(newStr, ", ", &newStr)) ) {
2411 0 : NS_NewURI(getter_AddRefs(uri), nsDependentCString(token), nullptr,
2412 0 : baseURI);
2413 0 : if (!uri) continue;
2414 :
2415 0 : cssLoader->LoadSheetSync(uri, &chromeSheet);
2416 0 : if (!chromeSheet) continue;
2417 :
2418 0 : styleSet->PrependStyleSheet(SheetType::Agent, chromeSheet);
2419 0 : shouldOverride = true;
2420 : }
2421 0 : free(str);
2422 : }
2423 : }
2424 : }
2425 :
2426 7 : if (!shouldOverride) {
2427 7 : sheet = cache->ScrollbarsSheet();
2428 7 : if (sheet) {
2429 7 : styleSet->PrependStyleSheet(SheetType::Agent, sheet);
2430 : }
2431 : }
2432 :
2433 7 : if (!aDocument->IsSVGDocument()) {
2434 : // !!! IMPORTANT - KEEP THIS BLOCK IN SYNC WITH
2435 : // !!! SVGDocument::EnsureNonSVGUserAgentStyleSheetsLoaded.
2436 :
2437 : // SVGForeignObjectElement::BindToTree calls SVGDocument::
2438 : // EnsureNonSVGUserAgentStyleSheetsLoaded to loads these UA sheet
2439 : // on-demand. (Excluding the quirks sheet, which should never be loaded for
2440 : // an SVG document, and excluding xul.css which will be loaded on demand by
2441 : // nsXULElement::BindToTree.)
2442 :
2443 7 : sheet = cache->NumberControlSheet();
2444 7 : if (sheet) {
2445 7 : styleSet->PrependStyleSheet(SheetType::Agent, sheet);
2446 : }
2447 :
2448 7 : sheet = cache->FormsSheet();
2449 7 : if (sheet) {
2450 7 : styleSet->PrependStyleSheet(SheetType::Agent, sheet);
2451 : }
2452 :
2453 7 : if (aDocument->LoadsFullXULStyleSheetUpFront()) {
2454 : // nsXULElement::BindToTree loads xul.css on-demand if we don't load it
2455 : // up-front here.
2456 3 : sheet = cache->XULSheet();
2457 3 : if (sheet) {
2458 3 : styleSet->PrependStyleSheet(SheetType::Agent, sheet);
2459 : }
2460 : }
2461 :
2462 7 : sheet = cache->MinimalXULSheet();
2463 7 : if (sheet) {
2464 : // Load the minimal XUL rules for scrollbars and a few other XUL things
2465 : // that non-XUL (typically HTML) documents commonly use.
2466 7 : styleSet->PrependStyleSheet(SheetType::Agent, sheet);
2467 : }
2468 :
2469 7 : sheet = cache->CounterStylesSheet();
2470 7 : if (sheet) {
2471 7 : styleSet->PrependStyleSheet(SheetType::Agent, sheet);
2472 : }
2473 :
2474 7 : if (nsLayoutUtils::ShouldUseNoScriptSheet(aDocument)) {
2475 7 : sheet = cache->NoScriptSheet();
2476 7 : if (sheet) {
2477 7 : styleSet->PrependStyleSheet(SheetType::Agent, sheet);
2478 : }
2479 : }
2480 :
2481 7 : if (nsLayoutUtils::ShouldUseNoFramesSheet(aDocument)) {
2482 0 : sheet = cache->NoFramesSheet();
2483 0 : if (sheet) {
2484 0 : styleSet->PrependStyleSheet(SheetType::Agent, sheet);
2485 : }
2486 : }
2487 :
2488 : // We don't add quirk.css here; nsPresContext::CompatibilityModeChanged will
2489 : // append it if needed.
2490 :
2491 7 : sheet = cache->HTMLSheet();
2492 7 : if (sheet) {
2493 7 : styleSet->PrependStyleSheet(SheetType::Agent, sheet);
2494 : }
2495 :
2496 7 : styleSet->PrependStyleSheet(SheetType::Agent,
2497 7 : cache->UASheet());
2498 : } else {
2499 : // SVG documents may have scrollbars and need the scrollbar styling.
2500 0 : sheet = cache->MinimalXULSheet();
2501 0 : if (sheet) {
2502 0 : styleSet->PrependStyleSheet(SheetType::Agent, sheet);
2503 : }
2504 : }
2505 :
2506 7 : nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance();
2507 7 : if (sheetService) {
2508 14 : for (StyleSheet* sheet : *sheetService->AgentStyleSheets(backendType)) {
2509 7 : styleSet->AppendStyleSheet(SheetType::Agent, sheet);
2510 : }
2511 7 : for (StyleSheet* sheet :
2512 7 : Reversed(*sheetService->UserStyleSheets(backendType))) {
2513 0 : styleSet->PrependStyleSheet(SheetType::User, sheet);
2514 : }
2515 : }
2516 :
2517 : // Caller will handle calling EndUpdate, per contract.
2518 7 : return styleSet;
2519 : }
2520 :
2521 : NS_IMETHODIMP
2522 0 : nsDocumentViewer::ClearHistoryEntry()
2523 : {
2524 0 : if (mDocument) {
2525 0 : nsJSContext::PokeGC(JS::gcreason::PAGE_HIDE,
2526 0 : mDocument->GetWrapperPreserveColor(),
2527 0 : NS_GC_DELAY * 2);
2528 : }
2529 :
2530 0 : mSHEntry = nullptr;
2531 0 : return NS_OK;
2532 : }
2533 :
2534 : //-------------------------------------------------------
2535 :
2536 : nsresult
2537 28 : nsDocumentViewer::MakeWindow(const nsSize& aSize, nsView* aContainerView)
2538 : {
2539 28 : if (GetIsPrintPreview())
2540 0 : return NS_OK;
2541 :
2542 28 : bool shouldAttach = ShouldAttachToTopLevel();
2543 :
2544 28 : if (shouldAttach) {
2545 : // If the old view is already attached to our parent, detach
2546 6 : DetachFromTopLevelWidget();
2547 : }
2548 :
2549 28 : mViewManager = new nsViewManager();
2550 :
2551 28 : nsDeviceContext *dx = mPresContext->DeviceContext();
2552 :
2553 28 : nsresult rv = mViewManager->Init(dx);
2554 28 : if (NS_FAILED(rv))
2555 0 : return rv;
2556 :
2557 28 : if (mPrintRelated) {
2558 0 : mViewManager->SetPrintRelated();
2559 : }
2560 :
2561 : // The root view is always at 0,0.
2562 56 : nsRect tbounds(nsPoint(0, 0), aSize);
2563 : // Create a view
2564 28 : nsView* view = mViewManager->CreateView(tbounds, aContainerView);
2565 28 : if (!view)
2566 0 : return NS_ERROR_OUT_OF_MEMORY;
2567 :
2568 : // Create a widget if we were given a parent widget or don't have a
2569 : // container view that we can hook up to without a widget.
2570 : // Don't create widgets for ResourceDocs (external resources & svg images),
2571 : // because when they're displayed, they're painted into *another* document's
2572 : // widget.
2573 41 : if (!mDocument->IsResourceDoc() &&
2574 8 : (mParentWidget || !aContainerView)) {
2575 : // pass in a native widget to be the parent widget ONLY if the view hierarchy will stand alone.
2576 : // otherwise the view will find its own parent widget and "do the right thing" to
2577 : // establish a parent/child widget relationship
2578 6 : nsWidgetInitData initData;
2579 : nsWidgetInitData* initDataPtr;
2580 6 : if (!mParentWidget) {
2581 0 : initDataPtr = &initData;
2582 0 : initData.mWindowType = eWindowType_invisible;
2583 : } else {
2584 6 : initDataPtr = nullptr;
2585 : }
2586 :
2587 6 : if (shouldAttach) {
2588 : // Reuse the top level parent widget.
2589 6 : rv = view->AttachToTopLevelWidget(mParentWidget);
2590 6 : mAttachedToParent = true;
2591 : }
2592 0 : else if (!aContainerView && mParentWidget) {
2593 0 : rv = view->CreateWidgetForParent(mParentWidget, initDataPtr,
2594 0 : true, false);
2595 : }
2596 : else {
2597 0 : rv = view->CreateWidget(initDataPtr, true, false);
2598 : }
2599 6 : if (NS_FAILED(rv))
2600 0 : return rv;
2601 : }
2602 :
2603 : // Setup hierarchical relationship in view manager
2604 28 : mViewManager->SetRootView(view);
2605 :
2606 28 : mWindow = view->GetWidget();
2607 :
2608 : // This SetFocus is necessary so the Arrow Key and Page Key events
2609 : // go to the scrolled view as soon as the Window is created instead of going to
2610 : // the browser window (this enables keyboard scrolling of the document)
2611 : // mWindow->SetFocus();
2612 :
2613 28 : return rv;
2614 : }
2615 :
2616 : void
2617 6 : nsDocumentViewer::DetachFromTopLevelWidget()
2618 : {
2619 6 : if (mViewManager) {
2620 0 : nsView* oldView = mViewManager->GetRootView();
2621 0 : if (oldView && oldView->IsAttachedToTopLevel()) {
2622 0 : oldView->DetachFromTopLevelWidget();
2623 : }
2624 : }
2625 6 : mAttachedToParent = false;
2626 6 : }
2627 :
2628 : nsView*
2629 50 : nsDocumentViewer::FindContainerView()
2630 : {
2631 50 : if (!mContainer) {
2632 42 : return nullptr;
2633 : }
2634 :
2635 16 : nsCOMPtr<nsIDocShell> docShell(mContainer);
2636 16 : nsCOMPtr<nsPIDOMWindowOuter> pwin(docShell->GetWindow());
2637 8 : if (!pwin) {
2638 0 : return nullptr;
2639 : }
2640 :
2641 16 : nsCOMPtr<Element> containerElement = pwin->GetFrameElementInternal();
2642 8 : if (!containerElement) {
2643 6 : return nullptr;
2644 : }
2645 :
2646 2 : nsIFrame* subdocFrame = nsLayoutUtils::GetRealPrimaryFrameFor(containerElement);
2647 2 : if (!subdocFrame) {
2648 : // XXX Silenced by default in bug 1175289
2649 1 : LAYOUT_WARNING("Subdocument container has no frame");
2650 1 : return nullptr;
2651 : }
2652 :
2653 : // subdocFrame might not be a subdocument frame; the frame
2654 : // constructor can treat a <frame> as an inline in some XBL
2655 : // cases. Treat that as display:none, the document is not
2656 : // displayed.
2657 1 : if (!subdocFrame->IsSubDocumentFrame()) {
2658 0 : NS_WARNING_ASSERTION(subdocFrame->Type() == LayoutFrameType::None,
2659 : "Subdocument container has non-subdocument frame");
2660 0 : return nullptr;
2661 : }
2662 :
2663 1 : NS_ASSERTION(subdocFrame->GetView(), "Subdoc frames must have views");
2664 1 : return static_cast<nsSubDocumentFrame*>(subdocFrame)->EnsureInnerView();
2665 : }
2666 :
2667 : nsresult
2668 29 : nsDocumentViewer::CreateDeviceContext(nsView* aContainerView)
2669 : {
2670 29 : NS_PRECONDITION(!mPresShell && !mWindow,
2671 : "This will screw up our existing presentation");
2672 29 : NS_PRECONDITION(mDocument, "Gotta have a document here");
2673 :
2674 29 : nsIDocument* doc = mDocument->GetDisplayDocument();
2675 29 : if (doc) {
2676 0 : NS_ASSERTION(!aContainerView, "External resource document embedded somewhere?");
2677 : // We want to use our display document's device context if possible
2678 0 : nsIPresShell* shell = doc->GetShell();
2679 0 : if (shell) {
2680 0 : nsPresContext* ctx = shell->GetPresContext();
2681 0 : if (ctx) {
2682 0 : mDeviceContext = ctx->DeviceContext();
2683 0 : return NS_OK;
2684 : }
2685 : }
2686 : }
2687 :
2688 : // Create a device context even if we already have one, since our widget
2689 : // might have changed.
2690 29 : nsIWidget* widget = nullptr;
2691 29 : if (aContainerView) {
2692 1 : widget = aContainerView->GetNearestWidget(nullptr);
2693 : }
2694 29 : if (!widget) {
2695 28 : widget = mParentWidget;
2696 : }
2697 29 : if (widget) {
2698 7 : widget = widget->GetTopLevelWidget();
2699 : }
2700 :
2701 29 : mDeviceContext = new nsDeviceContext();
2702 29 : mDeviceContext->Init(widget);
2703 29 : return NS_OK;
2704 : }
2705 :
2706 : // Return the selection for the document. Note that text fields have their
2707 : // own selection, which cannot be accessed with this method.
2708 : mozilla::dom::Selection*
2709 38 : nsDocumentViewer::GetDocumentSelection()
2710 : {
2711 38 : if (!mPresShell) {
2712 0 : return nullptr;
2713 : }
2714 :
2715 38 : return mPresShell->GetCurrentSelection(SelectionType::eNormal);
2716 : }
2717 :
2718 : /* ========================================================================================
2719 : * nsIContentViewerEdit
2720 : * ======================================================================================== */
2721 :
2722 0 : NS_IMETHODIMP nsDocumentViewer::ClearSelection()
2723 : {
2724 : // use nsCopySupport::GetSelectionForCopy() ?
2725 0 : RefPtr<mozilla::dom::Selection> selection = GetDocumentSelection();
2726 0 : if (!selection) {
2727 0 : return NS_ERROR_FAILURE;
2728 : }
2729 :
2730 0 : return selection->CollapseToStart();
2731 : }
2732 :
2733 0 : NS_IMETHODIMP nsDocumentViewer::SelectAll()
2734 : {
2735 : // XXX this is a temporary implementation copied from nsWebShell
2736 : // for now. I think nsDocument and friends should have some helper
2737 : // functions to make this easier.
2738 :
2739 : // use nsCopySupport::GetSelectionForCopy() ?
2740 0 : RefPtr<mozilla::dom::Selection> selection = GetDocumentSelection();
2741 0 : if (!selection) {
2742 0 : return NS_ERROR_FAILURE;
2743 : }
2744 :
2745 0 : nsCOMPtr<nsIDOMHTMLDocument> htmldoc = do_QueryInterface(mDocument);
2746 0 : nsCOMPtr<nsIDOMNode> bodyNode;
2747 :
2748 : nsresult rv;
2749 0 : if (htmldoc)
2750 : {
2751 0 : nsCOMPtr<nsIDOMHTMLElement>bodyElement;
2752 0 : rv = htmldoc->GetBody(getter_AddRefs(bodyElement));
2753 0 : if (NS_FAILED(rv) || !bodyElement) return rv;
2754 :
2755 0 : bodyNode = do_QueryInterface(bodyElement);
2756 : }
2757 0 : else if (mDocument)
2758 : {
2759 0 : bodyNode = do_QueryInterface(mDocument->GetRootElement());
2760 : }
2761 0 : if (!bodyNode) return NS_ERROR_FAILURE;
2762 :
2763 0 : rv = selection->RemoveAllRanges();
2764 0 : if (NS_FAILED(rv)) return rv;
2765 :
2766 0 : mozilla::dom::Selection::AutoUserInitiated userSelection(selection);
2767 0 : rv = selection->SelectAllChildren(bodyNode);
2768 0 : return rv;
2769 : }
2770 :
2771 0 : NS_IMETHODIMP nsDocumentViewer::CopySelection()
2772 : {
2773 0 : nsCopySupport::FireClipboardEvent(eCopy, nsIClipboard::kGlobalClipboard,
2774 0 : mPresShell, nullptr);
2775 0 : return NS_OK;
2776 : }
2777 :
2778 0 : NS_IMETHODIMP nsDocumentViewer::CopyLinkLocation()
2779 : {
2780 0 : NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);
2781 0 : nsCOMPtr<nsIDOMNode> node;
2782 0 : GetPopupLinkNode(getter_AddRefs(node));
2783 : // make noise if we're not in a link
2784 0 : NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
2785 :
2786 0 : nsCOMPtr<dom::Element> elm(do_QueryInterface(node));
2787 0 : NS_ENSURE_TRUE(elm, NS_ERROR_FAILURE);
2788 :
2789 0 : nsAutoString locationText;
2790 0 : nsContentUtils::GetLinkLocation(elm, locationText);
2791 0 : if (locationText.IsEmpty())
2792 0 : return NS_ERROR_FAILURE;
2793 :
2794 0 : nsresult rv = NS_OK;
2795 0 : nsCOMPtr<nsIClipboardHelper> clipboard(do_GetService("@mozilla.org/widget/clipboardhelper;1", &rv));
2796 0 : NS_ENSURE_SUCCESS(rv, rv);
2797 :
2798 : // copy the href onto the clipboard
2799 0 : return clipboard->CopyString(locationText);
2800 : }
2801 :
2802 0 : NS_IMETHODIMP nsDocumentViewer::CopyImage(int32_t aCopyFlags)
2803 : {
2804 0 : NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);
2805 0 : nsCOMPtr<nsIImageLoadingContent> node;
2806 0 : GetPopupImageNode(getter_AddRefs(node));
2807 : // make noise if we're not in an image
2808 0 : NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
2809 :
2810 0 : nsCOMPtr<nsILoadContext> loadContext(mContainer);
2811 0 : return nsCopySupport::ImageCopy(node, loadContext, aCopyFlags);
2812 : }
2813 :
2814 :
2815 0 : NS_IMETHODIMP nsDocumentViewer::GetCopyable(bool *aCopyable)
2816 : {
2817 0 : NS_ENSURE_ARG_POINTER(aCopyable);
2818 0 : *aCopyable = nsCopySupport::CanCopy(mDocument);
2819 0 : return NS_OK;
2820 : }
2821 :
2822 0 : NS_IMETHODIMP nsDocumentViewer::GetContents(const char *mimeType, bool selectionOnly, nsAString& aOutValue)
2823 : {
2824 0 : aOutValue.Truncate();
2825 :
2826 0 : NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);
2827 0 : NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_INITIALIZED);
2828 :
2829 : // Now we have the selection. Make sure it's nonzero:
2830 0 : nsCOMPtr<nsISelection> sel;
2831 0 : if (selectionOnly) {
2832 0 : nsCopySupport::GetSelectionForCopy(mDocument, getter_AddRefs(sel));
2833 0 : NS_ENSURE_TRUE(sel, NS_ERROR_FAILURE);
2834 :
2835 : bool isCollapsed;
2836 0 : sel->GetIsCollapsed(&isCollapsed);
2837 0 : if (isCollapsed)
2838 0 : return NS_OK;
2839 : }
2840 :
2841 : // call the copy code
2842 0 : return nsCopySupport::GetContents(nsDependentCString(mimeType), 0, sel,
2843 0 : mDocument, aOutValue);
2844 : }
2845 :
2846 2 : NS_IMETHODIMP nsDocumentViewer::GetCanGetContents(bool *aCanGetContents)
2847 : {
2848 2 : NS_ENSURE_ARG_POINTER(aCanGetContents);
2849 2 : *aCanGetContents = false;
2850 2 : NS_ENSURE_STATE(mDocument);
2851 2 : *aCanGetContents = nsCopySupport::CanCopy(mDocument);
2852 2 : return NS_OK;
2853 : }
2854 :
2855 0 : NS_IMETHODIMP nsDocumentViewer::SetCommandNode(nsIDOMNode* aNode)
2856 : {
2857 0 : nsIDocument* document = GetDocument();
2858 0 : NS_ENSURE_STATE(document);
2859 :
2860 0 : nsCOMPtr<nsPIDOMWindowOuter> window(document->GetWindow());
2861 0 : NS_ENSURE_TRUE(window, NS_ERROR_NOT_AVAILABLE);
2862 :
2863 0 : nsCOMPtr<nsPIWindowRoot> root = window->GetTopWindowRoot();
2864 0 : NS_ENSURE_STATE(root);
2865 :
2866 0 : root->SetPopupNode(aNode);
2867 0 : return NS_OK;
2868 : }
2869 :
2870 : /* ========================================================================================
2871 : * nsIContentViewerFile
2872 : * ======================================================================================== */
2873 : /** ---------------------------------------------------
2874 : * See documentation above in the nsIContentViewerfile class definition
2875 : * @update 01/24/00 dwc
2876 : */
2877 : NS_IMETHODIMP
2878 0 : nsDocumentViewer::Print(bool aSilent,
2879 : FILE * aDebugFile,
2880 : nsIPrintSettings* aPrintSettings)
2881 : {
2882 : #ifdef NS_PRINTING
2883 0 : SetPrintRelated();
2884 :
2885 0 : nsCOMPtr<nsIPrintSettings> printSettings;
2886 :
2887 : #ifdef DEBUG
2888 0 : nsresult rv = NS_ERROR_FAILURE;
2889 :
2890 0 : mDebugFile = aDebugFile;
2891 : // if they don't pass in a PrintSettings, then make one
2892 : // it will have all the default values
2893 0 : printSettings = aPrintSettings;
2894 : nsCOMPtr<nsIPrintSettingsService> printSettingsSvc
2895 0 : = do_GetService("@mozilla.org/gfx/printsettings-service;1", &rv);
2896 0 : if (NS_SUCCEEDED(rv)) {
2897 : // if they don't pass in a PrintSettings, then make one
2898 0 : if (printSettings == nullptr) {
2899 0 : printSettingsSvc->GetNewPrintSettings(getter_AddRefs(printSettings));
2900 : }
2901 0 : NS_ASSERTION(printSettings, "You can't PrintPreview without a PrintSettings!");
2902 : }
2903 0 : if (printSettings) printSettings->SetPrintSilent(aSilent);
2904 0 : if (printSettings) printSettings->SetShowPrintProgress(false);
2905 : #endif
2906 :
2907 :
2908 0 : return Print(printSettings, nullptr);
2909 : #else
2910 : return NS_ERROR_FAILURE;
2911 : #endif
2912 : }
2913 :
2914 : // nsIContentViewerFile interface
2915 : NS_IMETHODIMP
2916 0 : nsDocumentViewer::GetPrintable(bool *aPrintable)
2917 : {
2918 0 : NS_ENSURE_ARG_POINTER(aPrintable);
2919 :
2920 0 : *aPrintable = !GetIsPrinting();
2921 :
2922 0 : return NS_OK;
2923 : }
2924 :
2925 0 : NS_IMETHODIMP nsDocumentViewer::ScrollToNode(nsIDOMNode* aNode)
2926 : {
2927 0 : NS_ENSURE_ARG(aNode);
2928 0 : NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
2929 0 : nsCOMPtr<nsIPresShell> presShell;
2930 0 : NS_ENSURE_SUCCESS(GetPresShell(getter_AddRefs(presShell)), NS_ERROR_FAILURE);
2931 :
2932 : // Get the nsIContent interface, because that's what we need to
2933 : // get the primary frame
2934 :
2935 0 : nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
2936 0 : NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
2937 :
2938 : // Tell the PresShell to scroll to the primary frame of the content.
2939 0 : NS_ENSURE_SUCCESS(
2940 : presShell->ScrollContentIntoView(content,
2941 : nsIPresShell::ScrollAxis(
2942 : nsIPresShell::SCROLL_TOP,
2943 : nsIPresShell::SCROLL_ALWAYS),
2944 : nsIPresShell::ScrollAxis(),
2945 : nsIPresShell::SCROLL_OVERFLOW_HIDDEN),
2946 : NS_ERROR_FAILURE);
2947 0 : return NS_OK;
2948 : }
2949 :
2950 : void
2951 36 : nsDocumentViewer::CallChildren(CallChildFunc aFunc, void* aClosure)
2952 : {
2953 72 : nsCOMPtr<nsIDocShell> docShell(mContainer);
2954 36 : if (docShell)
2955 : {
2956 : int32_t i;
2957 : int32_t n;
2958 36 : docShell->GetChildCount(&n);
2959 36 : for (i=0; i < n; i++)
2960 : {
2961 0 : nsCOMPtr<nsIDocShellTreeItem> child;
2962 0 : docShell->GetChildAt(i, getter_AddRefs(child));
2963 0 : nsCOMPtr<nsIDocShell> childAsShell(do_QueryInterface(child));
2964 0 : NS_ASSERTION(childAsShell, "null child in docshell");
2965 0 : if (childAsShell)
2966 : {
2967 0 : nsCOMPtr<nsIContentViewer> childCV;
2968 0 : childAsShell->GetContentViewer(getter_AddRefs(childCV));
2969 0 : if (childCV)
2970 : {
2971 0 : (*aFunc)(childCV, aClosure);
2972 : }
2973 : }
2974 : }
2975 : }
2976 36 : }
2977 :
2978 : static void
2979 0 : ChangeChildPaintingEnabled(nsIContentViewer* aChild, void* aClosure)
2980 : {
2981 0 : bool* enablePainting = (bool*) aClosure;
2982 0 : if (*enablePainting) {
2983 0 : aChild->ResumePainting();
2984 : } else {
2985 0 : aChild->PausePainting();
2986 : }
2987 0 : }
2988 :
2989 : struct ZoomInfo
2990 : {
2991 : float mZoom;
2992 : };
2993 :
2994 : static void
2995 0 : SetChildTextZoom(nsIContentViewer* aChild, void* aClosure)
2996 : {
2997 0 : struct ZoomInfo* ZoomInfo = (struct ZoomInfo*) aClosure;
2998 0 : aChild->SetTextZoom(ZoomInfo->mZoom);
2999 0 : }
3000 :
3001 : static void
3002 0 : SetChildMinFontSize(nsIContentViewer* aChild, void* aClosure)
3003 : {
3004 0 : aChild->SetMinFontSize(NS_PTR_TO_INT32(aClosure));
3005 0 : }
3006 :
3007 : static void
3008 0 : SetChildFullZoom(nsIContentViewer* aChild, void* aClosure)
3009 : {
3010 0 : struct ZoomInfo* ZoomInfo = (struct ZoomInfo*) aClosure;
3011 0 : aChild->SetFullZoom(ZoomInfo->mZoom);
3012 0 : }
3013 :
3014 : static void
3015 0 : SetChildOverrideDPPX(nsIContentViewer* aChild, void* aClosure)
3016 : {
3017 0 : struct ZoomInfo* ZoomInfo = (struct ZoomInfo*) aClosure;
3018 0 : aChild->SetOverrideDPPX(ZoomInfo->mZoom);
3019 0 : }
3020 :
3021 : static bool
3022 0 : SetExtResourceTextZoom(nsIDocument* aDocument, void* aClosure)
3023 : {
3024 : // Would it be better to enumerate external resource viewers instead?
3025 0 : nsIPresShell* shell = aDocument->GetShell();
3026 0 : if (shell) {
3027 0 : nsPresContext* ctxt = shell->GetPresContext();
3028 0 : if (ctxt) {
3029 0 : struct ZoomInfo* ZoomInfo = static_cast<struct ZoomInfo*>(aClosure);
3030 0 : ctxt->SetTextZoom(ZoomInfo->mZoom);
3031 : }
3032 : }
3033 :
3034 0 : return true;
3035 : }
3036 :
3037 : static bool
3038 0 : SetExtResourceMinFontSize(nsIDocument* aDocument, void* aClosure)
3039 : {
3040 0 : nsIPresShell* shell = aDocument->GetShell();
3041 0 : if (shell) {
3042 0 : nsPresContext* ctxt = shell->GetPresContext();
3043 0 : if (ctxt) {
3044 0 : ctxt->SetBaseMinFontSize(NS_PTR_TO_INT32(aClosure));
3045 : }
3046 : }
3047 :
3048 0 : return true;
3049 : }
3050 :
3051 : static bool
3052 0 : SetExtResourceFullZoom(nsIDocument* aDocument, void* aClosure)
3053 : {
3054 : // Would it be better to enumerate external resource viewers instead?
3055 0 : nsIPresShell* shell = aDocument->GetShell();
3056 0 : if (shell) {
3057 0 : nsPresContext* ctxt = shell->GetPresContext();
3058 0 : if (ctxt) {
3059 0 : struct ZoomInfo* ZoomInfo = static_cast<struct ZoomInfo*>(aClosure);
3060 0 : ctxt->SetFullZoom(ZoomInfo->mZoom);
3061 : }
3062 : }
3063 :
3064 0 : return true;
3065 : }
3066 :
3067 : static bool
3068 0 : SetExtResourceOverrideDPPX(nsIDocument* aDocument, void* aClosure)
3069 : {
3070 0 : nsIPresShell* shell = aDocument->GetShell();
3071 0 : if (shell) {
3072 0 : nsPresContext* ctxt = shell->GetPresContext();
3073 0 : if (ctxt) {
3074 0 : struct ZoomInfo* ZoomInfo = static_cast<struct ZoomInfo*>(aClosure);
3075 0 : ctxt->SetOverrideDPPX(ZoomInfo->mZoom);
3076 : }
3077 : }
3078 :
3079 0 : return true;
3080 : }
3081 :
3082 : NS_IMETHODIMP
3083 6 : nsDocumentViewer::SetTextZoom(float aTextZoom)
3084 : {
3085 : // If we don't have a document, then we need to bail.
3086 6 : if (!mDocument) {
3087 0 : return NS_ERROR_FAILURE;
3088 : }
3089 :
3090 6 : if (GetIsPrintPreview()) {
3091 0 : return NS_OK;
3092 : }
3093 :
3094 6 : mTextZoom = aTextZoom;
3095 :
3096 : // Set the text zoom on all children of mContainer (even if our zoom didn't
3097 : // change, our children's zoom may be different, though it would be unusual).
3098 : // Do this first, in case kids are auto-sizing and post reflow commands on
3099 : // our presshell (which should be subsumed into our own style change reflow).
3100 6 : struct ZoomInfo ZoomInfo = { aTextZoom };
3101 6 : CallChildren(SetChildTextZoom, &ZoomInfo);
3102 :
3103 : // Now change our own zoom
3104 6 : nsPresContext* pc = GetPresContext();
3105 6 : if (pc && aTextZoom != mPresContext->TextZoom()) {
3106 0 : pc->SetTextZoom(aTextZoom);
3107 : }
3108 :
3109 : // And do the external resources
3110 6 : mDocument->EnumerateExternalResources(SetExtResourceTextZoom, &ZoomInfo);
3111 :
3112 6 : nsContentUtils::DispatchChromeEvent(mDocument, static_cast<nsIDocument*>(mDocument),
3113 12 : NS_LITERAL_STRING("TextZoomChange"),
3114 12 : true, true);
3115 :
3116 6 : return NS_OK;
3117 : }
3118 :
3119 : NS_IMETHODIMP
3120 7 : nsDocumentViewer::GetTextZoom(float* aTextZoom)
3121 : {
3122 7 : NS_ENSURE_ARG_POINTER(aTextZoom);
3123 7 : nsPresContext* pc = GetPresContext();
3124 7 : *aTextZoom = pc ? pc->TextZoom() : 1.0f;
3125 7 : return NS_OK;
3126 : }
3127 :
3128 : NS_IMETHODIMP
3129 0 : nsDocumentViewer::GetEffectiveTextZoom(float* aEffectiveTextZoom)
3130 : {
3131 0 : NS_ENSURE_ARG_POINTER(aEffectiveTextZoom);
3132 0 : nsPresContext* pc = GetPresContext();
3133 0 : *aEffectiveTextZoom = pc ? pc->EffectiveTextZoom() : 1.0f;
3134 0 : return NS_OK;
3135 : }
3136 :
3137 : NS_IMETHODIMP
3138 4 : nsDocumentViewer::SetMinFontSize(int32_t aMinFontSize)
3139 : {
3140 : // If we don't have a document, then we need to bail.
3141 4 : if (!mDocument) {
3142 0 : return NS_ERROR_FAILURE;
3143 : }
3144 :
3145 4 : if (GetIsPrintPreview()) {
3146 0 : return NS_OK;
3147 : }
3148 :
3149 4 : mMinFontSize = aMinFontSize;
3150 :
3151 : // Set the min font on all children of mContainer (even if our min font didn't
3152 : // change, our children's min font may be different, though it would be unusual).
3153 : // Do this first, in case kids are auto-sizing and post reflow commands on
3154 : // our presshell (which should be subsumed into our own style change reflow).
3155 4 : CallChildren(SetChildMinFontSize, NS_INT32_TO_PTR(aMinFontSize));
3156 :
3157 : // Now change our own min font
3158 4 : nsPresContext* pc = GetPresContext();
3159 4 : if (pc && aMinFontSize != mPresContext->MinFontSize(nullptr)) {
3160 0 : pc->SetBaseMinFontSize(aMinFontSize);
3161 : }
3162 :
3163 : // And do the external resources
3164 8 : mDocument->EnumerateExternalResources(SetExtResourceMinFontSize,
3165 8 : NS_INT32_TO_PTR(aMinFontSize));
3166 :
3167 4 : return NS_OK;
3168 : }
3169 :
3170 : NS_IMETHODIMP
3171 4 : nsDocumentViewer::GetMinFontSize(int32_t* aMinFontSize)
3172 : {
3173 4 : NS_ENSURE_ARG_POINTER(aMinFontSize);
3174 4 : nsPresContext* pc = GetPresContext();
3175 4 : *aMinFontSize = pc ? pc->BaseMinFontSize() : 0;
3176 4 : return NS_OK;
3177 : }
3178 :
3179 : NS_IMETHODIMP
3180 6 : nsDocumentViewer::SetFullZoom(float aFullZoom)
3181 : {
3182 : #ifdef NS_PRINT_PREVIEW
3183 6 : if (GetIsPrintPreview()) {
3184 0 : nsPresContext* pc = GetPresContext();
3185 0 : NS_ENSURE_TRUE(pc, NS_OK);
3186 0 : nsCOMPtr<nsIPresShell> shell = pc->GetPresShell();
3187 0 : NS_ENSURE_TRUE(shell, NS_OK);
3188 :
3189 0 : if (!mPrintPreviewZoomed) {
3190 0 : mOriginalPrintPreviewScale = pc->GetPrintPreviewScale();
3191 0 : mPrintPreviewZoomed = true;
3192 : }
3193 :
3194 0 : mPrintPreviewZoom = aFullZoom;
3195 0 : pc->SetPrintPreviewScale(aFullZoom * mOriginalPrintPreviewScale);
3196 0 : nsIPageSequenceFrame* pf = shell->GetPageSequenceFrame();
3197 0 : if (pf) {
3198 0 : nsIFrame* f = do_QueryFrame(pf);
3199 0 : shell->FrameNeedsReflow(f, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
3200 : }
3201 :
3202 0 : nsIFrame* rootFrame = shell->GetRootFrame();
3203 0 : if (rootFrame) {
3204 0 : rootFrame->InvalidateFrame();
3205 : }
3206 0 : return NS_OK;
3207 : }
3208 : #endif
3209 :
3210 : // If we don't have a document, then we need to bail.
3211 6 : if (!mDocument) {
3212 0 : return NS_ERROR_FAILURE;
3213 : }
3214 :
3215 6 : bool fullZoomChange = (mPageZoom != aFullZoom);
3216 6 : mPageZoom = aFullZoom;
3217 :
3218 6 : struct ZoomInfo ZoomInfo = { aFullZoom };
3219 6 : CallChildren(SetChildFullZoom, &ZoomInfo);
3220 :
3221 6 : nsPresContext* pc = GetPresContext();
3222 6 : if (pc) {
3223 5 : pc->SetFullZoom(aFullZoom);
3224 : }
3225 :
3226 : // And do the external resources
3227 6 : mDocument->EnumerateExternalResources(SetExtResourceFullZoom, &ZoomInfo);
3228 :
3229 : // Dispatch FullZoomChange event only if fullzoom value really was been changed
3230 6 : if (fullZoomChange) {
3231 0 : nsContentUtils::DispatchChromeEvent(mDocument, static_cast<nsIDocument*>(mDocument),
3232 0 : NS_LITERAL_STRING("FullZoomChange"),
3233 0 : true, true);
3234 : }
3235 :
3236 6 : return NS_OK;
3237 : }
3238 :
3239 : NS_IMETHODIMP
3240 4 : nsDocumentViewer::GetFullZoom(float* aFullZoom)
3241 : {
3242 4 : NS_ENSURE_ARG_POINTER(aFullZoom);
3243 : #ifdef NS_PRINT_PREVIEW
3244 4 : if (GetIsPrintPreview()) {
3245 0 : *aFullZoom = mPrintPreviewZoom;
3246 0 : return NS_OK;
3247 : }
3248 : #endif
3249 : // Check the prescontext first because it might have a temporary
3250 : // setting for print-preview
3251 4 : nsPresContext* pc = GetPresContext();
3252 4 : *aFullZoom = pc ? pc->GetFullZoom() : mPageZoom;
3253 4 : return NS_OK;
3254 : }
3255 :
3256 : NS_IMETHODIMP
3257 4 : nsDocumentViewer::SetOverrideDPPX(float aDPPX)
3258 : {
3259 : // If we don't have a document, then we need to bail.
3260 4 : if (!mDocument) {
3261 0 : return NS_ERROR_FAILURE;
3262 : }
3263 :
3264 4 : mOverrideDPPX = aDPPX;
3265 :
3266 4 : struct ZoomInfo ZoomInfo = { aDPPX };
3267 4 : CallChildren(SetChildOverrideDPPX, &ZoomInfo);
3268 :
3269 4 : nsPresContext* pc = GetPresContext();
3270 4 : if (pc) {
3271 3 : pc->SetOverrideDPPX(aDPPX);
3272 : }
3273 :
3274 : // And do the external resources
3275 4 : mDocument->EnumerateExternalResources(SetExtResourceOverrideDPPX, &ZoomInfo);
3276 :
3277 4 : return NS_OK;
3278 : }
3279 :
3280 : NS_IMETHODIMP
3281 4 : nsDocumentViewer::GetOverrideDPPX(float* aDPPX)
3282 : {
3283 4 : NS_ENSURE_ARG_POINTER(aDPPX);
3284 :
3285 4 : nsPresContext* pc = GetPresContext();
3286 4 : *aDPPX = pc ? pc->GetOverrideDPPX() : mOverrideDPPX;
3287 4 : return NS_OK;
3288 : }
3289 :
3290 : static void
3291 0 : SetChildAuthorStyleDisabled(nsIContentViewer* aChild, void* aClosure)
3292 : {
3293 0 : bool styleDisabled = *static_cast<bool*>(aClosure);
3294 0 : aChild->SetAuthorStyleDisabled(styleDisabled);
3295 0 : }
3296 :
3297 :
3298 : NS_IMETHODIMP
3299 4 : nsDocumentViewer::SetAuthorStyleDisabled(bool aStyleDisabled)
3300 : {
3301 4 : if (mPresShell) {
3302 3 : mPresShell->SetAuthorStyleDisabled(aStyleDisabled);
3303 : }
3304 4 : CallChildren(SetChildAuthorStyleDisabled, &aStyleDisabled);
3305 4 : return NS_OK;
3306 : }
3307 :
3308 : NS_IMETHODIMP
3309 7 : nsDocumentViewer::GetAuthorStyleDisabled(bool* aStyleDisabled)
3310 : {
3311 7 : if (mPresShell) {
3312 7 : *aStyleDisabled = mPresShell->GetAuthorStyleDisabled();
3313 : } else {
3314 0 : *aStyleDisabled = false;
3315 : }
3316 7 : return NS_OK;
3317 : }
3318 :
3319 : static bool
3320 0 : ExtResourceEmulateMedium(nsIDocument* aDocument, void* aClosure)
3321 : {
3322 0 : nsIPresShell* shell = aDocument->GetShell();
3323 0 : if (shell) {
3324 0 : nsPresContext* ctxt = shell->GetPresContext();
3325 0 : if (ctxt) {
3326 0 : const nsAString* mediaType = static_cast<nsAString*>(aClosure);
3327 0 : ctxt->EmulateMedium(*mediaType);
3328 : }
3329 : }
3330 :
3331 0 : return true;
3332 : }
3333 :
3334 : static void
3335 0 : ChildEmulateMedium(nsIContentViewer* aChild, void* aClosure)
3336 : {
3337 0 : const nsAString* mediaType = static_cast<nsAString*>(aClosure);
3338 0 : aChild->EmulateMedium(*mediaType);
3339 0 : }
3340 :
3341 : NS_IMETHODIMP
3342 0 : nsDocumentViewer::EmulateMedium(const nsAString& aMediaType)
3343 : {
3344 0 : if (mPresContext) {
3345 0 : mPresContext->EmulateMedium(aMediaType);
3346 : }
3347 0 : CallChildren(ChildEmulateMedium, const_cast<nsAString*>(&aMediaType));
3348 :
3349 0 : if (mDocument) {
3350 0 : mDocument->EnumerateExternalResources(ExtResourceEmulateMedium,
3351 0 : const_cast<nsAString*>(&aMediaType));
3352 : }
3353 :
3354 0 : return NS_OK;
3355 : }
3356 :
3357 : static bool
3358 0 : ExtResourceStopEmulatingMedium(nsIDocument* aDocument, void* aClosure)
3359 : {
3360 0 : nsIPresShell* shell = aDocument->GetShell();
3361 0 : if (shell) {
3362 0 : nsPresContext* ctxt = shell->GetPresContext();
3363 0 : if (ctxt) {
3364 0 : ctxt->StopEmulatingMedium();
3365 : }
3366 : }
3367 :
3368 0 : return true;
3369 : }
3370 :
3371 : static void
3372 0 : ChildStopEmulatingMedium(nsIContentViewer* aChild, void* aClosure)
3373 : {
3374 0 : aChild->StopEmulatingMedium();
3375 0 : }
3376 :
3377 : NS_IMETHODIMP
3378 0 : nsDocumentViewer::StopEmulatingMedium()
3379 : {
3380 0 : if (mPresContext) {
3381 0 : mPresContext->StopEmulatingMedium();
3382 : }
3383 0 : CallChildren(ChildStopEmulatingMedium, nullptr);
3384 :
3385 0 : if (mDocument) {
3386 0 : mDocument->EnumerateExternalResources(ExtResourceStopEmulatingMedium,
3387 0 : nullptr);
3388 : }
3389 :
3390 0 : return NS_OK;
3391 : }
3392 :
3393 0 : NS_IMETHODIMP nsDocumentViewer::GetForceCharacterSet(nsACString& aForceCharacterSet)
3394 : {
3395 0 : auto encoding = nsDocumentViewer::GetForceCharset();
3396 0 : if (encoding) {
3397 0 : encoding->Name(aForceCharacterSet);
3398 : } else {
3399 0 : aForceCharacterSet.Truncate();
3400 : }
3401 0 : return NS_OK;
3402 : }
3403 :
3404 : /* [noscript,notxpcom] Encoding getForceCharset (); */
3405 : NS_IMETHODIMP_(const Encoding *)
3406 5 : nsDocumentViewer::GetForceCharset()
3407 : {
3408 5 : return mForceCharacterSet;
3409 : }
3410 :
3411 : static void
3412 0 : SetChildForceCharacterSet(nsIContentViewer* aChild, void* aClosure)
3413 : {
3414 0 : auto encoding = static_cast<const Encoding*>(aClosure);
3415 0 : aChild->SetForceCharset(encoding);
3416 0 : }
3417 :
3418 : NS_IMETHODIMP
3419 0 : nsDocumentViewer::SetForceCharacterSet(const nsACString& aForceCharacterSet)
3420 : {
3421 : // This method is scriptable, so add-ons could pass in something other
3422 : // than a canonical name. However, in case where the input is a canonical
3423 : // name, "replacement" doesn't survive label resolution. Additionally, the
3424 : // empty string means no hint.
3425 0 : const Encoding* encoding = nullptr;
3426 0 : if (!aForceCharacterSet.IsEmpty()) {
3427 0 : if (aForceCharacterSet.EqualsLiteral("replacement")) {
3428 0 : encoding = REPLACEMENT_ENCODING;
3429 0 : } else if (!(encoding = Encoding::ForLabel(aForceCharacterSet))) {
3430 : // Reject unknown labels
3431 0 : return NS_ERROR_INVALID_ARG;
3432 : }
3433 : }
3434 0 : nsDocumentViewer::SetForceCharset(encoding);
3435 0 : return NS_OK;
3436 : }
3437 :
3438 : /* [noscript,notxpcom] void setForceCharset (in Encoding aEncoding); */
3439 : NS_IMETHODIMP_(void)
3440 4 : nsDocumentViewer::SetForceCharset(const Encoding *aEncoding)
3441 : {
3442 4 : mForceCharacterSet = aEncoding;
3443 : // now set the force char set on all children of mContainer
3444 4 : CallChildren(SetChildForceCharacterSet, (void*) aEncoding);
3445 4 : }
3446 :
3447 0 : NS_IMETHODIMP nsDocumentViewer::GetHintCharacterSet(nsACString& aHintCharacterSet)
3448 : {
3449 0 : auto encoding = nsDocumentViewer::GetHintCharset();
3450 0 : if (encoding) {
3451 0 : encoding->Name(aHintCharacterSet);
3452 : } else {
3453 0 : aHintCharacterSet.Truncate();
3454 : }
3455 0 : return NS_OK;
3456 : }
3457 :
3458 : /* [noscript,notxpcom] Encoding getHintCharset (); */
3459 : NS_IMETHODIMP_(const Encoding *)
3460 4 : nsDocumentViewer::GetHintCharset()
3461 : {
3462 4 : if(kCharsetUninitialized == mHintCharsetSource) {
3463 4 : return nullptr;
3464 : }
3465 : // this can't possibly be right. we can't set a value just because somebody got a related value!
3466 : //mHintCharsetSource = kCharsetUninitialized;
3467 0 : return mHintCharset;
3468 : }
3469 :
3470 7 : NS_IMETHODIMP nsDocumentViewer::GetHintCharacterSetSource(int32_t *aHintCharacterSetSource)
3471 : {
3472 7 : NS_ENSURE_ARG_POINTER(aHintCharacterSetSource);
3473 :
3474 7 : *aHintCharacterSetSource = mHintCharsetSource;
3475 7 : return NS_OK;
3476 : }
3477 :
3478 : static void
3479 0 : SetChildHintCharacterSetSource(nsIContentViewer* aChild, void* aClosure)
3480 : {
3481 0 : aChild->SetHintCharacterSetSource(NS_PTR_TO_INT32(aClosure));
3482 0 : }
3483 :
3484 : NS_IMETHODIMP
3485 4 : nsDocumentViewer::SetHintCharacterSetSource(int32_t aHintCharacterSetSource)
3486 : {
3487 4 : mHintCharsetSource = aHintCharacterSetSource;
3488 : // now set the hint char set source on all children of mContainer
3489 4 : CallChildren(SetChildHintCharacterSetSource,
3490 8 : NS_INT32_TO_PTR(aHintCharacterSetSource));
3491 4 : return NS_OK;
3492 : }
3493 :
3494 : static void
3495 0 : SetChildHintCharacterSet(nsIContentViewer* aChild, void* aClosure)
3496 : {
3497 0 : auto encoding = static_cast<const Encoding*>(aClosure);
3498 0 : aChild->SetHintCharset(encoding);
3499 0 : }
3500 :
3501 : NS_IMETHODIMP
3502 0 : nsDocumentViewer::SetHintCharacterSet(const nsACString& aHintCharacterSet)
3503 : {
3504 : // This method is scriptable, so add-ons could pass in something other
3505 : // than a canonical name. However, in case where the input is a canonical
3506 : // name, "replacement" doesn't survive label resolution. Additionally, the
3507 : // empty string means no hint.
3508 0 : const Encoding* encoding = nullptr;
3509 0 : if (!aHintCharacterSet.IsEmpty()) {
3510 0 : if (aHintCharacterSet.EqualsLiteral("replacement")) {
3511 0 : encoding = REPLACEMENT_ENCODING;
3512 0 : } else if (!(encoding = Encoding::ForLabel(aHintCharacterSet))) {
3513 : // Reject unknown labels
3514 0 : return NS_ERROR_INVALID_ARG;
3515 : }
3516 : }
3517 0 : nsDocumentViewer::SetHintCharset(encoding);
3518 0 : return NS_OK;
3519 : }
3520 :
3521 : /* [noscript,notxpcom] void setHintCharset (in Encoding aEncoding); */
3522 : NS_IMETHODIMP_(void)
3523 4 : nsDocumentViewer::SetHintCharset(const Encoding *aEncoding)
3524 : {
3525 4 : mHintCharset = aEncoding;
3526 : // now set the hint char set on all children of mContainer
3527 4 : CallChildren(SetChildHintCharacterSet, (void*) aEncoding);
3528 4 : }
3529 :
3530 : static void
3531 0 : AppendChildSubtree(nsIContentViewer* aChild, void* aClosure)
3532 : {
3533 : nsTArray<nsCOMPtr<nsIContentViewer> >& array =
3534 0 : *static_cast<nsTArray<nsCOMPtr<nsIContentViewer> >*>(aClosure);
3535 0 : aChild->AppendSubtree(array);
3536 0 : }
3537 :
3538 0 : NS_IMETHODIMP nsDocumentViewer::AppendSubtree(nsTArray<nsCOMPtr<nsIContentViewer> >& aArray)
3539 : {
3540 0 : aArray.AppendElement(this);
3541 0 : CallChildren(AppendChildSubtree, &aArray);
3542 0 : return NS_OK;
3543 : }
3544 :
3545 : NS_IMETHODIMP
3546 0 : nsDocumentViewer::PausePainting()
3547 : {
3548 0 : bool enablePaint = false;
3549 0 : CallChildren(ChangeChildPaintingEnabled, &enablePaint);
3550 :
3551 0 : nsIPresShell* presShell = GetPresShell();
3552 0 : if (presShell) {
3553 0 : presShell->PausePainting();
3554 : }
3555 :
3556 0 : return NS_OK;
3557 : }
3558 :
3559 : NS_IMETHODIMP
3560 0 : nsDocumentViewer::ResumePainting()
3561 : {
3562 0 : bool enablePaint = true;
3563 0 : CallChildren(ChangeChildPaintingEnabled, &enablePaint);
3564 :
3565 0 : nsIPresShell* presShell = GetPresShell();
3566 0 : if (presShell) {
3567 0 : presShell->ResumePainting();
3568 : }
3569 :
3570 0 : return NS_OK;
3571 : }
3572 :
3573 : nsresult
3574 0 : nsDocumentViewer::GetContentSizeInternal(int32_t* aWidth, int32_t* aHeight,
3575 : nscoord aMaxWidth, nscoord aMaxHeight)
3576 : {
3577 0 : NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
3578 :
3579 0 : nsCOMPtr<nsIPresShell> presShell;
3580 0 : GetPresShell(getter_AddRefs(presShell));
3581 0 : NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
3582 :
3583 : // Flush out all content and style updates. We can't use a resize reflow
3584 : // because it won't change some sizes that a style change reflow will.
3585 0 : mDocument->FlushPendingNotifications(FlushType::Layout);
3586 :
3587 0 : nsIFrame *root = presShell->GetRootFrame();
3588 0 : NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
3589 :
3590 : nscoord prefWidth;
3591 : {
3592 0 : RefPtr<gfxContext> rcx(presShell->CreateReferenceRenderingContext());
3593 0 : prefWidth = root->GetPrefISize(rcx);
3594 : }
3595 0 : if (prefWidth > aMaxWidth) {
3596 0 : prefWidth = aMaxWidth;
3597 : }
3598 :
3599 0 : nsresult rv = presShell->ResizeReflow(prefWidth, NS_UNCONSTRAINEDSIZE);
3600 0 : NS_ENSURE_SUCCESS(rv, rv);
3601 :
3602 0 : RefPtr<nsPresContext> presContext;
3603 0 : GetPresContext(getter_AddRefs(presContext));
3604 0 : NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
3605 :
3606 : // so how big is it?
3607 0 : nsRect shellArea = presContext->GetVisibleArea();
3608 0 : if (shellArea.height > aMaxHeight) {
3609 : // Reflow to max height if we would up too tall.
3610 0 : rv = presShell->ResizeReflow(prefWidth, aMaxHeight);
3611 0 : NS_ENSURE_SUCCESS(rv, rv);
3612 :
3613 0 : shellArea = presContext->GetVisibleArea();
3614 : }
3615 :
3616 : // Protect against bogus returns here
3617 0 : NS_ENSURE_TRUE(shellArea.width != NS_UNCONSTRAINEDSIZE &&
3618 : shellArea.height != NS_UNCONSTRAINEDSIZE,
3619 : NS_ERROR_FAILURE);
3620 :
3621 0 : *aWidth = presContext->AppUnitsToDevPixels(shellArea.width);
3622 0 : *aHeight = presContext->AppUnitsToDevPixels(shellArea.height);
3623 :
3624 0 : return NS_OK;
3625 : }
3626 :
3627 : NS_IMETHODIMP
3628 0 : nsDocumentViewer::GetContentSize(int32_t* aWidth, int32_t* aHeight)
3629 : {
3630 : // Skip doing this on docshell-less documents for now
3631 0 : nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(mContainer);
3632 0 : NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_NOT_AVAILABLE);
3633 :
3634 0 : nsCOMPtr<nsIDocShellTreeItem> docShellParent;
3635 0 : docShellAsItem->GetSameTypeParent(getter_AddRefs(docShellParent));
3636 :
3637 : // It's only valid to access this from a top frame. Doesn't work from
3638 : // sub-frames.
3639 0 : NS_ENSURE_TRUE(!docShellParent, NS_ERROR_FAILURE);
3640 :
3641 0 : return GetContentSizeInternal(aWidth, aHeight, NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
3642 : }
3643 :
3644 : NS_IMETHODIMP
3645 0 : nsDocumentViewer::GetContentSizeConstrained(int32_t aMaxWidth, int32_t aMaxHeight,
3646 : int32_t* aWidth, int32_t* aHeight)
3647 : {
3648 0 : RefPtr<nsPresContext> presContext;
3649 0 : GetPresContext(getter_AddRefs(presContext));
3650 0 : NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
3651 :
3652 0 : nscoord maxWidth = NS_UNCONSTRAINEDSIZE;
3653 0 : nscoord maxHeight = NS_UNCONSTRAINEDSIZE;
3654 0 : if (aMaxWidth > 0) {
3655 0 : maxWidth = presContext->DevPixelsToAppUnits(aMaxWidth);
3656 : }
3657 0 : if (aMaxHeight > 0) {
3658 0 : maxHeight = presContext->DevPixelsToAppUnits(aMaxHeight);
3659 : }
3660 :
3661 0 : return GetContentSizeInternal(aWidth, aHeight, maxWidth, maxHeight);
3662 : }
3663 :
3664 :
3665 159 : NS_IMPL_ISUPPORTS(nsDocViewerSelectionListener, nsISelectionListener)
3666 :
3667 28 : nsresult nsDocViewerSelectionListener::Init(nsDocumentViewer *aDocViewer)
3668 : {
3669 28 : mDocViewer = aDocViewer;
3670 28 : return NS_OK;
3671 : }
3672 :
3673 : /*
3674 : * GetPopupNode, GetPopupLinkNode and GetPopupImageNode are helpers
3675 : * for the cmd_copyLink / cmd_copyImageLocation / cmd_copyImageContents family
3676 : * of commands. The focus controller stores the popup node, these retrieve
3677 : * them and munge appropriately. Note that we have to store the popup node
3678 : * rather than retrieving it from EventStateManager::GetFocusedContent because
3679 : * not all content (images included) can receive focus.
3680 : */
3681 :
3682 : nsresult
3683 8 : nsDocumentViewer::GetPopupNode(nsIDOMNode** aNode)
3684 : {
3685 8 : NS_ENSURE_ARG_POINTER(aNode);
3686 :
3687 8 : *aNode = nullptr;
3688 :
3689 : // get the document
3690 8 : nsIDocument* document = GetDocument();
3691 8 : NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
3692 :
3693 : // get the private dom window
3694 16 : nsCOMPtr<nsPIDOMWindowOuter> window(document->GetWindow());
3695 8 : NS_ENSURE_TRUE(window, NS_ERROR_NOT_AVAILABLE);
3696 8 : if (window) {
3697 16 : nsCOMPtr<nsPIWindowRoot> root = window->GetTopWindowRoot();
3698 8 : NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
3699 :
3700 : // get the popup node
3701 16 : nsCOMPtr<nsIDOMNode> node = root->GetPopupNode();
3702 : #ifdef MOZ_XUL
3703 8 : if (!node) {
3704 8 : nsPIDOMWindowOuter* rootWindow = root->GetWindow();
3705 8 : if (rootWindow) {
3706 16 : nsCOMPtr<nsIDocument> rootDoc = rootWindow->GetExtantDoc();
3707 8 : if (rootDoc) {
3708 8 : nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
3709 8 : if (pm) {
3710 8 : node = pm->GetLastTriggerPopupNode(rootDoc);
3711 : }
3712 : }
3713 : }
3714 : }
3715 : #endif
3716 8 : node.swap(*aNode);
3717 : }
3718 :
3719 8 : return NS_OK;
3720 : }
3721 :
3722 : // GetPopupLinkNode: return popup link node or fail
3723 : nsresult
3724 2 : nsDocumentViewer::GetPopupLinkNode(nsIDOMNode** aNode)
3725 : {
3726 2 : NS_ENSURE_ARG_POINTER(aNode);
3727 :
3728 : // you get null unless i say so
3729 2 : *aNode = nullptr;
3730 :
3731 : // find popup node
3732 4 : nsCOMPtr<nsIDOMNode> node;
3733 2 : nsresult rv = GetPopupNode(getter_AddRefs(node));
3734 2 : NS_ENSURE_SUCCESS(rv, rv);
3735 :
3736 : // find out if we have a link in our ancestry
3737 2 : while (node) {
3738 :
3739 0 : nsCOMPtr<nsIContent> content(do_QueryInterface(node));
3740 0 : if (content) {
3741 0 : nsCOMPtr<nsIURI> hrefURI = content->GetHrefURI();
3742 0 : if (hrefURI) {
3743 0 : *aNode = node;
3744 0 : NS_IF_ADDREF(*aNode); // addref
3745 0 : return NS_OK;
3746 : }
3747 : }
3748 :
3749 : // get our parent and keep trying...
3750 0 : nsCOMPtr<nsIDOMNode> parentNode;
3751 0 : node->GetParentNode(getter_AddRefs(parentNode));
3752 0 : node = parentNode;
3753 : }
3754 :
3755 : // if we have no node, fail
3756 2 : return NS_ERROR_FAILURE;
3757 : }
3758 :
3759 : // GetPopupLinkNode: return popup image node or fail
3760 : nsresult
3761 6 : nsDocumentViewer::GetPopupImageNode(nsIImageLoadingContent** aNode)
3762 : {
3763 6 : NS_ENSURE_ARG_POINTER(aNode);
3764 :
3765 : // you get null unless i say so
3766 6 : *aNode = nullptr;
3767 :
3768 : // find popup node
3769 12 : nsCOMPtr<nsIDOMNode> node;
3770 6 : nsresult rv = GetPopupNode(getter_AddRefs(node));
3771 6 : NS_ENSURE_SUCCESS(rv, rv);
3772 :
3773 6 : if (node)
3774 0 : CallQueryInterface(node, aNode);
3775 :
3776 6 : return NS_OK;
3777 : }
3778 :
3779 : /*
3780 : * XXX dr
3781 : * ------
3782 : * These two functions -- GetInLink and GetInImage -- are kind of annoying
3783 : * in that they only get called from the controller (in
3784 : * nsDOMWindowController::IsCommandEnabled). The actual construction of the
3785 : * context menus in communicator (nsContextMenu.js) has its own, redundant
3786 : * tests. No big deal, but good to keep in mind if we ever clean context
3787 : * menus.
3788 : */
3789 :
3790 2 : NS_IMETHODIMP nsDocumentViewer::GetInLink(bool* aInLink)
3791 : {
3792 : #ifdef DEBUG_dr
3793 : printf("dr :: nsDocumentViewer::GetInLink\n");
3794 : #endif
3795 :
3796 2 : NS_ENSURE_ARG_POINTER(aInLink);
3797 :
3798 : // we're not in a link unless i say so
3799 2 : *aInLink = false;
3800 :
3801 : // get the popup link
3802 4 : nsCOMPtr<nsIDOMNode> node;
3803 2 : nsresult rv = GetPopupLinkNode(getter_AddRefs(node));
3804 2 : if (NS_FAILED(rv)) return rv;
3805 0 : NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
3806 :
3807 : // if we made it here, we're in a link
3808 0 : *aInLink = true;
3809 0 : return NS_OK;
3810 : }
3811 :
3812 6 : NS_IMETHODIMP nsDocumentViewer::GetInImage(bool* aInImage)
3813 : {
3814 : #ifdef DEBUG_dr
3815 : printf("dr :: nsDocumentViewer::GetInImage\n");
3816 : #endif
3817 :
3818 6 : NS_ENSURE_ARG_POINTER(aInImage);
3819 :
3820 : // we're not in an image unless i say so
3821 6 : *aInImage = false;
3822 :
3823 : // get the popup image
3824 12 : nsCOMPtr<nsIImageLoadingContent> node;
3825 6 : nsresult rv = GetPopupImageNode(getter_AddRefs(node));
3826 6 : if (NS_FAILED(rv)) return rv;
3827 6 : if (!node) {
3828 6 : return NS_ERROR_FAILURE;
3829 : }
3830 :
3831 : // Make sure there is a URI assigned. This allows <input type="image"> to
3832 : // be an image but rejects other <input> types. This matches what
3833 : // nsContextMenu.js does.
3834 0 : nsCOMPtr<nsIURI> uri;
3835 0 : node->GetCurrentURI(getter_AddRefs(uri));
3836 0 : if (uri) {
3837 : // if we made it here, we're in an image
3838 0 : *aInImage = true;
3839 : }
3840 :
3841 0 : return NS_OK;
3842 : }
3843 :
3844 6 : NS_IMETHODIMP nsDocViewerSelectionListener::NotifySelectionChanged(nsIDOMDocument *, nsISelection *, int16_t aReason)
3845 : {
3846 6 : if (!mDocViewer) {
3847 0 : return NS_OK;
3848 : }
3849 :
3850 : // get the selection state
3851 12 : RefPtr<mozilla::dom::Selection> selection = mDocViewer->GetDocumentSelection();
3852 6 : if (!selection) {
3853 0 : return NS_ERROR_FAILURE;
3854 : }
3855 :
3856 6 : nsIDocument* theDoc = mDocViewer->GetDocument();
3857 6 : if (!theDoc) return NS_ERROR_FAILURE;
3858 :
3859 12 : nsCOMPtr<nsPIDOMWindowOuter> domWindow = theDoc->GetWindow();
3860 6 : if (!domWindow) return NS_ERROR_FAILURE;
3861 :
3862 : bool selectionCollapsed;
3863 0 : selection->GetIsCollapsed(&selectionCollapsed);
3864 : // We only call UpdateCommands when the selection changes from collapsed to
3865 : // non-collapsed or vice versa, however we skip the initializing collapse. We
3866 : // might need another update string for simple selection changes, but that
3867 : // would be expenseive.
3868 0 : if (mSelectionWasCollapsed != selectionCollapsed)
3869 : {
3870 0 : domWindow->UpdateCommands(NS_LITERAL_STRING("select"), selection, aReason);
3871 0 : mSelectionWasCollapsed = selectionCollapsed;
3872 : }
3873 :
3874 0 : return NS_OK;
3875 : }
3876 :
3877 : //nsDocViewerFocusListener
3878 257 : NS_IMPL_ISUPPORTS(nsDocViewerFocusListener,
3879 : nsIDOMEventListener)
3880 :
3881 28 : nsDocViewerFocusListener::nsDocViewerFocusListener()
3882 28 : :mDocViewer(nullptr)
3883 : {
3884 28 : }
3885 :
3886 9 : nsDocViewerFocusListener::~nsDocViewerFocusListener(){}
3887 :
3888 : nsresult
3889 3 : nsDocViewerFocusListener::HandleEvent(nsIDOMEvent* aEvent)
3890 : {
3891 3 : NS_ENSURE_STATE(mDocViewer);
3892 :
3893 6 : nsCOMPtr<nsIPresShell> shell;
3894 3 : mDocViewer->GetPresShell(getter_AddRefs(shell));
3895 3 : NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE);
3896 :
3897 6 : nsCOMPtr<nsISelectionController> selCon = do_QueryInterface(shell);
3898 : int16_t selectionStatus;
3899 3 : selCon->GetDisplaySelection(&selectionStatus);
3900 :
3901 6 : nsAutoString eventType;
3902 3 : aEvent->GetType(eventType);
3903 3 : if (eventType.EqualsLiteral("focus")) {
3904 : // If selection was disabled, re-enable it.
3905 3 : if(selectionStatus == nsISelectionController::SELECTION_DISABLED ||
3906 0 : selectionStatus == nsISelectionController::SELECTION_HIDDEN) {
3907 3 : selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
3908 3 : selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL);
3909 : }
3910 : } else {
3911 0 : MOZ_ASSERT(eventType.EqualsLiteral("blur"), "Unexpected event type");
3912 : // If selection was on, disable it.
3913 0 : if(selectionStatus == nsISelectionController::SELECTION_ON ||
3914 0 : selectionStatus == nsISelectionController::SELECTION_ATTENTION) {
3915 0 : selCon->SetDisplaySelection(nsISelectionController::SELECTION_DISABLED);
3916 0 : selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL);
3917 : }
3918 : }
3919 :
3920 3 : return NS_OK;
3921 : }
3922 :
3923 : nsresult
3924 28 : nsDocViewerFocusListener::Init(nsDocumentViewer *aDocViewer)
3925 : {
3926 28 : mDocViewer = aDocViewer;
3927 28 : return NS_OK;
3928 : }
3929 :
3930 : /** ---------------------------------------------------
3931 : * From nsIWebBrowserPrint
3932 : */
3933 :
3934 : #ifdef NS_PRINTING
3935 :
3936 : NS_IMETHODIMP
3937 0 : nsDocumentViewer::Print(nsIPrintSettings* aPrintSettings,
3938 : nsIWebProgressListener* aWebProgressListener)
3939 : {
3940 0 : SetPrintRelated();
3941 :
3942 : // Printing XUL documents is not supported.
3943 0 : nsCOMPtr<nsIXULDocument> xulDoc(do_QueryInterface(mDocument));
3944 0 : if (xulDoc) {
3945 0 : return NS_ERROR_FAILURE;
3946 : }
3947 :
3948 0 : if (!mContainer) {
3949 0 : PR_PL(("Container was destroyed yet we are still trying to use it!"));
3950 0 : return NS_ERROR_FAILURE;
3951 : }
3952 :
3953 0 : nsCOMPtr<nsIDocShell> docShell(mContainer);
3954 0 : NS_ENSURE_STATE(docShell);
3955 :
3956 : // Check to see if this document is still busy
3957 : // If it is busy and we aren't already "queued" up to print then
3958 : // Indicate there is a print pending and cache the args for later
3959 0 : uint32_t busyFlags = nsIDocShell::BUSY_FLAGS_NONE;
3960 0 : if ((NS_FAILED(docShell->GetBusyFlags(&busyFlags)) ||
3961 0 : (busyFlags != nsIDocShell::BUSY_FLAGS_NONE && busyFlags & nsIDocShell::BUSY_FLAGS_PAGE_LOADING)) &&
3962 0 : !mPrintDocIsFullyLoaded) {
3963 0 : if (!mPrintIsPending) {
3964 0 : mCachedPrintSettings = aPrintSettings;
3965 0 : mCachedPrintWebProgressListner = aWebProgressListener;
3966 0 : mPrintIsPending = true;
3967 : }
3968 0 : PR_PL(("Printing Stopped - document is still busy!"));
3969 0 : return NS_ERROR_GFX_PRINTER_DOC_IS_BUSY;
3970 : }
3971 :
3972 0 : if (!mDocument || !mDeviceContext) {
3973 0 : PR_PL(("Can't Print without a document and a device context"));
3974 0 : return NS_ERROR_FAILURE;
3975 : }
3976 :
3977 : nsresult rv;
3978 :
3979 : // if we are printing another URL, then exit
3980 : // the reason we check here is because this method can be called while
3981 : // another is still in here (the printing dialog is a good example).
3982 : // the only time we can print more than one job at a time is the regression tests
3983 0 : if (GetIsPrinting()) {
3984 : // Let the user know we are not ready to print.
3985 0 : rv = NS_ERROR_NOT_AVAILABLE;
3986 :
3987 0 : if (mPrintEngine) {
3988 0 : mPrintEngine->FirePrintingErrorEvent(rv);
3989 : }
3990 :
3991 0 : return rv;
3992 : }
3993 :
3994 : // Dispatch 'beforeprint' event and ensure 'afterprint' will be dispatched:
3995 0 : MOZ_ASSERT(!mAutoBeforeAndAfterPrint,
3996 : "We don't want to dispatch nested beforeprint/afterprint");
3997 : nsAutoPtr<AutoPrintEventDispatcher> autoBeforeAndAfterPrint(
3998 0 : new AutoPrintEventDispatcher(mDocument));
3999 0 : NS_ENSURE_STATE(!GetIsPrinting());
4000 : // If we are hosting a full-page plugin, tell it to print
4001 : // first. It shows its own native print UI.
4002 0 : nsCOMPtr<nsIPluginDocument> pDoc(do_QueryInterface(mDocument));
4003 0 : if (pDoc)
4004 0 : return pDoc->Print();
4005 :
4006 0 : if (!mPrintEngine) {
4007 0 : NS_ENSURE_STATE(mDeviceContext);
4008 0 : mPrintEngine = new nsPrintEngine();
4009 :
4010 0 : rv = mPrintEngine->Initialize(this, mContainer, mDocument,
4011 0 : float(mDeviceContext->AppUnitsPerCSSInch()) /
4012 0 : float(mDeviceContext->AppUnitsPerDevPixel()) /
4013 0 : mPageZoom,
4014 : #ifdef DEBUG
4015 : mDebugFile
4016 : #else
4017 : nullptr
4018 : #endif
4019 0 : );
4020 0 : if (NS_FAILED(rv)) {
4021 0 : mPrintEngine->Destroy();
4022 0 : mPrintEngine = nullptr;
4023 0 : return rv;
4024 : }
4025 : }
4026 0 : if (mPrintEngine->HasPrintCallbackCanvas()) {
4027 : // Postpone the 'afterprint' event until after the mozPrintCallback
4028 : // callbacks have been called:
4029 0 : mAutoBeforeAndAfterPrint = autoBeforeAndAfterPrint;
4030 : }
4031 0 : dom::Element* root = mDocument->GetRootElement();
4032 0 : if (root && root->HasAttr(kNameSpaceID_None, nsGkAtoms::mozdisallowselectionprint)) {
4033 0 : mPrintEngine->SetDisallowSelectionPrint(true);
4034 : }
4035 0 : rv = mPrintEngine->Print(aPrintSettings, aWebProgressListener);
4036 0 : if (NS_FAILED(rv)) {
4037 0 : OnDonePrinting();
4038 : }
4039 0 : return rv;
4040 : }
4041 :
4042 : NS_IMETHODIMP
4043 0 : nsDocumentViewer::PrintPreview(nsIPrintSettings* aPrintSettings,
4044 : mozIDOMWindowProxy* aChildDOMWin,
4045 : nsIWebProgressListener* aWebProgressListener)
4046 : {
4047 0 : SetPrintRelated();
4048 :
4049 : #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
4050 0 : NS_WARNING_ASSERTION(
4051 : IsInitializedForPrintPreview(),
4052 : "Using docshell.printPreview is the preferred way for print previewing!");
4053 :
4054 0 : NS_ENSURE_ARG_POINTER(aChildDOMWin);
4055 0 : nsresult rv = NS_OK;
4056 :
4057 0 : if (GetIsPrinting()) {
4058 0 : nsPrintEngine::CloseProgressDialog(aWebProgressListener);
4059 0 : return NS_ERROR_FAILURE;
4060 : }
4061 :
4062 : // Printing XUL documents is not supported.
4063 0 : nsCOMPtr<nsIXULDocument> xulDoc(do_QueryInterface(mDocument));
4064 0 : if (xulDoc) {
4065 0 : nsPrintEngine::CloseProgressDialog(aWebProgressListener);
4066 0 : return NS_ERROR_FAILURE;
4067 : }
4068 :
4069 0 : nsCOMPtr<nsIDocShell> docShell(mContainer);
4070 0 : if (!docShell || !mDeviceContext) {
4071 0 : PR_PL(("Can't Print Preview without device context and docshell"));
4072 0 : return NS_ERROR_FAILURE;
4073 : }
4074 :
4075 0 : nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryInterface(aChildDOMWin);
4076 0 : MOZ_ASSERT(window);
4077 0 : nsCOMPtr<nsIDocument> doc = window->GetDoc();
4078 0 : NS_ENSURE_STATE(doc);
4079 :
4080 : // Dispatch 'beforeprint' event and ensure 'afterprint' will be dispatched:
4081 : // XXX Currently[1] when the user switches between portrait and landscape
4082 : // mode in print preview, we re-enter this function before
4083 : // mAutoBeforeAndAfterPrint (if set) is cleared to dispatch the 'afterprint'
4084 : // event. To avoid sending multiple 'beforeprint'/'afterprint' events we
4085 : // must avoid creating a new AutoPrintEventDispatcher object here if we
4086 : // already have one saved in mAutoBeforeAndAfterPrint.
4087 : // [1] Until PDF.js is removed (though, maybe after that as well).
4088 0 : nsAutoPtr<AutoPrintEventDispatcher> autoBeforeAndAfterPrint;
4089 0 : if (!mAutoBeforeAndAfterPrint) {
4090 0 : autoBeforeAndAfterPrint = new AutoPrintEventDispatcher(doc);
4091 : }
4092 0 : NS_ENSURE_STATE(!GetIsPrinting());
4093 : // beforeprint event may have caused ContentViewer to be shutdown.
4094 0 : NS_ENSURE_STATE(mContainer);
4095 0 : NS_ENSURE_STATE(mDeviceContext);
4096 0 : if (!mPrintEngine) {
4097 0 : mPrintEngine = new nsPrintEngine();
4098 :
4099 0 : rv = mPrintEngine->Initialize(this, mContainer, doc,
4100 0 : float(mDeviceContext->AppUnitsPerCSSInch()) /
4101 0 : float(mDeviceContext->AppUnitsPerDevPixel()) /
4102 0 : mPageZoom,
4103 : #ifdef DEBUG
4104 : mDebugFile
4105 : #else
4106 : nullptr
4107 : #endif
4108 0 : );
4109 0 : if (NS_FAILED(rv)) {
4110 0 : mPrintEngine->Destroy();
4111 0 : mPrintEngine = nullptr;
4112 0 : return rv;
4113 : }
4114 : }
4115 0 : if (autoBeforeAndAfterPrint &&
4116 0 : mPrintEngine->HasPrintCallbackCanvas()) {
4117 : // Postpone the 'afterprint' event until after the mozPrintCallback
4118 : // callbacks have been called:
4119 0 : mAutoBeforeAndAfterPrint = autoBeforeAndAfterPrint;
4120 : }
4121 0 : dom::Element* root = doc->GetRootElement();
4122 0 : if (root && root->HasAttr(kNameSpaceID_None, nsGkAtoms::mozdisallowselectionprint)) {
4123 0 : PR_PL(("PrintPreview: found mozdisallowselectionprint"));
4124 0 : mPrintEngine->SetDisallowSelectionPrint(true);
4125 : }
4126 0 : rv = mPrintEngine->PrintPreview(aPrintSettings, aChildDOMWin, aWebProgressListener);
4127 0 : mPrintPreviewZoomed = false;
4128 0 : if (NS_FAILED(rv)) {
4129 0 : OnDonePrinting();
4130 : }
4131 0 : return rv;
4132 : #else
4133 : return NS_ERROR_FAILURE;
4134 : #endif
4135 : }
4136 :
4137 : //----------------------------------------------------------------------
4138 : NS_IMETHODIMP
4139 0 : nsDocumentViewer::PrintPreviewNavigate(int16_t aType, int32_t aPageNum)
4140 : {
4141 0 : SetPrintRelated();
4142 :
4143 0 : if (!GetIsPrintPreview() ||
4144 0 : mPrintEngine->GetIsCreatingPrintPreview())
4145 0 : return NS_ERROR_FAILURE;
4146 :
4147 : nsIScrollableFrame* sf =
4148 0 : mPrintEngine->GetPrintPreviewPresShell()->GetRootScrollFrameAsScrollable();
4149 0 : if (!sf)
4150 0 : return NS_OK;
4151 :
4152 : // Check to see if we can short circut scrolling to the top
4153 0 : if (aType == nsIWebBrowserPrint::PRINTPREVIEW_HOME ||
4154 0 : (aType == nsIWebBrowserPrint::PRINTPREVIEW_GOTO_PAGENUM && aPageNum == 1)) {
4155 0 : sf->ScrollTo(nsPoint(0, 0), nsIScrollableFrame::INSTANT);
4156 0 : return NS_OK;
4157 : }
4158 :
4159 : // Finds the SimplePageSequencer frame
4160 : // in PP mPrtPreview->mPrintObject->mSeqFrame is null
4161 0 : nsIFrame* seqFrame = nullptr;
4162 0 : int32_t pageCount = 0;
4163 0 : if (NS_FAILED(mPrintEngine->GetSeqFrameAndCountPages(seqFrame, pageCount))) {
4164 0 : return NS_ERROR_FAILURE;
4165 : }
4166 :
4167 : // Figure where we are currently scrolled to
4168 0 : nsPoint pt = sf->GetScrollPosition();
4169 :
4170 0 : int32_t pageNum = 1;
4171 0 : nsIFrame * fndPageFrame = nullptr;
4172 0 : nsIFrame * currentPage = nullptr;
4173 :
4174 : // If it is "End" then just do a "goto" to the last page
4175 0 : if (aType == nsIWebBrowserPrint::PRINTPREVIEW_END) {
4176 0 : aType = nsIWebBrowserPrint::PRINTPREVIEW_GOTO_PAGENUM;
4177 0 : aPageNum = pageCount;
4178 : }
4179 :
4180 : // Now, locate the current page we are on and
4181 : // and the page of the page number
4182 0 : for (nsIFrame* pageFrame : seqFrame->PrincipalChildList()) {
4183 0 : nsRect pageRect = pageFrame->GetRect();
4184 0 : if (pageRect.Contains(pageRect.x, pt.y)) {
4185 0 : currentPage = pageFrame;
4186 : }
4187 0 : if (pageNum == aPageNum) {
4188 0 : fndPageFrame = pageFrame;
4189 0 : break;
4190 : }
4191 0 : pageNum++;
4192 : }
4193 :
4194 0 : if (aType == nsIWebBrowserPrint::PRINTPREVIEW_PREV_PAGE) {
4195 0 : if (currentPage) {
4196 0 : fndPageFrame = currentPage->GetPrevInFlow();
4197 0 : if (!fndPageFrame) {
4198 0 : return NS_OK;
4199 : }
4200 : } else {
4201 0 : return NS_OK;
4202 : }
4203 0 : } else if (aType == nsIWebBrowserPrint::PRINTPREVIEW_NEXT_PAGE) {
4204 0 : if (currentPage) {
4205 0 : fndPageFrame = currentPage->GetNextInFlow();
4206 0 : if (!fndPageFrame) {
4207 0 : return NS_OK;
4208 : }
4209 : } else {
4210 0 : return NS_OK;
4211 : }
4212 : } else { // If we get here we are doing "GoTo"
4213 0 : if (aPageNum < 0 || aPageNum > pageCount) {
4214 0 : return NS_OK;
4215 : }
4216 : }
4217 :
4218 0 : if (fndPageFrame) {
4219 : nscoord newYPosn =
4220 0 : nscoord(mPrintEngine->GetPrintPreviewScale() * fndPageFrame->GetPosition().y);
4221 0 : sf->ScrollTo(nsPoint(pt.x, newYPosn), nsIScrollableFrame::INSTANT);
4222 : }
4223 0 : return NS_OK;
4224 :
4225 : }
4226 :
4227 : NS_IMETHODIMP
4228 0 : nsDocumentViewer::GetGlobalPrintSettings(nsIPrintSettings * *aGlobalPrintSettings)
4229 : {
4230 0 : return nsPrintEngine::GetGlobalPrintSettings(aGlobalPrintSettings);
4231 : }
4232 :
4233 : // XXX This always returns false for subdocuments
4234 : NS_IMETHODIMP
4235 0 : nsDocumentViewer::GetDoingPrint(bool *aDoingPrint)
4236 : {
4237 0 : NS_ENSURE_ARG_POINTER(aDoingPrint);
4238 :
4239 0 : *aDoingPrint = false;
4240 0 : if (mPrintEngine) {
4241 : // XXX shouldn't this be GetDoingPrint() ?
4242 0 : return mPrintEngine->GetDoingPrintPreview(aDoingPrint);
4243 : }
4244 0 : return NS_OK;
4245 : }
4246 :
4247 : // XXX This always returns false for subdocuments
4248 : NS_IMETHODIMP
4249 0 : nsDocumentViewer::GetDoingPrintPreview(bool *aDoingPrintPreview)
4250 : {
4251 0 : NS_ENSURE_ARG_POINTER(aDoingPrintPreview);
4252 :
4253 0 : *aDoingPrintPreview = false;
4254 0 : if (mPrintEngine) {
4255 0 : return mPrintEngine->GetDoingPrintPreview(aDoingPrintPreview);
4256 : }
4257 0 : return NS_OK;
4258 : }
4259 :
4260 : NS_IMETHODIMP
4261 0 : nsDocumentViewer::GetCurrentPrintSettings(nsIPrintSettings * *aCurrentPrintSettings)
4262 : {
4263 0 : NS_ENSURE_ARG_POINTER(aCurrentPrintSettings);
4264 :
4265 0 : *aCurrentPrintSettings = nullptr;
4266 0 : NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
4267 :
4268 0 : return mPrintEngine->GetCurrentPrintSettings(aCurrentPrintSettings);
4269 : }
4270 :
4271 :
4272 : NS_IMETHODIMP
4273 0 : nsDocumentViewer::GetCurrentChildDOMWindow(mozIDOMWindowProxy** aCurrentChildDOMWindow)
4274 : {
4275 0 : NS_ENSURE_ARG_POINTER(aCurrentChildDOMWindow);
4276 0 : *aCurrentChildDOMWindow = nullptr;
4277 0 : return NS_ERROR_NOT_IMPLEMENTED;
4278 : }
4279 :
4280 : NS_IMETHODIMP
4281 0 : nsDocumentViewer::Cancel()
4282 : {
4283 0 : NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
4284 0 : return mPrintEngine->Cancelled();
4285 : }
4286 :
4287 : NS_IMETHODIMP
4288 0 : nsDocumentViewer::ExitPrintPreview()
4289 : {
4290 0 : if (GetIsPrinting())
4291 0 : return NS_ERROR_FAILURE;
4292 0 : NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
4293 :
4294 0 : if (GetIsPrintPreview()) {
4295 0 : ReturnToGalleyPresentation();
4296 : }
4297 0 : return NS_OK;
4298 : }
4299 :
4300 : //----------------------------------------------------------------------------------
4301 : // Enumerate all the documents for their titles
4302 : NS_IMETHODIMP
4303 0 : nsDocumentViewer::EnumerateDocumentNames(uint32_t* aCount,
4304 : char16_t*** aResult)
4305 : {
4306 : #ifdef NS_PRINTING
4307 0 : NS_ENSURE_ARG(aCount);
4308 0 : NS_ENSURE_ARG_POINTER(aResult);
4309 0 : NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
4310 :
4311 0 : return mPrintEngine->EnumerateDocumentNames(aCount, aResult);
4312 : #else
4313 : return NS_ERROR_FAILURE;
4314 : #endif
4315 : }
4316 :
4317 : NS_IMETHODIMP
4318 0 : nsDocumentViewer::GetIsFramesetFrameSelected(bool *aIsFramesetFrameSelected)
4319 : {
4320 : #ifdef NS_PRINTING
4321 0 : *aIsFramesetFrameSelected = false;
4322 0 : NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
4323 :
4324 0 : return mPrintEngine->GetIsFramesetFrameSelected(aIsFramesetFrameSelected);
4325 : #else
4326 : return NS_ERROR_FAILURE;
4327 : #endif
4328 : }
4329 :
4330 : NS_IMETHODIMP
4331 0 : nsDocumentViewer::GetPrintPreviewNumPages(int32_t *aPrintPreviewNumPages)
4332 : {
4333 : #ifdef NS_PRINTING
4334 0 : NS_ENSURE_ARG_POINTER(aPrintPreviewNumPages);
4335 0 : NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
4336 :
4337 0 : return mPrintEngine->GetPrintPreviewNumPages(aPrintPreviewNumPages);
4338 : #else
4339 : return NS_ERROR_FAILURE;
4340 : #endif
4341 : }
4342 :
4343 : NS_IMETHODIMP
4344 0 : nsDocumentViewer::GetIsFramesetDocument(bool *aIsFramesetDocument)
4345 : {
4346 : #ifdef NS_PRINTING
4347 0 : *aIsFramesetDocument = false;
4348 0 : NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
4349 :
4350 0 : return mPrintEngine->GetIsFramesetDocument(aIsFramesetDocument);
4351 : #else
4352 : return NS_ERROR_FAILURE;
4353 : #endif
4354 : }
4355 :
4356 : NS_IMETHODIMP
4357 0 : nsDocumentViewer::GetIsIFrameSelected(bool *aIsIFrameSelected)
4358 : {
4359 : #ifdef NS_PRINTING
4360 0 : *aIsIFrameSelected = false;
4361 0 : NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
4362 :
4363 0 : return mPrintEngine->GetIsIFrameSelected(aIsIFrameSelected);
4364 : #else
4365 : return NS_ERROR_FAILURE;
4366 : #endif
4367 : }
4368 :
4369 : NS_IMETHODIMP
4370 0 : nsDocumentViewer::GetIsRangeSelection(bool *aIsRangeSelection)
4371 : {
4372 : #ifdef NS_PRINTING
4373 0 : *aIsRangeSelection = false;
4374 0 : NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_FAILURE);
4375 :
4376 0 : return mPrintEngine->GetIsRangeSelection(aIsRangeSelection);
4377 : #else
4378 : return NS_ERROR_FAILURE;
4379 : #endif
4380 : }
4381 :
4382 : //----------------------------------------------------------------------------------
4383 : // Printing/Print Preview Helpers
4384 : //----------------------------------------------------------------------------------
4385 :
4386 : //----------------------------------------------------------------------------------
4387 : // Walks the document tree and tells each DocShell whether Printing/PP is happening
4388 : void
4389 0 : nsDocumentViewer::SetIsPrintingInDocShellTree(nsIDocShellTreeItem* aParentNode,
4390 : bool aIsPrintingOrPP,
4391 : bool aStartAtTop)
4392 : {
4393 0 : nsCOMPtr<nsIDocShellTreeItem> parentItem(do_QueryInterface(aParentNode));
4394 :
4395 : // find top of "same parent" tree
4396 0 : if (aStartAtTop) {
4397 0 : if (aIsPrintingOrPP) {
4398 0 : while (parentItem) {
4399 0 : nsCOMPtr<nsIDocShellTreeItem> parent;
4400 0 : parentItem->GetSameTypeParent(getter_AddRefs(parent));
4401 0 : if (!parent) {
4402 0 : break;
4403 : }
4404 0 : parentItem = do_QueryInterface(parent);
4405 : }
4406 0 : mTopContainerWhilePrinting = do_GetWeakReference(parentItem);
4407 : } else {
4408 0 : parentItem = do_QueryReferent(mTopContainerWhilePrinting);
4409 : }
4410 : }
4411 :
4412 : // Check to see if the DocShell's ContentViewer is printing/PP
4413 0 : nsCOMPtr<nsIContentViewerContainer> viewerContainer(do_QueryInterface(parentItem));
4414 0 : if (viewerContainer) {
4415 0 : viewerContainer->SetIsPrinting(aIsPrintingOrPP);
4416 : }
4417 :
4418 0 : if (!aParentNode) {
4419 0 : return;
4420 : }
4421 :
4422 : // Traverse children to see if any of them are printing.
4423 : int32_t n;
4424 0 : aParentNode->GetChildCount(&n);
4425 0 : for (int32_t i=0; i < n; i++) {
4426 0 : nsCOMPtr<nsIDocShellTreeItem> child;
4427 0 : aParentNode->GetChildAt(i, getter_AddRefs(child));
4428 0 : NS_ASSERTION(child, "child isn't nsIDocShell");
4429 0 : if (child) {
4430 0 : SetIsPrintingInDocShellTree(child, aIsPrintingOrPP, false);
4431 : }
4432 : }
4433 :
4434 : }
4435 : #endif // NS_PRINTING
4436 :
4437 : bool
4438 28 : nsDocumentViewer::ShouldAttachToTopLevel()
4439 : {
4440 28 : if (!mParentWidget)
4441 22 : return false;
4442 :
4443 12 : nsCOMPtr<nsIDocShellTreeItem> containerItem(mContainer);
4444 6 : if (!containerItem)
4445 0 : return false;
4446 :
4447 : // We always attach when using puppet widgets
4448 6 : if (nsIWidget::UsePuppetWidgets())
4449 2 : return true;
4450 :
4451 : #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_UIKIT)
4452 : // On windows, in the parent process we also attach, but just to
4453 : // chrome items
4454 4 : nsWindowType winType = mParentWidget->WindowType();
4455 6 : if ((winType == eWindowType_toplevel ||
4456 2 : winType == eWindowType_dialog ||
4457 8 : winType == eWindowType_invisible) &&
4458 4 : containerItem->ItemType() == nsIDocShellTreeItem::typeChrome) {
4459 4 : return true;
4460 : }
4461 : #endif
4462 :
4463 0 : return false;
4464 : }
4465 :
4466 : //------------------------------------------------------------
4467 : // XXX this always returns false for subdocuments
4468 : bool
4469 0 : nsDocumentViewer::GetIsPrinting()
4470 : {
4471 : #ifdef NS_PRINTING
4472 0 : if (mPrintEngine) {
4473 0 : return mPrintEngine->GetIsPrinting();
4474 : }
4475 : #endif
4476 0 : return false;
4477 : }
4478 :
4479 : //------------------------------------------------------------
4480 : // Notification from the PrintEngine of the current Printing status
4481 : void
4482 0 : nsDocumentViewer::SetIsPrinting(bool aIsPrinting)
4483 : {
4484 : #ifdef NS_PRINTING
4485 0 : if (aIsPrinting) {
4486 0 : SetPrintRelated();
4487 : }
4488 : // Set all the docShells in the docshell tree to be printing.
4489 : // that way if anyone of them tries to "navigate" it can't
4490 0 : nsCOMPtr<nsIDocShell> docShell(mContainer);
4491 0 : if (docShell || !aIsPrinting) {
4492 0 : SetIsPrintingInDocShellTree(docShell, aIsPrinting, true);
4493 : } else {
4494 0 : NS_WARNING("Did you close a window before printing?");
4495 : }
4496 :
4497 0 : if (!aIsPrinting) {
4498 : // Dispatch the 'afterprint' event now, if pending:
4499 0 : mAutoBeforeAndAfterPrint = nullptr;
4500 : }
4501 : #endif
4502 0 : }
4503 :
4504 : //------------------------------------------------------------
4505 : // The PrintEngine holds the current value
4506 : // this called from inside the DocViewer.
4507 : // XXX it always returns false for subdocuments
4508 : bool
4509 108 : nsDocumentViewer::GetIsPrintPreview()
4510 : {
4511 : #ifdef NS_PRINTING
4512 108 : if (mPrintEngine) {
4513 0 : return mPrintEngine->GetIsPrintPreview();
4514 : }
4515 : #endif
4516 108 : return false;
4517 : }
4518 :
4519 : //------------------------------------------------------------
4520 : // Notification from the PrintEngine of the current PP status
4521 : void
4522 0 : nsDocumentViewer::SetIsPrintPreview(bool aIsPrintPreview)
4523 : {
4524 : #ifdef NS_PRINTING
4525 0 : if (aIsPrintPreview) {
4526 0 : SetPrintRelated();
4527 : }
4528 : // Set all the docShells in the docshell tree to be printing.
4529 : // that way if anyone of them tries to "navigate" it can't
4530 0 : nsCOMPtr<nsIDocShell> docShell(mContainer);
4531 0 : if (docShell || !aIsPrintPreview) {
4532 0 : SetIsPrintingInDocShellTree(docShell, aIsPrintPreview, true);
4533 : }
4534 0 : if (!aIsPrintPreview) {
4535 : // Dispatch the 'afterprint' event now, if pending:
4536 0 : mAutoBeforeAndAfterPrint = nullptr;
4537 : }
4538 : #endif
4539 :
4540 : // Protect against pres shell destruction running scripts.
4541 0 : nsAutoScriptBlocker scriptBlocker;
4542 :
4543 0 : if (!aIsPrintPreview) {
4544 0 : if (mPresShell) {
4545 0 : DestroyPresShell();
4546 : }
4547 0 : mWindow = nullptr;
4548 0 : mViewManager = nullptr;
4549 0 : mPresContext = nullptr;
4550 0 : mPresShell = nullptr;
4551 : }
4552 0 : }
4553 :
4554 : //----------------------------------------------------------------------------------
4555 : // nsIDocumentViewerPrint IFace
4556 : //----------------------------------------------------------------------------------
4557 :
4558 : //------------------------------------------------------------
4559 : void
4560 0 : nsDocumentViewer::IncrementDestroyRefCount()
4561 : {
4562 0 : SetPrintRelated();
4563 0 : ++mDestroyRefCount;
4564 0 : }
4565 :
4566 : //------------------------------------------------------------
4567 :
4568 : #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
4569 : //------------------------------------------------------------
4570 : // Reset ESM focus for all descendent doc shells.
4571 : static void
4572 0 : ResetFocusState(nsIDocShell* aDocShell)
4573 : {
4574 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
4575 0 : if (!fm)
4576 0 : return;
4577 :
4578 0 : nsCOMPtr<nsISimpleEnumerator> docShellEnumerator;
4579 0 : aDocShell->GetDocShellEnumerator(nsIDocShellTreeItem::typeContent,
4580 : nsIDocShell::ENUMERATE_FORWARDS,
4581 0 : getter_AddRefs(docShellEnumerator));
4582 :
4583 0 : nsCOMPtr<nsISupports> currentContainer;
4584 : bool hasMoreDocShells;
4585 0 : while (NS_SUCCEEDED(docShellEnumerator->HasMoreElements(&hasMoreDocShells))
4586 0 : && hasMoreDocShells) {
4587 0 : docShellEnumerator->GetNext(getter_AddRefs(currentContainer));
4588 0 : nsCOMPtr<nsPIDOMWindowOuter> win = do_GetInterface(currentContainer);
4589 0 : if (win)
4590 0 : fm->ClearFocus(win);
4591 : }
4592 : }
4593 : #endif // NS_PRINTING && NS_PRINT_PREVIEW
4594 :
4595 : void
4596 0 : nsDocumentViewer::ReturnToGalleyPresentation()
4597 : {
4598 : #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
4599 0 : SetPrintRelated();
4600 :
4601 0 : if (!GetIsPrintPreview()) {
4602 0 : NS_ERROR("Wow, we should never get here!");
4603 0 : return;
4604 : }
4605 :
4606 0 : SetIsPrintPreview(false);
4607 :
4608 0 : mPrintEngine->TurnScriptingOn(true);
4609 0 : mPrintEngine->Destroy();
4610 0 : mPrintEngine = nullptr;
4611 :
4612 0 : nsCOMPtr<nsIDocShell> docShell(mContainer);
4613 0 : ResetFocusState(docShell);
4614 :
4615 0 : SetTextZoom(mTextZoom);
4616 0 : SetFullZoom(mPageZoom);
4617 0 : SetOverrideDPPX(mOverrideDPPX);
4618 0 : SetMinFontSize(mMinFontSize);
4619 0 : Show();
4620 :
4621 : #endif // NS_PRINTING && NS_PRINT_PREVIEW
4622 : }
4623 :
4624 : //------------------------------------------------------------
4625 : // This called ONLY when printing has completed and the DV
4626 : // is being notified that it should get rid of the PrintEngine.
4627 : //
4628 : // BUT, if we are in Print Preview then we want to ignore the
4629 : // notification (we do not get rid of the PrintEngine)
4630 : //
4631 : // One small caveat:
4632 : // This IS called from two places in this module for cleaning
4633 : // up when an error occurred during the start up printing
4634 : // and print preview
4635 : //
4636 : void
4637 0 : nsDocumentViewer::OnDonePrinting()
4638 : {
4639 : #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
4640 0 : SetPrintRelated();
4641 0 : if (mPrintEngine) {
4642 0 : RefPtr<nsPrintEngine> pe = mPrintEngine;
4643 0 : if (GetIsPrintPreview()) {
4644 0 : pe->DestroyPrintingData();
4645 : } else {
4646 0 : mPrintEngine = nullptr;
4647 0 : pe->Destroy();
4648 : }
4649 :
4650 : // We are done printing, now cleanup
4651 0 : if (mDeferredWindowClose) {
4652 0 : mDeferredWindowClose = false;
4653 0 : if (mContainer) {
4654 0 : if (nsCOMPtr<nsPIDOMWindowOuter> win = do_QueryInterface(mContainer->GetWindow())) {
4655 0 : win->Close();
4656 : }
4657 : }
4658 0 : } else if (mClosingWhilePrinting) {
4659 0 : if (mDocument) {
4660 0 : mDocument->Destroy();
4661 0 : mDocument = nullptr;
4662 : }
4663 0 : mClosingWhilePrinting = false;
4664 : }
4665 : }
4666 : #endif // NS_PRINTING && NS_PRINT_PREVIEW
4667 0 : }
4668 :
4669 0 : NS_IMETHODIMP nsDocumentViewer::SetPageMode(bool aPageMode, nsIPrintSettings* aPrintSettings)
4670 : {
4671 0 : if (aPageMode) {
4672 0 : SetPrintRelated();
4673 : }
4674 :
4675 : // XXX Page mode is only partially working; it's currently used for
4676 : // reftests that require a paginated context
4677 0 : mIsPageMode = aPageMode;
4678 :
4679 : // The DestroyPresShell call requires a script blocker, since the
4680 : // PresShell::Destroy call it does can cause scripts to run, which could
4681 : // re-entrantly call methods on the nsDocumentViewer.
4682 0 : nsAutoScriptBlocker scriptBlocker;
4683 :
4684 0 : if (mPresShell) {
4685 0 : DestroyPresShell();
4686 : }
4687 :
4688 0 : if (mPresContext) {
4689 0 : DestroyPresContext();
4690 : }
4691 :
4692 0 : mViewManager = nullptr;
4693 0 : mWindow = nullptr;
4694 :
4695 0 : NS_ENSURE_STATE(mDocument);
4696 0 : if (aPageMode)
4697 : {
4698 : mPresContext = CreatePresContext(mDocument,
4699 0 : nsPresContext::eContext_PageLayout, FindContainerView());
4700 0 : NS_ENSURE_TRUE(mPresContext, NS_ERROR_OUT_OF_MEMORY);
4701 0 : mPresContext->SetPaginatedScrolling(true);
4702 0 : mPresContext->SetPrintSettings(aPrintSettings);
4703 0 : nsresult rv = mPresContext->Init(mDeviceContext);
4704 0 : NS_ENSURE_SUCCESS(rv, rv);
4705 : }
4706 0 : NS_ENSURE_SUCCESS(InitInternal(mParentWidget, nullptr, mBounds, true, false),
4707 : NS_ERROR_FAILURE);
4708 :
4709 0 : Show();
4710 0 : return NS_OK;
4711 : }
4712 :
4713 : NS_IMETHODIMP
4714 0 : nsDocumentViewer::GetHistoryEntry(nsISHEntry **aHistoryEntry)
4715 : {
4716 0 : NS_IF_ADDREF(*aHistoryEntry = mSHEntry);
4717 0 : return NS_OK;
4718 : }
4719 :
4720 : NS_IMETHODIMP
4721 0 : nsDocumentViewer::GetIsTabModalPromptAllowed(bool *aAllowed)
4722 : {
4723 0 : *aAllowed = !mHidden;
4724 0 : return NS_OK;
4725 : }
4726 :
4727 : NS_IMETHODIMP
4728 5 : nsDocumentViewer::GetIsHidden(bool *aHidden)
4729 : {
4730 5 : *aHidden = mHidden;
4731 5 : return NS_OK;
4732 : }
4733 :
4734 : NS_IMETHODIMP
4735 0 : nsDocumentViewer::SetIsHidden(bool aHidden)
4736 : {
4737 0 : mHidden = aHidden;
4738 0 : return NS_OK;
4739 : }
4740 :
4741 : void
4742 4 : nsDocumentViewer::DestroyPresShell()
4743 : {
4744 : // We assert this because destroying the pres shell could otherwise cause
4745 : // re-entrancy into nsDocumentViewer methods, and all callers of
4746 : // DestroyPresShell need to do other cleanup work afterwards before it
4747 : // is safe for those re-entrant method calls to be made.
4748 4 : MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(),
4749 : "DestroyPresShell must only be called when scripts are blocked");
4750 :
4751 : nsIFrame* vmRootFrame =
4752 8 : mViewManager && mViewManager->GetRootView()
4753 8 : ? mViewManager->GetRootView()->GetFrame()
4754 4 : : nullptr;
4755 4 : nsIFrame* psRootFrame = mPresShell ? mPresShell->GetRootFrame() : nullptr;
4756 4 : MOZ_RELEASE_ASSERT(vmRootFrame == psRootFrame);
4757 :
4758 : // Break circular reference (or something)
4759 4 : mPresShell->EndObservingDocument();
4760 :
4761 8 : RefPtr<mozilla::dom::Selection> selection = GetDocumentSelection();
4762 4 : if (selection && mSelectionListener)
4763 4 : selection->RemoveSelectionListener(mSelectionListener);
4764 :
4765 4 : bool hadRootFrame = !!mPresShell->GetRootFrame();
4766 4 : mPresShell->Destroy();
4767 4 : mPresShellDestroyed = true;
4768 4 : MOZ_RELEASE_ASSERT(!mPresShell->GetRootFrame());
4769 : // destroying the frame tree via presshell destroy should have done this
4770 4 : if (hadRootFrame) {
4771 0 : MOZ_RELEASE_ASSERT(!mViewManager || !mViewManager->GetRootView());
4772 : }
4773 4 : MOZ_RELEASE_ASSERT(!mViewManager || !mViewManager->GetRootView() ||
4774 : (!mViewManager->GetRootView()->GetFrame() &&
4775 : !mViewManager->GetRootView()->GetFirstChild()));
4776 :
4777 4 : mPresShell = nullptr;
4778 4 : }
4779 :
4780 : void
4781 4 : nsDocumentViewer::DestroyPresContext()
4782 : {
4783 4 : mPresContext->Detach();
4784 4 : mPresContext = nullptr;
4785 4 : }
4786 :
4787 : bool
4788 0 : nsDocumentViewer::IsInitializedForPrintPreview()
4789 : {
4790 0 : return mInitializedForPrintPreview;
4791 : }
4792 :
4793 : void
4794 0 : nsDocumentViewer::InitializeForPrintPreview()
4795 : {
4796 0 : SetPrintRelated();
4797 0 : mInitializedForPrintPreview = true;
4798 0 : }
4799 :
4800 : void
4801 0 : nsDocumentViewer::SetPrintPreviewPresentation(nsViewManager* aViewManager,
4802 : nsPresContext* aPresContext,
4803 : nsIPresShell* aPresShell)
4804 : {
4805 : // Protect against pres shell destruction running scripts and re-entrantly
4806 : // creating a new presentation.
4807 0 : nsAutoScriptBlocker scriptBlocker;
4808 :
4809 0 : if (mPresShell) {
4810 0 : DestroyPresShell();
4811 : }
4812 :
4813 0 : mWindow = nullptr;
4814 0 : mViewManager = aViewManager;
4815 0 : mPresContext = aPresContext;
4816 0 : mPresShell = aPresShell;
4817 :
4818 0 : if (ShouldAttachToTopLevel()) {
4819 0 : DetachFromTopLevelWidget();
4820 0 : nsView* rootView = mViewManager->GetRootView();
4821 0 : rootView->AttachToTopLevelWidget(mParentWidget);
4822 0 : mAttachedToParent = true;
4823 : }
4824 0 : }
4825 :
4826 : // Fires the "document-shown" event so that interested parties are aware of it.
4827 : NS_IMETHODIMP
4828 5 : nsDocumentShownDispatcher::Run()
4829 : {
4830 : nsCOMPtr<nsIObserverService> observerService =
4831 10 : mozilla::services::GetObserverService();
4832 5 : if (observerService) {
4833 5 : observerService->NotifyObservers(mDocument, "document-shown", nullptr);
4834 : }
4835 10 : return NS_OK;
4836 : }
|