Fix up and enable hierarchical :hover and remove the hacks that made :hover work for anchors without it. Pass mask rather than pseudo-class to ContentStatesChanged notifications. Optimize event state changes in the style system by passing state mask to HasStateDependentStyle and using it in HasStateDependentStyle implementations. b=5693 r=bryner, joki sr=hyatt

This commit is contained in:
dbaron%fas.harvard.edu 2002-04-11 03:49:30 +00:00
Родитель ee356815ee
Коммит 324f543007
54 изменённых файлов: 359 добавлений и 343 удалений

Просмотреть файл

@ -319,7 +319,7 @@ public:
// either may be nsnull, but not both
NS_IMETHOD ContentStatesChanged(nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass) = 0;
PRInt32 aStateMask) = 0;
NS_IMETHOD AttributeWillChange(nsIContent* aChild,
PRInt32 aNameSpaceID,
nsIAtom* aAttribute) = 0;

Просмотреть файл

@ -139,7 +139,7 @@ public:
NS_IMETHOD ContentStatesChanged(nsIDocument* aDocument,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass) = 0;
PRInt32 aStateMask) = 0;
/**
* Notification that the content model has changed. This method is called

Просмотреть файл

@ -131,11 +131,15 @@ struct PseudoRuleProcessorData : public RuleProcessorData {
struct StateRuleProcessorData : public RuleProcessorData {
StateRuleProcessorData(nsIPresContext* aPresContext,
nsIContent* aContent)
: RuleProcessorData(aPresContext, aContent, nsnull)
nsIContent* aContent,
PRInt32 aStateMask)
: RuleProcessorData(aPresContext, aContent, nsnull),
mStateMask(aStateMask)
{
NS_PRECONDITION(aContent, "null pointer");
}
const PRInt32 mStateMask; // |HasStateDependentStyle| for which state(s)?
// Constants defined in nsIEventStateManager.h .
};
@ -162,8 +166,9 @@ public:
nsIAtom* aMedium) = 0;
// Test if style is dependent on content state
NS_IMETHOD HasStateDependentStyle(StateRuleProcessorData* aData,
nsIAtom* aMedium) = 0;
NS_IMETHOD HasStateDependentStyle(StateRuleProcessorData* aData,
nsIAtom* aMedium,
PRBool* aResult) = 0;
#ifdef DEBUG
virtual void SizeOf(nsISizeOfHandler *aSizeofHandler, PRUint32 &aSize) = 0;

Просмотреть файл

@ -139,7 +139,7 @@ public:
NS_IMETHOD ContentStatesChanged(nsIDocument* aDocument,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass) { return NS_OK; }
PRInt32 aStateMask) { return NS_OK; }
NS_IMETHOD AttributeChanged(nsIDocument *aDocument,
nsIContent* aContent,
PRInt32 aNameSpaceID,

Просмотреть файл

@ -1857,14 +1857,14 @@ nsDocument::ContentChanged(nsIContent* aContent,
NS_IMETHODIMP
nsDocument::ContentStatesChanged(nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass)
PRInt32 aStateMask)
{
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, aChangedPseudoClass);
observer->ContentStatesChanged(this, aContent1, aContent2, aStateMask);
// Make sure that the observer didn't remove itself during the
// notification. If it did, update our index and count.
if (i < mObservers.Count() &&

Просмотреть файл

@ -163,7 +163,7 @@ public:
NS_IMETHOD ContentStatesChanged(nsIDocument* aDocument,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass) { return NS_OK; }
PRInt32 aStateMask) { return NS_OK; }
NS_IMETHOD AttributeChanged(nsIDocument *aDocument,
nsIContent* aContent,
PRInt32 aNameSpaceID,
@ -454,7 +454,7 @@ public:
nsISupports* aSubContent);
NS_IMETHOD ContentStatesChanged(nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass);
PRInt32 aStateMask);
NS_IMETHOD AttributeWillChange(nsIContent* aChild,
PRInt32 aNameSpaceID,

Просмотреть файл

@ -205,8 +205,10 @@ public:
nsIStyleContext* aNewParentContext,
nsIStyleContext** aNewStyleContext);
NS_IMETHOD HasStateDependentStyle(nsIPresContext* aPresContext,
nsIContent* aContent);
NS_IMETHOD HasStateDependentStyle(nsIPresContext* aPresContext,
nsIContent* aContent,
PRInt32 aStateMask,
PRBool* aResult);
NS_IMETHOD ConstructRootFrame(nsIPresContext* aPresContext,
nsIContent* aContent,
@ -235,7 +237,7 @@ public:
NS_IMETHOD ContentStatesChanged(nsIPresContext* aPresContext,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass);
PRInt32 aStateMask);
NS_IMETHOD AttributeChanged(nsIPresContext* aPresContext,
nsIContent* aChild,
PRInt32 aNameSpaceID,
@ -1432,8 +1434,9 @@ StyleSetImpl::ReParentStyleContext(nsIPresContext* aPresContext,
}
struct StatefulData : public StateRuleProcessorData {
StatefulData(nsIPresContext* aPresContext, nsIAtom* aMedium, nsIContent* aContent)
: StateRuleProcessorData(aPresContext, aContent),
StatefulData(nsIPresContext* aPresContext, nsIAtom* aMedium,
nsIContent* aContent, PRInt32 aStateMask)
: StateRuleProcessorData(aPresContext, aContent, aStateMask),
mMedium(aMedium),
mStateful(PR_FALSE)
{}
@ -1445,17 +1448,18 @@ static PRBool SheetHasStatefulStyle(nsISupports* aProcessor, void *aData)
{
nsIStyleRuleProcessor* processor = (nsIStyleRuleProcessor*)aProcessor;
StatefulData* data = (StatefulData*)aData;
if (NS_OK == processor->HasStateDependentStyle(data, data->mMedium)) {
data->mStateful = PR_TRUE;
processor->HasStateDependentStyle(data, data->mMedium, &data->mStateful);
if (data->mStateful)
return PR_FALSE; // stop iteration
}
return PR_TRUE; // continue
}
// Test if style is dependent on content state
NS_IMETHODIMP
StyleSetImpl::HasStateDependentStyle(nsIPresContext* aPresContext,
nsIContent* aContent)
nsIContent* aContent,
PRInt32 aStateMask,
PRBool* aResult)
{
GatherRuleProcessors();
@ -1466,12 +1470,15 @@ StyleSetImpl::HasStateDependentStyle(nsIPresContext* aPresContext,
mOverrideRuleProcessors)) {
nsIAtom* medium = nsnull;
aPresContext->GetMedium(&medium);
StatefulData data(aPresContext, medium, aContent);
StatefulData data(aPresContext, medium, aContent, aStateMask);
WalkRuleProcessors(SheetHasStatefulStyle, &data);
NS_IF_RELEASE(medium);
return ((data.mStateful) ? NS_OK : NS_COMFALSE);
*aResult = data.mStateful;
} else {
*aResult = PR_FALSE;
}
return NS_COMFALSE;
return NS_OK;
}
@ -1541,10 +1548,10 @@ NS_IMETHODIMP
StyleSetImpl::ContentStatesChanged(nsIPresContext* aPresContext,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass)
PRInt32 aStateMask)
{
return mFrameConstructor->ContentStatesChanged(aPresContext, aContent1, aContent2,
aChangedPseudoClass);
return mFrameConstructor->ContentStatesChanged(aPresContext, aContent1,
aContent2, aStateMask);
}

Просмотреть файл

@ -126,6 +126,8 @@ public:
#define NS_EVENT_STATE_FOCUS 0x0002 // content has focus
#define NS_EVENT_STATE_HOVER 0x0004 // mouse is hovering over content
#define NS_EVENT_STATE_DRAGOVER 0x0008 // drag is hovering over content
// The following states are used only for ContentStatesChanged
#define NS_EVENT_STATE_CHECKED 0x0010
enum EFocusedWithType {
eEventFocusedByUnknown, // focus gained via unknown method

Просмотреть файл

@ -183,7 +183,6 @@ nsEventStateManager::nsEventStateManager()
mFirstFocusEvent = nsnull;
mAccessKeys = nsnull;
mBrowseWithCaret = PR_FALSE;
hHover = PR_FALSE;
mLeftClickOnly = PR_TRUE;
mNormalLMouseEventInProcess = PR_FALSE;
@ -210,7 +209,6 @@ nsEventStateManager::Init()
rv = getPrefService();
if (NS_SUCCEEDED(rv)) {
mPrefService->GetBoolPref("nglayout.events.showHierarchicalHover", &hHover);
mPrefService->GetBoolPref("nglayout.events.dispatchLeftClickOnly", &mLeftClickOnly);
}
@ -2278,8 +2276,9 @@ nsEventStateManager::GenerateMouseEnterExit(nsIPresContext* aPresContext, nsGUIE
targetContent->HandleDOMEvent(aPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status);
}
if ( status != nsEventStatus_eConsumeNoDefault )
SetContentState(targetContent, NS_EVENT_STATE_HOVER);
// :hover is a state that is more basic than a "default
// action", so we don't check |status|. See bug 38380.
SetContentState(targetContent, NS_EVENT_STATE_HOVER);
//Now dispatch to the frame
if (mCurrentTarget) {
@ -2330,8 +2329,9 @@ nsEventStateManager::GenerateMouseEnterExit(nsIPresContext* aPresContext, nsGUIE
if (mLastMouseOverContent) {
mLastMouseOverContent->HandleDOMEvent(aPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status);
if ( status != nsEventStatus_eConsumeNoDefault )
SetContentState(nsnull, NS_EVENT_STATE_HOVER);
// :hover is a state that is more basic than a "default
// action", so we don't check |status|. See bug 38380.
SetContentState(nsnull, NS_EVENT_STATE_HOVER);
}
//Now dispatch to the frame
@ -3392,24 +3392,17 @@ nsEventStateManager::GetContentState(nsIContent *aContent, PRInt32& aState)
if (aContent == mActiveContent) {
aState |= NS_EVENT_STATE_ACTIVE;
}
if (hHover) {
//If using hierchical hover check the ancestor chain of mHoverContent
//to see if we are on it.
nsCOMPtr<nsIContent> parent = mHoverContent;
nsIContent* child;
while (parent) {
if (aContent == parent.get()) {
aState |= NS_EVENT_STATE_HOVER;
break;
}
child = parent;
child->GetParent(*getter_AddRefs(parent));
}
}
else {
if (aContent == mHoverContent) {
// Hierchical hover: Check the ancestor chain of mHoverContent to see
// if we are on it.
nsCOMPtr<nsIContent> hoverContent = mHoverContent;
while (hoverContent) {
if (aContent == hoverContent) {
aState |= NS_EVENT_STATE_HOVER;
break;
}
nsIContent *parent;
hoverContent->GetParent(parent);
hoverContent = dont_AddRef(parent);
}
if (aContent == mCurrentFocus) {
@ -3428,6 +3421,7 @@ nsEventStateManager::SetContentState(nsIContent *aContent, PRInt32 aState)
nsIContent *notifyContent[maxNotify] = {nsnull, nsnull, nsnull, nsnull, nsnull};
// check to see that this state is allowed by style. Check dragover too?
// XXX This doesn't consider that |aState| is a bitfield.
if (mCurrentTarget && (aState == NS_EVENT_STATE_ACTIVE || aState == NS_EVENT_STATE_HOVER))
{
const nsStyleUserInterface* ui;
@ -3450,66 +3444,61 @@ nsEventStateManager::SetContentState(nsIContent *aContent, PRInt32 aState)
NS_IF_ADDREF(mActiveContent);
}
nsCOMPtr<nsIContent> newHover = nsnull;
nsCOMPtr<nsIContent> oldHover = nsnull;
nsCOMPtr<nsIContent> commonHoverParent = nsnull;
nsCOMPtr<nsIContent> commonHoverAncestor, oldHover, newHover;
if ((aState & NS_EVENT_STATE_HOVER) && (aContent != mHoverContent)) {
if (hHover) {
nsCOMPtr<nsIDocument> doc;
if (aContent && NS_SUCCEEDED(aContent->GetDocument(*getter_AddRefs(doc))) && doc) {
newHover = aContent;
oldHover = mHoverContent;
newHover = aContent;
// Find closest common ancestor (commonHoverAncestor)
if (mHoverContent && aContent) {
// Find the nearest common ancestor by counting the distance to the
// root and then walking up again, in pairs.
PRInt32 offset = 0;
nsCOMPtr<nsIContent> oldAncestor = mHoverContent;
for (;;) {
++offset;
nsIContent *parent;
oldAncestor->GetParent(parent);
if (!parent)
break;
oldAncestor = dont_AddRef(parent);
}
if (mHoverContent && NS_SUCCEEDED(mHoverContent->GetDocument(*getter_AddRefs(doc))) && doc) {
oldHover = mHoverContent;
nsCOMPtr<nsIContent> newAncestor = aContent;
for (;;) {
--offset;
nsIContent *parent;
newAncestor->GetParent(parent);
if (!parent)
break;
newAncestor = dont_AddRef(parent);
}
NS_ASSERTION(oldAncestor == newAncestor, "different documents");
if (oldAncestor == newAncestor) {
oldAncestor = mHoverContent;
newAncestor = aContent;
while (offset > 0) {
nsIContent *parent;
oldAncestor->GetParent(parent);
oldAncestor = dont_AddRef(parent);
--offset;
}
while (offset < 0) {
nsIContent *parent;
newAncestor->GetParent(parent);
newAncestor = dont_AddRef(parent);
++offset;
}
while (oldAncestor != newAncestor) {
nsIContent *parent;
oldAncestor->GetParent(parent);
oldAncestor = dont_AddRef(parent);
newAncestor->GetParent(parent);
newAncestor = dont_AddRef(parent);
}
commonHoverAncestor = oldAncestor;
}
}
//Find closest common parent
nsCOMPtr<nsIContent> parent1 = mHoverContent;
nsCOMPtr<nsIContent> parent2;
if (mHoverContent && aContent) {
while (parent1) {
parent2 = aContent;
while (parent2) {
if (parent1 == parent2) {
commonHoverParent = parent1;
break;
}
nsIContent* child2 = parent2;
child2->GetParent(*getter_AddRefs(parent2));
}
if (commonHoverParent) {
break;
}
nsIContent* child1 = parent1;
child1->GetParent(*getter_AddRefs(parent1));
}
}
//If new hover content is null we get the top parent of mHoverContent
else if (mHoverContent) {
nsCOMPtr<nsIContent> parent = mHoverContent;
nsIContent* child = nsnull;
while (parent) {
child = parent;
child->GetParent(*getter_AddRefs(parent));
}
commonHoverParent = child;
}
//Else if old hover content is null we get the top parent of aContent
else {
nsCOMPtr<nsIContent> parent = aContent;
nsIContent* child = nsnull;
while (parent) {
child = parent;
child->GetParent(*getter_AddRefs(parent));
}
commonHoverParent = child;
}
NS_IF_RELEASE(mHoverContent);
}
else {
//transferring ref to notifyContent from mHoverContent
notifyContent[1] = mHoverContent; // notify hover first, since more common case
}
NS_IF_RELEASE(mHoverContent);
mHoverContent = aContent;
NS_IF_ADDREF(mHoverContent);
}
@ -3533,7 +3522,7 @@ nsEventStateManager::SetContentState(nsIContent *aContent, PRInt32 aState)
}
}
if (aContent) { // notify about new content too
if (aContent && aContent != newHover) { // notify about new content too
notifyContent[0] = aContent;
NS_ADDREF(aContent); // everything in notify array has a ref
}
@ -3603,71 +3592,53 @@ nsEventStateManager::SetContentState(nsIContent *aContent, PRInt32 aState)
newHover->GetDocument(*getter_AddRefs(doc1));
}
else {
oldHover->GetDocument(*getter_AddRefs(doc2));
oldHover->GetDocument(*getter_AddRefs(doc1));
}
if (doc1) {
doc1->BeginUpdate();
//Notify all content from newHover to the commonHoverParent
if (newHover) {
nsCOMPtr<nsIContent> parent;
newHover->GetParent(*getter_AddRefs(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, nsCSSAtoms::hoverPseudo);
}
else {
doc1->ContentStatesChanged(newHover, parent, nsCSSAtoms::hoverPseudo);
}
}
else {
break;
}
}
// Notify all content from newHover to the commonHoverAncestor
while (newHover && newHover != commonHoverAncestor) {
doc1->ContentStatesChanged(newHover, nsnull, NS_EVENT_STATE_HOVER);
nsIContent *parent;
newHover->GetParent(parent);
newHover = dont_AddRef(parent);
}
//Notify all content from oldHover to the commonHoverParent
if (oldHover) {
nsCOMPtr<nsIContent> parent;
oldHover->GetParent(*getter_AddRefs(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, nsCSSAtoms::hoverPseudo);
}
else {
doc1->ContentStatesChanged(oldHover, parent, nsCSSAtoms::hoverPseudo);
}
}
else {
break;
}
}
// Notify all content from oldHover to the commonHoverAncestor
while (oldHover && oldHover != commonHoverAncestor) {
doc1->ContentStatesChanged(oldHover, nsnull, NS_EVENT_STATE_HOVER);
nsIContent *parent;
oldHover->GetParent(parent);
oldHover = dont_AddRef(parent);
}
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], nsnull);
if (notifyContent[4]) { // more that two notifications are needed (should be rare)
doc1->ContentStatesChanged(notifyContent[4], nsnull, nsnull);
if (notifyContent[0]) {
doc1->ContentStatesChanged(notifyContent[0], notifyContent[1],
aState & ~NS_EVENT_STATE_HOVER);
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],
aState & ~NS_EVENT_STATE_HOVER);
if (notifyContent[4]) {
// more that four notifications are needed (should be rare)
doc1->ContentStatesChanged(notifyContent[4], nsnull,
aState & ~NS_EVENT_STATE_HOVER);
}
}
}
doc1->EndUpdate();
if (doc2) {
doc2->BeginUpdate();
doc2->ContentStatesChanged(notifyContent[1], notifyContent[2], nsnull);
doc2->ContentStatesChanged(notifyContent[1], notifyContent[2],
aState & ~NS_EVENT_STATE_HOVER);
if (notifyContent[3]) {
doc1->ContentStatesChanged(notifyContent[3], notifyContent[4], nsnull);
doc1->ContentStatesChanged(notifyContent[3], notifyContent[4],
aState & ~NS_EVENT_STATE_HOVER);
}
doc2->EndUpdate();
}
@ -4282,7 +4253,8 @@ void nsEventStateManager::FocusElementButNotDocument(nsIContent *aContent)
mDocument->BeginUpdate();
if (!lastFocusInThisDoc)
lastFocusInThisDoc = mCurrentFocus;
mDocument->ContentStatesChanged(lastFocusInThisDoc, mCurrentFocus, nsnull);
mDocument->ContentStatesChanged(lastFocusInThisDoc, mCurrentFocus,
NS_EVENT_STATE_FOCUS);
mDocument->EndUpdate();
FlushPendingEvents(mPresContext);

Просмотреть файл

@ -260,9 +260,6 @@ protected:
nsCOMPtr<nsIPref> mPrefService;
PRBool m_haveShutdown;
//Pref for using hierarchical hover (possibly expensive) or not
PRBool hHover;
// So we don't have to keep checking accessibility.browsewithcaret pref
PRBool mBrowseWithCaret;

Просмотреть файл

@ -1390,8 +1390,9 @@ nsGenericHTMLElement::HandleDOMEventForAnchors(nsIContent* aOuter,
return ret;
if ((*aEventStatus == nsEventStatus_eIgnore ||
aEvent->message == NS_MOUSE_ENTER_SYNTH ||
aEvent->message == NS_MOUSE_EXIT_SYNTH) &&
(*aEventStatus != nsEventStatus_eConsumeNoDefault &&
(aEvent->message == NS_MOUSE_ENTER_SYNTH ||
aEvent->message == NS_MOUSE_EXIT_SYNTH))) &&
!(aFlags & NS_EVENT_FLAG_CAPTURE)) {
// If we're here, then aOuter should be an nsILink. We'll use the
@ -1483,20 +1484,9 @@ nsGenericHTMLElement::HandleDOMEventForAnchors(nsIContent* aOuter,
}
break;
case NS_MOUSE_ENTER_SYNTH:
{
nsCOMPtr<nsIEventStateManager> stateManager;
aPresContext->GetEventStateManager(getter_AddRefs(stateManager));
if (stateManager)
stateManager->SetContentState(this, NS_EVENT_STATE_HOVER);
// don't set status for onmouseover="...; return true;"
if (*aEventStatus == nsEventStatus_eConsumeNoDefault)
break;
*aEventStatus = nsEventStatus_eConsumeNoDefault;
}
// Set the status bar the same for focus and mouseover
case NS_MOUSE_ENTER_SYNTH:
*aEventStatus = nsEventStatus_eConsumeNoDefault;
case NS_FOCUS_CONTENT:
{
nsAutoString target;
@ -1513,15 +1503,6 @@ nsGenericHTMLElement::HandleDOMEventForAnchors(nsIContent* aOuter,
case NS_MOUSE_EXIT_SYNTH:
{
nsCOMPtr<nsIEventStateManager> stateManager;
aPresContext->GetEventStateManager(getter_AddRefs(stateManager));
if (stateManager)
stateManager->SetContentState(nsnull, NS_EVENT_STATE_HOVER);
// don't set status for onmouseover="...; return true;"
if (*aEventStatus == nsEventStatus_eConsumeNoDefault)
break;
*aEventStatus = nsEventStatus_eConsumeNoDefault;
nsAutoString empty;

Просмотреть файл

@ -905,7 +905,7 @@ nsHTMLInputElement::SetCheckedInternal(PRBool aChecked)
// Probably ContentStatesChanged() needs to be told not to worry if there is
// no frame in some cases. Bug 134560.
if (mDocument && frame) {
mDocument->ContentStatesChanged(this, nsnull, nsCSSAtoms::checkedPseudo);
mDocument->ContentStatesChanged(this, nsnull, NS_EVENT_STATE_CHECKED);
}
return NS_OK;

Просмотреть файл

@ -68,7 +68,7 @@
#include "nsNodeInfoManager.h"
#include "nsCOMPtr.h"
#include "nsLayoutAtoms.h"
#include "nsCSSAtoms.h"
#include "nsIEventStateManager.h"
class nsHTMLOptionElement : public nsGenericHTMLContainerElement,
public nsIDOMHTMLOptionElement,
@ -269,7 +269,7 @@ nsHTMLOptionElement::SetSelectedInternal(PRBool aValue, PRBool aNotify)
mIsSelected = aValue;
if (aNotify && mDocument)
mDocument->ContentStatesChanged(this, nsnull, nsCSSAtoms::checkedPseudo);
mDocument->ContentStatesChanged(this, nsnull, NS_EVENT_STATE_CHECKED);
return NS_OK;
}

Просмотреть файл

@ -294,7 +294,7 @@ public:
NS_IMETHOD ContentStatesChanged(nsIDocument* aDocument,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass) { return NS_OK; }
PRInt32 aStateMask) { return NS_OK; }
NS_IMETHOD AttributeChanged(nsIDocument *aDocument,
nsIContent* aContent,
PRInt32 aNameSpaceID,

Просмотреть файл

@ -735,7 +735,8 @@ public:
nsIAtom* aMedium);
NS_IMETHOD HasStateDependentStyle(StateRuleProcessorData* aData,
nsIAtom* aMedium);
nsIAtom* aMedium,
PRBool* aResult);
#ifdef DEBUG
virtual void SizeOf(nsISizeOfHandler *aSizeofHandler, PRUint32 &aSize);
@ -3456,9 +3457,14 @@ static PRBool IsSignificantChild(nsIContent* aChild, PRBool aAcceptNonWhitespace
}
// 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,
PRBool aTestState,
PRInt32 aStateMask, // states NOT to test
PRInt8 aNegationIndex)
{
@ -3587,24 +3593,28 @@ static PRBool SelectorMatches(RuleProcessorData &data,
if ((data.mIsHTMLContent) &&
(!IsEventSensitive(pseudoClass->mAtom, data.mContentTag, isSelectorGlobal))){
result = localFalse;
} else if (aTestState) {
} else {
if (nsCSSAtoms::activePseudo == pseudoClass->mAtom) {
result = PRBool(localTrue == (0 != (data.mEventState & NS_EVENT_STATE_ACTIVE)));
result = (aStateMask & NS_EVENT_STATE_ACTIVE) ||
(localTrue == (0 != (data.mEventState & NS_EVENT_STATE_ACTIVE)));
}
else if (nsCSSAtoms::focusPseudo == pseudoClass->mAtom) {
result = PRBool(localTrue == (0 != (data.mEventState & NS_EVENT_STATE_FOCUS)));
result = (aStateMask & NS_EVENT_STATE_FOCUS) ||
(localTrue == (0 != (data.mEventState & NS_EVENT_STATE_FOCUS)));
}
else if (nsCSSAtoms::hoverPseudo == pseudoClass->mAtom) {
result = PRBool(localTrue == (0 != (data.mEventState & NS_EVENT_STATE_HOVER)));
result = (aStateMask & NS_EVENT_STATE_HOVER) ||
(localTrue == (0 != (data.mEventState & NS_EVENT_STATE_HOVER)));
}
else if (nsCSSAtoms::dragOverPseudo == pseudoClass->mAtom) {
result = PRBool(localTrue == (0 != (data.mEventState & NS_EVENT_STATE_DRAGOVER)));
result = (aStateMask & NS_EVENT_STATE_DRAGOVER) ||
(localTrue == (0 != (data.mEventState & NS_EVENT_STATE_DRAGOVER)));
}
}
}
else if (IsLinkPseudo(pseudoClass->mAtom)) {
if (data.mIsHTMLLink || data.mIsSimpleXLink) {
if (result && aTestState) {
if (result) {
if (nsCSSAtoms::anyLinkPseudo == pseudoClass->mAtom) {
result = localTrue;
}
@ -3625,7 +3635,7 @@ static PRBool SelectorMatches(RuleProcessorData &data,
// <option>
// <input type=checkbox>
// <input type=radio>
if (aTestState)
if (!(aStateMask & NS_EVENT_STATE_CHECKED))
result = data.mIsChecked ? localTrue : localFalse;
}
else {
@ -3778,7 +3788,8 @@ static PRBool SelectorMatches(RuleProcessorData &data,
// apply SelectorMatches to the negated selectors in the chain
if (result && (nsnull != aSelector->mNegations)) {
result = SelectorMatches(data, aSelector->mNegations, aTestState, aNegationIndex+1);
result = SelectorMatches(data, aSelector->mNegations, aStateMask,
aNegationIndex+1);
}
return result;
}
@ -3853,7 +3864,7 @@ static PRBool SelectorMatchesTree(RuleProcessorData &data,
NS_ASSERTION(!content, "content must be null");
break;
}
if (SelectorMatches(*newdata, selector, PR_TRUE, 0)) {
if (SelectorMatches(*newdata, selector, 0, 0)) {
// to avoid greedy matching, we need to recurse if this is a
// descendant combinator and the next combinator is not
if ((NS_IS_GREEDY_OPERATOR(selector->mOperator)) &&
@ -3897,7 +3908,7 @@ static void ContentEnumFunc(nsICSSStyleRule* aRule, void* aData)
ElementRuleProcessorData* data = (ElementRuleProcessorData*)aData;
nsCSSSelector* selector = aRule->FirstSelector();
if (SelectorMatches(*data, selector, PR_TRUE, 0)) {
if (SelectorMatches(*data, selector, 0, 0)) {
selector = selector->mNext;
if (SelectorMatchesTree(*data, selector)) {
// for performance, require that every implementation of
@ -3976,7 +3987,7 @@ static void PseudoEnumFunc(nsICSSStyleRule* aRule, void* aData)
if (PRUnichar('+') == selector->mOperator) {
return; // not valid here, can't match
}
if (SelectorMatches(*data, selector, PR_TRUE, 0)) {
if (SelectorMatches(*data, selector, 0, 0)) {
selector = selector->mNext;
}
else {
@ -4049,7 +4060,7 @@ PRBool PR_CALLBACK StateEnumFunc(void* aSelector, void* aData)
StateRuleProcessorData* data = (StateRuleProcessorData*)aData;
nsCSSSelector* selector = (nsCSSSelector*)aSelector;
if (SelectorMatches(*data, selector, PR_FALSE, 0)) {
if (SelectorMatches(*data, selector, data->mStateMask, 0)) {
selector = selector->mNext;
if (SelectorMatchesTree(*data, selector)) {
return PR_FALSE;
@ -4060,21 +4071,19 @@ PRBool PR_CALLBACK StateEnumFunc(void* aSelector, void* aData)
NS_IMETHODIMP
CSSRuleProcessor::HasStateDependentStyle(StateRuleProcessorData* aData,
nsIAtom* aMedium)
nsIAtom* aMedium,
PRBool* aResult)
{
NS_PRECONDITION(aData->mContent->IsContentOfType(nsIContent::eELEMENT),
"content must be element");
PRBool isStateful = PR_FALSE;
RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext, aMedium);
if (cascade) {
// look up content in state rule list
isStateful = ! cascade->mStateSelectors.EnumerateForwards(StateEnumFunc, aData); // if stopped, have state
}
// Look up content in state rule list. If enumeration stopped, have state.
*aResult = cascade &&
!cascade->mStateSelectors.EnumerateForwards(StateEnumFunc, aData);
return ((isStateful) ? NS_OK : NS_COMFALSE);
return NS_OK;
}

Просмотреть файл

@ -251,7 +251,8 @@ public:
nsIAtom* aMedium);
NS_IMETHOD HasStateDependentStyle(StateRuleProcessorData* aData,
nsIAtom* aMedium);
nsIAtom* aMedium,
PRBool* aResult);
// XXX style rule enumerations
@ -422,9 +423,11 @@ HTMLCSSStyleSheetImpl::Init(nsIURI* aURL, nsIDocument* aDocument)
// Test if style is dependent on content state
NS_IMETHODIMP
HTMLCSSStyleSheetImpl::HasStateDependentStyle(StateRuleProcessorData* aData,
nsIAtom* aMedium)
nsIAtom* aMedium,
PRBool* aResult)
{
return NS_COMFALSE;
*aResult = PR_FALSE;
return NS_OK;
}

Просмотреть файл

@ -840,7 +840,8 @@ public:
nsIAtom* aMedium);
NS_IMETHOD HasStateDependentStyle(StateRuleProcessorData* aData,
nsIAtom* aMedium);
nsIAtom* aMedium,
PRBool* aResult);
// nsIHTMLStyleSheet api
NS_IMETHOD Init(nsIURI* aURL, nsIDocument* aDocument);
@ -1149,26 +1150,21 @@ HTMLStyleSheetImpl::RulesMatching(ElementRuleProcessorData* aData,
// Test if style is dependent on content state
NS_IMETHODIMP
HTMLStyleSheetImpl::HasStateDependentStyle(StateRuleProcessorData* aData,
nsIAtom* aMedium)
nsIAtom* aMedium,
PRBool* aResult)
{
nsresult result = NS_COMFALSE;
*aResult = mActiveRule &&
(aData->mStateMask & NS_EVENT_STATE_ACTIVE) &&
aData->mStyledContent &&
aData->mIsHTMLContent &&
aData->mContentTag == nsHTMLAtoms::a &&
aData->mStyledContent->HasAttr(kNameSpaceID_None,
nsHTMLAtoms::href);
if ((mActiveRule || mLinkRule || mVisitedRule) &&
aData->mStyledContent &&
aData->mIsHTMLContent &&
aData->mContentTag == nsHTMLAtoms::a) {
PRBool hasHrefAttr =
aData->mStyledContent->HasAttr(kNameSpaceID_None,
nsHTMLAtoms::href);
if (hasHrefAttr)
result = NS_OK; // yes, style will depend on link state
}
return result;
return NS_OK;
}
NS_IMETHODIMP
HTMLStyleSheetImpl::RulesMatching(PseudoRuleProcessorData* aData,
nsIAtom* aMedium)

Просмотреть файл

@ -305,7 +305,7 @@ public:
NS_IMETHOD ContentStatesChanged(nsIDocument* aDocument,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass) { return NS_OK; }
PRInt32 aStateMask) { return NS_OK; }
NS_IMETHOD AttributeChanged(nsIDocument* aDocument,
nsIContent* aContent,
PRInt32 aNameSpaceID,

Просмотреть файл

@ -1926,11 +1926,11 @@ nsXULDocument::ContentChanged(nsIContent* aContent,
NS_IMETHODIMP
nsXULDocument::ContentStatesChanged(nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass)
PRInt32 aStateMask)
{
for (PRInt32 i = mObservers.Count() - 1; i >= 0; --i) {
nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i];
observer->ContentStatesChanged(this, aContent1, aContent2, aChangedPseudoClass);
observer->ContentStatesChanged(this, aContent1, aContent2, aStateMask);
}
return NS_OK;
}

Просмотреть файл

@ -280,7 +280,7 @@ public:
NS_IMETHOD ContentStatesChanged(nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass);
PRInt32 aStateMask);
NS_IMETHOD AttributeChanged(nsIContent* aChild,
PRInt32 aNameSpaceID,

Просмотреть файл

@ -338,7 +338,7 @@ NS_IMETHODIMP
nsXULTemplateBuilder::ContentStatesChanged(nsIDocument* aDocument,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass)
PRInt32 aStateMask)
{
return NS_OK;
}

Просмотреть файл

@ -116,7 +116,7 @@ public:
NS_IMETHOD ContentStatesChanged(nsIDocument* aDocument,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass);
PRInt32 aStateMask);
NS_IMETHOD AttributeChanged(nsIDocument *aDocument,
nsIContent* aContent,

Просмотреть файл

@ -92,7 +92,7 @@ public:
NS_IMETHOD ContentStatesChanged(nsIDocument* aDocument,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass) { return NS_OK; }
PRInt32 aStateMask) { return NS_OK; }
NS_IMETHOD BeginUpdate(nsIDocument *aDocument) { return NS_OK; }
NS_IMETHOD EndUpdate(nsIDocument *aDocument) { return NS_OK; }
NS_IMETHOD BeginLoad(nsIDocument *aDocument) { return NS_OK; }

Просмотреть файл

@ -253,7 +253,7 @@ NS_IMETHODIMP
nsXPathResult::ContentStatesChanged(nsIDocument* aDocument,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass)
PRInt32 aStateMask)
{
return NS_OK;
}

Просмотреть файл

@ -93,7 +93,7 @@ public:
NS_IMETHOD ContentStatesChanged(nsIDocument* aDocument,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass);
PRInt32 aStateMask);
NS_IMETHOD AttributeChanged(nsIDocument* aDocument,
nsIContent* aContent,
PRInt32 aNameSpaceID,

Просмотреть файл

@ -10037,7 +10037,7 @@ NS_IMETHODIMP
nsCSSFrameConstructor::ContentStatesChanged(nsIPresContext* aPresContext,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass)
PRInt32 aStateMask)
{
nsresult result = NS_OK;
@ -10063,9 +10063,14 @@ nsCSSFrameConstructor::ContentStatesChanged(nsIPresContext* aPresContext,
app1 = disp->mAppearance;
}
if (!app1 && (NS_OK != styleSet->HasStateDependentStyle(aPresContext, aContent1))) {
primaryFrame1 = nsnull;
aContent1 = nsnull;
if (!app1) {
PRBool depends = PR_FALSE;
styleSet->HasStateDependentStyle(aPresContext, aContent1,
aStateMask, &depends);
if (!depends) {
primaryFrame1 = nsnull;
aContent1 = nsnull;
}
}
if (aContent2 == aContent1)
@ -10078,9 +10083,14 @@ nsCSSFrameConstructor::ContentStatesChanged(nsIPresContext* aPresContext,
app2 = disp2->mAppearance;
}
if (!app2 && (NS_OK != styleSet->HasStateDependentStyle(aPresContext, aContent2))) {
primaryFrame2 = nsnull;
aContent2 = nsnull;
if (!app2) {
PRBool depends = PR_FALSE;
styleSet->HasStateDependentStyle(aPresContext, aContent2,
aStateMask, &depends);
if (!depends) {
primaryFrame2 = nsnull;
aContent2 = nsnull;
}
}
}

Просмотреть файл

@ -123,7 +123,7 @@ public:
NS_IMETHOD ContentStatesChanged(nsIPresContext* aPresContext,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass);
PRInt32 aStateMask);
NS_IMETHOD AttributeChanged(nsIPresContext* aPresContext,
nsIContent* aContent,

Просмотреть файл

@ -1029,7 +1029,7 @@ public:
NS_IMETHOD ContentStatesChanged(nsIDocument* aDocument,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass);
PRInt32 aStateMask);
NS_IMETHOD AttributeChanged(nsIDocument *aDocument,
nsIContent* aContent,
PRInt32 aNameSpaceID,
@ -5111,11 +5111,11 @@ NS_IMETHODIMP
PresShell::ContentStatesChanged(nsIDocument* aDocument,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass)
PRInt32 aStateMask)
{
WillCauseReflow();
nsresult rv = mStyleSet->ContentStatesChanged(mPresContext, aContent1, aContent2,
aChangedPseudoClass);
nsresult rv = mStyleSet->ContentStatesChanged(mPresContext, aContent1,
aContent2, aStateMask);
VERIFY_STYLE_TREE;
DidCauseReflow();

Просмотреть файл

@ -203,7 +203,7 @@ public:
NS_IMETHOD ContentStatesChanged(nsIPresContext* aPresContext,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass) = 0;
PRInt32 aStateMask) = 0;
/**
* Notification that an attribute was changed for a content node

Просмотреть файл

@ -195,7 +195,9 @@ public:
// Test if style is dependent on content state
NS_IMETHOD HasStateDependentStyle(nsIPresContext* aPresContext,
nsIContent* aContent) = 0;
nsIContent* aContent,
PRInt32 aStateMask,
PRBool* aResult) = 0;
// Create frames for the root content element and its child content
NS_IMETHOD ConstructRootFrame(nsIPresContext* aPresContext,
@ -231,7 +233,7 @@ public:
NS_IMETHOD ContentStatesChanged(nsIPresContext* aPresContext,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass) = 0;
PRInt32 aStateMask) = 0;
NS_IMETHOD AttributeChanged(nsIPresContext* aPresContext,
nsIContent* aChild,
PRInt32 aNameSpaceID,

Просмотреть файл

@ -105,7 +105,7 @@ public:
NS_IMETHOD ContentStatesChanged(nsIDocument* aDocument,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass) { return NS_OK; }
PRInt32 aStateMask) { return NS_OK; }
NS_IMETHOD AttributeChanged(nsIDocument *aDocument,
nsIContent* aContent,
PRInt32 aNameSpaceID,

Просмотреть файл

@ -1117,7 +1117,7 @@ NS_IMETHODIMP
nsImageMap::ContentStatesChanged(nsIDocument* aDocument,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass)
PRInt32 aStateMask)
{
return NS_OK;
}

Просмотреть файл

@ -109,7 +109,7 @@ public:
NS_IMETHOD ContentStatesChanged(nsIDocument* aDocument,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass);
PRInt32 aStateMask);
NS_IMETHOD AttributeChanged(nsIDocument *aDocument,
nsIContent* aContent,
PRInt32 aNameSpaceID,

Просмотреть файл

@ -105,7 +105,7 @@ public:
NS_IMETHOD ContentStatesChanged(nsIDocument* aDocument,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass) { return NS_OK; }
PRInt32 aStateMask) { return NS_OK; }
NS_IMETHOD AttributeChanged(nsIDocument *aDocument,
nsIContent* aContent,
PRInt32 aNameSpaceID,

Просмотреть файл

@ -1117,7 +1117,7 @@ NS_IMETHODIMP
nsImageMap::ContentStatesChanged(nsIDocument* aDocument,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass)
PRInt32 aStateMask)
{
return NS_OK;
}

Просмотреть файл

@ -109,7 +109,7 @@ public:
NS_IMETHOD ContentStatesChanged(nsIDocument* aDocument,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass);
PRInt32 aStateMask);
NS_IMETHOD AttributeChanged(nsIDocument *aDocument,
nsIContent* aContent,
PRInt32 aNameSpaceID,

Просмотреть файл

@ -1029,7 +1029,7 @@ public:
NS_IMETHOD ContentStatesChanged(nsIDocument* aDocument,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass);
PRInt32 aStateMask);
NS_IMETHOD AttributeChanged(nsIDocument *aDocument,
nsIContent* aContent,
PRInt32 aNameSpaceID,
@ -5111,11 +5111,11 @@ NS_IMETHODIMP
PresShell::ContentStatesChanged(nsIDocument* aDocument,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass)
PRInt32 aStateMask)
{
WillCauseReflow();
nsresult rv = mStyleSet->ContentStatesChanged(mPresContext, aContent1, aContent2,
aChangedPseudoClass);
nsresult rv = mStyleSet->ContentStatesChanged(mPresContext, aContent1,
aContent2, aStateMask);
VERIFY_STYLE_TREE;
DidCauseReflow();

Просмотреть файл

@ -10037,7 +10037,7 @@ NS_IMETHODIMP
nsCSSFrameConstructor::ContentStatesChanged(nsIPresContext* aPresContext,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass)
PRInt32 aStateMask)
{
nsresult result = NS_OK;
@ -10063,9 +10063,14 @@ nsCSSFrameConstructor::ContentStatesChanged(nsIPresContext* aPresContext,
app1 = disp->mAppearance;
}
if (!app1 && (NS_OK != styleSet->HasStateDependentStyle(aPresContext, aContent1))) {
primaryFrame1 = nsnull;
aContent1 = nsnull;
if (!app1) {
PRBool depends = PR_FALSE;
styleSet->HasStateDependentStyle(aPresContext, aContent1,
aStateMask, &depends);
if (!depends) {
primaryFrame1 = nsnull;
aContent1 = nsnull;
}
}
if (aContent2 == aContent1)
@ -10078,9 +10083,14 @@ nsCSSFrameConstructor::ContentStatesChanged(nsIPresContext* aPresContext,
app2 = disp2->mAppearance;
}
if (!app2 && (NS_OK != styleSet->HasStateDependentStyle(aPresContext, aContent2))) {
primaryFrame2 = nsnull;
aContent2 = nsnull;
if (!app2) {
PRBool depends = PR_FALSE;
styleSet->HasStateDependentStyle(aPresContext, aContent2,
aStateMask, &depends);
if (!depends) {
primaryFrame2 = nsnull;
aContent2 = nsnull;
}
}
}

Просмотреть файл

@ -123,7 +123,7 @@ public:
NS_IMETHOD ContentStatesChanged(nsIPresContext* aPresContext,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass);
PRInt32 aStateMask);
NS_IMETHOD AttributeChanged(nsIPresContext* aPresContext,
nsIContent* aContent,

Просмотреть файл

@ -735,7 +735,8 @@ public:
nsIAtom* aMedium);
NS_IMETHOD HasStateDependentStyle(StateRuleProcessorData* aData,
nsIAtom* aMedium);
nsIAtom* aMedium,
PRBool* aResult);
#ifdef DEBUG
virtual void SizeOf(nsISizeOfHandler *aSizeofHandler, PRUint32 &aSize);
@ -3456,9 +3457,14 @@ static PRBool IsSignificantChild(nsIContent* aChild, PRBool aAcceptNonWhitespace
}
// 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,
PRBool aTestState,
PRInt32 aStateMask, // states NOT to test
PRInt8 aNegationIndex)
{
@ -3587,24 +3593,28 @@ static PRBool SelectorMatches(RuleProcessorData &data,
if ((data.mIsHTMLContent) &&
(!IsEventSensitive(pseudoClass->mAtom, data.mContentTag, isSelectorGlobal))){
result = localFalse;
} else if (aTestState) {
} else {
if (nsCSSAtoms::activePseudo == pseudoClass->mAtom) {
result = PRBool(localTrue == (0 != (data.mEventState & NS_EVENT_STATE_ACTIVE)));
result = (aStateMask & NS_EVENT_STATE_ACTIVE) ||
(localTrue == (0 != (data.mEventState & NS_EVENT_STATE_ACTIVE)));
}
else if (nsCSSAtoms::focusPseudo == pseudoClass->mAtom) {
result = PRBool(localTrue == (0 != (data.mEventState & NS_EVENT_STATE_FOCUS)));
result = (aStateMask & NS_EVENT_STATE_FOCUS) ||
(localTrue == (0 != (data.mEventState & NS_EVENT_STATE_FOCUS)));
}
else if (nsCSSAtoms::hoverPseudo == pseudoClass->mAtom) {
result = PRBool(localTrue == (0 != (data.mEventState & NS_EVENT_STATE_HOVER)));
result = (aStateMask & NS_EVENT_STATE_HOVER) ||
(localTrue == (0 != (data.mEventState & NS_EVENT_STATE_HOVER)));
}
else if (nsCSSAtoms::dragOverPseudo == pseudoClass->mAtom) {
result = PRBool(localTrue == (0 != (data.mEventState & NS_EVENT_STATE_DRAGOVER)));
result = (aStateMask & NS_EVENT_STATE_DRAGOVER) ||
(localTrue == (0 != (data.mEventState & NS_EVENT_STATE_DRAGOVER)));
}
}
}
else if (IsLinkPseudo(pseudoClass->mAtom)) {
if (data.mIsHTMLLink || data.mIsSimpleXLink) {
if (result && aTestState) {
if (result) {
if (nsCSSAtoms::anyLinkPseudo == pseudoClass->mAtom) {
result = localTrue;
}
@ -3625,7 +3635,7 @@ static PRBool SelectorMatches(RuleProcessorData &data,
// <option>
// <input type=checkbox>
// <input type=radio>
if (aTestState)
if (!(aStateMask & NS_EVENT_STATE_CHECKED))
result = data.mIsChecked ? localTrue : localFalse;
}
else {
@ -3778,7 +3788,8 @@ static PRBool SelectorMatches(RuleProcessorData &data,
// apply SelectorMatches to the negated selectors in the chain
if (result && (nsnull != aSelector->mNegations)) {
result = SelectorMatches(data, aSelector->mNegations, aTestState, aNegationIndex+1);
result = SelectorMatches(data, aSelector->mNegations, aStateMask,
aNegationIndex+1);
}
return result;
}
@ -3853,7 +3864,7 @@ static PRBool SelectorMatchesTree(RuleProcessorData &data,
NS_ASSERTION(!content, "content must be null");
break;
}
if (SelectorMatches(*newdata, selector, PR_TRUE, 0)) {
if (SelectorMatches(*newdata, selector, 0, 0)) {
// to avoid greedy matching, we need to recurse if this is a
// descendant combinator and the next combinator is not
if ((NS_IS_GREEDY_OPERATOR(selector->mOperator)) &&
@ -3897,7 +3908,7 @@ static void ContentEnumFunc(nsICSSStyleRule* aRule, void* aData)
ElementRuleProcessorData* data = (ElementRuleProcessorData*)aData;
nsCSSSelector* selector = aRule->FirstSelector();
if (SelectorMatches(*data, selector, PR_TRUE, 0)) {
if (SelectorMatches(*data, selector, 0, 0)) {
selector = selector->mNext;
if (SelectorMatchesTree(*data, selector)) {
// for performance, require that every implementation of
@ -3976,7 +3987,7 @@ static void PseudoEnumFunc(nsICSSStyleRule* aRule, void* aData)
if (PRUnichar('+') == selector->mOperator) {
return; // not valid here, can't match
}
if (SelectorMatches(*data, selector, PR_TRUE, 0)) {
if (SelectorMatches(*data, selector, 0, 0)) {
selector = selector->mNext;
}
else {
@ -4049,7 +4060,7 @@ PRBool PR_CALLBACK StateEnumFunc(void* aSelector, void* aData)
StateRuleProcessorData* data = (StateRuleProcessorData*)aData;
nsCSSSelector* selector = (nsCSSSelector*)aSelector;
if (SelectorMatches(*data, selector, PR_FALSE, 0)) {
if (SelectorMatches(*data, selector, data->mStateMask, 0)) {
selector = selector->mNext;
if (SelectorMatchesTree(*data, selector)) {
return PR_FALSE;
@ -4060,21 +4071,19 @@ PRBool PR_CALLBACK StateEnumFunc(void* aSelector, void* aData)
NS_IMETHODIMP
CSSRuleProcessor::HasStateDependentStyle(StateRuleProcessorData* aData,
nsIAtom* aMedium)
nsIAtom* aMedium,
PRBool* aResult)
{
NS_PRECONDITION(aData->mContent->IsContentOfType(nsIContent::eELEMENT),
"content must be element");
PRBool isStateful = PR_FALSE;
RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext, aMedium);
if (cascade) {
// look up content in state rule list
isStateful = ! cascade->mStateSelectors.EnumerateForwards(StateEnumFunc, aData); // if stopped, have state
}
// Look up content in state rule list. If enumeration stopped, have state.
*aResult = cascade &&
!cascade->mStateSelectors.EnumerateForwards(StateEnumFunc, aData);
return ((isStateful) ? NS_OK : NS_COMFALSE);
return NS_OK;
}

Просмотреть файл

@ -251,7 +251,8 @@ public:
nsIAtom* aMedium);
NS_IMETHOD HasStateDependentStyle(StateRuleProcessorData* aData,
nsIAtom* aMedium);
nsIAtom* aMedium,
PRBool* aResult);
// XXX style rule enumerations
@ -422,9 +423,11 @@ HTMLCSSStyleSheetImpl::Init(nsIURI* aURL, nsIDocument* aDocument)
// Test if style is dependent on content state
NS_IMETHODIMP
HTMLCSSStyleSheetImpl::HasStateDependentStyle(StateRuleProcessorData* aData,
nsIAtom* aMedium)
nsIAtom* aMedium,
PRBool* aResult)
{
return NS_COMFALSE;
*aResult = PR_FALSE;
return NS_OK;
}

Просмотреть файл

@ -840,7 +840,8 @@ public:
nsIAtom* aMedium);
NS_IMETHOD HasStateDependentStyle(StateRuleProcessorData* aData,
nsIAtom* aMedium);
nsIAtom* aMedium,
PRBool* aResult);
// nsIHTMLStyleSheet api
NS_IMETHOD Init(nsIURI* aURL, nsIDocument* aDocument);
@ -1149,26 +1150,21 @@ HTMLStyleSheetImpl::RulesMatching(ElementRuleProcessorData* aData,
// Test if style is dependent on content state
NS_IMETHODIMP
HTMLStyleSheetImpl::HasStateDependentStyle(StateRuleProcessorData* aData,
nsIAtom* aMedium)
nsIAtom* aMedium,
PRBool* aResult)
{
nsresult result = NS_COMFALSE;
*aResult = mActiveRule &&
(aData->mStateMask & NS_EVENT_STATE_ACTIVE) &&
aData->mStyledContent &&
aData->mIsHTMLContent &&
aData->mContentTag == nsHTMLAtoms::a &&
aData->mStyledContent->HasAttr(kNameSpaceID_None,
nsHTMLAtoms::href);
if ((mActiveRule || mLinkRule || mVisitedRule) &&
aData->mStyledContent &&
aData->mIsHTMLContent &&
aData->mContentTag == nsHTMLAtoms::a) {
PRBool hasHrefAttr =
aData->mStyledContent->HasAttr(kNameSpaceID_None,
nsHTMLAtoms::href);
if (hasHrefAttr)
result = NS_OK; // yes, style will depend on link state
}
return result;
return NS_OK;
}
NS_IMETHODIMP
HTMLStyleSheetImpl::RulesMatching(PseudoRuleProcessorData* aData,
nsIAtom* aMedium)

Просмотреть файл

@ -131,11 +131,15 @@ struct PseudoRuleProcessorData : public RuleProcessorData {
struct StateRuleProcessorData : public RuleProcessorData {
StateRuleProcessorData(nsIPresContext* aPresContext,
nsIContent* aContent)
: RuleProcessorData(aPresContext, aContent, nsnull)
nsIContent* aContent,
PRInt32 aStateMask)
: RuleProcessorData(aPresContext, aContent, nsnull),
mStateMask(aStateMask)
{
NS_PRECONDITION(aContent, "null pointer");
}
const PRInt32 mStateMask; // |HasStateDependentStyle| for which state(s)?
// Constants defined in nsIEventStateManager.h .
};
@ -162,8 +166,9 @@ public:
nsIAtom* aMedium) = 0;
// Test if style is dependent on content state
NS_IMETHOD HasStateDependentStyle(StateRuleProcessorData* aData,
nsIAtom* aMedium) = 0;
NS_IMETHOD HasStateDependentStyle(StateRuleProcessorData* aData,
nsIAtom* aMedium,
PRBool* aResult) = 0;
#ifdef DEBUG
virtual void SizeOf(nsISizeOfHandler *aSizeofHandler, PRUint32 &aSize) = 0;

Просмотреть файл

@ -205,8 +205,10 @@ public:
nsIStyleContext* aNewParentContext,
nsIStyleContext** aNewStyleContext);
NS_IMETHOD HasStateDependentStyle(nsIPresContext* aPresContext,
nsIContent* aContent);
NS_IMETHOD HasStateDependentStyle(nsIPresContext* aPresContext,
nsIContent* aContent,
PRInt32 aStateMask,
PRBool* aResult);
NS_IMETHOD ConstructRootFrame(nsIPresContext* aPresContext,
nsIContent* aContent,
@ -235,7 +237,7 @@ public:
NS_IMETHOD ContentStatesChanged(nsIPresContext* aPresContext,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass);
PRInt32 aStateMask);
NS_IMETHOD AttributeChanged(nsIPresContext* aPresContext,
nsIContent* aChild,
PRInt32 aNameSpaceID,
@ -1432,8 +1434,9 @@ StyleSetImpl::ReParentStyleContext(nsIPresContext* aPresContext,
}
struct StatefulData : public StateRuleProcessorData {
StatefulData(nsIPresContext* aPresContext, nsIAtom* aMedium, nsIContent* aContent)
: StateRuleProcessorData(aPresContext, aContent),
StatefulData(nsIPresContext* aPresContext, nsIAtom* aMedium,
nsIContent* aContent, PRInt32 aStateMask)
: StateRuleProcessorData(aPresContext, aContent, aStateMask),
mMedium(aMedium),
mStateful(PR_FALSE)
{}
@ -1445,17 +1448,18 @@ static PRBool SheetHasStatefulStyle(nsISupports* aProcessor, void *aData)
{
nsIStyleRuleProcessor* processor = (nsIStyleRuleProcessor*)aProcessor;
StatefulData* data = (StatefulData*)aData;
if (NS_OK == processor->HasStateDependentStyle(data, data->mMedium)) {
data->mStateful = PR_TRUE;
processor->HasStateDependentStyle(data, data->mMedium, &data->mStateful);
if (data->mStateful)
return PR_FALSE; // stop iteration
}
return PR_TRUE; // continue
}
// Test if style is dependent on content state
NS_IMETHODIMP
StyleSetImpl::HasStateDependentStyle(nsIPresContext* aPresContext,
nsIContent* aContent)
nsIContent* aContent,
PRInt32 aStateMask,
PRBool* aResult)
{
GatherRuleProcessors();
@ -1466,12 +1470,15 @@ StyleSetImpl::HasStateDependentStyle(nsIPresContext* aPresContext,
mOverrideRuleProcessors)) {
nsIAtom* medium = nsnull;
aPresContext->GetMedium(&medium);
StatefulData data(aPresContext, medium, aContent);
StatefulData data(aPresContext, medium, aContent, aStateMask);
WalkRuleProcessors(SheetHasStatefulStyle, &data);
NS_IF_RELEASE(medium);
return ((data.mStateful) ? NS_OK : NS_COMFALSE);
*aResult = data.mStateful;
} else {
*aResult = PR_FALSE;
}
return NS_COMFALSE;
return NS_OK;
}
@ -1541,10 +1548,10 @@ NS_IMETHODIMP
StyleSetImpl::ContentStatesChanged(nsIPresContext* aPresContext,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass)
PRInt32 aStateMask)
{
return mFrameConstructor->ContentStatesChanged(aPresContext, aContent1, aContent2,
aChangedPseudoClass);
return mFrameConstructor->ContentStatesChanged(aPresContext, aContent1,
aContent2, aStateMask);
}

Просмотреть файл

@ -50,6 +50,7 @@
#include "nsChildIterator.h"
#include "nsIDOMHTMLOptionElement.h"
#include "nsIDOMClassInfo.h"
#include "nsIEventStateManager.h"
// A content model view implementation for the tree.
@ -730,10 +731,11 @@ NS_IMETHODIMP
nsTreeContentView::ContentStatesChanged(nsIDocument* aDocument,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass)
PRInt32 aStateMask)
{
if (!aContent1 || !mSelection || !aContent1->IsContentOfType(nsIContent::eHTML) ||
aChangedPseudoClass != nsCSSAtoms::checkedPseudo)
if (!aContent1 || !mSelection ||
!aContent1->IsContentOfType(nsIContent::eHTML) ||
!(aStateMask & NS_EVENT_STATE_CHECKED))
return NS_OK;
nsCOMPtr<nsIAtom> contentTag;

Просмотреть файл

@ -92,7 +92,7 @@ class nsTreeContentView : public nsITreeView,
NS_IMETHOD ContentStatesChanged(nsIDocument* aDocument,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudo);
PRInt32 aStateMask);
NS_IMETHOD AttributeChanged(nsIDocument *aDocument,
nsIContent* aContent,

Просмотреть файл

@ -771,7 +771,7 @@ nsMenuBarX::ContentChanged( nsIDocument * aDocument, nsIContent * aContent, nsIS
NS_IMETHODIMP
nsMenuBarX::ContentStatesChanged( nsIDocument * aDocument, nsIContent * aContent1,
nsIContent * aContent2, nsIAtom * aChangedPseudoClass)
nsIContent * aContent2, PRInt32 aStateMask)
{
return NS_OK;
}

Просмотреть файл

@ -113,7 +113,7 @@ public:
NS_IMETHOD ContentStatesChanged(nsIDocument *aDocument,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass);
PRInt32 aStateMask);
NS_IMETHOD AttributeChanged(nsIDocument *aDocument,
nsIContent* aContent,
PRInt32 aNameSpaceID,

Просмотреть файл

@ -665,7 +665,7 @@ nsMenuBar::ContentChanged( nsIDocument * aDocument, nsIContent * aContent, nsISu
NS_IMETHODIMP
nsMenuBar::ContentStatesChanged( nsIDocument * aDocument, nsIContent * aContent1,
nsIContent * aContent2, nsIAtom * aChangedPseudoClass)
nsIContent * aContent2, PRInt32 aStateMask)
{
return NS_OK;
}

Просмотреть файл

@ -116,7 +116,7 @@ public:
NS_IMETHOD ContentStatesChanged(nsIDocument *aDocument,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass);
PRInt32 aStateMask);
NS_IMETHOD AttributeChanged(nsIDocument *aDocument,
nsIContent* aContent,
PRInt32 aNameSpaceID,

Просмотреть файл

@ -761,7 +761,7 @@ nsMenuBarX::ContentChanged( nsIDocument * aDocument, nsIContent * aContent, nsIS
NS_IMETHODIMP
nsMenuBarX::ContentStatesChanged( nsIDocument * aDocument, nsIContent * aContent1,
nsIContent * aContent2, nsIAtom * aChangedPseudoClass)
nsIContent * aContent2, PRInt32 aStateMask)
{
return NS_OK;
}

Просмотреть файл

@ -115,7 +115,7 @@ public:
NS_IMETHOD ContentStatesChanged(nsIDocument *aDocument,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass);
PRInt32 aStateMask);
NS_IMETHOD AttributeChanged(nsIDocument *aDocument,
nsIContent* aContent,
PRInt32 aNameSpaceID,

Просмотреть файл

@ -1551,7 +1551,7 @@ NS_IMETHODIMP
nsWebShellWindow::ContentStatesChanged(nsIDocument *aDocument,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass)
PRInt32 aStateMask)
{
return NS_OK;
}

Просмотреть файл

@ -125,7 +125,7 @@ public:
NS_IMETHOD ContentStatesChanged(nsIDocument *aDocument,
nsIContent* aContent1,
nsIContent* aContent2,
nsIAtom* aChangedPseudoClass);
PRInt32 aStateMask);
NS_IMETHOD AttributeChanged(nsIDocument *aDocument,
nsIContent* aContent,
PRInt32 aNameSpaceID,