diff options
Diffstat (limited to 'dom/html/nsGenericHTMLElement.cpp')
-rw-r--r-- | dom/html/nsGenericHTMLElement.cpp | 237 |
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); } |