Coverage Report

Created: 2018-09-25 14:53

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