Bug 426082, part 3: Reflect a label's :hover/:active state on its associated natively themed control.

This patch adds an aFollowLabels argument to nsIEventStateManager::GetContentState which defaults to false. Setting it to true will return NS_EVENT_STATE_HOVER / _ACTIVE for labeled controls even if only their label is subject to this state. At the moment this flag is only set by native theming, so there won't be an observable change for the :hover / :active pseudoclasses.
In order to make dynamic state changes on the label work, SetContentState will now always notify the labeled control of state changes when its label changes state.
r=smaug
This commit is contained in:
Markus Stange 2010-05-31 19:49:55 +02:00
Родитель 65469b4a69
Коммит adb70d0cbc
4 изменённых файлов: 49 добавлений и 9 удалений

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

@ -85,7 +85,18 @@ public:
NS_IMETHOD GetEventTarget(nsIFrame **aFrame) = 0;
NS_IMETHOD GetEventTargetContent(nsEvent* aEvent, nsIContent** aContent) = 0;
virtual PRInt32 GetContentState(nsIContent *aContent) = 0;
/**
* Returns the content state of aContent.
* @param aContent The control whose state is requested.
* @param aFollowLabels Whether to reflect a label's content state on its
* associated control. If aFollowLabels is true and
* aContent is a control which has a label that has the
* hover or active content state set, GetContentState
* will pretend that those states are also set on aContent.
* @return The content state.
*/
virtual PRInt32 GetContentState(nsIContent *aContent,
PRBool aFollowLabels = PR_FALSE) = 0;
/**
* Notify that the given NS_EVENT_STATE_* bit has changed for this content.

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

@ -66,6 +66,7 @@
#include "nsIDOMHTMLAnchorElement.h"
#include "nsIDOMHTMLInputElement.h"
#include "nsIDOMNSHTMLInputElement.h"
#include "nsIDOMNSHTMLLabelElement.h"
#include "nsIDOMHTMLSelectElement.h"
#include "nsIDOMHTMLTextAreaElement.h"
#include "nsIDOMHTMLAreaElement.h"
@ -3977,25 +3978,48 @@ nsEventStateManager::GetEventTargetContent(nsEvent* aEvent,
return NS_OK;
}
static already_AddRefed<nsIContent>
GetLabelTarget(nsIContent* aLabel)
{
nsCOMPtr<nsIDOMNSHTMLLabelElement> label = do_QueryInterface(aLabel);
if (!label)
return nsnull;
nsCOMPtr<nsIDOMHTMLElement> target;
label->GetControl(getter_AddRefs(target));
nsIContent* targetContent = nsnull;
if (target) {
CallQueryInterface(target, &targetContent);
}
return targetContent;
}
static bool
IsAncestorOf(nsIContent* aPossibleAncestor, nsIContent* aPossibleDescendant)
IsAncestorOf(nsIContent* aPossibleAncestor, nsIContent* aPossibleDescendant,
PRBool aFollowLabels)
{
for (; aPossibleDescendant; aPossibleDescendant = aPossibleDescendant->GetParent()) {
if (aPossibleAncestor == aPossibleDescendant)
return true;
if (aFollowLabels) {
nsCOMPtr<nsIContent> labelTarget = GetLabelTarget(aPossibleDescendant);
if (labelTarget == aPossibleAncestor)
return true;
}
}
return false;
}
PRInt32
nsEventStateManager::GetContentState(nsIContent *aContent)
nsEventStateManager::GetContentState(nsIContent *aContent, PRBool aFollowLabels)
{
PRInt32 state = aContent->IntrinsicState();
if (IsAncestorOf(aContent, mActiveContent)) {
if (IsAncestorOf(aContent, mActiveContent, aFollowLabels)) {
state |= NS_EVENT_STATE_ACTIVE;
}
if (IsAncestorOf(aContent, mHoverContent)) {
if (IsAncestorOf(aContent, mHoverContent, aFollowLabels)) {
state |= NS_EVENT_STATE_HOVER;
}
@ -4071,6 +4095,10 @@ NotifyAncestors(nsIDocument* aDocument, nsIContent* aStartNode,
{
while (aStartNode && aStartNode != aStopBefore) {
aDocument->ContentStatesChanged(aStartNode, nsnull, aState);
nsCOMPtr<nsIContent> labelTarget = GetLabelTarget(aStartNode);
if (labelTarget) {
aDocument->ContentStatesChanged(labelTarget, nsnull, aState);
}
aStartNode = aStartNode->GetParent();
}
}
@ -4281,14 +4309,14 @@ nsEventStateManager::ContentRemoved(nsIDocument* aDocument, nsIContent* aContent
nsContentUtils::ContentIsDescendantOf(mHoverContent, aContent)) {
// Since hover is hierarchical, set the current hover to the
// content's parent node.
mHoverContent = aContent->GetParent();
SetContentState(aContent->GetParent(), NS_EVENT_STATE_HOVER);
}
if (mActiveContent &&
nsContentUtils::ContentIsDescendantOf(mActiveContent, aContent)) {
// Active is hierarchical, so set the current active to the
// content's parent node.
mActiveContent = aContent->GetParent();
SetContentState(aContent->GetParent(), NS_EVENT_STATE_ACTIVE);
}
if (mDragOverContent &&

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

@ -120,7 +120,8 @@ public:
NS_IMETHOD GetEventTarget(nsIFrame **aFrame);
NS_IMETHOD GetEventTargetContent(nsEvent* aEvent, nsIContent** aContent);
virtual PRInt32 GetContentState(nsIContent *aContent);
virtual PRInt32 GetContentState(nsIContent *aContent,
PRBool aFollowLabels = PR_FALSE);
virtual PRBool SetContentState(nsIContent *aContent, PRInt32 aState);
NS_IMETHOD ContentRemoved(nsIDocument* aDocument, nsIContent* aContent);
NS_IMETHOD EventStatusOK(nsGUIEvent* aEvent, PRBool *aOK);

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

@ -90,7 +90,7 @@ nsNativeTheme::GetContentState(nsIFrame* aFrame, PRUint8 aWidgetType)
return 0;
nsIEventStateManager* esm = shell->GetPresContext()->EventStateManager();
PRInt32 flags = esm->GetContentState(aFrame->GetContent());
PRInt32 flags = esm->GetContentState(aFrame->GetContent(), PR_TRUE);
if (isXULCheckboxRadio && aWidgetType == NS_THEME_RADIO) {
if (IsFocused(aFrame))