зеркало из https://github.com/mozilla/gecko-dev.git
Make :active hierarchical. b=65917 r+sr=bzbarsky
This commit is contained in:
Родитель
3e623876f0
Коммит
678827b364
|
@ -3842,8 +3842,14 @@ nsEventStateManager::GetContentState(nsIContent *aContent, PRInt32& aState)
|
||||||
{
|
{
|
||||||
aState = NS_EVENT_STATE_UNSPECIFIED;
|
aState = NS_EVENT_STATE_UNSPECIFIED;
|
||||||
|
|
||||||
if (aContent == mActiveContent) {
|
// Hierchical active: Check the ancestor chain of mActiveContent to see
|
||||||
aState |= NS_EVENT_STATE_ACTIVE;
|
// if we are on it.
|
||||||
|
for (nsIContent* activeContent = mActiveContent; activeContent;
|
||||||
|
activeContent = activeContent->GetParent()) {
|
||||||
|
if (aContent == activeContent) {
|
||||||
|
aState |= NS_EVENT_STATE_ACTIVE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Hierchical hover: Check the ancestor chain of mHoverContent to see
|
// Hierchical hover: Check the ancestor chain of mHoverContent to see
|
||||||
// if we are on it.
|
// if we are on it.
|
||||||
|
@ -3867,10 +3873,68 @@ nsEventStateManager::GetContentState(nsIContent *aContent, PRInt32& aState)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static nsIContent* FindCommonAncestor(nsIContent *aNode1, nsIContent *aNode2)
|
||||||
|
{
|
||||||
|
// Find closest common ancestor
|
||||||
|
if (aNode1 && aNode2) {
|
||||||
|
// Find the nearest common ancestor by counting the distance to the
|
||||||
|
// root and then walking up again, in pairs.
|
||||||
|
PRInt32 offset = 0;
|
||||||
|
nsIContent *anc1 = aNode1;
|
||||||
|
for (;;) {
|
||||||
|
++offset;
|
||||||
|
nsIContent* parent = anc1->GetParent();
|
||||||
|
if (!parent)
|
||||||
|
break;
|
||||||
|
anc1 = parent;
|
||||||
|
}
|
||||||
|
nsIContent *anc2 = aNode2;
|
||||||
|
for (;;) {
|
||||||
|
--offset;
|
||||||
|
nsIContent* parent = anc2->GetParent();
|
||||||
|
if (!parent)
|
||||||
|
break;
|
||||||
|
anc2 = parent;
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (anc1 != anc2) {
|
||||||
|
// This could be a performance problem.
|
||||||
|
|
||||||
|
// The |!anc1->GetDocument()| case (that aNode1 has been removed
|
||||||
|
// from the document) could be a slight performance problem. It's
|
||||||
|
// rare enough that it shouldn't be an issue, but common enough
|
||||||
|
// that we don't want to assert..
|
||||||
|
NS_ASSERTION(!anc1->GetDocument(),
|
||||||
|
"moved hover/active between nodes in different documents");
|
||||||
|
// XXX Why don't we ever hit this code because we're not using
|
||||||
|
// |GetBindingParent|?
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (anc1 == anc2) {
|
||||||
|
anc1 = aNode1;
|
||||||
|
anc2 = aNode2;
|
||||||
|
while (offset > 0) {
|
||||||
|
anc1 = anc1->GetParent();
|
||||||
|
--offset;
|
||||||
|
}
|
||||||
|
while (offset < 0) {
|
||||||
|
anc2 = anc2->GetParent();
|
||||||
|
++offset;
|
||||||
|
}
|
||||||
|
while (anc1 != anc2) {
|
||||||
|
anc1 = anc1->GetParent();
|
||||||
|
anc2 = anc2->GetParent();
|
||||||
|
}
|
||||||
|
return anc1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nsnull;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsEventStateManager::SetContentState(nsIContent *aContent, PRInt32 aState)
|
nsEventStateManager::SetContentState(nsIContent *aContent, PRInt32 aState)
|
||||||
{
|
{
|
||||||
const PRInt32 maxNotify = 6;
|
const PRInt32 maxNotify = 5;
|
||||||
// We must initialize this array with memset for the sake of the boneheaded
|
// We must initialize this array with memset for the sake of the boneheaded
|
||||||
// OS X compiler. See bug 134934.
|
// OS X compiler. See bug 134934.
|
||||||
nsIContent *notifyContent[maxNotify];
|
nsIContent *notifyContent[maxNotify];
|
||||||
|
@ -3878,6 +3942,7 @@ nsEventStateManager::SetContentState(nsIContent *aContent, PRInt32 aState)
|
||||||
|
|
||||||
// check to see that this state is allowed by style. Check dragover too?
|
// check to see that this state is allowed by style. Check dragover too?
|
||||||
// XXX This doesn't consider that |aState| is a bitfield.
|
// XXX This doesn't consider that |aState| is a bitfield.
|
||||||
|
// XXX Is this even what we want?
|
||||||
if (mCurrentTarget && (aState == NS_EVENT_STATE_ACTIVE || aState == NS_EVENT_STATE_HOVER))
|
if (mCurrentTarget && (aState == NS_EVENT_STATE_ACTIVE || aState == NS_EVENT_STATE_HOVER))
|
||||||
{
|
{
|
||||||
const nsStyleUserInterface* ui = mCurrentTarget->GetStyleUserInterface();
|
const nsStyleUserInterface* ui = mCurrentTarget->GetStyleUserInterface();
|
||||||
|
@ -3886,21 +3951,22 @@ nsEventStateManager::SetContentState(nsIContent *aContent, PRInt32 aState)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((aState & NS_EVENT_STATE_DRAGOVER) && (aContent != mDragOverContent)) {
|
if ((aState & NS_EVENT_STATE_DRAGOVER) && (aContent != mDragOverContent)) {
|
||||||
notifyContent[4] = mDragOverContent; // notify dragover first, since more common case
|
notifyContent[3] = mDragOverContent; // notify dragover first, since more common case
|
||||||
NS_IF_ADDREF(notifyContent[4]);
|
NS_IF_ADDREF(notifyContent[3]);
|
||||||
mDragOverContent = aContent;
|
mDragOverContent = aContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((aState & NS_EVENT_STATE_URLTARGET) && (aContent != mURLTargetContent)) {
|
if ((aState & NS_EVENT_STATE_URLTARGET) && (aContent != mURLTargetContent)) {
|
||||||
notifyContent[5] = mURLTargetContent;
|
notifyContent[4] = mURLTargetContent;
|
||||||
NS_IF_ADDREF(notifyContent[5]);
|
NS_IF_ADDREF(notifyContent[4]);
|
||||||
mURLTargetContent = aContent;
|
mURLTargetContent = aContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIContent> commonActiveAncestor, oldActive, newActive;
|
||||||
if ((aState & NS_EVENT_STATE_ACTIVE) && (aContent != mActiveContent)) {
|
if ((aState & NS_EVENT_STATE_ACTIVE) && (aContent != mActiveContent)) {
|
||||||
//transferring ref to notifyContent from mActiveContent
|
oldActive = mActiveContent;
|
||||||
notifyContent[2] = mActiveContent;
|
newActive = aContent;
|
||||||
NS_IF_ADDREF(notifyContent[2]);
|
commonActiveAncestor = FindCommonAncestor(mActiveContent, aContent);
|
||||||
mActiveContent = aContent;
|
mActiveContent = aContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3908,60 +3974,7 @@ nsEventStateManager::SetContentState(nsIContent *aContent, PRInt32 aState)
|
||||||
if ((aState & NS_EVENT_STATE_HOVER) && (aContent != mHoverContent)) {
|
if ((aState & NS_EVENT_STATE_HOVER) && (aContent != mHoverContent)) {
|
||||||
oldHover = mHoverContent;
|
oldHover = mHoverContent;
|
||||||
newHover = aContent;
|
newHover = aContent;
|
||||||
// Find closest common ancestor (commonHoverAncestor)
|
commonHoverAncestor = FindCommonAncestor(mHoverContent, aContent);
|
||||||
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();
|
|
||||||
if (!parent)
|
|
||||||
break;
|
|
||||||
oldAncestor = parent;
|
|
||||||
}
|
|
||||||
nsCOMPtr<nsIContent> newAncestor = aContent;
|
|
||||||
for (;;) {
|
|
||||||
--offset;
|
|
||||||
nsIContent* parent = newAncestor->GetParent();
|
|
||||||
if (!parent)
|
|
||||||
break;
|
|
||||||
newAncestor = parent;
|
|
||||||
}
|
|
||||||
#ifdef DEBUG
|
|
||||||
if (oldAncestor != newAncestor) {
|
|
||||||
// This could be a performance problem.
|
|
||||||
|
|
||||||
// The |!oldAncestor->GetDocument()| case (that the old hover node has
|
|
||||||
// been removed from the document) could be a slight performance
|
|
||||||
// problem. It's rare enough that it shouldn't be an issue, but common
|
|
||||||
// enough that we don't want to assert..
|
|
||||||
NS_ASSERTION(!oldAncestor->GetDocument(),
|
|
||||||
"moved hover between nodes in different documents");
|
|
||||||
// XXX Why don't we ever hit this code because we're not using
|
|
||||||
// |GetBindingParent|?
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (oldAncestor == newAncestor) {
|
|
||||||
oldAncestor = mHoverContent;
|
|
||||||
newAncestor = aContent;
|
|
||||||
while (offset > 0) {
|
|
||||||
oldAncestor = oldAncestor->GetParent();
|
|
||||||
--offset;
|
|
||||||
}
|
|
||||||
while (offset < 0) {
|
|
||||||
newAncestor = newAncestor->GetParent();
|
|
||||||
++offset;
|
|
||||||
}
|
|
||||||
while (oldAncestor != newAncestor) {
|
|
||||||
oldAncestor = oldAncestor->GetParent();
|
|
||||||
newAncestor = newAncestor->GetParent();
|
|
||||||
}
|
|
||||||
commonHoverAncestor = oldAncestor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mHoverContent = aContent;
|
mHoverContent = aContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3986,7 +3999,7 @@ nsEventStateManager::SetContentState(nsIContent *aContent, PRInt32 aState)
|
||||||
if (fc)
|
if (fc)
|
||||||
fc->GetActive(&fcActive);
|
fc->GetActive(&fcActive);
|
||||||
}
|
}
|
||||||
notifyContent[3] = gLastFocusedContent;
|
notifyContent[2] = gLastFocusedContent;
|
||||||
NS_IF_ADDREF(gLastFocusedContent);
|
NS_IF_ADDREF(gLastFocusedContent);
|
||||||
// only raise window if the the focus controller is active
|
// only raise window if the the focus controller is active
|
||||||
SendFocusBlur(mPresContext, aContent, fcActive);
|
SendFocusBlur(mPresContext, aContent, fcActive);
|
||||||
|
@ -4003,7 +4016,10 @@ nsEventStateManager::SetContentState(nsIContent *aContent, PRInt32 aState)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aContent && aContent != newHover) { // notify about new content too
|
PRInt32 simpleStates = aState & ~(NS_EVENT_STATE_ACTIVE|NS_EVENT_STATE_HOVER);
|
||||||
|
|
||||||
|
if (aContent && simpleStates != 0) {
|
||||||
|
// notify about new content too
|
||||||
notifyContent[0] = aContent;
|
notifyContent[0] = aContent;
|
||||||
NS_ADDREF(aContent); // everything in notify array has a ref
|
NS_ADDREF(aContent); // everything in notify array has a ref
|
||||||
}
|
}
|
||||||
|
@ -4056,7 +4072,8 @@ nsEventStateManager::SetContentState(nsIContent *aContent, PRInt32 aState)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (notifyContent[0] || newHover || oldHover) { // have at least one to notify about
|
if (notifyContent[0] || newHover || oldHover || newActive || oldActive) {
|
||||||
|
// have at least one to notify about
|
||||||
nsCOMPtr<nsIDocument> doc1, doc2; // this presumes content can't get/lose state if not connected to doc
|
nsCOMPtr<nsIDocument> doc1, doc2; // this presumes content can't get/lose state if not connected to doc
|
||||||
if (notifyContent[0]) {
|
if (notifyContent[0]) {
|
||||||
doc1 = notifyContent[0]->GetDocument();
|
doc1 = notifyContent[0]->GetDocument();
|
||||||
|
@ -4071,12 +4088,29 @@ nsEventStateManager::SetContentState(nsIContent *aContent, PRInt32 aState)
|
||||||
else if (newHover) {
|
else if (newHover) {
|
||||||
doc1 = newHover->GetDocument();
|
doc1 = newHover->GetDocument();
|
||||||
}
|
}
|
||||||
else {
|
else if (oldHover) {
|
||||||
doc1 = oldHover->GetDocument();
|
doc1 = oldHover->GetDocument();
|
||||||
}
|
}
|
||||||
|
else if (newActive) {
|
||||||
|
doc1 = newActive->GetDocument();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
doc1 = oldActive->GetDocument();
|
||||||
|
}
|
||||||
if (doc1) {
|
if (doc1) {
|
||||||
doc1->BeginUpdate(UPDATE_CONTENT_STATE);
|
doc1->BeginUpdate(UPDATE_CONTENT_STATE);
|
||||||
|
|
||||||
|
// Notify all content from newActive to the commonActiveAncestor
|
||||||
|
while (newActive && newActive != commonActiveAncestor) {
|
||||||
|
doc1->ContentStatesChanged(newActive, nsnull, NS_EVENT_STATE_ACTIVE);
|
||||||
|
newActive = newActive->GetParent();
|
||||||
|
}
|
||||||
|
// Notify all content from oldActive to the commonActiveAncestor
|
||||||
|
while (oldActive && oldActive != commonActiveAncestor) {
|
||||||
|
doc1->ContentStatesChanged(oldActive, nsnull, NS_EVENT_STATE_ACTIVE);
|
||||||
|
oldActive = oldActive->GetParent();
|
||||||
|
}
|
||||||
|
|
||||||
// Notify all content from newHover to the commonHoverAncestor
|
// Notify all content from newHover to the commonHoverAncestor
|
||||||
while (newHover && newHover != commonHoverAncestor) {
|
while (newHover && newHover != commonHoverAncestor) {
|
||||||
doc1->ContentStatesChanged(newHover, nsnull, NS_EVENT_STATE_HOVER);
|
doc1->ContentStatesChanged(newHover, nsnull, NS_EVENT_STATE_HOVER);
|
||||||
|
@ -4090,7 +4124,7 @@ nsEventStateManager::SetContentState(nsIContent *aContent, PRInt32 aState)
|
||||||
|
|
||||||
if (notifyContent[0]) {
|
if (notifyContent[0]) {
|
||||||
doc1->ContentStatesChanged(notifyContent[0], notifyContent[1],
|
doc1->ContentStatesChanged(notifyContent[0], notifyContent[1],
|
||||||
aState & ~NS_EVENT_STATE_HOVER);
|
simpleStates);
|
||||||
if (notifyContent[2]) {
|
if (notifyContent[2]) {
|
||||||
// more that two notifications are needed (should be rare)
|
// more that two notifications are needed (should be rare)
|
||||||
// XXX a further optimization here would be to group the
|
// XXX a further optimization here would be to group the
|
||||||
|
@ -4098,11 +4132,11 @@ nsEventStateManager::SetContentState(nsIContent *aContent, PRInt32 aState)
|
||||||
// more than two content changed (ie: if [0] and [2] are
|
// more than two content changed (ie: if [0] and [2] are
|
||||||
// parent/child, then notify (0,2) (1,3))
|
// parent/child, then notify (0,2) (1,3))
|
||||||
doc1->ContentStatesChanged(notifyContent[2], notifyContent[3],
|
doc1->ContentStatesChanged(notifyContent[2], notifyContent[3],
|
||||||
aState & ~NS_EVENT_STATE_HOVER);
|
simpleStates);
|
||||||
if (notifyContent[4]) {
|
if (notifyContent[4]) {
|
||||||
// more that four notifications are needed (should be rare)
|
// more that four notifications are needed (should be rare)
|
||||||
doc1->ContentStatesChanged(notifyContent[4], nsnull,
|
doc1->ContentStatesChanged(notifyContent[4], nsnull,
|
||||||
aState & ~NS_EVENT_STATE_HOVER);
|
simpleStates);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4111,10 +4145,10 @@ nsEventStateManager::SetContentState(nsIContent *aContent, PRInt32 aState)
|
||||||
if (doc2) {
|
if (doc2) {
|
||||||
doc2->BeginUpdate(UPDATE_CONTENT_STATE);
|
doc2->BeginUpdate(UPDATE_CONTENT_STATE);
|
||||||
doc2->ContentStatesChanged(notifyContent[1], notifyContent[2],
|
doc2->ContentStatesChanged(notifyContent[1], notifyContent[2],
|
||||||
aState & ~NS_EVENT_STATE_HOVER);
|
simpleStates);
|
||||||
if (notifyContent[3]) {
|
if (notifyContent[3]) {
|
||||||
doc1->ContentStatesChanged(notifyContent[3], notifyContent[4],
|
doc1->ContentStatesChanged(notifyContent[3], notifyContent[4],
|
||||||
aState & ~NS_EVENT_STATE_HOVER);
|
simpleStates);
|
||||||
}
|
}
|
||||||
doc2->EndUpdate(UPDATE_CONTENT_STATE);
|
doc2->EndUpdate(UPDATE_CONTENT_STATE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3555,8 +3555,6 @@ static PRBool SelectorMatches(RuleProcessorData &data,
|
||||||
!IsQuirkEventSensitive(data.mContentTag)) {
|
!IsQuirkEventSensitive(data.mContentTag)) {
|
||||||
// In quirks mode, only make certain elements sensitive to
|
// In quirks mode, only make certain elements sensitive to
|
||||||
// selectors ":hover" and ":active".
|
// selectors ":hover" and ":active".
|
||||||
// XXX Once we make ":active" work correctly (bug 65917) this
|
|
||||||
// quirk should apply only to ":hover" (if to anything at all).
|
|
||||||
result = localFalse;
|
result = localFalse;
|
||||||
} else {
|
} else {
|
||||||
if (nsCSSPseudoClasses::active == pseudoClass->mAtom) {
|
if (nsCSSPseudoClasses::active == pseudoClass->mAtom) {
|
||||||
|
|
|
@ -3555,8 +3555,6 @@ static PRBool SelectorMatches(RuleProcessorData &data,
|
||||||
!IsQuirkEventSensitive(data.mContentTag)) {
|
!IsQuirkEventSensitive(data.mContentTag)) {
|
||||||
// In quirks mode, only make certain elements sensitive to
|
// In quirks mode, only make certain elements sensitive to
|
||||||
// selectors ":hover" and ":active".
|
// selectors ":hover" and ":active".
|
||||||
// XXX Once we make ":active" work correctly (bug 65917) this
|
|
||||||
// quirk should apply only to ":hover" (if to anything at all).
|
|
||||||
result = localFalse;
|
result = localFalse;
|
||||||
} else {
|
} else {
|
||||||
if (nsCSSPseudoClasses::active == pseudoClass->mAtom) {
|
if (nsCSSPseudoClasses::active == pseudoClass->mAtom) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче