From 01634657fad34be5ece7f5e174579140ec36c523 Mon Sep 17 00:00:00 2001 From: "bryner%netscape.com" Date: Thu, 7 Mar 2002 03:34:29 +0000 Subject: [PATCH] - Implement the :checked CSS pseudoclass which maps to the "selected" property on option elements. - Eliminate the _moz-option-selected attribute; move the actual selected state into the option content node. - Change all users of _moz-option-selected to use :checked. - Add a third parameter to nsIDocument[Observer]::ContentStatesChanged to indicate which pseudoclass changed, this is used for optimizing handling of :checked state changes. Bug 128947, r=dbaron, sr=jst, a=asa. git-svn-id: svn://10.0.0.236/trunk@116029 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/content/base/public/nsIDocument.h | 3 +- .../content/base/public/nsIDocumentObserver.h | 3 +- .../base/public/nsIStyleRuleProcessor.h | 3 +- mozilla/content/base/src/nsContentList.h | 3 +- mozilla/content/base/src/nsDocument.cpp | 5 +- mozilla/content/base/src/nsDocument.h | 6 +- mozilla/content/base/src/nsStyleSet.cpp | 9 +- .../events/src/nsEventStateManager.cpp | 23 ++-- .../html/content/public/nsIOptionElement.h | 7 -- .../html/content/src/nsHTMLOptionElement.cpp | 61 ++++------- .../html/content/src/nsHTMLSelectElement.cpp | 4 +- .../html/document/src/nsHTMLContentSink.cpp | 3 +- .../html/style/src/nsCSSStyleSheet.cpp | 19 ++++ .../content/shared/public/nsLayoutAtomList.h | 1 - mozilla/content/xbl/src/nsBindingManager.cpp | 3 +- .../xul/document/src/nsXULDocument.cpp | 6 +- .../content/xul/document/src/nsXULDocument.h | 4 +- .../templates/src/nsXULTemplateBuilder.cpp | 3 +- .../xul/templates/src/nsXULTemplateBuilder.h | 3 +- .../extensions/inspector/base/src/inDOMView.h | 3 +- mozilla/layout/base/nsCSSFrameConstructor.cpp | 3 +- mozilla/layout/base/nsCSSFrameConstructor.h | 3 +- mozilla/layout/base/nsLayoutAtomList.h | 1 - mozilla/layout/base/nsPresShell.cpp | 9 +- .../base/public/nsIStyleFrameConstruction.h | 3 +- mozilla/layout/base/public/nsIStyleSet.h | 3 +- mozilla/layout/forms/nsListControlFrame.cpp | 16 ++- mozilla/layout/generic/nsGfxScrollFrame.cpp | 3 +- mozilla/layout/generic/nsImageMap.cpp | 3 +- mozilla/layout/generic/nsImageMap.h | 3 +- .../layout/html/base/src/nsGfxScrollFrame.cpp | 3 +- mozilla/layout/html/base/src/nsImageMap.cpp | 3 +- mozilla/layout/html/base/src/nsImageMap.h | 3 +- mozilla/layout/html/base/src/nsPresShell.cpp | 9 +- mozilla/layout/html/document/src/forms.css | 2 +- .../html/forms/src/nsListControlFrame.cpp | 16 ++- .../html/style/src/nsCSSFrameConstructor.cpp | 3 +- .../html/style/src/nsCSSFrameConstructor.h | 3 +- mozilla/layout/style/forms.css | 2 +- mozilla/layout/style/nsCSSStyleSheet.cpp | 19 ++++ mozilla/layout/style/nsIStyleRuleProcessor.h | 3 +- mozilla/layout/style/nsStyleSet.cpp | 9 +- .../outliner/src/nsOutlinerContentView.cpp | 100 ++++++++++++------ .../src/outliner/src/nsOutlinerContentView.h | 3 +- .../base/src/tree/src/nsTreeContentView.cpp | 100 ++++++++++++------ .../xul/base/src/tree/src/nsTreeContentView.h | 3 +- .../webshell/tests/viewer/samples/aform.css | 6 +- .../webshell/tests/viewer/samples/bform.css | 2 +- .../tests/viewer/samples/demoform.css | 2 +- .../webshell/tests/viewer/samples/mozform.css | 8 +- mozilla/widget/src/cocoa/nsMenuBarX.cpp | 3 +- mozilla/widget/src/cocoa/nsMenuBarX.h | 3 +- mozilla/widget/src/mac/nsMenuBar.cpp | 3 +- mozilla/widget/src/mac/nsMenuBar.h | 3 +- mozilla/widget/src/mac/nsMenuBarX.cpp | 3 +- mozilla/widget/src/mac/nsMenuBarX.h | 3 +- .../xpfe/appshell/src/nsWebShellWindow.cpp | 3 +- mozilla/xpfe/appshell/src/nsWebShellWindow.h | 3 +- 58 files changed, 334 insertions(+), 208 deletions(-) diff --git a/mozilla/content/base/public/nsIDocument.h b/mozilla/content/base/public/nsIDocument.h index 790bad506b7..d290547b7f8 100644 --- a/mozilla/content/base/public/nsIDocument.h +++ b/mozilla/content/base/public/nsIDocument.h @@ -318,7 +318,8 @@ public: // notify that one or two content nodes changed state // either may be nsnull, but not both NS_IMETHOD ContentStatesChanged(nsIContent* aContent1, - nsIContent* aContent2) = 0; + nsIContent* aContent2, + nsIAtom* aChangedPseudoClass) = 0; NS_IMETHOD AttributeWillChange(nsIContent* aChild, PRInt32 aNameSpaceID, nsIAtom* aAttribute) = 0; diff --git a/mozilla/content/base/public/nsIDocumentObserver.h b/mozilla/content/base/public/nsIDocumentObserver.h index 4fc9217c194..8b6741620df 100644 --- a/mozilla/content/base/public/nsIDocumentObserver.h +++ b/mozilla/content/base/public/nsIDocumentObserver.h @@ -138,7 +138,8 @@ public: */ NS_IMETHOD ContentStatesChanged(nsIDocument* aDocument, nsIContent* aContent1, - nsIContent* aContent2) = 0; + nsIContent* aContent2, + nsIAtom* aChangedPseudoClass) = 0; /** * Notification that the content model has changed. This method is called diff --git a/mozilla/content/base/public/nsIStyleRuleProcessor.h b/mozilla/content/base/public/nsIStyleRuleProcessor.h index e3558a8fe1a..7079ad111cc 100644 --- a/mozilla/content/base/public/nsIStyleRuleProcessor.h +++ b/mozilla/content/base/public/nsIStyleRuleProcessor.h @@ -90,9 +90,10 @@ struct RuleProcessorData { PRPackedBool mIsHTMLContent; // if content, then does QI on HTMLContent, true or false PRPackedBool mIsHTMLLink; // if content, calls nsStyleUtil::IsHTMLLink PRPackedBool mIsSimpleXLink; // if content, calls nsStyleUtil::IsSimpleXLink - nsLinkState mLinkState; // if a link, this is the state, otherwise unknown PRPackedBool mIsQuirkMode; // Possibly remove use of this in SelectorMatches? PRPackedBool mHasAttributes; // if content, content->GetAttrCount() > 0 + PRPackedBool mIsChecked; // checked/selected attribute for option and select elements + nsLinkState mLinkState; // if a link, this is the state, otherwise unknown PRInt32 mEventState; // if content, eventStateMgr->GetContentState() PRInt32 mNameSpaceID; // if content, content->GetNameSapce() RuleProcessorData* mPreviousSiblingData; diff --git a/mozilla/content/base/src/nsContentList.h b/mozilla/content/base/src/nsContentList.h index bc58a7a0ebb..9314e0ef024 100644 --- a/mozilla/content/base/src/nsContentList.h +++ b/mozilla/content/base/src/nsContentList.h @@ -138,7 +138,8 @@ public: nsISupports* aSubContent) { return NS_OK; } NS_IMETHOD ContentStatesChanged(nsIDocument* aDocument, nsIContent* aContent1, - nsIContent* aContent2) { return NS_OK; } + nsIContent* aContent2, + nsIAtom* aChangedPseudoClass) { return NS_OK; } NS_IMETHOD AttributeChanged(nsIDocument *aDocument, nsIContent* aContent, PRInt32 aNameSpaceID, diff --git a/mozilla/content/base/src/nsDocument.cpp b/mozilla/content/base/src/nsDocument.cpp index 46d5cb82be1..5b5df264c34 100644 --- a/mozilla/content/base/src/nsDocument.cpp +++ b/mozilla/content/base/src/nsDocument.cpp @@ -1847,14 +1847,15 @@ nsDocument::ContentChanged(nsIContent* aContent, NS_IMETHODIMP nsDocument::ContentStatesChanged(nsIContent* aContent1, - nsIContent* aContent2) + nsIContent* aContent2, + nsIAtom* aChangedPseudoClass) { PRInt32 i; // Get new value of count for every iteration in case // observers remove themselves during the loop. for (i = 0; i < mObservers.Count(); i++) { nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i]; - observer->ContentStatesChanged(this, aContent1, aContent2); + observer->ContentStatesChanged(this, aContent1, aContent2, aChangedPseudoClass); // Make sure that the observer didn't remove itself during the // notification. If it did, update our index and count. if (i < mObservers.Count() && diff --git a/mozilla/content/base/src/nsDocument.h b/mozilla/content/base/src/nsDocument.h index 0214ab38800..cf77fee6871 100644 --- a/mozilla/content/base/src/nsDocument.h +++ b/mozilla/content/base/src/nsDocument.h @@ -162,7 +162,8 @@ public: nsISupports* aSubContent) { return NS_OK; } NS_IMETHOD ContentStatesChanged(nsIDocument* aDocument, nsIContent* aContent1, - nsIContent* aContent2) { return NS_OK; } + nsIContent* aContent2, + nsIAtom* aChangedPseudoClass) { return NS_OK; } NS_IMETHOD AttributeChanged(nsIDocument *aDocument, nsIContent* aContent, PRInt32 aNameSpaceID, @@ -452,7 +453,8 @@ public: NS_IMETHOD ContentChanged(nsIContent* aContent, nsISupports* aSubContent); NS_IMETHOD ContentStatesChanged(nsIContent* aContent1, - nsIContent* aContent2); + nsIContent* aContent2, + nsIAtom* aChangedPseudoClass); NS_IMETHOD AttributeWillChange(nsIContent* aChild, PRInt32 aNameSpaceID, diff --git a/mozilla/content/base/src/nsStyleSet.cpp b/mozilla/content/base/src/nsStyleSet.cpp index ca9dc575c8b..bb5d829263f 100644 --- a/mozilla/content/base/src/nsStyleSet.cpp +++ b/mozilla/content/base/src/nsStyleSet.cpp @@ -206,7 +206,8 @@ public: nsISupports* aSubContent); NS_IMETHOD ContentStatesChanged(nsIPresContext* aPresContext, nsIContent* aContent1, - nsIContent* aContent2); + nsIContent* aContent2, + nsIAtom* aChangedPseudoClass); NS_IMETHOD AttributeChanged(nsIPresContext* aPresContext, nsIContent* aChild, PRInt32 aNameSpaceID, @@ -1476,9 +1477,11 @@ StyleSetImpl::ContentChanged(nsIPresContext* aPresContext, NS_IMETHODIMP StyleSetImpl::ContentStatesChanged(nsIPresContext* aPresContext, nsIContent* aContent1, - nsIContent* aContent2) + nsIContent* aContent2, + nsIAtom* aChangedPseudoClass) { - return mFrameConstructor->ContentStatesChanged(aPresContext, aContent1, aContent2); + return mFrameConstructor->ContentStatesChanged(aPresContext, aContent1, aContent2, + aChangedPseudoClass); } diff --git a/mozilla/content/events/src/nsEventStateManager.cpp b/mozilla/content/events/src/nsEventStateManager.cpp index 5b6e87df775..0e124cb6219 100644 --- a/mozilla/content/events/src/nsEventStateManager.cpp +++ b/mozilla/content/events/src/nsEventStateManager.cpp @@ -110,6 +110,7 @@ #include "nsLayoutCID.h" #include "nsIInterfaceRequestorUtils.h" #include "nsUnicharUtils.h" +#include "nsCSSAtoms.h" #if defined(DEBUG_rods) || defined(DEBUG_bryner) //#define DEBUG_DOCSHELL_FOCUS @@ -3528,16 +3529,16 @@ nsEventStateManager::SetContentState(nsIContent *aContent, PRInt32 aState) if (newHover) { nsCOMPtr parent; newHover->GetParent(*getter_AddRefs(parent)); - doc1->ContentStatesChanged(newHover, parent); + doc1->ContentStatesChanged(newHover, parent, nsCSSAtoms::hoverPseudo); while (parent && parent != commonHoverParent) { parent->GetParent(*getter_AddRefs(newHover)); if (newHover && newHover != commonHoverParent) { newHover->GetParent(*getter_AddRefs(parent)); if (parent == commonHoverParent) { - doc1->ContentStatesChanged(newHover, nsnull); + doc1->ContentStatesChanged(newHover, nsnull, nsCSSAtoms::hoverPseudo); } else { - doc1->ContentStatesChanged(newHover, parent); + doc1->ContentStatesChanged(newHover, parent, nsCSSAtoms::hoverPseudo); } } else { @@ -3549,16 +3550,16 @@ nsEventStateManager::SetContentState(nsIContent *aContent, PRInt32 aState) if (oldHover) { nsCOMPtr parent; oldHover->GetParent(*getter_AddRefs(parent)); - doc1->ContentStatesChanged(oldHover, parent); + doc1->ContentStatesChanged(oldHover, parent, nsCSSAtoms::hoverPseudo); while (parent && parent != commonHoverParent) { parent->GetParent(*getter_AddRefs(oldHover)); if (oldHover && oldHover != commonHoverParent) { oldHover->GetParent(*getter_AddRefs(parent)); if (parent == commonHoverParent) { - doc1->ContentStatesChanged(oldHover, nsnull); + doc1->ContentStatesChanged(oldHover, nsnull, nsCSSAtoms::hoverPseudo); } else { - doc1->ContentStatesChanged(oldHover, parent); + doc1->ContentStatesChanged(oldHover, parent, nsCSSAtoms::hoverPseudo); } } else { @@ -3567,23 +3568,23 @@ nsEventStateManager::SetContentState(nsIContent *aContent, PRInt32 aState) } } - doc1->ContentStatesChanged(notifyContent[0], notifyContent[1]); + doc1->ContentStatesChanged(notifyContent[0], notifyContent[1], nsnull); if (notifyContent[2]) { // more that two notifications are needed (should be rare) // XXX a further optimization here would be to group the notification pairs // together by parent/child, only needed if more than two content changed // (ie: if [0] and [2] are parent/child, then notify (0,2) (1,3)) - doc1->ContentStatesChanged(notifyContent[2], notifyContent[3]); + doc1->ContentStatesChanged(notifyContent[2], notifyContent[3], nsnull); if (notifyContent[4]) { // more that two notifications are needed (should be rare) - doc1->ContentStatesChanged(notifyContent[4], nsnull); + doc1->ContentStatesChanged(notifyContent[4], nsnull, nsnull); } } doc1->EndUpdate(); if (doc2) { doc2->BeginUpdate(); - doc2->ContentStatesChanged(notifyContent[1], notifyContent[2]); + doc2->ContentStatesChanged(notifyContent[1], notifyContent[2], nsnull); if (notifyContent[3]) { - doc1->ContentStatesChanged(notifyContent[3], notifyContent[4]); + doc1->ContentStatesChanged(notifyContent[3], notifyContent[4], nsnull); } doc2->EndUpdate(); } diff --git a/mozilla/content/html/content/public/nsIOptionElement.h b/mozilla/content/html/content/public/nsIOptionElement.h index eb34de99d3e..79af428be93 100644 --- a/mozilla/content/html/content/public/nsIOptionElement.h +++ b/mozilla/content/html/content/public/nsIOptionElement.h @@ -60,13 +60,6 @@ public: NS_DEFINE_STATIC_IID_ACCESSOR(NS_IOPTIONELEMENT_IID) - /** - * Check whether the option element is selected from its own point - * of view. This should only be used by SelectElement, really. - * Everyone else is safe using GetSelected() on the DOMHTMLOptionElement. - */ - NS_IMETHOD GetSelectedInternal(PRBool* aValue) = 0; - /** * Check whether the option element is selected from its own point * of view. This should only be used by SelectElement, really. diff --git a/mozilla/content/html/content/src/nsHTMLOptionElement.cpp b/mozilla/content/html/content/src/nsHTMLOptionElement.cpp index a2d8607bf5a..c0e0a72959d 100644 --- a/mozilla/content/html/content/src/nsHTMLOptionElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLOptionElement.cpp @@ -68,7 +68,7 @@ #include "nsNodeInfoManager.h" #include "nsCOMPtr.h" #include "nsLayoutAtoms.h" - +#include "nsCSSAtoms.h" class nsHTMLOptionElement : public nsGenericHTMLContainerElement, public nsIDOMHTMLOptionElement, @@ -108,7 +108,6 @@ public: #endif // nsIOptionElement - NS_IMETHOD GetSelectedInternal(PRBool* aValue); NS_IMETHOD SetSelectedInternal(PRBool aValue, PRBool aNotify); NS_IMETHOD GetValueOrText(nsAString& aValue); @@ -121,7 +120,8 @@ protected: // there's a select associated with this option or not. void GetSelect(nsIDOMHTMLSelectElement **aSelectElement) const; - PRBool mIsInitialized; + PRPackedBool mIsInitialized; + PRPackedBool mIsSelected; }; nsresult @@ -170,8 +170,9 @@ NS_NewHTMLOptionElement(nsIHTMLContent** aInstancePtrResult, nsHTMLOptionElement::nsHTMLOptionElement() + : mIsInitialized(PR_FALSE), + mIsSelected(PR_FALSE) { - mIsInitialized = PR_FALSE; } nsHTMLOptionElement::~nsHTMLOptionElement() @@ -241,43 +242,16 @@ nsHTMLOptionElement::GetForm(nsIDOMHTMLFormElement** aForm) return NS_OK; } -NS_IMETHODIMP -nsHTMLOptionElement::GetSelectedInternal(PRBool* aValue) -{ - // If it's not initialized, initialize it. - if (!mIsInitialized) { - mIsInitialized = PR_TRUE; - PRBool selected; - GetDefaultSelected(&selected); - // This does not need to be SetSelected (which sets selected in the select) - // because we *will* be initialized when we are placed into a select. Plus - // it seems like that's just inviting an infinite loop. - SetSelectedInternal(selected, PR_TRUE); - } - nsAutoString tmpVal; - nsresult rv = GetAttr(kNameSpaceID_None, - nsLayoutAtoms::optionSelectedPseudo, - tmpVal); - *aValue = !(NS_FAILED(rv) || NS_CONTENT_ATTR_NOT_THERE == rv); - return NS_OK; -} - NS_IMETHODIMP nsHTMLOptionElement::SetSelectedInternal(PRBool aValue, PRBool aNotify) { mIsInitialized = PR_TRUE; + mIsSelected = aValue; - // This affects the display, but what the hey, it's a good place for it - if (aValue) { - return SetAttr(kNameSpaceID_None, - nsLayoutAtoms::optionSelectedPseudo, - NS_LITERAL_STRING(""), - aNotify); - } else { - return UnsetAttr(kNameSpaceID_None, - nsLayoutAtoms::optionSelectedPseudo, - aNotify); - } + if (aNotify && mDocument) + mDocument->ContentStatesChanged(this, nsnull, nsCSSAtoms::checkedPseudo); + + return NS_OK; } NS_IMETHODIMP @@ -309,8 +283,19 @@ nsHTMLOptionElement::GetSelected(PRBool* aValue) NS_ENSURE_ARG_POINTER(aValue); *aValue = PR_FALSE; - // If there is no select element, return the selected - return GetSelectedInternal(aValue); + // If it's not initialized, initialize it. + if (!mIsInitialized) { + mIsInitialized = PR_TRUE; + PRBool selected; + GetDefaultSelected(&selected); + // This does not need to be SetSelected (which sets selected in the select) + // because we *will* be initialized when we are placed into a select. Plus + // it seems like that's just inviting an infinite loop. + SetSelectedInternal(selected, PR_TRUE); + } + + *aValue = mIsSelected; + return NS_OK; } NS_IMETHODIMP diff --git a/mozilla/content/html/content/src/nsHTMLSelectElement.cpp b/mozilla/content/html/content/src/nsHTMLSelectElement.cpp index 9f2656b19ca..ecaa541054d 100644 --- a/mozilla/content/html/content/src/nsHTMLSelectElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLSelectElement.cpp @@ -438,7 +438,7 @@ nsHTMLSelectElement::InsertOptionsIntoList(nsIContent* aOptions, // Actually select the options if the added options warrant it nsCOMPtr optionNode; - nsCOMPtr option; + nsCOMPtr option; for (PRInt32 i=aListIndex;iGetSelectedInternal(&selected); + option->GetSelected(&selected); if (selected) { // Clear all other options PRBool isMultiple; diff --git a/mozilla/content/html/document/src/nsHTMLContentSink.cpp b/mozilla/content/html/document/src/nsHTMLContentSink.cpp index 99c702bce8b..8693a5ff60d 100644 --- a/mozilla/content/html/document/src/nsHTMLContentSink.cpp +++ b/mozilla/content/html/document/src/nsHTMLContentSink.cpp @@ -290,7 +290,8 @@ public: nsISupports* aSubContent) { return NS_OK; } NS_IMETHOD ContentStatesChanged(nsIDocument* aDocument, nsIContent* aContent1, - nsIContent* aContent2) { return NS_OK; } + nsIContent* aContent2, + nsIAtom* aChangedPseudoClass) { return NS_OK; } NS_IMETHOD AttributeChanged(nsIDocument *aDocument, nsIContent* aContent, PRInt32 aNameSpaceID, diff --git a/mozilla/content/html/style/src/nsCSSStyleSheet.cpp b/mozilla/content/html/style/src/nsCSSStyleSheet.cpp index a5fe0885193..d5347bc050f 100644 --- a/mozilla/content/html/style/src/nsCSSStyleSheet.cpp +++ b/mozilla/content/html/style/src/nsCSSStyleSheet.cpp @@ -70,6 +70,7 @@ #include "nsIDOMHTMLAnchorElement.h" #include "nsIDOMHTMLLinkElement.h" #include "nsIDOMHTMLAreaElement.h" +#include "nsIDOMHTMLOptionElement.h" #include "nsIDOMStyleSheetList.h" #include "nsIDOMCSSStyleSheet.h" #include "nsIDOMCSSStyleRule.h" @@ -3232,6 +3233,7 @@ RuleProcessorData::RuleProcessorData(nsIPresContext* aPresContext, mIsHTMLContent = PR_FALSE; mIsHTMLLink = PR_FALSE; mIsSimpleXLink = PR_FALSE; + mIsChecked = PR_FALSE; mLinkState = eLinkState_Unknown; mEventState = NS_EVENT_STATE_UNSPECIFIED; mNameSpaceID = kNameSpaceID_Unknown; @@ -3299,6 +3301,15 @@ RuleProcessorData::RuleProcessorData(nsIPresContext* aPresContext, nsStyleUtil::IsSimpleXlink(aContent, mPresContext, &mLinkState)) { mIsSimpleXLink = PR_TRUE; } + + if (mIsHTMLContent) { + PRBool isChecked = PR_FALSE; + if (mContentTag == nsHTMLAtoms::option) { + nsCOMPtr optEl = do_QueryInterface(mContent); + optEl->GetSelected(&isChecked); + } + mIsChecked = isChecked; + } } } @@ -3590,6 +3601,14 @@ static PRBool SelectorMatches(RuleProcessorData &data, result = localFalse; // not a link } } + else if (nsCSSAtoms::checkedPseudo == pseudoClass->mAtom) { + // This pseudoclass matches the selected state on the following elements: + //