/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is the Mozilla browser. * * The Initial Developer of the Original Code is Netscape * Communications, Inc. Portions created by Netscape are * Copyright (C) 1999, Mozilla. All Rights Reserved. * * Contributor(s): * Travis Bogard */ #include "nsHTMLDocShell.h" #include "nsString.h" //***************************************************************************** //*** nsHTMLDocShell: Object Management //***************************************************************************** nsHTMLDocShell::nsHTMLDocShell() : nsDocShellBase(), mAllowPlugins(PR_TRUE), mMarginWidth(0), mMarginHeight(0), mIsFrame(PR_FALSE) { } nsHTMLDocShell::~nsHTMLDocShell() { } NS_IMETHODIMP nsHTMLDocShell::Create(nsISupports* aOuter, const nsIID& aIID, void** ppv) { NS_ENSURE_ARG_POINTER(ppv); NS_ENSURE_NO_AGGREGATION(aOuter); nsHTMLDocShell* docShell = new nsHTMLDocShell(); NS_ENSURE_TRUE(docShell, NS_ERROR_OUT_OF_MEMORY); NS_ADDREF(docShell); nsresult rv = docShell->QueryInterface(aIID, ppv); NS_RELEASE(docShell); return rv; } //***************************************************************************** // nsHTMLDocShell::nsISupports Overrides //***************************************************************************** NS_IMPL_ISUPPORTS7(nsHTMLDocShell, nsIDocShell, nsIHTMLDocShell, nsIDocShellEdit, nsIDocShellFile, nsIGenericWindow, nsIScrollable, nsITextScroll) //***************************************************************************** // nsHTMLDocShell::nsIDocShell Overrides //***************************************************************************** NS_IMETHODIMP nsHTMLDocShell::CanHandleContentType(const PRUnichar* contentType, PRBool* canHandle) { NS_ENSURE_ARG_POINTER(canHandle); nsAutoString aType(contentType); if(aType.EqualsIgnoreCase("text/html")) *canHandle = PR_TRUE; else *canHandle = PR_FALSE; return NS_OK; } //***************************************************************************** // nsHTMLDocShell::nsIHTMLDocShell //***************************************************************************** NS_IMETHODIMP nsHTMLDocShell::ScrollToNode(nsIDOMNode* aNode) { NS_ENSURE_ARG(aNode); NS_ENSURE_STATE(mContentViewer); nsCOMPtr presShell; NS_ENSURE_SUCCESS(GetPresShell(getter_AddRefs(presShell)), NS_ERROR_FAILURE); // Get the nsIContent interface, because that's what we need to // get the primary frame nsCOMPtr content(do_QueryInterface(aNode)); NS_ENSURE_TRUE(content, NS_ERROR_FAILURE); // Get the primary frame nsIFrame* frame; // Remember Frames aren't ref-counted. They are in their // own special little world. NS_ENSURE_SUCCESS(GetPrimaryFrameFor(content, &frame), NS_ERROR_FAILURE); // tell the pres shell to scroll to the frame NS_ENSURE_SUCCESS(presShell->ScrollFrameIntoView(frame, NS_PRESSHELL_SCROLL_TOP, NS_PRESSHELL_SCROLL_ANYWHERE), NS_ERROR_FAILURE); return NS_OK; } NS_IMETHODIMP nsHTMLDocShell::GetAllowPlugins(PRBool* aAllowPlugins) { NS_ENSURE_ARG_POINTER(aAllowPlugins); *aAllowPlugins = mAllowPlugins; return NS_OK; } NS_IMETHODIMP nsHTMLDocShell::SetAllowPlugins(PRBool aAllowPlugins) { mAllowPlugins = aAllowPlugins; return NS_OK; } NS_IMETHODIMP nsHTMLDocShell::GetMarginWidth(PRInt32* aMarginWidth) { NS_ENSURE_ARG_POINTER(aMarginWidth); *aMarginWidth = mMarginWidth; return NS_OK; } NS_IMETHODIMP nsHTMLDocShell::SetMarginWidth(PRInt32 aMarginWidth) { mMarginWidth = aMarginWidth; return NS_OK; } NS_IMETHODIMP nsHTMLDocShell::GetMarginHeight(PRInt32* aMarginHeight) { NS_ENSURE_ARG_POINTER(aMarginHeight); *aMarginHeight = mMarginHeight; return NS_OK; } NS_IMETHODIMP nsHTMLDocShell::SetMarginHeight(PRInt32 aMarginHeight) { mMarginHeight = aMarginHeight; return NS_OK; } NS_IMETHODIMP nsHTMLDocShell::GetIsFrame(PRBool* aIsFrame) { NS_ENSURE_ARG_POINTER(aIsFrame); *aIsFrame = mIsFrame; return NS_OK; } NS_IMETHODIMP nsHTMLDocShell::SetIsFrame(PRBool aIsFrame) { mIsFrame = aIsFrame; return NS_OK; } // XXX: SEMANTIC CHANGE! // returns a copy of the string. Caller is responsible for freeing result // using Recycle(aDefaultCharacterSet) NS_IMETHODIMP nsHTMLDocShell::GetDefaultCharacterSet(PRUnichar** aDefaultCharacterSet) { NS_ENSURE_ARG_POINTER(aDefaultCharacterSet); static char *gDefCharset = nsnull; // XXX: memory leak! if (0 == mDefaultCharacterSet.Length()) { if ((nsnull == gDefCharset) || (nsnull == *gDefCharset)) { if(mPrefs) mPrefs->CopyCharPref("intl.charset.default", &gDefCharset); } if ((nsnull == gDefCharset) || (nsnull == *gDefCharset)) mDefaultCharacterSet = "ISO-8859-1"; else mDefaultCharacterSet = gDefCharset; } *aDefaultCharacterSet = mDefaultCharacterSet.ToNewUnicode(); return NS_OK; } NS_IMETHODIMP nsHTMLDocShell::SetDefaultCharacterSet(const PRUnichar* aDefaultCharacterSet) { mDefaultCharacterSet = aDefaultCharacterSet; // this does a copy of aDefaultCharacterSet PRInt32 i, n = mChildren.Count(); for (i = 0; i < n; i++) { nsIDocShell* child = (nsIDocShell*) mChildren.ElementAt(i); NS_WARN_IF_FALSE(child, "null child in docshell"); if (child) { nsCOMPtr childAsHTMLDocShell = do_QueryInterface(child); if (childAsHTMLDocShell) { childAsHTMLDocShell->SetDefaultCharacterSet(aDefaultCharacterSet); } } } return NS_OK; } // XXX: SEMANTIC CHANGE! // returns a copy of the string. Caller is responsible for freeing result // using Recycle(aForceCharacterSet) NS_IMETHODIMP nsHTMLDocShell::GetForceCharacterSet(PRUnichar** aForceCharacterSet) { NS_ENSURE_ARG_POINTER(aForceCharacterSet); nsAutoString emptyStr; if (mForceCharacterSet.Equals(emptyStr)) { *aForceCharacterSet = nsnull; } else { *aForceCharacterSet = mForceCharacterSet.ToNewUnicode(); } return NS_OK; } NS_IMETHODIMP nsHTMLDocShell::SetForceCharacterSet(const PRUnichar* aForceCharacterSet) { mForceCharacterSet = aForceCharacterSet; PRInt32 i, n = mChildren.Count(); for (i = 0; i < n; i++) { nsIDocShell* child = (nsIDocShell*) mChildren.ElementAt(i); NS_WARN_IF_FALSE(child, "null child in docshell"); if (child) { nsCOMPtr childAsHTMLDocShell = do_QueryInterface(child); if (childAsHTMLDocShell) { childAsHTMLDocShell->SetForceCharacterSet(aForceCharacterSet); } } } return NS_OK; } // XXX: SEMANTIC CHANGE! // returns a copy of the string. Caller is responsible for freeing result // using Recycle(aHintCharacterSet) NS_IMETHODIMP nsHTMLDocShell::GetHintCharacterSet(PRUnichar * *aHintCharacterSet) { NS_ENSURE_ARG_POINTER(aHintCharacterSet); if(kCharsetUninitialized == mHintCharsetSource) { *aHintCharacterSet = nsnull; } else { *aHintCharacterSet = mHintCharset.ToNewUnicode(); mHintCharsetSource = kCharsetUninitialized; } return NS_OK; } NS_IMETHODIMP nsHTMLDocShell::GetHintCharacterSetSource(PRInt32 *aHintCharacterSetSource) { NS_ENSURE_ARG_POINTER(aHintCharacterSetSource); *aHintCharacterSetSource = mHintCharsetSource; return NS_OK; } // XXX: poor error checking NS_IMETHODIMP nsHTMLDocShell::SizeToContent() { // get the presentation shell nsCOMPtr presShell; NS_ENSURE_SUCCESS(GetPresShell(getter_AddRefs(presShell)), NS_ERROR_FAILURE); NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE); nsRect shellArea; PRInt32 width, height; float pixelScale; NS_ENSURE_SUCCESS(presShell->ResizeReflow(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE), NS_ERROR_FAILURE); // so how big is it? nsCOMPtr presContext; NS_ENSURE_SUCCESS(GetPresContext(getter_AddRefs(presContext)), NS_ERROR_FAILURE); NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE); presContext->GetVisibleArea(shellArea); presContext->GetTwipsToPixels(&pixelScale); width = PRInt32((float)shellArea.width*pixelScale); height = PRInt32((float)shellArea.height*pixelScale); // if we're the outermost webshell for this window, size the window /* XXX: how do we do this now? if (mContainer) { nsCOMPtr browser = do_QueryInterface(mContainer); if (browser) { nsCOMPtr browserWebShell; PRInt32 oldX, oldY, oldWidth, oldHeight, widthDelta, heightDelta; nsRect windowBounds; GetBounds(oldX, oldY, oldWidth, oldHeight); widthDelta = width - oldWidth; heightDelta = height - oldHeight; browser->GetWindowBounds(windowBounds); browser->SizeWindowTo(windowBounds.width + widthDelta, windowBounds.height + heightDelta); } } */ NS_ASSERTION(PR_FALSE, "NOT YET IMPLEMENTED"); return NS_ERROR_NOT_IMPLEMENTED; //return NS_OK; } //***************************************************************************** // nsHTMLDocShell::nsIDocShellEdit Overrides //***************************************************************************** /* the basic idea here is to grab the topmost content object * (for HTML documents, that's the BODY) * and select all it's children */ NS_IMETHODIMP nsHTMLDocShell::SelectAll() { NS_ENSURE_STATE(mContentViewer); nsCOMPtr presShell; NS_ENSURE_SUCCESS(GetPresShell(getter_AddRefs(presShell)), NS_ERROR_FAILURE); NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE); // get the selection object nsCOMPtr selection; NS_ENSURE_SUCCESS(presShell->GetSelection(SELECTION_NORMAL, getter_AddRefs(selection)), NS_ERROR_FAILURE); NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE); // get the document nsCOMPtr nodeList; nsAutoString bodyTag = "body"; nsCOMPtr document; NS_ENSURE_SUCCESS(GetDocument(getter_AddRefs(document)), NS_ERROR_FAILURE); // get the body tag(s) in the document NS_ENSURE_SUCCESS(document->GetElementsByTagName(bodyTag, getter_AddRefs(nodeList)), NS_ERROR_FAILURE); NS_ENSURE_TRUE(nodeList, NS_OK); // this means the document has no body, so nothing to select // verify this document has exactly one body node PRUint32 count; NS_ENSURE_SUCCESS(nodeList->GetLength(&count), NS_ERROR_FAILURE); NS_ENSURE_TRUE(count != 1, NS_OK); // could be true for a frameset doc // select all children of the body nsCOMPtr bodyNode; NS_ENSURE_SUCCESS(nodeList->Item(0, getter_AddRefs(bodyNode)), NS_ERROR_FAILURE); NS_ENSURE_TRUE(bodyNode, NS_ERROR_FAILURE); // start the selection in front of the first child NS_ENSURE_SUCCESS(selection->Collapse(bodyNode, 0), NS_ERROR_FAILURE); // end the selection after the last child PRInt32 numBodyChildren=0; nsCOMPtrlastChild; NS_ENSURE_SUCCESS(bodyNode->GetLastChild(getter_AddRefs(lastChild)), NS_ERROR_FAILURE); NS_ENSURE_TRUE(lastChild, NS_OK); // body isn't required to have any children, so it's ok if lastChild is null. // in this case, we just have a collapsed selection at (body, 0) NS_ENSURE_SUCCESS(GetChildOffset(lastChild, bodyNode, &numBodyChildren), NS_ERROR_FAILURE); NS_ENSURE_SUCCESS(selection->Extend(bodyNode, numBodyChildren+1), NS_ERROR_FAILURE); return NS_OK; } //***************************************************************************** // nsHTMLDocShell::nsIDocShellFile Overrides //***************************************************************************** //***************************************************************************** // nsHTMLDocShell::nsIDocShellContainer Overrides //***************************************************************************** NS_IMETHODIMP nsHTMLDocShell::AddChild(nsIDocShell *aChild) { NS_ENSURE_ARG_POINTER(aChild); // base class does most the work NS_ENSURE_SUCCESS(nsDocShellBase::AddChild(aChild), NS_ERROR_FAILURE); nsCOMPtr childAsHTMLDocShell = do_QueryInterface(aChild); if (childAsHTMLDocShell) { PRUnichar *defaultCharset=nsnull; NS_ENSURE_SUCCESS(GetDefaultCharacterSet(&defaultCharset), NS_ERROR_FAILURE); NS_ENSURE_SUCCESS(childAsHTMLDocShell->SetDefaultCharacterSet(defaultCharset), NS_ERROR_FAILURE); NS_ENSURE_SUCCESS(childAsHTMLDocShell->SetForceCharacterSet(mForceCharacterSet.GetUnicode()), NS_ERROR_FAILURE); } return NS_OK; } //***************************************************************************** // nsHTMLDocShell::nsIGenericWindow Overrides //***************************************************************************** /* NS_IMETHODIMP nsHTMLDocShell::SetVisibility(PRBool aVisibility) { nsCOMPtr viewManager; nsresult rv = GetViewManager(getter_AddRefs(viewManager)); if (NS_FAILED(rv)) { return rv; } if (!viewManager) { return NS_ERROR_NOT_INITIALIZED; } nsIView *rootView; // views are not ref counted viewManager->GetRootView(&rootView); if (NS_FAILED(rv)) { return rv; } if (!rootView) { return NS_ERROR_NOT_INITIALIZED; } rv = rootView->SetVisibility(aVisibility); return rv; } */ // XXX: SEMANTIC CHANGE! // returns a copy of the string. Caller is responsible for freeing result // using Recycle(aTitle) /*NS_IMETHODIMP nsHTMLDocShell::GetTitle(PRUnichar **aTitle) { NS_ENSURE_ARG_POINTER(aTitle); *aTitle = mTitle.GetNewUnicode(); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsHTMLDocShell::SetTitle(const PRUnichar * aTitle) { NS_ENSURE_ARG_POINTER(aTitle); // Record local title mTitle = aTitle; // Title's set on the top level web-shell are passed on to the container nsIWebShell* parent; GetParent(parent); if (nsnull == parent) { // null parent means it's top-level doc shell nsIBrowserWindow *browserWindow = GetBrowserWindow(); if (nsnull != browserWindow) { browserWindow->SetTitle(aTitle); NS_RELEASE(browserWindow); // XXX: remove when global history is pulled out of docShell // Oh this hack sucks. But there isn't any other way that I can // reliably get the title text. Sorry. do { nsresult rv; NS_WITH_SERVICE(nsIGlobalHistory, history, "component://netscape/browser/global-history", &rv); if (NS_FAILED(rv)) break; rv = history->SetPageTitle(nsCAutoString(mURL), aTitle); if (NS_FAILED(rv)) break; } while (0); } } else { parent->SetTitle(aTitle); NS_RELEASE(parent); } return NS_OK; } */ /*NS_IMETHODIMP nsHTMLDocShell::GetZoom(float *aZoom) { NS_ENSURE_ARG_POINTER(aZoom); *aZoom = mZoom; return NS_OK; } // XXX: poor error checking NS_IMETHODIMP nsHTMLDocShell::SetZoom(float aZoom) { mZoom = aZoom; if (mDeviceContext) mDeviceContext->SetZoom(mZoom); nsCOMPtr viewManager; rv = GetViewManager(getter_AddRefs(viewManager)); if (NS_FAILED(rv)) { return rv; } if (!viewManager) { return NS_ERROR_NULL_POINTER; } nsIView *rootview = nsnull; nsIScrollableView *sv = nsnull; viewManager->GetRootScrollableView(&sv); if (nsnull != sv) { sv->ComputeScrollOffsets(); } vm->GetRootView(rootview); if (nsnull != rootview) { vm->UpdateView(rootview, nsnull, 0); } return NS_OK; } */ //***************************************************************************** // nsHTMLDocShell::nsIScrollable Overrides //***************************************************************************** //***************************************************************************** // nsHTMLDocShell::nsITextScroll Overrides //***************************************************************************** //***************************************************************************** // nsHTMLDocShell: Helper Routines //***************************************************************************** nsresult nsHTMLDocShell::GetPrimaryFrameFor(nsIContent* content, nsIFrame** frame) { //XXX Implement return NS_ERROR_FAILURE; }