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