From 867068ef8a2bf3580f2efdd69b14027428c764b0 Mon Sep 17 00:00:00 2001 From: "bzbarsky%mit.edu" Date: Thu, 11 Jan 2007 19:32:31 +0000 Subject: [PATCH] Implement the proposed Web Apps 1.0 API for changing the selected style sheet set, querying the available sets, etc. Bug 200930, r=sicking, sr=dbaron --- browser/base/content/browser.js | 2 +- content/base/src/nsDocument.cpp | 265 ++++++++++++++++-- content/base/src/nsDocument.h | 11 + dom/public/idl/stylesheets/Makefile.in | 2 +- .../idl/stylesheets/nsIDOMNSDocumentStyle.idl | 85 +++++- editor/libeditor/html/nsHTMLEditor.cpp | 13 +- layout/base/nsIPresShell.h | 18 +- layout/base/nsPresShell.cpp | 94 ------- layout/style/nsCSSLoader.cpp | 32 ++- layout/style/nsCSSStyleSheet.cpp | 28 +- layout/style/nsIStyleSheet.h | 12 +- suite/browser/navigator.js | 2 +- 12 files changed, 389 insertions(+), 175 deletions(-) diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 6d679fa9e362..8e5cff3844ef 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -4881,7 +4881,7 @@ function stylesheetFillPopup(menuPopup) noStyle.setAttribute("checked", styleDisabled); persistentOnly.setAttribute("checked", !altStyleSelected && !styleDisabled); - persistentOnly.hidden = (window.content.document.preferredStylesheetSet) ? haveAltSheets : false; + persistentOnly.hidden = (window.content.document.preferredStyleSheetSet) ? haveAltSheets : false; sep.hidden = (noStyle.hidden && persistentOnly.hidden) || !haveAltSheets; return true; } diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index 3c9d30f9a870..c97fcd24ae0e 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -66,6 +66,7 @@ #include "nsIDOMStyleSheet.h" #include "nsDOMAttribute.h" +#include "nsIDOMDOMStringList.h" #include "nsIDOMDOMImplementation.h" #include "nsIDOMDocumentView.h" #include "nsIDOMAbstractView.h" @@ -486,6 +487,117 @@ nsOnloadBlocker::SetLoadFlags(nsLoadFlags aLoadFlags) return NS_OK; } +// ================================================================== +// = +// ================================================================== + +// If we ever have an nsIDocumentObserver notification for stylesheet title +// changes, we could make this inherit from nsDOMStringList instead of +// reimplementing nsIDOMDOMStringList. +class nsDOMStyleSheetSetList : public nsIDOMDOMStringList + +{ +public: + NS_DECL_ISUPPORTS + + NS_DECL_NSIDOMDOMSTRINGLIST + + nsDOMStyleSheetSetList(nsIDocument* aDocument); + + void Disconnect() + { + mDocument = nsnull; + } + +protected: + // Rebuild our list of style sets + nsresult GetSets(nsStringArray& aStyleSets); + + nsIDocument* mDocument; // Our document; weak ref. It'll let us know if it + // dies. +}; + +NS_IMPL_ADDREF(nsDOMStyleSheetSetList) +NS_IMPL_RELEASE(nsDOMStyleSheetSetList) +NS_INTERFACE_MAP_BEGIN(nsDOMStyleSheetSetList) + NS_INTERFACE_MAP_ENTRY(nsIDOMDOMStringList) + NS_INTERFACE_MAP_ENTRY(nsISupports) + NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(DOMStringList) +NS_INTERFACE_MAP_END + +nsDOMStyleSheetSetList::nsDOMStyleSheetSetList(nsIDocument* aDocument) + : mDocument(aDocument) +{ + NS_ASSERTION(mDocument, "Must have document!"); +} + +NS_IMETHODIMP +nsDOMStyleSheetSetList::Item(PRUint32 aIndex, nsAString& aResult) +{ + nsStringArray styleSets; + nsresult rv = GetSets(styleSets); + NS_ENSURE_SUCCESS(rv, rv); + + if (aIndex >= (PRUint32)styleSets.Count()) { + SetDOMStringToNull(aResult); + } else { + styleSets.StringAt(aIndex, aResult); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMStyleSheetSetList::GetLength(PRUint32 *aLength) +{ + nsStringArray styleSets; + nsresult rv = GetSets(styleSets); + NS_ENSURE_SUCCESS(rv, rv); + + *aLength = (PRUint32)styleSets.Count(); + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMStyleSheetSetList::Contains(const nsAString& aString, PRBool *aResult) +{ + nsStringArray styleSets; + nsresult rv = GetSets(styleSets); + NS_ENSURE_SUCCESS(rv, rv); + + *aResult = styleSets.IndexOf(aString) != -1; + + return NS_OK; +} + +nsresult +nsDOMStyleSheetSetList::GetSets(nsStringArray& aStyleSets) +{ + if (!mDocument) { + return NS_OK; // Spec says "no exceptions", and we have no style sets if we + // have no document, for sure + } + + PRInt32 count = mDocument->GetNumberOfStyleSheets(); + nsAutoString title; + nsAutoString temp; + for (PRInt32 index = 0; index < count; index++) { + nsIStyleSheet* sheet = mDocument->GetStyleSheetAt(index); + NS_ASSERTION(sheet, "Null sheet in sheet list!"); + sheet->GetTitle(title); + if (!title.IsEmpty() && aStyleSets.IndexOf(title) == -1 && + !aStyleSets.AppendString(title)) { + return NS_ERROR_OUT_OF_MEMORY; + } + } + + return NS_OK; +} + +// ================================================================== +// = +// ================================================================== class nsDOMImplementation : public nsIDOMDOMImplementation, public nsIPrivateDOMImplementation @@ -656,6 +768,9 @@ nsDocument::nsDocument(const char* aContentType) PR_LOG(gDocumentLeakPRLog, PR_LOG_DEBUG, ("DOCUMENT %p created", this)); #endif + + // Start out mLastStyleSheetSet as null, per spec + SetDOMStringToNull(mLastStyleSheetSet); } nsDocument::~nsDocument() @@ -671,6 +786,10 @@ nsDocument::~nsDocument() // Clear mObservers to keep it in sync with the mutationobserver list mObservers.Clear(); + if (mStyleSheetSetList) { + mStyleSheetSetList->Disconnect(); + } + mParentDocument = nsnull; // Kill the subdocument map, doing this will release its strong @@ -1585,29 +1704,15 @@ nsDocument::SetHeaderData(nsIAtom* aHeaderField, const nsAString& aData) } if (aHeaderField == nsGkAtoms::headerDefaultStyle) { - // switch alternate style sheets based on default - // XXXldb What if we don't have all the sheets yet? Should this use - // the DOM API for preferred stylesheet set that's "coming soon"? - nsAutoString type; - nsAutoString title; - PRInt32 index; - - CSSLoader()->SetPreferredSheet(aData); - - PRInt32 count = mStyleSheets.Count(); - for (index = 0; index < count; index++) { - nsIStyleSheet* sheet = mStyleSheets[index]; - sheet->GetType(type); - if (!type.EqualsLiteral("text/html")) { - sheet->GetTitle(title); - if (!title.IsEmpty()) { // if sheet has title - PRBool enabled = - (!aData.IsEmpty() && - title.Equals(aData, nsCaseInsensitiveStringComparator())); - - sheet->SetEnabled(enabled); - } - } + // Only mess with our stylesheets if we don't have a lastStyleSheetSet, per + // spec. + if (DOMStringIsNull(mLastStyleSheetSet)) { + // Calling EnableStyleSheetsForSetInternal, not SetSelectedStyleSheetSet, + // per spec. The idea here is that we're changing our preferred set and + // that shouldn't change the value of lastStyleSheetSet. Also, we're + // using the Internal version so we can update the CSSLoader and not have + // to worry about null strings. + EnableStyleSheetsForSetInternal(aData, PR_TRUE); } } @@ -2073,7 +2178,7 @@ void nsDocument::UpdateStyleSheets(nsCOMArray& aOldSheets, nsCOMArray& aNewSheets) { - NS_DOCUMENT_NOTIFY_OBSERVERS(BeginUpdate, (this, UPDATE_STYLE)); + BeginUpdate(UPDATE_STYLE); // XXX Need to set the sheet on the ownernode, if any NS_PRECONDITION(aOldSheets.Count() == aNewSheets.Count(), @@ -2105,7 +2210,7 @@ nsDocument::UpdateStyleSheets(nsCOMArray& aOldSheets, } } - NS_DOCUMENT_NOTIFY_OBSERVERS(EndUpdate, (this, UPDATE_STYLE)); + EndUpdate(UPDATE_STYLE); } void @@ -2942,12 +3047,118 @@ nsDocument::GetStyleSheets(nsIDOMStyleSheetList** aStyleSheets) } NS_IMETHODIMP -nsDocument::GetPreferredStylesheetSet(nsAString& aStyleTitle) +nsDocument::GetSelectedStyleSheetSet(nsAString& aSheetSet) { - CSSLoader()->GetPreferredSheet(aStyleTitle); + aSheetSet.Truncate(); + + // Look through our sheets, find the selected set title + PRInt32 count = GetNumberOfStyleSheets(); + nsAutoString title; + for (PRInt32 index = 0; index < count; index++) { + nsIStyleSheet* sheet = GetStyleSheetAt(index); + NS_ASSERTION(sheet, "Null sheet in sheet list!"); + + nsCOMPtr domSheet = do_QueryInterface(sheet); + NS_ASSERTION(domSheet, "Sheet must QI to nsIDOMStyleSheet"); + PRBool disabled; + domSheet->GetDisabled(&disabled); + if (disabled) { + // Disabled sheets don't affect the currently selected set + continue; + } + + sheet->GetTitle(title); + + if (aSheetSet.IsEmpty()) { + aSheetSet = title; + } else if (!title.IsEmpty() && !aSheetSet.Equals(title)) { + // Sheets from multiple sets enabled; return null string, per spec. + SetDOMStringToNull(aSheetSet); + break; + } + } + return NS_OK; } +NS_IMETHODIMP +nsDocument::SetSelectedStyleSheetSet(const nsAString& aSheetSet) +{ + if (DOMStringIsNull(aSheetSet)) { + return NS_OK; + } + + // Must update mLastStyleSheetSet before doing anything else with stylesheets + // or CSSLoaders. + mLastStyleSheetSet = aSheetSet; + EnableStyleSheetsForSetInternal(aSheetSet, PR_TRUE); + return NS_OK; +} + +NS_IMETHODIMP +nsDocument::GetLastStyleSheetSet(nsAString& aSheetSet) +{ + aSheetSet = mLastStyleSheetSet; + return NS_OK; +} + +NS_IMETHODIMP +nsDocument::GetPreferredStyleSheetSet(nsAString& aSheetSet) +{ + GetHeaderData(nsGkAtoms::headerDefaultStyle, aSheetSet); + return NS_OK; +} + +NS_IMETHODIMP +nsDocument::GetStyleSheetSets(nsIDOMDOMStringList** aList) +{ + if (!mStyleSheetSetList) { + mStyleSheetSetList = new nsDOMStyleSheetSetList(this); + if (!mStyleSheetSetList) { + return NS_ERROR_OUT_OF_MEMORY; + } + } + + NS_ADDREF(*aList = mStyleSheetSetList); + return NS_OK; +} + +NS_IMETHODIMP +nsDocument::EnableStyleSheetsForSet(const nsAString& aSheetSet) +{ + // Per spec, passing in null is a no-op. + if (!DOMStringIsNull(aSheetSet)) { + // Note: must make sure to not change the CSSLoader's preferred sheet -- + // that value should be equal to either our lastStyleSheetSet (if that's + // non-null) or to our preferredStyleSheetSet. And this method doesn't + // change either of those. + EnableStyleSheetsForSetInternal(aSheetSet, PR_FALSE); + } + + return NS_OK; +} + +void +nsDocument::EnableStyleSheetsForSetInternal(const nsAString& aSheetSet, + PRBool aUpdateCSSLoader) +{ + BeginUpdate(UPDATE_STYLE); + PRInt32 count = GetNumberOfStyleSheets(); + nsAutoString title; + for (PRInt32 index = 0; index < count; index++) { + nsIStyleSheet* sheet = GetStyleSheetAt(index); + NS_ASSERTION(sheet, "Null sheet in sheet list!"); + sheet->GetTitle(title); + if (!title.IsEmpty()) { + sheet->SetEnabled(title.Equals(aSheetSet)); + } + } + if (aUpdateCSSLoader) { + CSSLoader()->SetPreferredSheet(aSheetSet); + } + EndUpdate(UPDATE_STYLE); +} + NS_IMETHODIMP nsDocument::GetCharacterSet(nsAString& aCharacterSet) { diff --git a/content/base/src/nsDocument.h b/content/base/src/nsDocument.h index d27237c223d8..e79af93a552f 100644 --- a/content/base/src/nsDocument.h +++ b/content/base/src/nsDocument.h @@ -111,6 +111,7 @@ class nsIEventListenerManager; class nsDOMStyleSheetList; +class nsDOMStyleSheetSetList; class nsIOutputStream; class nsDocument; class nsIDTD; @@ -732,6 +733,7 @@ protected: nsCOMPtr mListenerManager; nsCOMPtr mDOMStyleSheets; + nsRefPtr mStyleSheetSetList; nsRefPtr mScriptLoader; nsDocHeaderData* mHeaderData; @@ -776,6 +778,12 @@ private: already_AddRefed CheckAncestryAndGetFrame(nsIDocument* aDocument) const; + // Just like EnableStyleSheetsForSet, but doesn't check whether + // aSheetSet is null and allows the caller to control whether to set + // aSheetSet as the preferred set in the CSSLoader. + void EnableStyleSheetsForSetInternal(const nsAString& aSheetSet, + PRBool aUpdateCSSLoader); + // These are not implemented and not supported. nsDocument(const nsDocument& aOther); nsDocument& operator=(const nsDocument& aOther); @@ -797,6 +805,9 @@ private: nsTHashtable mLinkMap; // URIs whose visitedness has changed while we were hidden nsCOMArray mVisitednessChangedURIs; + + // Member to store out last-selected stylesheet set. + nsString mLastStyleSheetSet; }; diff --git a/dom/public/idl/stylesheets/Makefile.in b/dom/public/idl/stylesheets/Makefile.in index 3e59eb1785e6..4365a59f98bc 100644 --- a/dom/public/idl/stylesheets/Makefile.in +++ b/dom/public/idl/stylesheets/Makefile.in @@ -48,7 +48,6 @@ GRE_MODULE = 1 SDK_XPIDLSRCS = \ nsIDOMDocumentStyle.idl \ - nsIDOMNSDocumentStyle.idl \ nsIDOMMediaList.idl \ nsIDOMStyleSheet.idl \ nsIDOMStyleSheetList.idl \ @@ -56,6 +55,7 @@ SDK_XPIDLSRCS = \ XPIDLSRCS = \ nsIDOMLinkStyle.idl \ + nsIDOMNSDocumentStyle.idl \ $(NULL) include $(topsrcdir)/config/rules.mk diff --git a/dom/public/idl/stylesheets/nsIDOMNSDocumentStyle.idl b/dom/public/idl/stylesheets/nsIDOMNSDocumentStyle.idl index 7e4414e519b2..7ffaeba91d90 100644 --- a/dom/public/idl/stylesheets/nsIDOMNSDocumentStyle.idl +++ b/dom/public/idl/stylesheets/nsIDOMNSDocumentStyle.idl @@ -43,18 +43,87 @@ * nsIDOMDocumentStyle interface. This interface exposes more ways to interact * with style sheets in the Document Object Model. This interface is currently * very much experimental. + * + * NOTE: This interface represents the additions to nsIDOMDocumentStyle defined + * by . + * The comments here describe our implementation; if those comments don't match + * that spec, file bugs. */ -[scriptable, uuid(4ecdf254-a21e-47b0-8d72-55da8208299f)] +[scriptable, uuid(26311d10-7e24-4c7b-bb3d-17aad86f4d88)] interface nsIDOMNSDocumentStyle : nsIDOMDocumentStyle { /** - * This attribute indicates the preferredStylesheetSet as set by the - * author. It is determined from the order of stylesheet declarations and the - * Default-Style HTTP headers. See [[HTML4]]. If there is no preferred - * stylesheet set, this attribute returns the empty string. The case of this - * attribute must exactly match the case given by the author where the - * preferred stylesheet is specified or implied. + * This attribute must return the preferred style sheet set as set by the + * author. It is determined from the order of style sheet declarations and + * the Default-Style HTTP headers, as eventually defined elsewhere in the Web + * Apps 1.0 specification. If there is no preferred style sheet set, this + * attribute must return the empty string. The case of this attribute must + * exactly match the case given by the author where the preferred style sheet + * is specified or implied. This attribute must never return null. */ - readonly attribute DOMString preferredStylesheetSet; + readonly attribute DOMString preferredStyleSheetSet; + + /** + * This attribute indicates which style sheet set is in use. This attribute + * is live; changing the disabled attribute on style sheets directly will + * change the value of this attribute. + * + * If all the sheets that are enabled and have a title have the same title + * (by case-sensitive comparisons) then the value of this attribute must be + * exactly equal to the title of the first enabled style sheet with a title + * in the styleSheets list. Otherwise, if style sheets from different sets + * are enabled, then the return value must be null (there is no way to + * determine what the currently selected style sheet set is in those + * conditions). Otherwise, either all style sheets that have a title are + * disabled, or there are no alternate style sheets, and + * selectedStyleSheetSet must return the empty string. + * + * Setting this attribute to the null value must have no effect. + * + * Setting this attribute to a non-null value must call + * enableStyleSheetsForSet() with that value as the function's argument, and + * set lastStyleSheetSet to that value. + * + * From the DOM's perspective, all views have the same + * selectedStyleSheetSet. If a UA supports multiple views with different + * selected alternate style sheets, then this attribute (and the StyleSheet + * interface's disabled attribute) must return and set the value for the + * default view. + */ + attribute DOMString selectedStyleSheetSet; + + /* + * This property must initially have the value null. Its value changes when + * the selectedStyleSheetSet attribute is set. + */ + readonly attribute DOMString lastStyleSheetSet; + + /** + * This must return the live list of the currently available style sheet + * sets. This list is constructed by enumerating all the style sheets for + * this document available to the implementation, in the order they are + * listed in the styleSheets attribute, adding the title of each style sheet + * with a title to the list, avoiding duplicates by dropping titles that + * match (case-sensitively) titles that have already been added to the + * list. + */ + readonly attribute nsIDOMDOMStringList styleSheetSets; + + /** + * Calling this method must change the disabled attribute on each StyleSheet + * object with a title attribute with a length greater than 0 in the + * styleSheets attribute, so that all those whose title matches the name + * argument are enabled, and all others are disabled. Title matches must be + * case-sensitive. Calling this method with the empty string disables all + * alternate and preferred style sheets (but does not change the state of + * persistent style sheets, that is those with no title attribute). + * + * Calling this method with a null value must have no effect. + * + * Style sheets that do not have a title are never affected by this + * method. This method does not change the values of the lastStyleSheetSet or + * preferredStyleSheetSet attributes. + */ + void enableStyleSheetsForSet(in DOMString name); }; diff --git a/editor/libeditor/html/nsHTMLEditor.cpp b/editor/libeditor/html/nsHTMLEditor.cpp index a580e3ed65d3..bec4ab1ed18c 100644 --- a/editor/libeditor/html/nsHTMLEditor.cpp +++ b/editor/libeditor/html/nsHTMLEditor.cpp @@ -77,6 +77,7 @@ #include "nsICSSLoader.h" #include "nsICSSStyleSheet.h" +#include "nsIDOMStyleSheet.h" #include "nsIDocumentObserver.h" #include "nsIDocumentStateListener.h" @@ -3686,8 +3687,10 @@ nsHTMLEditor::EnableStyleSheet(const nsAString &aURL, PRBool aEnable) if (!sheet) return NS_OK; // Don't fail if sheet not found - nsCOMPtr nsISheet = do_QueryInterface(sheet); - return nsISheet->SetEnabled(aEnable); + nsCOMPtr domSheet(do_QueryInterface(sheet)); + NS_ASSERTION(domSheet, "Sheet not implementing nsIDOMStyleSheet!"); + + return domSheet->SetDisabled(!aEnable); } @@ -3701,8 +3704,10 @@ nsHTMLEditor::EnableExistingStyleSheet(const nsAString &aURL) // Enable sheet if already loaded. if (sheet) { - nsCOMPtr nsISheet = do_QueryInterface(sheet); - nsISheet->SetEnabled(PR_TRUE); + nsCOMPtr domSheet(do_QueryInterface(sheet)); + NS_ASSERTION(domSheet, "Sheet not implementing nsIDOMStyleSheet!"); + + domSheet->SetDisabled(PR_FALSE); return PR_TRUE; } return PR_FALSE; diff --git a/layout/base/nsIPresShell.h b/layout/base/nsIPresShell.h index b093e5e702ef..0e4b266197b4 100644 --- a/layout/base/nsIPresShell.h +++ b/layout/base/nsIPresShell.h @@ -97,10 +97,10 @@ class nsWeakFrame; typedef short SelectionType; -// 56719ada-52e9-4d81-b23d-acba10c5c1e2 +// 5A76F236-B93A-4C70-BC22-250F71C90518 #define NS_IPRESSHELL_IID \ -{ 0x56719ada, 0x52e9, 0x4d81, \ - { 0xb2, 0x3d, 0xac, 0xba, 0x10, 0xc5, 0xc1, 0xe2 } } +{ 0x5a76f236, 0xb93a, 0x4c70, \ + { 0xbc, 0x22, 0x25, 0x0f, 0x71, 0xc9, 0x05, 0x18 } } // Constants uses for ScrollFrameIntoView() function #define NS_PRESSHELL_SCROLL_TOP 0 @@ -198,12 +198,6 @@ public: #endif - // These two methods are used only by viewer - NS_IMETHOD GetActiveAlternateStyleSheet(nsString& aSheetTitle) = 0; - - NS_IMETHOD SelectAlternateStyleSheet(const nsString& aSheetTitle) = 0; - - /* Enable/disable author style level. Disabling author style disables the entire * author level of the cascade, including the HTML preshint level. */ @@ -240,12 +234,6 @@ public: */ NS_IMETHOD SetPreferenceStyleRules(PRBool aForceReflow) = 0; - /** - * Gather titles of all selectable (alternate and preferred) style sheets - * fills void array with nsString* caller must free strings - */ - NS_IMETHOD ListAlternateStyleSheets(nsStringArray& aTitleList) = 0; - /** * FrameSelection will return the Frame based selection API. * You cannot go back and forth anymore with QI between nsIDOM sel and diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 13feb32ddd0b..1b7214208319 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -807,9 +807,6 @@ public: NS_IMETHOD PopStackMemory(); NS_IMETHOD AllocateStackMemory(size_t aSize, void** aResult); - NS_IMETHOD GetActiveAlternateStyleSheet(nsString& aSheetTitle); - NS_IMETHOD SelectAlternateStyleSheet(const nsString& aSheetTitle); - NS_IMETHOD ListAlternateStyleSheets(nsStringArray& aTitleList); NS_IMETHOD SetPreferenceStyleRules(PRBool aForceReflow); NS_IMETHOD GetSelection(SelectionType aType, nsISelection** aSelection); @@ -1764,97 +1761,6 @@ PresShell::AllocateFrame(size_t aSize) return mFrameArena.AllocateFrame(aSize); } -NS_IMETHODIMP -PresShell::GetActiveAlternateStyleSheet(nsString& aSheetTitle) -{ // first non-html sheet in style set that has title - if (mStyleSet) { - PRInt32 count = mStyleSet->SheetCount(nsStyleSet::eDocSheet); - PRInt32 index; - NS_NAMED_LITERAL_STRING(textHtml, "text/html"); - for (index = 0; index < count; index++) { - nsIStyleSheet* sheet = mStyleSet->StyleSheetAt(nsStyleSet::eDocSheet, - index); - if (nsnull != sheet) { - nsAutoString type; - sheet->GetType(type); - if (PR_FALSE == type.Equals(textHtml)) { - nsAutoString title; - sheet->GetTitle(title); - if (!title.IsEmpty()) { - aSheetTitle = title; - index = count; // stop looking - } - } - } - } - } - return NS_OK; -} - -NS_IMETHODIMP -PresShell::SelectAlternateStyleSheet(const nsString& aSheetTitle) -{ - if (mDocument && mStyleSet) { - mStyleSet->BeginUpdate(); - PRInt32 count = mDocument->GetNumberOfStyleSheets(); - PRInt32 index; - NS_NAMED_LITERAL_STRING(textHtml,"text/html"); - for (index = 0; index < count; index++) { - nsIStyleSheet *sheet = mDocument->GetStyleSheetAt(index); - PRBool complete; - sheet->GetComplete(complete); - if (complete) { - nsAutoString type; - sheet->GetType(type); - if (!type.Equals(textHtml)) { - nsAutoString title; - sheet->GetTitle(title); - if (!title.IsEmpty()) { - if (title.Equals(aSheetTitle)) { - mStyleSet->AddDocStyleSheet(sheet, mDocument); - } - else { - mStyleSet->RemoveStyleSheet(nsStyleSet::eDocSheet, sheet); - } - } - } - } - } - - mStyleSet->EndUpdate(); - ReconstructStyleData(); - } - return NS_OK; -} - -NS_IMETHODIMP -PresShell::ListAlternateStyleSheets(nsStringArray& aTitleList) -{ - // XXX should this be returning incomplete sheets? Probably. - if (mDocument) { - PRInt32 count = mDocument->GetNumberOfStyleSheets(); - PRInt32 index; - NS_NAMED_LITERAL_STRING(textHtml,"text/html"); - for (index = 0; index < count; index++) { - nsIStyleSheet *sheet = mDocument->GetStyleSheetAt(index); - if (sheet) { - nsAutoString type; - sheet->GetType(type); - if (PR_FALSE == type.Equals(textHtml)) { - nsAutoString title; - sheet->GetTitle(title); - if (!title.IsEmpty()) { - if (-1 == aTitleList.IndexOf(title)) { - aTitleList.AppendString(title); - } - } - } - } - } - } - return NS_OK; -} - void nsIPresShell::SetAuthorStyleDisabled(PRBool aStyleDisabled) { diff --git a/layout/style/nsCSSLoader.cpp b/layout/style/nsCSSLoader.cpp index 7a7b714a1c17..3a55750afd86 100644 --- a/layout/style/nsCSSLoader.cpp +++ b/layout/style/nsCSSLoader.cpp @@ -52,6 +52,7 @@ #include "nsIDOMNode.h" #include "nsIDOMWindow.h" #include "nsIDocument.h" +#include "nsIDOMNSDocumentStyle.h" #include "nsIUnicharInputStream.h" #include "nsIConverterInputStream.h" #include "nsICharsetAlias.h" @@ -292,11 +293,16 @@ CSSLoaderImpl::Init(nsIDocument* aDocument) { NS_ASSERTION(! mDocument, "already initialized"); - if (! mDocument) { - mDocument = aDocument; - return NS_OK; + mDocument = aDocument; + + // We can just use the preferred set, since there are no sheets in the + // document yet (if there are, how did they get there? _we_ load the sheets!) + // and hence the selected set makes no sense at this time. + nsCOMPtr domDoc(do_QueryInterface(mDocument)); + if (domDoc) { + domDoc->GetPreferredStyleSheetSet(mPreferredSheet); } - return NS_ERROR_ALREADY_INITIALIZED; + return NS_OK; } PR_STATIC_CALLBACK(PLDHashOperator) @@ -353,6 +359,19 @@ StartNonAlternates(nsIURI *aKey, SheetLoadData* &aData, void* aClosure) NS_IMETHODIMP CSSLoaderImpl::SetPreferredSheet(const nsAString& aTitle) { +#ifdef DEBUG + nsCOMPtr doc(do_QueryInterface(mDocument)); + if (doc) { + nsAutoString currentPreferred; + doc->GetLastStyleSheetSet(currentPreferred); + if (DOMStringIsNull(currentPreferred)) { + doc->GetPreferredStyleSheetSet(currentPreferred); + } + NS_ASSERTION(currentPreferred.Equals(aTitle), + "Unexpected argument to SetPreferredSheet"); + } +#endif + mPreferredSheet = aTitle; // start any pending alternates that aren't alternates anymore @@ -865,15 +884,12 @@ CSSLoaderImpl::IsAlternate(const nsAString& aTitle, PRBool aHasAlternateRel) if (!aHasAlternateRel && mDocument && mPreferredSheet.IsEmpty()) { // There's no preferred set yet, and we now have a sheet with a title. // Make that be the preferred set. - // XXXbz maybe this should be checking IsVoid(), actually, since the - // preferred set can be explicitly set to the empty string. Look into - // this. mDocument->SetHeaderData(nsGkAtoms::headerDefaultStyle, aTitle); // We're definitely not an alternate return PR_FALSE; } - return !aTitle.Equals(mPreferredSheet, nsCaseInsensitiveStringComparator()); + return !aTitle.Equals(mPreferredSheet); } /** diff --git a/layout/style/nsCSSStyleSheet.cpp b/layout/style/nsCSSStyleSheet.cpp index 4d0ca02d3c60..09b06e51391b 100644 --- a/layout/style/nsCSSStyleSheet.cpp +++ b/layout/style/nsCSSStyleSheet.cpp @@ -841,7 +841,17 @@ nsCSSStyleSheet::GetApplicable(PRBool& aApplicable) const NS_IMETHODIMP nsCSSStyleSheet::SetEnabled(PRBool aEnabled) { - return nsCSSStyleSheet::SetDisabled(!aEnabled); + // Internal method, so callers must handle BeginUpdate/EndUpdate + PRBool oldDisabled = mDisabled; + mDisabled = !aEnabled; + + if (mDocument && mInner && mInner->mComplete && oldDisabled != mDisabled) { + ClearRuleCascades(); + + mDocument->SetStyleSheetApplicableState(this, !mDisabled); + } + + return NS_OK; } NS_IMETHODIMP @@ -1341,18 +1351,10 @@ nsCSSStyleSheet::GetDisabled(PRBool* aDisabled) NS_IMETHODIMP nsCSSStyleSheet::SetDisabled(PRBool aDisabled) { - PRBool oldDisabled = mDisabled; - mDisabled = aDisabled; - - if (mDocument && mInner && mInner->mComplete && oldDisabled != mDisabled) { - ClearRuleCascades(); - - mDocument->BeginUpdate(UPDATE_STYLE); - mDocument->SetStyleSheetApplicableState(this, !mDisabled); - mDocument->EndUpdate(UPDATE_STYLE); - } - - return NS_OK; + // DOM method, so handle BeginUpdate/EndUpdate + MOZ_AUTO_DOC_UPDATE(mDocument, UPDATE_STYLE, PR_TRUE); + nsresult rv = nsCSSStyleSheet::SetEnabled(!aDisabled); + return rv; } NS_IMETHODIMP diff --git a/layout/style/nsIStyleSheet.h b/layout/style/nsIStyleSheet.h index 2412c8e82bce..0674a23d794f 100644 --- a/layout/style/nsIStyleSheet.h +++ b/layout/style/nsIStyleSheet.h @@ -56,9 +56,10 @@ class nsIDocument; class nsIStyleRuleProcessor; // IID for the nsIStyleSheet interface -// 93eea32f-681b-4405-b908-3933cf1d5091 +// 7b2d31da-c3fb-4537-bd97-337272b83568 #define NS_ISTYLE_SHEET_IID \ -{0x93eea32f, 0x681b, 0x4405, {0xb9, 0x08, 0x39, 0x33, 0xcf, 0x1d, 0x50, 0x91}} +{ 0x7b2d31da, 0xc3fb, 0x4537, \ + { 0xbd, 0x97, 0x33, 0x72, 0x72, 0xb8, 0x35, 0x68 } } /** * A style sheet is a thing associated with a document that has style @@ -91,7 +92,12 @@ public: /** * Set the stylesheet to be enabled. This may or may not make it - * applicable. + * applicable. Note that this WILL inform the sheet's document of + * its new applicable state if the state changes but WILL NOT call + * BeginUpdate() or EndUpdate() on the document -- calling those is + * the caller's responsibility. This allows use of SetEnabled when + * batched updates are desired. If you want updates handled for + * you, see nsIDOMStyleSheet::SetDisabled(). */ NS_IMETHOD SetEnabled(PRBool aEnabled) = 0; diff --git a/suite/browser/navigator.js b/suite/browser/navigator.js index 572f174a4091..fba257a93183 100644 --- a/suite/browser/navigator.js +++ b/suite/browser/navigator.js @@ -1987,7 +1987,7 @@ function stylesheetFillPopup(menuPopup) } menuPopup.firstChild.setAttribute("checked", styleDisabled); itemPersistentOnly.setAttribute("checked", !altStyleSelected && !styleDisabled); - itemPersistentOnly.hidden = (window.content.document.preferredStylesheetSet) ? true : false; + itemPersistentOnly.hidden = (window.content.document.preferredStyleSheetSet) ? true : false; } function stylesheetInFrame(frame, title) {