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