From 562d828fddb7f5a766fbf9160ab0f91b8c0e1f0c Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Sun, 28 Sep 2008 15:14:28 -0400 Subject: [PATCH] Bug 433616 part 1. Make it possible to create a document viewer with no parent widget or container, and make various code saner about handling null document/prescontext/documentviewer containers. r=roc, sr=jst --- content/base/public/nsContentUtils.h | 7 ++ content/base/src/nsContentUtils.cpp | 18 ++++ content/base/src/nsDocument.cpp | 4 +- content/events/src/nsEventStateManager.cpp | 3 + content/html/document/src/nsHTMLDocument.cpp | 23 +++-- dom/src/base/nsFocusController.cpp | 2 +- layout/base/nsDocumentViewer.cpp | 93 ++++++++++++-------- layout/base/nsPresShell.cpp | 72 +++++++-------- layout/forms/nsFileControlFrame.cpp | 7 +- layout/style/nsMediaFeatures.cpp | 6 +- layout/xul/base/src/nsTitleBarFrame.cpp | 4 +- 11 files changed, 146 insertions(+), 93 deletions(-) diff --git a/content/base/public/nsContentUtils.h b/content/base/public/nsContentUtils.h index 9c15db3408ba..9ad2ed269200 100644 --- a/content/base/public/nsContentUtils.h +++ b/content/base/public/nsContentUtils.h @@ -807,6 +807,13 @@ public: */ static PRBool IsChromeDoc(nsIDocument *aDocument); + /** + * Returns true if aDocument belongs to a chrome docshell for + * display purposes. Returns false for null documents or documents + * which do not belong to a docshell. + */ + static PRBool IsInChromeDocshell(nsIDocument *aDocument); + /** * Release *aSupportsPtr when the shutdown notification is received */ diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp index 7279b9edffa2..4941911c9fd5 100644 --- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -2903,6 +2903,24 @@ nsContentUtils::IsChromeDoc(nsIDocument *aDocument) return aDocument->NodePrincipal() == systemPrincipal; } +// static +PRBool +nsContentUtils::IsInChromeDocshell(nsIDocument *aDocument) +{ + if (!aDocument) { + return PR_FALSE; + } + + nsCOMPtr docContainer = aDocument->GetContainer(); + nsCOMPtr docShell(do_QueryInterface(docContainer)); + PRInt32 itemType = nsIDocShellTreeItem::typeContent; + if (docShell) { + docShell->GetItemType(&itemType); + } + + return itemType == nsIDocShellTreeItem::typeChrome; +} + // static nsIContentPolicy* nsContentUtils::GetContentPolicy() diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index 91e7df1812c5..8c15fbab17b7 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -5727,9 +5727,7 @@ nsDocument::FlushPendingNotifications(mozFlushType aType) // Should we be flushing pending binding constructors in here? - nsPIDOMWindow *window = GetWindow(); - - if (aType <= Flush_ContentAndNotify || !window) { + if (aType <= Flush_ContentAndNotify) { // Nothing to do here return; } diff --git a/content/events/src/nsEventStateManager.cpp b/content/events/src/nsEventStateManager.cpp index 1957bfb2b362..2235ff4965dd 100644 --- a/content/events/src/nsEventStateManager.cpp +++ b/content/events/src/nsEventStateManager.cpp @@ -6282,6 +6282,9 @@ nsEventStateManager::ShiftFocusByDoc(PRBool aForward) nsCOMPtr pcContainer = mPresContext->GetContainer(); nsCOMPtr curNode = do_QueryInterface(pcContainer); + if (!curNode) { + return; + } // perform a depth first search (preorder) of the docshell tree // looking for an HTML Frame or a chrome document diff --git a/content/html/document/src/nsHTMLDocument.cpp b/content/html/document/src/nsHTMLDocument.cpp index daaf980eece5..f1a78ccd6afc 100644 --- a/content/html/document/src/nsHTMLDocument.cpp +++ b/content/html/document/src/nsHTMLDocument.cpp @@ -709,10 +709,6 @@ nsHTMLDocument::StartDocumentLoad(const char* aCommand, NS_ENSURE_SUCCESS(rv, rv); } - nsCOMPtr docShell(do_QueryInterface(aContainer)); - - nsCOMPtr dcInfo; - docShell->GetDocumentCharsetInfo(getter_AddRefs(dcInfo)); PRInt32 textType = GET_BIDI_OPTION_TEXTTYPE(GetBidiOptions()); // Look for the parent document. Note that at this point we don't have our @@ -722,11 +718,17 @@ nsHTMLDocument::StartDocumentLoad(const char* aCommand, // in this block of code, if we get an error result, we return it // but if we get a null pointer, that's perfectly legal for parent // and parentContentViewer + nsCOMPtr docShell(do_QueryInterface(aContainer)); + + // No support yet for docshell-less HTML + NS_ENSURE_TRUE(docShell || IsXHTML(), NS_ERROR_FAILURE); + nsCOMPtr docShellAsItem(do_QueryInterface(docShell)); - NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE); nsCOMPtr parentAsItem; - docShellAsItem->GetSameTypeParent(getter_AddRefs(parentAsItem)); + if (docShellAsItem) { + docShellAsItem->GetSameTypeParent(getter_AddRefs(parentAsItem)); + } nsCOMPtr parent(do_QueryInterface(parentAsItem)); nsCOMPtr parentDocument; @@ -747,7 +749,9 @@ nsHTMLDocument::StartDocumentLoad(const char* aCommand, nsCOMPtr muCV; PRBool muCVIsParent = PR_FALSE; nsCOMPtr cv; - docShell->GetContentViewer(getter_AddRefs(cv)); + if (docShell) { + docShell->GetContentViewer(getter_AddRefs(cv)); + } if (cv) { muCV = do_QueryInterface(cv); } else { @@ -784,6 +788,11 @@ nsHTMLDocument::StartDocumentLoad(const char* aCommand, parserCharsetSource = charsetSource; parserCharset = charset; } else { + NS_ASSERTION(docShell && docShellAsItem, "Unexpected null value"); + + nsCOMPtr dcInfo; + docShell->GetDocumentCharsetInfo(getter_AddRefs(dcInfo)); + charsetSource = kCharsetUninitialized; wyciwygChannel = do_QueryInterface(aChannel); diff --git a/dom/src/base/nsFocusController.cpp b/dom/src/base/nsFocusController.cpp index 34ab5ea82b19..4535e8fa0afc 100644 --- a/dom/src/base/nsFocusController.cpp +++ b/dom/src/base/nsFocusController.cpp @@ -423,7 +423,7 @@ nsFocusController::GetWindowFromDocument(nsIDOMDocument* aDocument) { nsCOMPtr doc = do_QueryInterface(aDocument); if (!doc) - return NS_OK; + return nsnull; return doc->GetWindow(); } diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp index e98e22865a5b..26d33fa1b0ee 100644 --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -433,7 +433,7 @@ protected: nsCOMPtr mPreviousViewer; nsCOMPtr mSHEntry; - nsIWidget* mParentWidget; // purposely won't be ref counted + nsIWidget* mParentWidget; // purposely won't be ref counted. May be null // mTextZoom/mPageZoom record the textzoom/pagezoom of the first (galley) // presshell only. @@ -958,14 +958,11 @@ DocumentViewerImpl::LoadComplete(nsresult aStatus) // First, get the window from the document... nsPIDOMWindow *window = mDocument->GetWindow(); - // Fail if no window is available... - NS_ENSURE_TRUE(window, NS_ERROR_NULL_POINTER); - mLoaded = PR_TRUE; // Now, fire either an OnLoad or OnError event to the document... PRBool restoring = PR_FALSE; - if(NS_SUCCEEDED(aStatus)) { + if(NS_SUCCEEDED(aStatus) && window) { nsEventStatus status = nsEventStatus_eIgnore; nsEvent event(PR_TRUE, NS_LOAD); event.flags |= NS_EVENT_FLAG_CANT_BUBBLE; @@ -1241,12 +1238,6 @@ DocumentViewerImpl::Open(nsISupports *aState, nsISHEntry *aSHEntry) { NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED); - // Our container might have gone away while we were closed. - // If this is the case, we must fail to open so we don't crash. - nsCOMPtr container = do_QueryReferent(mContainer); - if (!container) - return NS_ERROR_NOT_AVAILABLE; - nsRect bounds; mWindow->GetBounds(bounds); @@ -1262,11 +1253,13 @@ DocumentViewerImpl::Open(nsISupports *aState, nsISHEntry *aSHEntry) // Rehook the child presentations. The child shells are still in // session history, so get them from there. - nsCOMPtr item; - PRInt32 itemIndex = 0; - while (NS_SUCCEEDED(aSHEntry->ChildShellAt(itemIndex++, - getter_AddRefs(item))) && item) { - AttachContainerRecurse(nsCOMPtr(do_QueryInterface(item))); + if (aSHEntry) { + nsCOMPtr item; + PRInt32 itemIndex = 0; + while (NS_SUCCEEDED(aSHEntry->ChildShellAt(itemIndex++, + getter_AddRefs(item))) && item) { + AttachContainerRecurse(nsCOMPtr(do_QueryInterface(item))); + } } SyncParentSubDocMap(); @@ -1873,11 +1866,11 @@ DocumentViewerImpl::Show(void) if (mDocument && !mPresShell && !mWindow) { nsCOMPtr base_win(do_QueryReferent(mContainer)); - NS_ENSURE_TRUE(base_win, NS_ERROR_UNEXPECTED); - - base_win->GetParentWidget(&mParentWidget); - NS_ENSURE_TRUE(mParentWidget, NS_ERROR_UNEXPECTED); - mParentWidget->Release(); // GetParentWidget AddRefs, but mParentWidget is weak + if (base_win) { + base_win->GetParentWidget(&mParentWidget); + NS_ENSURE_TRUE(mParentWidget, NS_ERROR_UNEXPECTED); + mParentWidget->Release(); // GetParentWidget AddRefs, but mParentWidget is weak + } nsresult rv = CreateDeviceContext(mParentWidget); NS_ENSURE_SUCCESS(rv, rv); @@ -1894,7 +1887,12 @@ DocumentViewerImpl::Show(void) } nsRect tbounds; - mParentWidget->GetBounds(tbounds); + if (mParentWidget) { + mParentWidget->GetBounds(tbounds); + } else { + // No good default size; just size to 0 by 0 for lack of anything better. + tbounds = nsRect(0, 0, 0, 0); + } rv = MakeWindow(nsSize(mPresContext->DevPixelsToAppUnits(tbounds.width), mPresContext->DevPixelsToAppUnits(tbounds.height))); @@ -2098,9 +2096,11 @@ DocumentViewerImpl::CreateStyleSet(nsIDocument* aDocument, // The document will fill in the document sheets when we create the presshell // Handle the user sheets. + PRInt32 shellType = nsIDocShellTreeItem::typeContent;; nsCOMPtr docShell(do_QueryReferent(mContainer)); - PRInt32 shellType; - docShell->GetItemType(&shellType); + if (docShell) { + docShell->GetItemType(&shellType); + } nsICSSStyleSheet* sheet = nsnull; if (shellType == nsIDocShellTreeItem::typeChrome) { sheet = nsLayoutStylesheetCache::UserChromeSheet(); @@ -2119,7 +2119,9 @@ DocumentViewerImpl::CreateStyleSet(nsIDocument* aDocument, nsCOMPtr uri; nsCOMPtr csssheet; - ds->GetChromeEventHandler(getter_AddRefs(chromeHandler)); + if (ds) { + ds->GetChromeEventHandler(getter_AddRefs(chromeHandler)); + } if (chromeHandler) { nsCOMPtr elt(do_QueryInterface(chromeHandler)); nsCOMPtr content(do_QueryInterface(elt)); @@ -2209,7 +2211,8 @@ DocumentViewerImpl::MakeWindow(const nsSize& aSize) // Create a child window of the parent that is our "root view/window" // if aParentWidget has a view, we'll hook our view manager up to its view tree - nsIView* containerView = nsIView::GetViewFor(mParentWidget); + nsIView* containerView = + mParentWidget ? nsIView::GetViewFor(mParentWidget) : nsnull; if (containerView) { // see if the containerView has already been hooked into a foreign view manager hierarchy @@ -2251,8 +2254,21 @@ DocumentViewerImpl::MakeWindow(const nsSize& aSize) // pass in a native widget to be the parent widget ONLY if the view hierarchy will stand alone. // otherwise the view will find its own parent widget and "do the right thing" to // establish a parent/child widget relationship - rv = view->CreateWidget(kWidgetCID, nsnull, - containerView != nsnull ? nsnull : mParentWidget->GetNativeData(NS_NATIVE_WIDGET), + nsWidgetInitData initData; + nsWidgetInitData* initDataPtr; + if (!mParentWidget) { + initDataPtr = &initData; + initData.mWindowType = eWindowType_invisible; + + initData.mContentType = + nsContentUtils::IsInChromeDocshell(mDocument) ? + eContentTypeUI : eContentTypeContent; + } else { + initDataPtr = nsnull; + } + rv = view->CreateWidget(kWidgetCID, initDataPtr, + (containerView != nsnull || !mParentWidget) ? + nsnull : mParentWidget->GetNativeData(NS_NATIVE_WIDGET), PR_TRUE, PR_FALSE); if (NS_FAILED(rv)) return rv; @@ -2273,12 +2289,14 @@ DocumentViewerImpl::MakeWindow(const nsSize& aSize) nsresult DocumentViewerImpl::CreateDeviceContext(nsIWidget* aWidget) { - NS_PRECONDITION(!mDeviceContext, "How come we're calling this?"); - if (aWidget) { - mDeviceContext = do_CreateInstance(kDeviceContextCID); - NS_ENSURE_TRUE(mDeviceContext, NS_ERROR_FAILURE); - mDeviceContext->Init(aWidget->GetNativeData(NS_NATIVE_WIDGET)); - } + NS_PRECONDITION(!mPresShell && !mPresContext && !mWindow, + "This will screw up our existing presentation"); + // Create a device context even if we already have one, since our widget + // might have changed. + mDeviceContext = do_CreateInstance(kDeviceContextCID); + NS_ENSURE_TRUE(mDeviceContext, NS_ERROR_FAILURE); + mDeviceContext->Init(aWidget ? + aWidget->GetNativeData(NS_NATIVE_WIDGET) : nsnull); return NS_OK; } @@ -2762,8 +2780,6 @@ DocumentViewerImpl::GetAuthorStyleDisabled(PRBool* aStyleDisabled) NS_IMETHODIMP DocumentViewerImpl::GetDefaultCharacterSet(nsACString& aDefaultCharacterSet) { - NS_ENSURE_STATE(nsCOMPtr(do_QueryReferent(mContainer))); - if (mDefaultCharacterSet.IsEmpty()) { const nsAdoptingString& defCharset = @@ -3058,9 +3074,10 @@ NS_IMETHODIMP DocumentViewerImpl::SizeToContent() { NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE); + // Skip doing this on docshell-less documents for now nsCOMPtr docShellAsItem(do_QueryReferent(mContainer)); - NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE); - + NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_NOT_AVAILABLE); + nsCOMPtr docShellParent; docShellAsItem->GetSameTypeParent(getter_AddRefs(docShellParent)); diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 5189cd8008ee..f00f52ee40cd 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -1804,49 +1804,35 @@ PresShell::SetPreferenceStyleRules(PRBool aForceReflow) NS_PRECONDITION(mPresContext, "presContext cannot be null"); if (mPresContext) { - nsresult result = NS_OK; - // first, make sure this is not a chrome shell - nsCOMPtr container = mPresContext->GetContainer(); - if (container) { - nsCOMPtr docShell(do_QueryInterface(container, &result)); - if (NS_SUCCEEDED(result) && docShell){ - PRInt32 docShellType; - result = docShell->GetItemType(&docShellType); - if (NS_SUCCEEDED(result)){ - if (nsIDocShellTreeItem::typeChrome == docShellType){ - return NS_OK; - } - } - } + if (nsContentUtils::IsInChromeDocshell(mDocument)) { + return NS_OK; + } + +#ifdef DEBUG_attinasi + printf("Setting Preference Style Rules:\n"); +#endif + // if here, we need to create rules for the prefs + // - this includes the background-color, the text-color, + // the link color, the visited link color and the link-underlining + + // first clear any exising rules + nsresult result = ClearPreferenceStyleRules(); + + // now the link rules (must come after the color rules, or links will not be correct color!) + // XXX - when there is both an override and agent pref stylesheet this won't matter, + // as the color rules will be overrides and the links rules will be agent + if (NS_SUCCEEDED(result)) { + result = SetPrefLinkRules(); } if (NS_SUCCEEDED(result)) { - -#ifdef DEBUG_attinasi - printf("Setting Preference Style Rules:\n"); -#endif - // if here, we need to create rules for the prefs - // - this includes the background-color, the text-color, - // the link color, the visited link color and the link-underlining - - // first clear any exising rules - result = ClearPreferenceStyleRules(); - - // now the link rules (must come after the color rules, or links will not be correct color!) - // XXX - when there is both an override and agent pref stylesheet this won't matter, - // as the color rules will be overrides and the links rules will be agent - if (NS_SUCCEEDED(result)) { - result = SetPrefLinkRules(); - } - if (NS_SUCCEEDED(result)) { - result = SetPrefFocusRules(); - } - if (NS_SUCCEEDED(result)) { - result = SetPrefNoScriptRule(); - } - if (NS_SUCCEEDED(result)) { - result = SetPrefNoFramesRule(); - } + result = SetPrefFocusRules(); + } + if (NS_SUCCEEDED(result)) { + result = SetPrefNoScriptRule(); + } + if (NS_SUCCEEDED(result)) { + result = SetPrefNoFramesRule(); } #ifdef DEBUG_attinasi printf( "Preference Style Rules set: error=%ld\n", (long)result); @@ -5488,7 +5474,11 @@ nsresult PresShell::RetargetEventToParent(nsGUIEvent* aEvent, // Now, find the parent pres shell and send the event there nsCOMPtr treeItem = do_QueryInterface(container); - NS_ASSERTION(treeItem, "No tree item for container."); + if (!treeItem) { + // Might have gone away, or never been around to start with + return NS_ERROR_FAILURE; + } + nsCOMPtr parentTreeItem; treeItem->GetParent(getter_AddRefs(parentTreeItem)); nsCOMPtr parentDocShell = diff --git a/layout/forms/nsFileControlFrame.cpp b/layout/forms/nsFileControlFrame.cpp index d9a6ce45c2e8..361dbaa09f58 100644 --- a/layout/forms/nsFileControlFrame.cpp +++ b/layout/forms/nsFileControlFrame.cpp @@ -306,7 +306,12 @@ nsFileControlFrame::MouseListener::MouseClick(nsIDOMEvent* aMouseEvent) if (!filePicker) return NS_ERROR_FAILURE; - result = filePicker->Init(doc->GetWindow(), title, nsIFilePicker::modeOpen); + nsPIDOMWindow* win = doc->GetWindow(); + if (!win) { + return NS_ERROR_FAILURE; + } + + result = filePicker->Init(win, title, nsIFilePicker::modeOpen); if (NS_FAILED(result)) return result; diff --git a/layout/style/nsMediaFeatures.cpp b/layout/style/nsMediaFeatures.cpp index 9477c5a0d060..abbefb137303 100644 --- a/layout/style/nsMediaFeatures.cpp +++ b/layout/style/nsMediaFeatures.cpp @@ -84,9 +84,13 @@ GetDeviceContextFor(nsPresContext* aPresContext) // things right in multi-monitor situations. // (It's not clear if this is really needed for GetDepth and GetColor, // but do it anyway.) - return nsLayoutUtils::GetDeviceContextForScreenInfo( + nsIDeviceContext* ctx = nsLayoutUtils::GetDeviceContextForScreenInfo( nsCOMPtr(do_QueryInterface( nsCOMPtr(aPresContext->GetContainer())))); + if (!ctx) { + ctx = aPresContext->DeviceContext(); + } + return ctx; } PR_STATIC_CALLBACK(nsresult) diff --git a/layout/xul/base/src/nsTitleBarFrame.cpp b/layout/xul/base/src/nsTitleBarFrame.cpp index cfd4ef79a80d..9564e7e23d7c 100644 --- a/layout/xul/base/src/nsTitleBarFrame.cpp +++ b/layout/xul/base/src/nsTitleBarFrame.cpp @@ -178,7 +178,9 @@ nsTitleBarFrame::HandleEvent(nsPresContext* aPresContext, else { nsIPresShell* presShell = aPresContext->PresShell(); nsPIDOMWindow *window = presShell->GetDocument()->GetWindow(); - window->MoveBy(nsMoveBy.x, nsMoveBy.y); + if (window) { + window->MoveBy(nsMoveBy.x, nsMoveBy.y); + } } *aEventStatus = nsEventStatus_eConsumeNoDefault;