diff --git a/content/base/public/nsIDocument.h b/content/base/public/nsIDocument.h index 790bad506b7b..d290547b7f86 100644 --- a/content/base/public/nsIDocument.h +++ b/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/content/base/public/nsIDocumentObserver.h b/content/base/public/nsIDocumentObserver.h index 4fc9217c1944..8b6741620dfb 100644 --- a/content/base/public/nsIDocumentObserver.h +++ b/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/content/base/public/nsIStyleRuleProcessor.h b/content/base/public/nsIStyleRuleProcessor.h index e3558a8fe1ad..7079ad111cca 100644 --- a/content/base/public/nsIStyleRuleProcessor.h +++ b/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/content/base/src/nsContentList.h b/content/base/src/nsContentList.h index bc58a7a0ebbf..9314e0ef0243 100644 --- a/content/base/src/nsContentList.h +++ b/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/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index 46d5cb82be12..5b5df264c340 100644 --- a/content/base/src/nsDocument.cpp +++ b/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/content/base/src/nsDocument.h b/content/base/src/nsDocument.h index 0214ab38800b..cf77fee6871a 100644 --- a/content/base/src/nsDocument.h +++ b/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/content/base/src/nsStyleSet.cpp b/content/base/src/nsStyleSet.cpp index ca9dc575c8b1..bb5d829263fe 100644 --- a/content/base/src/nsStyleSet.cpp +++ b/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/content/events/src/nsEventStateManager.cpp b/content/events/src/nsEventStateManager.cpp index 5b6e87df775f..0e124cb62195 100644 --- a/content/events/src/nsEventStateManager.cpp +++ b/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/content/html/content/public/nsIOptionElement.h b/content/html/content/public/nsIOptionElement.h index eb34de99d3e7..79af428be93e 100644 --- a/content/html/content/public/nsIOptionElement.h +++ b/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/content/html/content/src/nsHTMLOptionElement.cpp b/content/html/content/src/nsHTMLOptionElement.cpp index a2d8607bf5ac..c0e0a72959df 100644 --- a/content/html/content/src/nsHTMLOptionElement.cpp +++ b/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/content/html/content/src/nsHTMLSelectElement.cpp b/content/html/content/src/nsHTMLSelectElement.cpp index 9f2656b19ca4..ecaa541054d9 100644 --- a/content/html/content/src/nsHTMLSelectElement.cpp +++ b/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/content/html/document/src/nsHTMLContentSink.cpp b/content/html/document/src/nsHTMLContentSink.cpp index 99c702bce8be..8693a5ff60de 100644 --- a/content/html/document/src/nsHTMLContentSink.cpp +++ b/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/content/html/style/src/nsCSSStyleSheet.cpp b/content/html/style/src/nsCSSStyleSheet.cpp index a5fe08851939..d5347bc050f6 100644 --- a/content/html/style/src/nsCSSStyleSheet.cpp +++ b/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: + //