summaryrefslogtreecommitdiffstats
path: root/dom/html/nsGenericHTMLElement.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/html/nsGenericHTMLElement.cpp')
-rw-r--r--dom/html/nsGenericHTMLElement.cpp237
1 files changed, 118 insertions, 119 deletions
diff --git a/dom/html/nsGenericHTMLElement.cpp b/dom/html/nsGenericHTMLElement.cpp
index 78e4d5b95..3cf19ea8f 100644
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -607,16 +607,16 @@ nsGenericHTMLElement::CheckHandleEventForAnchorsPreconditions(
}
nsresult
-nsGenericHTMLElement::PreHandleEventForAnchors(EventChainPreVisitor& aVisitor)
+nsGenericHTMLElement::GetEventTargetParentForAnchors(EventChainPreVisitor& aVisitor)
{
- nsresult rv = nsGenericHTMLElementBase::PreHandleEvent(aVisitor);
+ nsresult rv = nsGenericHTMLElementBase::GetEventTargetParent(aVisitor);
NS_ENSURE_SUCCESS(rv, rv);
if (!CheckHandleEventForAnchorsPreconditions(aVisitor)) {
return NS_OK;
}
- return PreHandleEventForLinks(aVisitor);
+ return GetEventTargetParentForLinks(aVisitor);
}
nsresult
@@ -655,8 +655,46 @@ nsGenericHTMLElement::GetHrefURIForAnchors() const
}
nsresult
+nsGenericHTMLElement::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString* aValue,
+ bool aNotify)
+{
+ if (aNamespaceID == kNameSpaceID_None) {
+ if (aName == nsGkAtoms::accesskey) {
+ // Have to unregister before clearing flag. See UnregAccessKey
+ UnregAccessKey();
+ if (!aValue) {
+ UnsetFlags(NODE_HAS_ACCESSKEY);
+ }
+ } else if (aName == nsGkAtoms::name) {
+ // Have to do this before clearing flag. See RemoveFromNameTable
+ RemoveFromNameTable();
+ if (!aValue || aValue->IsEmpty()) {
+ ClearHasName();
+ }
+ } else if (aName == nsGkAtoms::contenteditable) {
+ if (aValue) {
+ // Set this before the attribute is set so that any subclass code that
+ // runs before the attribute is set won't think we're missing a
+ // contenteditable attr when we actually have one.
+ SetMayHaveContentEditableAttr();
+ }
+ }
+ if (!aValue && IsEventAttributeName(aName)) {
+ if (EventListenerManager* manager = GetExistingListenerManager()) {
+ manager->RemoveEventHandler(aName, EmptyString());
+ }
+ }
+ }
+
+ return nsGenericHTMLElementBase::BeforeSetAttr(aNamespaceID, aName, aValue,
+ aNotify);
+}
+
+nsresult
nsGenericHTMLElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aNamespaceID == kNameSpaceID_None) {
if (IsEventAttributeName(aName) && aValue) {
@@ -670,34 +708,83 @@ nsGenericHTMLElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
}
else if (aName == nsGkAtoms::dir) {
Directionality dir = eDir_LTR;
+ // A boolean tracking whether we need to recompute our directionality.
+ // This needs to happen after we update our internal "dir" attribute
+ // state but before we call SetDirectionalityOnDescendants.
+ bool recomputeDirectionality = false;
+ // We don't want to have to keep getting the "dir" attribute in
+ // IntrinsicState, so we manually recompute our dir-related event states
+ // here and send the relevant update notifications.
+ EventStates dirStates;
if (aValue && aValue->Type() == nsAttrValue::eEnum) {
SetHasValidDir();
+ dirStates |= NS_EVENT_STATE_HAS_DIR_ATTR;
Directionality dirValue = (Directionality)aValue->GetEnumValue();
if (dirValue == eDir_Auto) {
- SetHasDirAuto();
- ClearHasFixedDir();
+ dirStates |= NS_EVENT_STATE_DIR_ATTR_LIKE_AUTO;
} else {
dir = dirValue;
SetDirectionality(dir, aNotify);
- ClearHasDirAuto();
- SetHasFixedDir();
+ if (dirValue == eDir_LTR) {
+ dirStates |= NS_EVENT_STATE_DIR_ATTR_LTR;
+ } else {
+ MOZ_ASSERT(dirValue == eDir_RTL);
+ dirStates |= NS_EVENT_STATE_DIR_ATTR_RTL;
+ }
}
} else {
+ if (aValue) {
+ // We have a value, just not a valid one.
+ dirStates |= NS_EVENT_STATE_HAS_DIR_ATTR;
+ }
ClearHasValidDir();
- ClearHasFixedDir();
if (NodeInfo()->Equals(nsGkAtoms::bdi)) {
- SetHasDirAuto();
+ dirStates |= NS_EVENT_STATE_DIR_ATTR_LIKE_AUTO;
} else {
- ClearHasDirAuto();
- dir = RecomputeDirectionality(this, aNotify);
+ recomputeDirectionality = true;
}
}
+ // Now figure out what's changed about our dir states.
+ EventStates oldDirStates = State() & DIR_ATTR_STATES;
+ EventStates changedStates = dirStates ^ oldDirStates;
+ ToggleStates(changedStates, aNotify);
+ if (recomputeDirectionality) {
+ dir = RecomputeDirectionality(this, aNotify);
+ }
SetDirectionalityOnDescendants(this, dir, aNotify);
+ } else if (aName == nsGkAtoms::contenteditable) {
+ int32_t editableCountDelta = 0;
+ if (aOldValue &&
+ (aOldValue->Equals(NS_LITERAL_STRING("true"), eIgnoreCase) ||
+ aOldValue->Equals(EmptyString(), eIgnoreCase))) {
+ editableCountDelta = -1;
+ }
+ if (aValue && (aValue->Equals(NS_LITERAL_STRING("true"), eIgnoreCase) ||
+ aValue->Equals(EmptyString(), eIgnoreCase))) {
+ ++editableCountDelta;
+ }
+ ChangeEditableState(editableCountDelta);
+ } else if (aName == nsGkAtoms::accesskey) {
+ if (aValue && !aValue->Equals(EmptyString(), eIgnoreCase)) {
+ SetFlags(NODE_HAS_ACCESSKEY);
+ RegAccessKey();
+ }
+ } else if (aName == nsGkAtoms::name) {
+ if (aValue && !aValue->Equals(EmptyString(), eIgnoreCase) &&
+ CanHaveName(NodeInfo()->NameAtom())) {
+ // This may not be quite right because we can have subclass code run
+ // before here. But in practice subclasses don't care about this flag,
+ // and in particular selector matching does not care. Otherwise we'd
+ // want to handle it like we handle id attributes (in PreIdMaybeChange
+ // and PostIdMaybeChange).
+ SetHasName();
+ AddToNameTable(aValue->GetAtomValue());
+ }
}
}
return nsGenericHTMLElementBase::AfterSetAttr(aNamespaceID, aName,
- aValue, aNotify);
+ aValue, aOldValue, aNotify);
}
EventListenerManager*
@@ -818,87 +905,6 @@ nsGenericHTMLElement::SetOn##name_(EventHandlerNonNull* handler) \
#undef FORWARDED_EVENT
#undef EVENT
-nsresult
-nsGenericHTMLElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsIAtom* aPrefix, const nsAString& aValue,
- bool aNotify)
-{
- bool contentEditable = aNameSpaceID == kNameSpaceID_None &&
- aName == nsGkAtoms::contenteditable;
- bool accessKey = aName == nsGkAtoms::accesskey &&
- aNameSpaceID == kNameSpaceID_None;
-
- int32_t change = 0;
- if (contentEditable) {
- change = GetContentEditableValue() == eTrue ? -1 : 0;
- SetMayHaveContentEditableAttr();
- }
-
- if (accessKey) {
- UnregAccessKey();
- }
-
- nsresult rv = nsStyledElement::SetAttr(aNameSpaceID, aName, aPrefix, aValue,
- aNotify);
- NS_ENSURE_SUCCESS(rv, rv);
-
- if (contentEditable) {
- if (aValue.IsEmpty() || aValue.LowerCaseEqualsLiteral("true")) {
- change += 1;
- }
-
- ChangeEditableState(change);
- }
-
- if (accessKey && !aValue.IsEmpty()) {
- SetFlags(NODE_HAS_ACCESSKEY);
- RegAccessKey();
- }
-
- return NS_OK;
-}
-
-nsresult
-nsGenericHTMLElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
- bool aNotify)
-{
- bool contentEditable = false;
- int32_t contentEditableChange = 0;
-
- // Check for event handlers
- if (aNameSpaceID == kNameSpaceID_None) {
- if (aAttribute == nsGkAtoms::name) {
- // Have to do this before clearing flag. See RemoveFromNameTable
- RemoveFromNameTable();
- ClearHasName();
- }
- else if (aAttribute == nsGkAtoms::contenteditable) {
- contentEditable = true;
- contentEditableChange = GetContentEditableValue() == eTrue ? -1 : 0;
- }
- else if (aAttribute == nsGkAtoms::accesskey) {
- // Have to unregister before clearing flag. See UnregAccessKey
- UnregAccessKey();
- UnsetFlags(NODE_HAS_ACCESSKEY);
- }
- else if (IsEventAttributeName(aAttribute)) {
- if (EventListenerManager* manager = GetExistingListenerManager()) {
- manager->RemoveEventHandler(aAttribute, EmptyString());
- }
- }
- }
-
- nsresult rv = nsGenericHTMLElementBase::UnsetAttr(aNameSpaceID, aAttribute,
- aNotify);
- NS_ENSURE_SUCCESS(rv, rv);
-
- if (contentEditable) {
- ChangeEditableState(contentEditableChange);
- }
-
- return NS_OK;
-}
-
void
nsGenericHTMLElement::GetBaseTarget(nsAString& aBaseTarget) const
{
@@ -928,19 +934,13 @@ nsGenericHTMLElement::ParseAttribute(int32_t aNamespaceID,
if (aAttribute == nsGkAtoms::name) {
// Store name as an atom. name="" means that the element has no name,
- // not that it has an emptystring as the name.
- RemoveFromNameTable();
+ // not that it has an empty string as the name.
if (aValue.IsEmpty()) {
ClearHasName();
return false;
}
aResult.ParseAtom(aValue);
-
- if (CanHaveName(NodeInfo()->NameAtom())) {
- SetHasName();
- AddToNameTable(aResult.GetAtomValue());
- }
return true;
}
@@ -1962,7 +1962,7 @@ nsGenericHTMLFormElement::UnbindFromTree(bool aDeep, bool aNullParent)
nsresult
nsGenericHTMLFormElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsAttrValueOrString* aValue,
+ const nsAttrValueOrString* aValue,
bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None) {
@@ -1995,13 +1995,6 @@ nsGenericHTMLFormElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
}
mForm->RemoveElement(this, false);
-
- // Removing the element from the form can make it not be the default
- // control anymore. Go ahead and notify on that change, though we might
- // end up readding and becoming the default control again in
- // AfterSetAttr.
- // FIXME: Bug 656197
- UpdateState(aNotify);
}
if (aName == nsGkAtoms::form) {
@@ -2022,7 +2015,8 @@ nsGenericHTMLFormElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
nsresult
nsGenericHTMLFormElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None) {
// add the control to the hashtable as needed
@@ -2051,12 +2045,6 @@ nsGenericHTMLFormElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
}
mForm->AddElement(this, false, aNotify);
-
- // Adding the element to the form can make it be the default control .
- // Go ahead and notify on that change.
- // Note: no need to notify on CanBeDisabled(), since type attr
- // changes can't affect that.
- UpdateState(aNotify);
}
if (aName == nsGkAtoms::form) {
@@ -2077,11 +2065,23 @@ nsGenericHTMLFormElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
}
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName,
- aValue, aNotify);
+ aValue, aOldValue, aNotify);
+}
+
+nsresult
+nsGenericHTMLFormElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
+{
+ if (aVisitor.mEvent->IsTrusted() && (aVisitor.mEvent->mMessage == eFocus ||
+ aVisitor.mEvent->mMessage == eBlur)) {
+ // We have to handle focus/blur event to change focus states in
+ // PreHandleEvent to prevent it breaks event target chain creation.
+ aVisitor.mWantsPreHandleEvent = true;
+ }
+ return nsGenericHTMLElement::GetEventTargetParent(aVisitor);
}
nsresult
-nsGenericHTMLFormElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+nsGenericHTMLFormElement::PreHandleEvent(EventChainVisitor& aVisitor)
{
if (aVisitor.mEvent->IsTrusted()) {
switch (aVisitor.mEvent->mMessage) {
@@ -2105,7 +2105,6 @@ nsGenericHTMLFormElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
break;
}
}
-
return nsGenericHTMLElement::PreHandleEvent(aVisitor);
}