From 1decc3f74ca93d346508b7303342b5cfa28837a9 Mon Sep 17 00:00:00 2001 From: "jaggernaut%netscape.com" Date: Fri, 30 May 2003 00:21:01 +0000 Subject: [PATCH] Bug 203960: Make bookmark groups replace existing tabs instead of appending. r=jkeiser, varga, adamlock, sr=jst, hewitt --- content/base/public/nsContentUtils.h | 5 + content/base/src/nsContentUtils.cpp | 211 +++++++++++++++++ content/base/src/nsDocumentViewer.cpp | 10 + content/base/src/nsPrintEngine.cpp | 4 +- .../html/content/src/nsGenericHTMLElement.cpp | 25 +- .../html/document/src/nsHTMLContentSink.cpp | 3 - docshell/base/nsDocShell.cpp | 59 +++-- docshell/base/nsDocShell.h | 3 +- docshell/base/nsIDocShell.idl | 5 + docshell/base/nsWebShell.cpp | 3 - layout/base/nsCSSFrameConstructor.cpp | 6 +- layout/base/nsDocumentViewer.cpp | 10 + layout/base/nsFrameManager.cpp | 218 +----------------- layout/base/nsIPresShell.h | 2 - layout/base/nsPresShell.cpp | 51 ++-- layout/base/public/nsIFrameManager.h | 4 - layout/base/public/nsIPresShell.h | 2 - layout/html/base/src/nsFrameManager.cpp | 218 +----------------- layout/html/base/src/nsPresShell.cpp | 51 ++-- .../html/style/src/nsCSSFrameConstructor.cpp | 6 +- layout/printing/nsPrintEngine.cpp | 4 +- xpfe/browser/resources/content/navigator.js | 56 ++++- .../locale/en-US/navigator.properties | 2 + .../bookmarks/resources/bookmarks.js | 15 +- .../resources/content/bindings/tabbrowser.xml | 165 ++++++++++++- 25 files changed, 563 insertions(+), 575 deletions(-) diff --git a/content/base/public/nsContentUtils.h b/content/base/public/nsContentUtils.h index 643957c33f9..956d8ba27ea 100644 --- a/content/base/public/nsContentUtils.h +++ b/content/base/public/nsContentUtils.h @@ -44,6 +44,7 @@ #include "nsIJSContextStack.h" #include "nsIScriptContext.h" #include "nsCOMArray.h" +#include "nsIStatefulFrame.h" class nsIScriptGlobalObject; class nsIXPConnect; @@ -243,6 +244,10 @@ public: return sNameSpaceManager; }; + static nsresult GenerateStateKey(nsIContent* aContent, + nsIStatefulFrame::SpecialStateID aID, + nsACString& aKey); + private: static nsresult GetDocumentAndPrincipal(nsIDOMNode* aNode, nsIDocument** aDocument, diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp index 5243fa8c5d6..3748d322401 100644 --- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -38,6 +38,9 @@ #include "jsapi.h" #include "nsCOMPtr.h" +#include "nsAString.h" +#include "nsPrintfCString.h" +#include "nsUnicharUtils.h" #include "nsIServiceManagerUtils.h" #include "nsIScriptGlobalObject.h" #include "nsIScriptContext.h" @@ -62,6 +65,14 @@ #include "nsIParserService.h" #include "nsIServiceManager.h" #include "nsIAttribute.h" +#include "nsIContentList.h" +#include "nsIHTMLDocument.h" +#include "nsIDOMHTMLDocument.h" +#include "nsIDOMHTMLCollection.h" +#include "nsIDOMHTMLFormElement.h" +#include "nsIForm.h" +#include "nsIFormControl.h" +#include "nsHTMLAtoms.h" static const char kJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1"; static NS_DEFINE_IID(kParserServiceCID, NS_PARSERSERVICE_CID); @@ -1318,6 +1329,206 @@ nsContentUtils::TrimWhitespace(const nsAString& aStr, PRBool aTrimTrailing) return Substring(start, end); } +static inline void KeyAppendSep(nsACString& aKey) +{ + if (!aKey.IsEmpty()) { + aKey.Append('>'); + } +} + +static inline void KeyAppendString(const nsAString& aString, nsACString& aKey) +{ + KeyAppendSep(aKey); + + // Could escape separator here if collisions happen. > is not a legal char + // for a name or type attribute, so we should be safe avoiding that extra work. + + aKey.Append(NS_ConvertUCS2toUTF8(aString)); +} + +static inline void KeyAppendString(const nsACString& aString, nsACString& aKey) +{ + KeyAppendSep(aKey); + + // Could escape separator here if collisions happen. > is not a legal char + // for a name or type attribute, so we should be safe avoiding that extra work. + + aKey.Append(aString); +} + +static inline void KeyAppendInt(PRInt32 aInt, nsACString& aKey) +{ + KeyAppendSep(aKey); + + aKey.Append(nsPrintfCString("%d", aInt)); +} + +static inline void KeyAppendAtom(nsIAtom* aAtom, nsACString& aKey) +{ + NS_PRECONDITION(aAtom, "KeyAppendAtom: aAtom can not be null!\n"); + + const char* atomString = nsnull; + aAtom->GetUTF8String(&atomString); + + KeyAppendString(nsDependentCString(atomString), aKey); +} + +static inline PRBool IsAutocompleteOff(nsIDOMElement* aElement) +{ + nsAutoString autocomplete; + aElement->GetAttribute(NS_LITERAL_STRING("autocomplete"), autocomplete); + return autocomplete.Equals(NS_LITERAL_STRING("off"), + nsCaseInsensitiveStringComparator()); +} + +/*static*/ nsresult +nsContentUtils::GenerateStateKey(nsIContent* aContent, + nsIStatefulFrame::SpecialStateID aID, + nsACString& aKey) +{ + aKey.Truncate(); + + // SpecialStateID case - e.g. scrollbars around the content window + // The key in this case is the special state id (always < min(contentID)) + if (nsIStatefulFrame::eNoID != aID) { + KeyAppendInt(aID, aKey); + return NS_OK; + } + + // We must have content if we're not using a special state id + NS_ENSURE_TRUE(aContent, NS_ERROR_FAILURE); + + // Don't capture state for anonymous content + PRUint32 contentID; + aContent->GetContentID(&contentID); + if (!contentID) { + return NS_OK; + } + + nsCOMPtr element(do_QueryInterface(aContent)); + if (element && IsAutocompleteOff(element)) { + return NS_OK; + } + + nsCOMPtr doc; + aContent->GetDocument(*getter_AddRefs(doc)); + nsCOMPtr htmlDocument(do_QueryInterface(doc)); + + PRBool generatedUniqueKey = PR_FALSE; + + if (htmlDocument) { + nsCOMPtr domHtmlDocument(do_QueryInterface(htmlDocument)); + nsCOMPtr forms; + domHtmlDocument->GetForms(getter_AddRefs(forms)); + nsCOMPtr htmlForms(do_QueryInterface(forms)); + + nsCOMPtr formControls; + htmlDocument->GetFormControlElements(getter_AddRefs(formControls)); + nsCOMPtr htmlFormControls(do_QueryInterface(formControls)); + + // If we have a form control and can calculate form information, use + // that as the key - it is more reliable than contentID. + // Important to have a unique key, and tag/type/name may not be. + // + // If the control has a form, the format of the key is: + // type>IndOfFormInDoc>IndOfControlInForm>FormName>name + // else: + // type>IndOfControlInDoc>name + // + // XXX We don't need to use index if name is there + // + nsCOMPtr control(do_QueryInterface(aContent)); + if (control && htmlFormControls && htmlForms) { + + // Append the control type + KeyAppendInt(control->GetType(), aKey); + + // If in a form, add form name / index of form / index in form + PRInt32 index = -1; + nsCOMPtr formElement; + control->GetForm(getter_AddRefs(formElement)); + if (formElement) { + + if (IsAutocompleteOff(formElement)) { + aKey.Truncate(); + return NS_OK; + } + + // Append the index of the form in the document + nsCOMPtr formContent(do_QueryInterface(formElement)); + htmlForms->IndexOf(formContent, index, PR_FALSE); + if (index <= -1) { + // + // XXX HACK this uses some state that was dumped into the document + // specifically to fix bug 138892. What we are trying to do is *guess* + // which form this control's state is found in, with the highly likely + // guess that the highest form parsed so far is the one. + // This code should not be on trunk, only branch. + // + htmlDocument->GetNumFormsSynchronous(&index); + index--; + } + if (index > -1) { + KeyAppendInt(index, aKey); + + // Append the index of the control in the form + nsCOMPtr form(do_QueryInterface(formElement)); + form->IndexOfControl(control, &index); + NS_ASSERTION(index > -1, + "nsFrameManager::GenerateStateKey didn't find form control index!"); + + if (index > -1) { + KeyAppendInt(index, aKey); + generatedUniqueKey = PR_TRUE; + } + } + + // Append the form name + nsAutoString formName; + formElement->GetName(formName); + KeyAppendString(formName, aKey); + + } else { + + // If not in a form, add index of control in document + // Less desirable than indexing by form info. + + // Hash by index of control in doc (we are not in a form) + // These are important as they are unique, and type/name may not be. + + // We don't refresh the form control list here (passing PR_TRUE + // for aFlush), although we really should. Forcing a flush + // causes a signficant pageload performance hit. See bug + // 166636. Doing this wrong means you will see the assertion + // below being hit. + htmlFormControls->IndexOf(aContent, index, PR_FALSE); + NS_ASSERTION(index > -1, + "nsFrameManager::GenerateStateKey didn't find content " + "by type! See bug 139568"); + + if (index > -1) { + KeyAppendInt(index, aKey); + generatedUniqueKey = PR_TRUE; + } + } + + // Append the control name + nsAutoString name; + aContent->GetAttr(kNameSpaceID_None, nsHTMLAtoms::name, name); + KeyAppendString(name, aKey); + } + } + + if (!generatedUniqueKey) { + + // Either we didn't have a form control or we aren't in an HTML document + // so we can't figure out form info, hash by content ID instead :( + KeyAppendInt(contentID, aKey); + } + + return NS_OK; +} + void nsCxPusher::Push(nsISupports *aCurrentTarget) { diff --git a/content/base/src/nsDocumentViewer.cpp b/content/base/src/nsDocumentViewer.cpp index 15b70451964..bccdc9d4b3d 100644 --- a/content/base/src/nsDocumentViewer.cpp +++ b/content/base/src/nsDocumentViewer.cpp @@ -1509,6 +1509,16 @@ DocumentViewerImpl::Hide(void) } #endif + nsCOMPtr docShell(do_QueryInterface(mContainer)); + if (docShell) { + PRBool saveLayoutState = PR_FALSE; + docShell->GetShouldSaveLayoutState(&saveLayoutState); + if (saveLayoutState) { + nsCOMPtr layoutState; + mPresShell->CaptureHistoryState(getter_AddRefs(layoutState), PR_TRUE); + } + } + mPresShell->Destroy(); mPresShell = nsnull; diff --git a/content/base/src/nsPrintEngine.cpp b/content/base/src/nsPrintEngine.cpp index ded0419f961..8f3eab353e3 100644 --- a/content/base/src/nsPrintEngine.cpp +++ b/content/base/src/nsPrintEngine.cpp @@ -2761,7 +2761,8 @@ nsPrintEngine::ReflowPrintObject(nsPrintObject * aPO, PRBool aDoCalcShrink) presShell->CaptureHistoryState(getter_AddRefs(layoutState), PR_TRUE); // set it on the new pres shell - aPO->mPresShell->SetHistoryState(layoutState); + nsCOMPtr docShell(do_QueryInterface(aPO->mWebShell)); + docShell->SetLayoutHistoryState(layoutState); // turn off animated GIFs if (aPO->mPresContext) { @@ -2876,7 +2877,6 @@ nsPrintEngine::ReflowPrintObject(nsPrintObject * aPO, PRBool aDoCalcShrink) } else { printf("View is null!\n"); } - nsCOMPtr docShell(do_QueryInterface(aPO->mWebShell)); if (docShell) { fprintf(fd, "--------------- All Views ----------------\n"); DumpViews(docShell, fd); diff --git a/content/html/content/src/nsGenericHTMLElement.cpp b/content/html/content/src/nsGenericHTMLElement.cpp index 84e9c07d3b7..0efaf61cdc3 100644 --- a/content/html/content/src/nsGenericHTMLElement.cpp +++ b/content/html/content/src/nsGenericHTMLElement.cpp @@ -77,6 +77,7 @@ #include "nsRange.h" #include "nsIPresShell.h" #include "nsIPresContext.h" +#include "nsIDocShell.h" #include "nsIView.h" #include "nsIViewManager.h" #include "nsINameSpaceManager.h" @@ -90,6 +91,7 @@ #include "nsIHTMLContentContainer.h" #include "nsHTMLParts.h" +#include "nsContentUtils.h" #include "nsString.h" #include "nsReadableUtils.h" #include "nsUnicharUtils.h" @@ -2679,27 +2681,24 @@ nsGenericHTMLElement::GetLayoutHistoryAndKey(nsIHTMLContent* aContent, return rv; } - nsCOMPtr presShell; - doc->GetShellAt(0, getter_AddRefs(presShell)); - NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE); - // // Get the history (don't bother with the key if the history is not there) // - rv = presShell->GetHistoryState(aHistory); - NS_ENSURE_SUCCESS(rv, rv); - if (!*aHistory) { - return NS_OK; + nsCOMPtr container; + doc->GetContainer(getter_AddRefs(container)); + nsCOMPtr docShell(do_QueryInterface(container)); + if (docShell) { + rv = docShell->GetLayoutHistoryState(aHistory); + NS_ENSURE_SUCCESS(rv, rv); + if (!*aHistory) { + return NS_OK; + } } // // Get the state key // - nsCOMPtr frameManager; - presShell->GetFrameManager(getter_AddRefs(frameManager)); - NS_ENSURE_TRUE(frameManager, NS_ERROR_FAILURE); - - rv = frameManager->GenerateStateKey(aContent, nsIStatefulFrame::eNoID, aKey); + rv = nsContentUtils::GenerateStateKey(aContent, nsIStatefulFrame::eNoID, aKey); NS_ENSURE_SUCCESS(rv, rv); // If the state key is blank, this is anonymous content or for diff --git a/content/html/document/src/nsHTMLContentSink.cpp b/content/html/document/src/nsHTMLContentSink.cpp index 7244f6673a5..086b79e6803 100644 --- a/content/html/document/src/nsHTMLContentSink.cpp +++ b/content/html/document/src/nsHTMLContentSink.cpp @@ -150,7 +150,6 @@ #include "nsLayoutCID.h" #include "nsIFrameManager.h" -#include "nsILayoutHistoryState.h" #include "nsIDocShellTreeItem.h" #include "plevent.h" @@ -159,8 +158,6 @@ #include "nsIElementObserver.h" -static NS_DEFINE_CID(kLayoutHistoryStateCID, NS_LAYOUT_HISTORY_STATE_CID); - #ifdef ALLOW_ASYNCH_STYLE_SHEETS const PRBool kBlockByDefault = PR_FALSE; #else diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 96cbad9f8eb..724169c1dd4 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -4177,19 +4177,9 @@ nsDocShell::Embed(nsIContentViewer * aContentViewer, break; } - if (mOSHE && updateHistory) { - nsCOMPtr layoutState; + if (!updateHistory) + SetLayoutHistoryState(nsnull); - rv = mOSHE->GetLayoutHistoryState(getter_AddRefs(layoutState)); - if (layoutState) { - // This is a SH load. That's why there is a LayoutHistoryState in mOSHE - nsCOMPtr presShell; - rv = GetPresShell(getter_AddRefs(presShell)); - if (NS_SUCCEEDED(rv) && presShell) { - rv = presShell->SetHistoryState(layoutState); - } - } - } return NS_OK; } @@ -6270,32 +6260,37 @@ nsDocShell::LoadHistoryEntry(nsISHEntry * aEntry, PRUint32 aLoadType) return rv; } +NS_IMETHODIMP nsDocShell::GetShouldSaveLayoutState(PRBool* aShould) +{ + *aShould = PR_FALSE; + if (mOSHE) { + // Don't capture historystate and save it in history + // if the page asked not to do so. + mOSHE->GetSaveLayoutStateFlag(aShould); + } + + return NS_OK; +} NS_IMETHODIMP nsDocShell::PersistLayoutHistoryState() { nsresult rv = NS_OK; - if (mOSHE) { - PRBool saveHistoryState = PR_TRUE; - mOSHE->GetSaveLayoutStateFlag(&saveHistoryState); - // Don't capture historystate and save it in history - // if the page asked not to do so. - if (!saveHistoryState) - return NS_OK; - nsCOMPtr shell; + PRBool shouldSave; + GetShouldSaveLayoutState(&shouldSave); + if (!shouldSave) + return NS_OK; + nsCOMPtr shell; rv = GetPresShell(getter_AddRefs(shell)); if (NS_SUCCEEDED(rv) && shell) { nsCOMPtr layoutState; rv = shell->CaptureHistoryState(getter_AddRefs(layoutState), PR_TRUE); - if (NS_SUCCEEDED(rv) && layoutState) { - rv = mOSHE->SetLayoutHistoryState(layoutState); - } } - } + return rv; } @@ -6933,6 +6928,22 @@ nsDocShell::GetIsExecutingOnLoadHandler(PRBool *aResult) return NS_OK; } +NS_IMETHODIMP +nsDocShell::GetLayoutHistoryState(nsILayoutHistoryState **aLayoutHistoryState) +{ + if (mOSHE) + mOSHE->GetLayoutHistoryState(aLayoutHistoryState); + return NS_OK; +} + +NS_IMETHODIMP +nsDocShell::SetLayoutHistoryState(nsILayoutHistoryState *aLayoutHistoryState) +{ + if (mOSHE) + mOSHE->SetLayoutHistoryState(aLayoutHistoryState); + return NS_OK; +} + //***************************************************************************** //*** nsRefreshTimer: Object Management //***************************************************************************** diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h index ad2176db5b1..0ea4d16656b 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -68,6 +68,7 @@ #include "nsIScriptGlobalObject.h" #include "nsIScriptGlobalObjectOwner.h" #include "nsISHistory.h" +#include "nsILayoutHistoryState.h" #include "nsIStringBundle.h" #include "nsISupportsArray.h" #include "nsIWebNavigation.h" @@ -397,7 +398,7 @@ protected: nsIDocShellTreeOwner * mTreeOwner; // Weak Reference nsIChromeEventHandler * mChromeEventHandler; //Weak Reference - // Indivates that a DocShell in this "docshell tree" is printing + // Indicates that a DocShell in this "docshell tree" is printing PRBool mIsPrintingOrPP; public: diff --git a/docshell/base/nsIDocShell.idl b/docshell/base/nsIDocShell.idl index f8700b7cd66..e47e4c1e7cc 100644 --- a/docshell/base/nsIDocShell.idl +++ b/docshell/base/nsIDocShell.idl @@ -46,6 +46,7 @@ interface nsISimpleEnumerator; interface nsIInputStream; interface nsIRequest; interface nsISHEntry; +interface nsILayoutHistoryState; [scriptable, uuid(69E5DE00-7B8B-11d3-AF61-00A024FFC08C)] interface nsIDocShell : nsISupports @@ -316,5 +317,9 @@ interface nsIDocShell : nsISupports * Returns true if the docshell is currently executing the onLoad Handler */ readonly attribute boolean isExecutingOnLoadHandler; + + attribute nsILayoutHistoryState layoutHistoryState; + + readonly attribute boolean shouldSaveLayoutState; }; diff --git a/docshell/base/nsWebShell.cpp b/docshell/base/nsWebShell.cpp index 300ab56b5b7..5613ffc9351 100644 --- a/docshell/base/nsWebShell.cpp +++ b/docshell/base/nsWebShell.cpp @@ -106,7 +106,6 @@ typedef unsigned long HMTX; #include "nsIPlatformCharset.h" #include "nsICharsetConverterManager.h" #include "nsISocketTransportService.h" -#include "nsILayoutHistoryState.h" #include "nsTextFormatter.h" #include "nsPIDOMWindow.h" #include "nsPICommandUpdater.h" @@ -157,8 +156,6 @@ static PRLogModuleInfo* gLogModule = PR_NewLogModule("webshell"); #define WEB_TRACE(_bit,_args) #endif -static NS_DEFINE_CID(kSimpleURICID, NS_SIMPLEURI_CID); - //---------------------------------------------------------------------- //---------------------------------------------------------------------- diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index e6d488827bc..e72d33e458f 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -820,7 +820,11 @@ nsFrameConstructorState::nsFrameConstructorState(nsIPresContext* aPresCon { aPresContext->GetShell(getter_AddRefs(mPresShell)); mPresShell->GetFrameManager(getter_AddRefs(mFrameManager)); - mPresShell->GetHistoryState(getter_AddRefs(mFrameState)); + nsCOMPtr container; + aPresContext->GetContainer(getter_AddRefs(container)); + nsCOMPtr docShell(do_QueryInterface(container)); + if (docShell) + docShell->GetLayoutHistoryState(getter_AddRefs(mFrameState)); } // Use the first-in-flow of a positioned inline frame in galley mode as the diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp index 15b70451964..bccdc9d4b3d 100644 --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -1509,6 +1509,16 @@ DocumentViewerImpl::Hide(void) } #endif + nsCOMPtr docShell(do_QueryInterface(mContainer)); + if (docShell) { + PRBool saveLayoutState = PR_FALSE; + docShell->GetShouldSaveLayoutState(&saveLayoutState); + if (saveLayoutState) { + nsCOMPtr layoutState; + mPresShell->CaptureHistoryState(getter_AddRefs(layoutState), PR_TRUE); + } + } + mPresShell->Destroy(); mPresShell = nsnull; diff --git a/layout/base/nsFrameManager.cpp b/layout/base/nsFrameManager.cpp index 469526c6858..35b3b5ed950 100644 --- a/layout/base/nsFrameManager.cpp +++ b/layout/base/nsFrameManager.cpp @@ -71,6 +71,7 @@ #include "nsIDOMHTMLFormElement.h" #include "nsIForm.h" #include "nsIContentList.h" +#include "nsContentUtils.h" #include "nsReadableUtils.h" #include "nsUnicharUtils.h" #include "nsPrintfCString.h" @@ -368,10 +369,6 @@ public: nsIFrame* aFrame, nsILayoutHistoryState* aState, nsIStatefulFrame::SpecialStateID aID = nsIStatefulFrame::eNoID); - NS_IMETHOD GenerateStateKey(nsIContent* aContent, - nsIStatefulFrame::SpecialStateID aID, - nsACString& aString); - // Gets and sets properties on a given frame NS_IMETHOD GetFrameProperty(nsIFrame* aFrame, nsIAtom* aPropertyName, @@ -415,8 +412,6 @@ private: UndisplayedMap* mUndisplayedMap; CantRenderReplacedElementEvent* mPostedEvents; PropertyList* mPropertyList; - nsCOMPtr mHTMLForms; - nsCOMPtr mHTMLFormControls; PRBool mIsDestroyingFrames; void ReResolveStyleContext(nsIPresContext* aPresContext, @@ -477,23 +472,6 @@ FrameManager::Init(nsIPresShell* aPresShell, mPresShell = aPresShell; mStyleSet = aStyleSet; - // Force the forms and form control content lists to be added as - // document observers *before* us (pres shell) so they will be - // up to date when we try to use them. - nsCOMPtr document; - mPresShell->GetDocument(getter_AddRefs(document)); - nsCOMPtr htmlDocument(do_QueryInterface(document)); - nsCOMPtr domHtmlDocument(do_QueryInterface(htmlDocument)); - if (domHtmlDocument) { - nsCOMPtr forms; - domHtmlDocument->GetForms(getter_AddRefs(forms)); - mHTMLForms = do_QueryInterface(forms); - - nsCOMPtr formControls; - htmlDocument->GetFormControlElements(getter_AddRefs(formControls)); - mHTMLFormControls = do_QueryInterface(formControls); - } - return NS_OK; } @@ -2117,7 +2095,7 @@ FrameManager::CaptureFrameStateFor(nsIPresContext* aPresContext, rv = aFrame->GetContent(getter_AddRefs(content)); nsCAutoString stateKey; - rv = GenerateStateKey(content, aID, stateKey); + rv = nsContentUtils::GenerateStateKey(content, aID, stateKey); if(NS_FAILED(rv) || stateKey.IsEmpty()) { return rv; } @@ -2181,7 +2159,7 @@ FrameManager::RestoreFrameStateFor(nsIPresContext* aPresContext, nsIFrame* aFram } nsCAutoString stateKey; - rv = GenerateStateKey(content, aID, stateKey); + rv = nsContentUtils::GenerateStateKey(content, aID, stateKey); if (NS_FAILED(rv) || stateKey.IsEmpty()) { return rv; } @@ -2228,196 +2206,6 @@ FrameManager::RestoreFrameState(nsIPresContext* aPresContext, nsIFrame* aFrame, return rv; } - -static inline void KeyAppendSep(nsACString& aKey) -{ - if (!aKey.IsEmpty()) { - aKey.Append('>'); - } -} - -static inline void KeyAppendString(const nsAString& aString, nsACString& aKey) -{ - KeyAppendSep(aKey); - - // Could escape separator here if collisions happen. > is not a legal char - // for a name or type attribute, so we should be safe avoiding that extra work. - - aKey.Append(NS_ConvertUCS2toUTF8(aString)); -} - -static inline void KeyAppendString(const nsACString& aString, nsACString& aKey) -{ - KeyAppendSep(aKey); - - // Could escape separator here if collisions happen. > is not a legal char - // for a name or type attribute, so we should be safe avoiding that extra work. - - aKey.Append(aString); -} - -static inline void KeyAppendInt(PRInt32 aInt, nsACString& aKey) -{ - KeyAppendSep(aKey); - - aKey.Append(nsPrintfCString("%d", aInt)); -} - -static inline void KeyAppendAtom(nsIAtom* aAtom, nsACString& aKey) -{ - NS_PRECONDITION(aAtom, "KeyAppendAtom: aAtom can not be null!\n"); - - const char* atomString = nsnull; - aAtom->GetUTF8String(&atomString); - - KeyAppendString(nsDependentCString(atomString), aKey); -} - -static inline PRBool IsAutocompleteOff(nsIDOMElement* aElement) -{ - nsAutoString autocomplete; - aElement->GetAttribute(NS_LITERAL_STRING("autocomplete"), autocomplete); - ToLowerCase(autocomplete); - return autocomplete.Equals(NS_LITERAL_STRING("off")); -} - -NS_IMETHODIMP -FrameManager::GenerateStateKey(nsIContent* aContent, - nsIStatefulFrame::SpecialStateID aID, - nsACString& aKey) -{ - aKey.Truncate(); - - // SpecialStateID case - e.g. scrollbars around the content window - // The key in this case is the special state id (always < min(contentID)) - if (nsIStatefulFrame::eNoID != aID) { - KeyAppendInt(aID, aKey); - return NS_OK; - } - - // We must have content if we're not using a special state id - NS_ENSURE_TRUE(aContent, NS_ERROR_FAILURE); - - // Don't capture state for anonymous content - PRUint32 contentID; - aContent->GetContentID(&contentID); - if (!contentID) { - return NS_OK; - } - - nsCOMPtr element(do_QueryInterface(aContent)); - if (element && IsAutocompleteOff(element)) { - return NS_OK; - } - - // If we have a form control and can calculate form information, use - // that as the key - it is more reliable than contentID. - // Important to have a unique key, and tag/type/name may not be. - // - // If the control has a form, the format of the key is: - // type>IndOfFormInDoc>IndOfControlInForm>FormName>name - // else: - // type>IndOfControlInDoc>name - // - // XXX We don't need to use index if name is there - // - nsCOMPtr control(do_QueryInterface(aContent)); - PRBool generatedUniqueKey = PR_FALSE; - if (control && mHTMLFormControls && mHTMLForms) { - - // Append the control type - KeyAppendInt(control->GetType(), aKey); - - // If in a form, add form name / index of form / index in form - PRInt32 index = -1; - nsCOMPtr formElement; - control->GetForm(getter_AddRefs(formElement)); - if (formElement) { - - if (IsAutocompleteOff(formElement)) { - aKey.Truncate(); - return NS_OK; - } - - // Append the index of the form in the document - nsCOMPtr formContent(do_QueryInterface(formElement)); - mHTMLForms->IndexOf(formContent, index, PR_FALSE); - if (index <= -1) { - // - // XXX HACK this uses some state that was dumped into the document - // specifically to fix bug 138892. What we are trying to do is *guess* - // which form this control's state is found in, with the highly likely - // guess that the highest form parsed so far is the one. - // This code should not be on trunk, only branch. - // - nsCOMPtr doc; - formContent->GetDocument(*getter_AddRefs(doc)); - nsCOMPtr htmlDoc = do_QueryInterface(doc); - if (htmlDoc) { - htmlDoc->GetNumFormsSynchronous(&index); - index--; - } - } - if (index > -1) { - KeyAppendInt(index, aKey); - - // Append the index of the control in the form - nsCOMPtr form(do_QueryInterface(formElement)); - form->IndexOfControl(control, &index); - NS_ASSERTION(index > -1, - "nsFrameManager::GenerateStateKey didn't find form control index!"); - - if (index > -1) { - KeyAppendInt(index, aKey); - generatedUniqueKey = PR_TRUE; - } - } - - // Append the form name - nsAutoString formName; - formElement->GetName(formName); - KeyAppendString(formName, aKey); - - } else { - - // If not in a form, add index of control in document - // Less desirable than indexing by form info. - - // Hash by index of control in doc (we are not in a form) - // These are important as they are unique, and type/name may not be. - - // We don't refresh the form control list here (passing PR_TRUE - // for aFlush), although we really should. Forcing a flush - // causes a signficant pageload performance hit. See bug - // 166636. Doing this wrong means you will see the assertion - // below being hit. - mHTMLFormControls->IndexOf(aContent, index, PR_FALSE); - NS_ASSERTION(index > -1, - "nsFrameManager::GenerateStateKey didn't find content " - "by type! See bug 139568"); - - if (index > -1) { - KeyAppendInt(index, aKey); - generatedUniqueKey = PR_TRUE; - } - } - - // Append the control name - nsAutoString name; - aContent->GetAttr(kNameSpaceID_None, nsHTMLAtoms::name, name); - KeyAppendString(name, aKey); - } - - if (!generatedUniqueKey) { - - // Either we didn't have a form control or we aren't in an HTML document - // so we can't figure out form info, hash by content ID instead :( - KeyAppendInt(contentID, aKey); - } - - return NS_OK; -} - //---------------------------------------------------------------------- static PLHashNumber diff --git a/layout/base/nsIPresShell.h b/layout/base/nsIPresShell.h index 29d107d6ca4..f5d64fc0b2e 100644 --- a/layout/base/nsIPresShell.h +++ b/layout/base/nsIPresShell.h @@ -485,8 +485,6 @@ public: */ NS_IMETHOD CaptureHistoryState(nsILayoutHistoryState** aLayoutHistoryState, PRBool aLeavingPage = PR_FALSE) = 0; - NS_IMETHOD GetHistoryState(nsILayoutHistoryState** aLayoutHistoryState) = 0; - NS_IMETHOD SetHistoryState(nsILayoutHistoryState* aLayoutHistoryState) = 0; /** * Determine if reflow is currently locked diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 759d4112a69..2b5074d0bab 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -1144,8 +1144,6 @@ public: NS_IMETHOD DoGetContents(const nsACString& aMimeType, PRUint32 aFlags, PRBool aSelectionOnly, nsAString& outValue); NS_IMETHOD CaptureHistoryState(nsILayoutHistoryState** aLayoutHistoryState, PRBool aLeavingPage); - NS_IMETHOD GetHistoryState(nsILayoutHistoryState** aLayoutHistoryState); - NS_IMETHOD SetHistoryState(nsILayoutHistoryState* aLayoutHistoryState); NS_IMETHOD GetGeneratedContentIterator(nsIContent* aContent, GeneratedContentType aType, @@ -1308,7 +1306,6 @@ protected: nsCOMPtr mStyleSet; nsICSSStyleSheet* mPrefStyleSheet; // mStyleSet owns it but we maintaina ref, may be null nsIViewManager* mViewManager; // [WEAK] docViewer owns it so I don't have to - nsWeakPtr mHistoryState; // [WEAK] session history owns this PRUint32 mUpdateCount; // normal reflow commands nsVoidArray mReflowCommands; @@ -1661,8 +1658,6 @@ PresShell::Init(nsIDocument* aDocument, // before creating any frames. SetPreferenceStyleRules(PR_FALSE); - mHistoryState = nsnull; - nsresult result = nsComponentManager::CreateInstance(kFrameSelectionCID, nsnull, NS_GET_IID(nsIFrameSelection), getter_AddRefs(mSelection)); @@ -1799,9 +1794,6 @@ PresShell::Destroy() mIsDestroying = PR_TRUE; - // Clobber weak leaks in case of re-entrancy during tear down - mHistoryState = nsnull; - // We can't release all the event content in // mCurrentEventContentStack here since there might be code on the // stack that will release the event content too. Double release @@ -3673,7 +3665,18 @@ PresShell::EndLoad(nsIDocument *aDocument) // Restore frame state for the root scroll frame nsIFrame* rootFrame = nsnull; GetRootFrame(&rootFrame); - nsCOMPtr historyState = do_QueryReferent(mHistoryState); + nsCOMPtr container; + mPresContext->GetContainer(getter_AddRefs(container)); + if (!container) + return NS_ERROR_FAILURE; + + nsCOMPtr docShell(do_QueryInterface(container)); + if (!docShell) + return NS_ERROR_FAILURE; + + nsCOMPtr historyState; + docShell->GetLayoutHistoryState(getter_AddRefs(historyState)); + if (rootFrame && historyState) { nsIFrame* scrollFrame = nsnull; GetRootScrollFrame(mPresContext, rootFrame, &scrollFrame); @@ -4709,7 +4712,17 @@ PresShell::CaptureHistoryState(nsILayoutHistoryState** aState, PRBool aLeavingPa NS_PRECONDITION(nsnull != aState, "null state pointer"); - nsCOMPtr historyState = do_QueryReferent(mHistoryState); + nsCOMPtr container; + mPresContext->GetContainer(getter_AddRefs(container)); + if (!container) + return NS_ERROR_FAILURE; + + nsCOMPtr docShell(do_QueryInterface(container)); + if (!docShell) + return NS_ERROR_FAILURE; + + nsCOMPtr historyState; + docShell->GetLayoutHistoryState(getter_AddRefs(historyState)); if (!historyState) { // Create the document state object rv = NS_NewLayoutHistoryState(getter_AddRefs(historyState)); @@ -4719,7 +4732,7 @@ PresShell::CaptureHistoryState(nsILayoutHistoryState** aState, PRBool aLeavingPa return rv; } - mHistoryState = getter_AddRefs(NS_GetWeakReference(historyState)); + docShell->SetLayoutHistoryState(historyState); } *aState = historyState; @@ -4747,22 +4760,6 @@ PresShell::CaptureHistoryState(nsILayoutHistoryState** aState, PRBool aLeavingPa return rv; } -NS_IMETHODIMP -PresShell::GetHistoryState(nsILayoutHistoryState** aState) -{ - nsCOMPtr historyState = do_QueryReferent(mHistoryState); - *aState = historyState; - NS_IF_ADDREF(*aState); - return NS_OK; -} - -NS_IMETHODIMP -PresShell::SetHistoryState(nsILayoutHistoryState* aLayoutHistoryState) -{ - mHistoryState = getter_AddRefs(NS_GetWeakReference(aLayoutHistoryState)); - return NS_OK; -} - NS_IMETHODIMP PresShell::GetGeneratedContentIterator(nsIContent* aContent, GeneratedContentType aType, diff --git a/layout/base/public/nsIFrameManager.h b/layout/base/public/nsIFrameManager.h index 558bf27845f..692edb805d7 100644 --- a/layout/base/public/nsIFrameManager.h +++ b/layout/base/public/nsIFrameManager.h @@ -188,10 +188,6 @@ public: nsIFrame* aFrame, nsILayoutHistoryState* aState, nsIStatefulFrame::SpecialStateID aID = nsIStatefulFrame::eNoID) = 0; - NS_IMETHOD GenerateStateKey(nsIContent* aContent, - nsIStatefulFrame::SpecialStateID aID, - nsACString& aString) = 0; - /** * Gets a property value for a given frame. diff --git a/layout/base/public/nsIPresShell.h b/layout/base/public/nsIPresShell.h index 29d107d6ca4..f5d64fc0b2e 100644 --- a/layout/base/public/nsIPresShell.h +++ b/layout/base/public/nsIPresShell.h @@ -485,8 +485,6 @@ public: */ NS_IMETHOD CaptureHistoryState(nsILayoutHistoryState** aLayoutHistoryState, PRBool aLeavingPage = PR_FALSE) = 0; - NS_IMETHOD GetHistoryState(nsILayoutHistoryState** aLayoutHistoryState) = 0; - NS_IMETHOD SetHistoryState(nsILayoutHistoryState* aLayoutHistoryState) = 0; /** * Determine if reflow is currently locked diff --git a/layout/html/base/src/nsFrameManager.cpp b/layout/html/base/src/nsFrameManager.cpp index 469526c6858..35b3b5ed950 100644 --- a/layout/html/base/src/nsFrameManager.cpp +++ b/layout/html/base/src/nsFrameManager.cpp @@ -71,6 +71,7 @@ #include "nsIDOMHTMLFormElement.h" #include "nsIForm.h" #include "nsIContentList.h" +#include "nsContentUtils.h" #include "nsReadableUtils.h" #include "nsUnicharUtils.h" #include "nsPrintfCString.h" @@ -368,10 +369,6 @@ public: nsIFrame* aFrame, nsILayoutHistoryState* aState, nsIStatefulFrame::SpecialStateID aID = nsIStatefulFrame::eNoID); - NS_IMETHOD GenerateStateKey(nsIContent* aContent, - nsIStatefulFrame::SpecialStateID aID, - nsACString& aString); - // Gets and sets properties on a given frame NS_IMETHOD GetFrameProperty(nsIFrame* aFrame, nsIAtom* aPropertyName, @@ -415,8 +412,6 @@ private: UndisplayedMap* mUndisplayedMap; CantRenderReplacedElementEvent* mPostedEvents; PropertyList* mPropertyList; - nsCOMPtr mHTMLForms; - nsCOMPtr mHTMLFormControls; PRBool mIsDestroyingFrames; void ReResolveStyleContext(nsIPresContext* aPresContext, @@ -477,23 +472,6 @@ FrameManager::Init(nsIPresShell* aPresShell, mPresShell = aPresShell; mStyleSet = aStyleSet; - // Force the forms and form control content lists to be added as - // document observers *before* us (pres shell) so they will be - // up to date when we try to use them. - nsCOMPtr document; - mPresShell->GetDocument(getter_AddRefs(document)); - nsCOMPtr htmlDocument(do_QueryInterface(document)); - nsCOMPtr domHtmlDocument(do_QueryInterface(htmlDocument)); - if (domHtmlDocument) { - nsCOMPtr forms; - domHtmlDocument->GetForms(getter_AddRefs(forms)); - mHTMLForms = do_QueryInterface(forms); - - nsCOMPtr formControls; - htmlDocument->GetFormControlElements(getter_AddRefs(formControls)); - mHTMLFormControls = do_QueryInterface(formControls); - } - return NS_OK; } @@ -2117,7 +2095,7 @@ FrameManager::CaptureFrameStateFor(nsIPresContext* aPresContext, rv = aFrame->GetContent(getter_AddRefs(content)); nsCAutoString stateKey; - rv = GenerateStateKey(content, aID, stateKey); + rv = nsContentUtils::GenerateStateKey(content, aID, stateKey); if(NS_FAILED(rv) || stateKey.IsEmpty()) { return rv; } @@ -2181,7 +2159,7 @@ FrameManager::RestoreFrameStateFor(nsIPresContext* aPresContext, nsIFrame* aFram } nsCAutoString stateKey; - rv = GenerateStateKey(content, aID, stateKey); + rv = nsContentUtils::GenerateStateKey(content, aID, stateKey); if (NS_FAILED(rv) || stateKey.IsEmpty()) { return rv; } @@ -2228,196 +2206,6 @@ FrameManager::RestoreFrameState(nsIPresContext* aPresContext, nsIFrame* aFrame, return rv; } - -static inline void KeyAppendSep(nsACString& aKey) -{ - if (!aKey.IsEmpty()) { - aKey.Append('>'); - } -} - -static inline void KeyAppendString(const nsAString& aString, nsACString& aKey) -{ - KeyAppendSep(aKey); - - // Could escape separator here if collisions happen. > is not a legal char - // for a name or type attribute, so we should be safe avoiding that extra work. - - aKey.Append(NS_ConvertUCS2toUTF8(aString)); -} - -static inline void KeyAppendString(const nsACString& aString, nsACString& aKey) -{ - KeyAppendSep(aKey); - - // Could escape separator here if collisions happen. > is not a legal char - // for a name or type attribute, so we should be safe avoiding that extra work. - - aKey.Append(aString); -} - -static inline void KeyAppendInt(PRInt32 aInt, nsACString& aKey) -{ - KeyAppendSep(aKey); - - aKey.Append(nsPrintfCString("%d", aInt)); -} - -static inline void KeyAppendAtom(nsIAtom* aAtom, nsACString& aKey) -{ - NS_PRECONDITION(aAtom, "KeyAppendAtom: aAtom can not be null!\n"); - - const char* atomString = nsnull; - aAtom->GetUTF8String(&atomString); - - KeyAppendString(nsDependentCString(atomString), aKey); -} - -static inline PRBool IsAutocompleteOff(nsIDOMElement* aElement) -{ - nsAutoString autocomplete; - aElement->GetAttribute(NS_LITERAL_STRING("autocomplete"), autocomplete); - ToLowerCase(autocomplete); - return autocomplete.Equals(NS_LITERAL_STRING("off")); -} - -NS_IMETHODIMP -FrameManager::GenerateStateKey(nsIContent* aContent, - nsIStatefulFrame::SpecialStateID aID, - nsACString& aKey) -{ - aKey.Truncate(); - - // SpecialStateID case - e.g. scrollbars around the content window - // The key in this case is the special state id (always < min(contentID)) - if (nsIStatefulFrame::eNoID != aID) { - KeyAppendInt(aID, aKey); - return NS_OK; - } - - // We must have content if we're not using a special state id - NS_ENSURE_TRUE(aContent, NS_ERROR_FAILURE); - - // Don't capture state for anonymous content - PRUint32 contentID; - aContent->GetContentID(&contentID); - if (!contentID) { - return NS_OK; - } - - nsCOMPtr element(do_QueryInterface(aContent)); - if (element && IsAutocompleteOff(element)) { - return NS_OK; - } - - // If we have a form control and can calculate form information, use - // that as the key - it is more reliable than contentID. - // Important to have a unique key, and tag/type/name may not be. - // - // If the control has a form, the format of the key is: - // type>IndOfFormInDoc>IndOfControlInForm>FormName>name - // else: - // type>IndOfControlInDoc>name - // - // XXX We don't need to use index if name is there - // - nsCOMPtr control(do_QueryInterface(aContent)); - PRBool generatedUniqueKey = PR_FALSE; - if (control && mHTMLFormControls && mHTMLForms) { - - // Append the control type - KeyAppendInt(control->GetType(), aKey); - - // If in a form, add form name / index of form / index in form - PRInt32 index = -1; - nsCOMPtr formElement; - control->GetForm(getter_AddRefs(formElement)); - if (formElement) { - - if (IsAutocompleteOff(formElement)) { - aKey.Truncate(); - return NS_OK; - } - - // Append the index of the form in the document - nsCOMPtr formContent(do_QueryInterface(formElement)); - mHTMLForms->IndexOf(formContent, index, PR_FALSE); - if (index <= -1) { - // - // XXX HACK this uses some state that was dumped into the document - // specifically to fix bug 138892. What we are trying to do is *guess* - // which form this control's state is found in, with the highly likely - // guess that the highest form parsed so far is the one. - // This code should not be on trunk, only branch. - // - nsCOMPtr doc; - formContent->GetDocument(*getter_AddRefs(doc)); - nsCOMPtr htmlDoc = do_QueryInterface(doc); - if (htmlDoc) { - htmlDoc->GetNumFormsSynchronous(&index); - index--; - } - } - if (index > -1) { - KeyAppendInt(index, aKey); - - // Append the index of the control in the form - nsCOMPtr form(do_QueryInterface(formElement)); - form->IndexOfControl(control, &index); - NS_ASSERTION(index > -1, - "nsFrameManager::GenerateStateKey didn't find form control index!"); - - if (index > -1) { - KeyAppendInt(index, aKey); - generatedUniqueKey = PR_TRUE; - } - } - - // Append the form name - nsAutoString formName; - formElement->GetName(formName); - KeyAppendString(formName, aKey); - - } else { - - // If not in a form, add index of control in document - // Less desirable than indexing by form info. - - // Hash by index of control in doc (we are not in a form) - // These are important as they are unique, and type/name may not be. - - // We don't refresh the form control list here (passing PR_TRUE - // for aFlush), although we really should. Forcing a flush - // causes a signficant pageload performance hit. See bug - // 166636. Doing this wrong means you will see the assertion - // below being hit. - mHTMLFormControls->IndexOf(aContent, index, PR_FALSE); - NS_ASSERTION(index > -1, - "nsFrameManager::GenerateStateKey didn't find content " - "by type! See bug 139568"); - - if (index > -1) { - KeyAppendInt(index, aKey); - generatedUniqueKey = PR_TRUE; - } - } - - // Append the control name - nsAutoString name; - aContent->GetAttr(kNameSpaceID_None, nsHTMLAtoms::name, name); - KeyAppendString(name, aKey); - } - - if (!generatedUniqueKey) { - - // Either we didn't have a form control or we aren't in an HTML document - // so we can't figure out form info, hash by content ID instead :( - KeyAppendInt(contentID, aKey); - } - - return NS_OK; -} - //---------------------------------------------------------------------- static PLHashNumber diff --git a/layout/html/base/src/nsPresShell.cpp b/layout/html/base/src/nsPresShell.cpp index 759d4112a69..2b5074d0bab 100644 --- a/layout/html/base/src/nsPresShell.cpp +++ b/layout/html/base/src/nsPresShell.cpp @@ -1144,8 +1144,6 @@ public: NS_IMETHOD DoGetContents(const nsACString& aMimeType, PRUint32 aFlags, PRBool aSelectionOnly, nsAString& outValue); NS_IMETHOD CaptureHistoryState(nsILayoutHistoryState** aLayoutHistoryState, PRBool aLeavingPage); - NS_IMETHOD GetHistoryState(nsILayoutHistoryState** aLayoutHistoryState); - NS_IMETHOD SetHistoryState(nsILayoutHistoryState* aLayoutHistoryState); NS_IMETHOD GetGeneratedContentIterator(nsIContent* aContent, GeneratedContentType aType, @@ -1308,7 +1306,6 @@ protected: nsCOMPtr mStyleSet; nsICSSStyleSheet* mPrefStyleSheet; // mStyleSet owns it but we maintaina ref, may be null nsIViewManager* mViewManager; // [WEAK] docViewer owns it so I don't have to - nsWeakPtr mHistoryState; // [WEAK] session history owns this PRUint32 mUpdateCount; // normal reflow commands nsVoidArray mReflowCommands; @@ -1661,8 +1658,6 @@ PresShell::Init(nsIDocument* aDocument, // before creating any frames. SetPreferenceStyleRules(PR_FALSE); - mHistoryState = nsnull; - nsresult result = nsComponentManager::CreateInstance(kFrameSelectionCID, nsnull, NS_GET_IID(nsIFrameSelection), getter_AddRefs(mSelection)); @@ -1799,9 +1794,6 @@ PresShell::Destroy() mIsDestroying = PR_TRUE; - // Clobber weak leaks in case of re-entrancy during tear down - mHistoryState = nsnull; - // We can't release all the event content in // mCurrentEventContentStack here since there might be code on the // stack that will release the event content too. Double release @@ -3673,7 +3665,18 @@ PresShell::EndLoad(nsIDocument *aDocument) // Restore frame state for the root scroll frame nsIFrame* rootFrame = nsnull; GetRootFrame(&rootFrame); - nsCOMPtr historyState = do_QueryReferent(mHistoryState); + nsCOMPtr container; + mPresContext->GetContainer(getter_AddRefs(container)); + if (!container) + return NS_ERROR_FAILURE; + + nsCOMPtr docShell(do_QueryInterface(container)); + if (!docShell) + return NS_ERROR_FAILURE; + + nsCOMPtr historyState; + docShell->GetLayoutHistoryState(getter_AddRefs(historyState)); + if (rootFrame && historyState) { nsIFrame* scrollFrame = nsnull; GetRootScrollFrame(mPresContext, rootFrame, &scrollFrame); @@ -4709,7 +4712,17 @@ PresShell::CaptureHistoryState(nsILayoutHistoryState** aState, PRBool aLeavingPa NS_PRECONDITION(nsnull != aState, "null state pointer"); - nsCOMPtr historyState = do_QueryReferent(mHistoryState); + nsCOMPtr container; + mPresContext->GetContainer(getter_AddRefs(container)); + if (!container) + return NS_ERROR_FAILURE; + + nsCOMPtr docShell(do_QueryInterface(container)); + if (!docShell) + return NS_ERROR_FAILURE; + + nsCOMPtr historyState; + docShell->GetLayoutHistoryState(getter_AddRefs(historyState)); if (!historyState) { // Create the document state object rv = NS_NewLayoutHistoryState(getter_AddRefs(historyState)); @@ -4719,7 +4732,7 @@ PresShell::CaptureHistoryState(nsILayoutHistoryState** aState, PRBool aLeavingPa return rv; } - mHistoryState = getter_AddRefs(NS_GetWeakReference(historyState)); + docShell->SetLayoutHistoryState(historyState); } *aState = historyState; @@ -4747,22 +4760,6 @@ PresShell::CaptureHistoryState(nsILayoutHistoryState** aState, PRBool aLeavingPa return rv; } -NS_IMETHODIMP -PresShell::GetHistoryState(nsILayoutHistoryState** aState) -{ - nsCOMPtr historyState = do_QueryReferent(mHistoryState); - *aState = historyState; - NS_IF_ADDREF(*aState); - return NS_OK; -} - -NS_IMETHODIMP -PresShell::SetHistoryState(nsILayoutHistoryState* aLayoutHistoryState) -{ - mHistoryState = getter_AddRefs(NS_GetWeakReference(aLayoutHistoryState)); - return NS_OK; -} - NS_IMETHODIMP PresShell::GetGeneratedContentIterator(nsIContent* aContent, GeneratedContentType aType, diff --git a/layout/html/style/src/nsCSSFrameConstructor.cpp b/layout/html/style/src/nsCSSFrameConstructor.cpp index e6d488827bc..e72d33e458f 100644 --- a/layout/html/style/src/nsCSSFrameConstructor.cpp +++ b/layout/html/style/src/nsCSSFrameConstructor.cpp @@ -820,7 +820,11 @@ nsFrameConstructorState::nsFrameConstructorState(nsIPresContext* aPresCon { aPresContext->GetShell(getter_AddRefs(mPresShell)); mPresShell->GetFrameManager(getter_AddRefs(mFrameManager)); - mPresShell->GetHistoryState(getter_AddRefs(mFrameState)); + nsCOMPtr container; + aPresContext->GetContainer(getter_AddRefs(container)); + nsCOMPtr docShell(do_QueryInterface(container)); + if (docShell) + docShell->GetLayoutHistoryState(getter_AddRefs(mFrameState)); } // Use the first-in-flow of a positioned inline frame in galley mode as the diff --git a/layout/printing/nsPrintEngine.cpp b/layout/printing/nsPrintEngine.cpp index ded0419f961..8f3eab353e3 100644 --- a/layout/printing/nsPrintEngine.cpp +++ b/layout/printing/nsPrintEngine.cpp @@ -2761,7 +2761,8 @@ nsPrintEngine::ReflowPrintObject(nsPrintObject * aPO, PRBool aDoCalcShrink) presShell->CaptureHistoryState(getter_AddRefs(layoutState), PR_TRUE); // set it on the new pres shell - aPO->mPresShell->SetHistoryState(layoutState); + nsCOMPtr docShell(do_QueryInterface(aPO->mWebShell)); + docShell->SetLayoutHistoryState(layoutState); // turn off animated GIFs if (aPO->mPresContext) { @@ -2876,7 +2877,6 @@ nsPrintEngine::ReflowPrintObject(nsPrintObject * aPO, PRBool aDoCalcShrink) } else { printf("View is null!\n"); } - nsCOMPtr docShell(do_QueryInterface(aPO->mWebShell)); if (docShell) { fprintf(fd, "--------------- All Views ----------------\n"); DumpViews(docShell, fd); diff --git a/xpfe/browser/resources/content/navigator.js b/xpfe/browser/resources/content/navigator.js index 07b0fd8d9e0..4a62cb988c0 100644 --- a/xpfe/browser/resources/content/navigator.js +++ b/xpfe/browser/resources/content/navigator.js @@ -39,6 +39,7 @@ * ***** END LICENSE BLOCK ***** */ const XREMOTESERVICE_CONTRACTID = "@mozilla.org/browser/xremoteservice;1"; +const XUL_NAMESPACE = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; var gURLBar = null; var gProxyButton = null; var gProxyFavIcon = null; @@ -277,7 +278,6 @@ function contentAreaFrameFocus() function updateHomeButtonTooltip() { - const XUL_NAMESPACE = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; var homePage = getHomePage(); var tooltip = document.getElementById("home-button-tooltip-inner"); @@ -373,7 +373,7 @@ function UpdateBackForwardButtons() { var backBroadcaster = document.getElementById("canGoBack"); var forwardBroadcaster = document.getElementById("canGoForward"); - var webNavigation = getWebNavigation(); + var browser = getBrowser(); // Avoid setting attributes on broadcasters if the value hasn't changed! // Remember, guys, setting attributes on elements is expensive! They @@ -382,13 +382,13 @@ function UpdateBackForwardButtons() var backDisabled = backBroadcaster.hasAttribute("disabled"); var forwardDisabled = forwardBroadcaster.hasAttribute("disabled"); - if (backDisabled == webNavigation.canGoBack) { + if (backDisabled == browser.canGoBack) { if (backDisabled) backBroadcaster.removeAttribute("disabled"); else backBroadcaster.setAttribute("disabled", true); } - if (forwardDisabled == webNavigation.canGoForward) { + if (forwardDisabled == browser.canGoForward) { if (forwardDisabled) forwardBroadcaster.removeAttribute("disabled"); else @@ -721,11 +721,18 @@ function gotoHistoryIndex(aEvent) var index = aEvent.target.getAttribute("index"); if (!index) return false; - try { - getWebNavigation().gotoIndex(index); - } - catch(ex) { - return false; + + if (index == "back") + gBrowser.goBackGroup(); + else if (index == "forward") + gBrowser.goForwardGroup(); + else { + try { + getWebNavigation().gotoIndex(index); + } + catch(ex) { + return false; + } } return true; @@ -734,7 +741,7 @@ function gotoHistoryIndex(aEvent) function BrowserBack() { try { - getWebNavigation().goBack(); + getBrowser().goBack(); } catch(ex) { } @@ -764,19 +771,41 @@ function BrowserHandleBackspace() function BrowserForward() { try { - getWebNavigation().goForward(); + getBrowser().goForward(); } catch(ex) { } } +function SetGroupHistory(popupMenu, direction) +{ + while (popupMenu.firstChild) + popupMenu.removeChild(popupMenu.firstChild); + + var menuItem = document.createElementNS(XUL_NAMESPACE, "menuitem"); + var label = gNavigatorBundle.getString("tabs.historyItem"); + menuItem.setAttribute("label", label); + menuItem.setAttribute("index", direction); + popupMenu.appendChild(menuItem); +} + function BrowserBackMenu(event) { + if (gBrowser.backBrowserGroup.length != 0) { + SetGroupHistory(event.target, "back"); + return true; + } + return FillHistoryMenu(event.target, "back"); } function BrowserForwardMenu(event) { + if (gBrowser.forwardBrowserGroup.length != 0) { + SetGroupHistory(event.target, "forward"); + return true; + } + return FillHistoryMenu(event.target, "forward"); } @@ -809,8 +838,11 @@ function BrowserHome() if (homePage.length == 1) { loadURI(homePage[0]); } else { + var URIs = []; for (var i in homePage) - gBrowser.addTab(homePage[i]); + URIs.push({URI: homePage[i]}); + + gBrowser.loadGroup(URIs); } } diff --git a/xpfe/browser/resources/locale/en-US/navigator.properties b/xpfe/browser/resources/locale/en-US/navigator.properties index 05d04c7960a..87b2e2efcd0 100644 --- a/xpfe/browser/resources/locale/en-US/navigator.properties +++ b/xpfe/browser/resources/locale/en-US/navigator.properties @@ -60,6 +60,8 @@ showskinsdescription=true tabs.closeTab=Close Tab tabs.close=Close +tabs.historyItem=Group of Tabs + # urlbarBindings.xml # LOCALIZATION NOTE: This is for the location bar drop-down string: # "Seach " + search_engine_name + " for " + user_input diff --git a/xpfe/components/bookmarks/resources/bookmarks.js b/xpfe/components/bookmarks/resources/bookmarks.js index 97ce9bca5cf..cf6b9eca118 100644 --- a/xpfe/components/bookmarks/resources/bookmarks.js +++ b/xpfe/components/bookmarks/resources/bookmarks.js @@ -573,25 +573,16 @@ var BookmarksCommand = { var tabPanels = browser.mPanelContainer.childNodes; var tabCount = tabPanels.length; var index = 0; + var URIs = []; while (containerChildren.hasMoreElements()) { var res = containerChildren.getNext().QueryInterface(kRDFRSCIID); var target = BMDS.GetTarget(res, urlArc, true); if (target) { - var uri = target.QueryInterface(kRDFLITIID).Value; - browser.addTab(uri); + URIs.push({ URI: target.QueryInterface(kRDFLITIID).Value }); ++index; } } - - // If the bookmark group was completely invalid, just bail. - if (index == 0) - return; - - // Select the first tab in the group if we aren't loading in the background. - if (!PREF.getBoolPref("browser.tabs.loadInBackground")) { - var tabs = browser.mTabContainer.childNodes; - browser.selectedTab = tabs[tabCount]; - } + browser.loadGroup(URIs); } else { dump("Open Group in new window: not implemented...\n"); } diff --git a/xpfe/global/resources/content/bindings/tabbrowser.xml b/xpfe/global/resources/content/bindings/tabbrowser.xml index 6f58e04b9f7..572f48cb609 100644 --- a/xpfe/global/resources/content/bindings/tabbrowser.xml +++ b/xpfe/global/resources/content/bindings/tabbrowser.xml @@ -232,10 +232,22 @@ p.onStateChange(aWebProgress, aRequest, aStateFlags, aStatus); } } - } - , + }, + + // The first location change is gotoIndex called from mInstallSH, + // the second one is considered a user action. + mLocationChangeCount : 0, onLocationChange : function(aWebProgress, aRequest, aLocation) { + if (this.mLocationChangeCount > 0 || + aLocation.spec != "about:blank") + ++this.mLocationChangeCount; + + if (this.mLocationChangeCount == 2) { + this.mTabBrowser.backBrowserGroup = []; + this.mTabBrowser.forwardBrowserGroup = []; + } + if (!this.mBlank && this.mTabBrowser.mCurrentTab == this.mTab) { for (var i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) { var p = this.mTabBrowser.mProgressListeners[i]; @@ -282,6 +294,58 @@ + + + + + + + + @@ -649,16 +713,14 @@ - + + + [] + + + + [] + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1003,6 +1147,9 @@