Index: content/events/src/nsEventStateManager.cpp =================================================================== RCS file: /home/bzbarsky/mozilla/cvs-mirror/mozilla/content/events/src/nsEventStateManager.cpp,v retrieving revision 1.572 diff -u -p -d -8 -r1.572 nsEventStateManager.cpp --- content/events/src/nsEventStateManager.cpp 19 May 2005 16:18:32 -0000 1.572 +++ content/events/src/nsEventStateManager.cpp 2 Jun 2005 00:30:29 -0000 @@ -3620,17 +3620,17 @@ nsEventStateManager::GetEventRelatedCont *aContent = mCurrentRelatedContent; NS_IF_ADDREF(*aContent); return NS_OK; } NS_IMETHODIMP nsEventStateManager::GetContentState(nsIContent *aContent, PRInt32& aState) { - aState = NS_EVENT_STATE_UNSPECIFIED; + aState = aContent->IntrinsicState(); // Hierchical active: Check the ancestor chain of mActiveContent to see // if we are on it. for (nsIContent* activeContent = mActiveContent; activeContent; activeContent = activeContent->GetParent()) { if (aContent == activeContent) { aState |= NS_EVENT_STATE_ACTIVE; break; Index: content/base/public/nsIContent.h =================================================================== RCS file: /home/bzbarsky/mozilla/cvs-mirror/mozilla/content/base/public/nsIContent.h,v retrieving revision 3.108 diff -u -p -d -8 -r3.108 nsIContent.h --- content/base/public/nsIContent.h 1 May 2005 13:06:48 -0000 3.108 +++ content/base/public/nsIContent.h 2 Jun 2005 00:30:29 -0000 @@ -646,16 +646,30 @@ public: * PR_TRUE if all children have been added OR if the element was not * created by the parser. Returns PR_TRUE for all other elements. */ virtual PRBool IsDoneAddingChildren() { return PR_TRUE; } + /** + * Method to get the _intrinsic_ content state of this content node. This is + * the state that is independent of the node's presentation. To get the full + * content state, use nsIEventStateManager. Also see nsIEventStateManager + * for the possible bits that could be set here. + */ + // XXXbz this is PRInt32 because all the ESM content state APIs use + // PRInt32. We should really use PRUint32 instead. + virtual PRInt32 IntrinsicState() const + { + return 0; + } + + /* Methods for manipulating content node properties. For documentation on * properties, see nsPropertyTable.h. */ virtual void* GetProperty(nsIAtom *aPropertyName, nsresult *aStatus = nsnull) const { if (aStatus) *aStatus = NS_ERROR_NOT_IMPLEMENTED; return nsnull; } Index: content/html/content/src/nsHTMLInputElement.cpp =================================================================== RCS file: /home/bzbarsky/mozilla/cvs-mirror/mozilla/content/html/content/src/nsHTMLInputElement.cpp,v retrieving revision 1.388 diff -u -p -d -8 -r1.388 nsHTMLInputElement.cpp --- content/html/content/src/nsHTMLInputElement.cpp 4 May 2005 20:22:25 -0000 1.388 +++ content/html/content/src/nsHTMLInputElement.cpp 2 Jun 2005 00:32:01 -0000 @@ -220,16 +220,18 @@ public: aNotify); AfterSetAttr(aNameSpaceID, aAttribute, nsnull, aNotify); return rv; } virtual void DoneCreatingElement(); + virtual PRInt32 IntrinsicState() const; + // nsITextControlElement NS_IMETHOD TakeTextFrameValue(const nsAString& aValue); NS_IMETHOD SetValueChanged(PRBool aValueChanged); // nsIRadioControlElement NS_IMETHOD RadioSetChecked(PRBool aNotify); NS_IMETHOD SetCheckedChanged(PRBool aCheckedChanged); NS_IMETHOD SetCheckedChangedInternal(PRBool aCheckedChanged); @@ -2456,16 +2458,28 @@ nsHTMLInputElement::DoneCreatingElement( GetDefaultChecked(&resetVal); DoSetChecked(resetVal, PR_FALSE); SetCheckedChanged(PR_FALSE); } SET_BOOLBIT(mBitField, BF_SHOULD_INIT_CHECKED, PR_FALSE); } +PRInt32 +nsHTMLInputElement::IntrinsicState() const +{ + PRInt32 state = nsGenericHTMLFormElement::IntrinsicState(); + if (GET_BOOLBIT(mBitField, BF_CHECKED) && + (mType == NS_FORM_INPUT_CHECKBOX || + mType == NS_FORM_INPUT_RADIO)) { + state |= NS_EVENT_STATE_CHECKED; + } + return state; +} + PRBool nsHTMLInputElement::RestoreState(nsPresState* aState) { PRBool restoredCheckedState = PR_FALSE; nsresult rv; switch (mType) { Index: content/html/content/src/nsHTMLOptionElement.cpp =================================================================== RCS file: /home/bzbarsky/mozilla/cvs-mirror/mozilla/content/html/content/src/nsHTMLOptionElement.cpp,v retrieving revision 1.132 diff -u -p -d -8 -r1.132 nsHTMLOptionElement.cpp --- content/html/content/src/nsHTMLOptionElement.cpp 18 Apr 2005 22:58:30 -0000 1.132 +++ content/html/content/src/nsHTMLOptionElement.cpp 2 Jun 2005 00:30:29 -0000 @@ -117,16 +117,17 @@ public: } virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, nsIAtom* aPrefix, const nsAString& aValue, PRBool aNotify); virtual nsresult InsertChildAt(nsIContent* aKid, PRUint32 aIndex, PRBool aNotify); virtual nsresult AppendChildTo(nsIContent* aKid, PRBool aNotify); virtual nsresult RemoveChildAt(PRUint32 aIndex, PRBool aNotify); + virtual PRInt32 IntrinsicState() const; protected: /** * Get the primary frame associated with this content * @return the primary frame associated with this content */ nsIFormControlFrame *GetSelectFrame() const; @@ -488,16 +489,30 @@ nsHTMLOptionElement::AppendChildTo(nsICo nsresult nsHTMLOptionElement::RemoveChildAt(PRUint32 aIndex, PRBool aNotify) { nsresult rv = nsGenericHTMLElement::RemoveChildAt(aIndex, aNotify); NotifyTextChanged(); return rv; } +PRInt32 +nsHTMLOptionElement::IntrinsicState() const +{ + PRInt32 state = nsGenericHTMLElement::IntrinsicState(); + // Nasty hack because we need to call an interface method, and one that + // toggles some of our hidden internal state at that! Would that we could + // use |mutable|. + PRBool selected; + NS_CONST_CAST(nsHTMLOptionElement*, this)->GetSelected(&selected); + if (selected) { + state |= NS_EVENT_STATE_CHECKED; + } + return state; +} // Options don't have frames - get the select content node // then call nsGenericHTMLElement::GetFormControlFrameFor() nsIFormControlFrame * nsHTMLOptionElement::GetSelectFrame() const { if (!GetParent()) { Index: layout/style/nsIStyleRuleProcessor.h =================================================================== RCS file: /home/bzbarsky/mozilla/cvs-mirror/mozilla/layout/style/nsIStyleRuleProcessor.h,v retrieving revision 3.35 diff -u -p -d -8 -r3.35 nsIStyleRuleProcessor.h --- layout/style/nsIStyleRuleProcessor.h 8 Dec 2004 19:39:47 -0000 3.35 +++ layout/style/nsIStyleRuleProcessor.h 2 Jun 2005 00:30:29 -0000 @@ -85,17 +85,16 @@ struct RuleProcessorData { nsIAtom* mContentTag; // if content, then content->GetTag() nsIAtom* mContentID; // if styled content, then weak reference to styledcontent->GetID() nsIStyledContent* mStyledContent; // if content, content->QI(nsIStyledContent) 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 nsCompatibility mCompatMode; // 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; RuleProcessorData* mParentData; protected: nsAutoString *mLanguage; // NULL means we haven't found out the language yet Index: layout/style/nsCSSStyleSheet.cpp =================================================================== RCS file: /home/bzbarsky/mozilla/cvs-mirror/mozilla/layout/style/nsCSSStyleSheet.cpp,v retrieving revision 3.330 diff -u -p -d -8 -r3.330 nsCSSStyleSheet.cpp --- layout/style/nsCSSStyleSheet.cpp 19 Apr 2005 01:27:10 -0000 3.330 +++ layout/style/nsCSSStyleSheet.cpp 2 Jun 2005 00:32:13 -0000 @@ -2650,17 +2650,16 @@ RuleProcessorData::RuleProcessorData(nsP mScopedRoot = nsnull; mContentTag = nsnull; mContentID = nsnull; mStyledContent = nsnull; mIsHTMLContent = PR_FALSE; mIsHTMLLink = PR_FALSE; mIsSimpleXLink = PR_FALSE; - mIsChecked = PR_FALSE; mLinkState = eLinkState_Unknown; mEventState = NS_EVENT_STATE_UNSPECIFIED; mNameSpaceID = kNameSpaceID_Unknown; mPreviousSiblingData = nsnull; mParentData = nsnull; mLanguage = nsnull; // get the compat. mode (unless it is provided) @@ -2716,28 +2715,16 @@ RuleProcessorData::RuleProcessorData(nsP // if not an HTML link, check for a simple xlink (cannot be both HTML link and xlink) // NOTE: optimization: cannot be an XLink if no attributes (since it needs an if(!mIsHTMLLink && mHasAttributes && !(mIsHTMLContent || aContent->IsContentOfType(nsIContent::eXUL)) && 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); - } else if (mContentTag == nsHTMLAtoms::input) { - nsCOMPtr inputEl = do_QueryInterface(mContent); - inputEl->GetChecked(&isChecked); - } - mIsChecked = isChecked; - } } } RuleProcessorData::~RuleProcessorData() { MOZ_COUNT_DTOR(RuleProcessorData); if (mPreviousSiblingData) @@ -2895,16 +2882,20 @@ static PRBool AttrMatchesValue(const nsA case NS_ATTR_FUNC_CONTAINSMATCH: return FindInReadable(aAttrSelector->mValue, aValue, comparator); default: NS_NOTREACHED("Shouldn't be ending up here"); return PR_FALSE; } } +#define STATE_CHECK(_state) \ + ((aStateMask & (_state)) || \ + (localTrue == (0 != (data.mEventState & (_state))))) + // NOTE: The |aStateMask| code isn't going to work correctly anymore if // we start batching style changes, because if multiple states change in // separate notifications then we might determine the style is not // state-dependent when it really is (e.g., determining that a // :hover:active rule no longer matches when both states are unset). static PRBool SelectorMatches(RuleProcessorData &data, nsCSSSelector* aSelector, PRInt32 aStateMask, // states NOT to test @@ -3090,34 +3081,29 @@ static PRBool SelectorMatches(RuleProces // important for |IsQuirkEventSensitive|: data.mIsHTMLContent && !data.mIsHTMLLink && !IsQuirkEventSensitive(data.mContentTag)) { // In quirks mode, only make certain elements sensitive to // selectors ":hover" and ":active". result = localFalse; } else { if (nsCSSPseudoClasses::active == pseudoClass->mAtom) { - result = (aStateMask & NS_EVENT_STATE_ACTIVE) || - (localTrue == (0 != (data.mEventState & NS_EVENT_STATE_ACTIVE))); + result = STATE_CHECK(NS_EVENT_STATE_ACTIVE); } else if (nsCSSPseudoClasses::focus == pseudoClass->mAtom) { - result = (aStateMask & NS_EVENT_STATE_FOCUS) || - (localTrue == (0 != (data.mEventState & NS_EVENT_STATE_FOCUS))); + result = STATE_CHECK(NS_EVENT_STATE_FOCUS); } else if (nsCSSPseudoClasses::hover == pseudoClass->mAtom) { - result = (aStateMask & NS_EVENT_STATE_HOVER) || - (localTrue == (0 != (data.mEventState & NS_EVENT_STATE_HOVER))); + result = STATE_CHECK(NS_EVENT_STATE_HOVER); } else if (nsCSSPseudoClasses::mozDragOver == pseudoClass->mAtom) { - result = (aStateMask & NS_EVENT_STATE_DRAGOVER) || - (localTrue == (0 != (data.mEventState & NS_EVENT_STATE_DRAGOVER))); + result = STATE_CHECK(NS_EVENT_STATE_DRAGOVER); } else if (nsCSSPseudoClasses::target == pseudoClass->mAtom) { - result = (aStateMask & NS_EVENT_STATE_URLTARGET) || - (localTrue == (0 != (data.mEventState & NS_EVENT_STATE_URLTARGET))); + result = STATE_CHECK(NS_EVENT_STATE_URLTARGET); } } } else if (IsLinkPseudo(pseudoClass->mAtom)) { if (data.mIsHTMLLink || data.mIsSimpleXLink) { if (nsCSSPseudoClasses::mozAnyLink == pseudoClass->mAtom) { result = localTrue; } @@ -3132,18 +3118,17 @@ static PRBool SelectorMatches(RuleProces result = localFalse; // not a link } } else if (nsCSSPseudoClasses::checked == pseudoClass->mAtom) { // This pseudoclass matches the selected state on the following elements: //