Bug 598833 part 12. Add dom::Element::UpdateState and use it in various places where elements update their own state. r=smaug,sdwilsh,mounir

This commit is contained in:
Boris Zbarsky 2011-05-31 21:46:57 -04:00
parent f46b921065
commit 76f757828a
37 changed files with 487 additions and 580 deletions

View File

@ -85,11 +85,16 @@ enum {
namespace mozilla {
namespace dom {
class Link;
class Element : public nsIContent
{
public:
#ifdef MOZILLA_INTERNAL_API
Element(already_AddRefed<nsINodeInfo> aNodeInfo) : nsIContent(aNodeInfo) {}
Element(already_AddRefed<nsINodeInfo> aNodeInfo) :
nsIContent(aNodeInfo),
mState(NS_EVENT_STATE_MOZ_READONLY)
{}
#endif // MOZILLA_INTERNAL_API
/**
@ -97,7 +102,9 @@ public:
* the possible bits that could be set here.
*/
nsEventStates State() const {
return IntrinsicState() | mState;
// mState is maintained by having whoever might have changed it
// call UpdateState() or one of the other mState mutators.
return mState;
}
/**
@ -111,6 +118,18 @@ public:
*/
virtual void RequestLinkStateUpdate();
/**
* Ask this element to update its state. If aNotify is false, then
* state change notifications will not be dispatched; in that
* situation it is the caller's responsibility to dispatch them.
*
* In general, aNotify should only be false if we're guaranteed that
* the element can't have a frame no matter what its style is
* (e.g. if we're in the middle of adding it to the document or
* removing it from the document).
*/
void UpdateState(bool aNotify);
protected:
/**
* Method to get the _intrinsic_ content state of this element. This is the
@ -125,6 +144,26 @@ protected:
*/
void UpdateLinkState(nsEventStates aState);
/**
* Method to add state bits. This should be called from subclass
* constructors to set up our event state correctly at construction
* time and other places where we don't want to notify a state
* change.
*/
void AddStatesSilently(nsEventStates aStates) {
mState |= aStates;
}
/**
* Method to remove state bits. This should be called from subclass
* constructors to set up our event state correctly at construction
* time and other places where we don't want to notify a state
* change.
*/
void RemoveStatesSilently(nsEventStates aStates) {
mState &= ~aStates;
}
private:
// Need to allow the ESM, nsGlobalWindow, and the focus manager to
// set our state
@ -132,6 +171,9 @@ private:
friend class ::nsGlobalWindow;
friend class ::nsFocusManager;
// Also need to allow Link to call UpdateLinkState.
friend class Link;
void NotifyStateChange(nsEventStates aStates);
// Methods for the ESM to manage state bits. These will handle
@ -140,13 +182,13 @@ private:
void AddStates(nsEventStates aStates) {
NS_PRECONDITION(!aStates.HasAtLeastOneOfStates(INTRINSIC_STATES),
"Should only be adding ESM-managed states here");
mState |= aStates;
AddStatesSilently(aStates);
NotifyStateChange(aStates);
}
void RemoveStates(nsEventStates aStates) {
NS_PRECONDITION(!aStates.HasAtLeastOneOfStates(INTRINSIC_STATES),
"Should only be removing ESM-managed states here");
mState &= ~aStates;
RemoveStatesSilently(aStates);
NotifyStateChange(aStates);
}

View File

@ -76,8 +76,8 @@ enum nsLinkState {
// IID for the nsIContent interface
#define NS_ICONTENT_IID \
{ 0xba1c9e22, 0x4b73, 0x42ae, \
{ 0xb6, 0x45, 0xa7, 0x83, 0xd0, 0x7e, 0xee, 0x2c } }
{ 0x860ee35b, 0xe505, 0x438f, \
{ 0xa7, 0x7b, 0x65, 0xb9, 0xf5, 0x0b, 0xe5, 0x29 } }
/**
* A node of content in a document's content model. This interface
@ -856,9 +856,10 @@ public:
/**
* Should be called when the node can become editable or when it can stop
* being editable (for example when its contentEditable attribute changes,
* when it is moved into an editable parent, ...).
* when it is moved into an editable parent, ...). If aNotify is true and
* the node is an element, this will notify the state change.
*/
virtual void UpdateEditableState();
virtual void UpdateEditableState(PRBool aNotify);
/**
* Destroy this node and its children. Ideally this shouldn't be needed

View File

@ -85,25 +85,18 @@ Link::SetLinkState(nsLinkState aState)
NS_ASSERTION(mLinkState != aState,
"Setting state to the currently set state!");
// Remember our old link state for when we notify.
nsEventStates oldLinkState = LinkState();
// Set our current state as appropriate.
mLinkState = aState;
// Per IHistory interface documentation, we are no longer registered.
mRegistered = false;
// Notify the document that our visited state has changed.
Element *element = mElement;
nsIDocument *doc = element->GetCurrentDoc();
NS_ASSERTION(doc, "Registered but we have no document?!");
nsEventStates newLinkState = LinkState();
NS_ASSERTION(newLinkState == NS_EVENT_STATE_VISITED ||
newLinkState == NS_EVENT_STATE_UNVISITED,
"Unexpected state obtained from LinkState()!");
nsAutoScriptBlocker scriptBlocker;
doc->ContentStateChanged(element, oldLinkState ^ newLinkState);
NS_ABORT_IF_FALSE(LinkState() == NS_EVENT_STATE_VISITED ||
LinkState() == NS_EVENT_STATE_UNVISITED,
"Unexpected state obtained from LinkState()!");
// Tell the element to update its visited state
mElement->UpdateState(true);
}
nsEventStates
@ -484,15 +477,16 @@ Link::ResetLinkState(bool aNotify)
// Get rid of our cached URI.
mCachedURI = nsnull;
// If aNotify is true, notify both of the visited-related states. We have
// to do that, because we might be racing with a response from history and
// hence need to make sure that we get restyled whether we were visited or
// not before. In particular, we need to make sure that our LinkState() is
// called so that we'll start a new history query as needed.
if (aNotify && doc) {
nsEventStates changedState = NS_EVENT_STATE_VISITED ^ NS_EVENT_STATE_UNVISITED;
nsAutoScriptBlocker scriptBlocker;
doc->ContentStateChanged(element, changedState);
// We have to be very careful here: if aNotify is false we do NOT
// want to call UpdateState, because that will call into LinkState()
// and try to start off loads, etc. But ResetLinkState is called
// with aNotify false when things are in inconsistent states, so
// we'll get confused in that situation. Instead, just silently
// update the link state on mElement.
if (aNotify) {
mElement->UpdateState(aNotify);
} else {
mElement->UpdateLinkState(nsEventStates());
}
}

View File

@ -55,6 +55,9 @@ public:
nsGenConImageContent(already_AddRefed<nsINodeInfo> aNodeInfo)
: nsXMLElement(aNodeInfo)
{
// nsImageLoadingContent starts out broken, so we start out
// suppressed to match it.
AddStatesSilently(NS_EVENT_STATE_SUPPRESSED);
}
nsresult Init(imgIRequest* aImageRequest)

View File

@ -535,7 +535,7 @@ nsGenericDOMDataNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsNodeUtils::ParentChainChanged(this);
UpdateEditableState();
UpdateEditableState(PR_FALSE);
NS_POSTCONDITION(aDocument == GetCurrentDoc(), "Bound to wrong document");
NS_POSTCONDITION(aParent == GetParent(), "Bound to wrong parent");

View File

@ -819,13 +819,59 @@ Element::UpdateLinkState(nsEventStates aState)
}
void
nsIContent::UpdateEditableState()
Element::UpdateState(bool aNotify)
{
nsEventStates oldState = mState;
mState = IntrinsicState() | (oldState & ESM_MANAGED_STATES);
if (aNotify) {
nsEventStates changedStates = oldState ^ mState;
if (!changedStates.IsEmpty()) {
nsIDocument* doc = GetCurrentDoc();
if (doc) {
nsAutoScriptBlocker scriptBlocker;
doc->ContentStateChanged(this, changedStates);
}
}
}
}
void
nsIContent::UpdateEditableState(PRBool aNotify)
{
// Guaranteed to be non-element content
NS_ASSERTION(!IsElement(), "What happened here?");
nsIContent *parent = GetParent();
SetEditableFlag(parent && parent->HasFlag(NODE_IS_EDITABLE));
}
void
nsGenericElement::UpdateEditableState(PRBool aNotify)
{
nsIContent *parent = GetParent();
PRBool oldEditable = IsEditable();
SetEditableFlag(parent && parent->HasFlag(NODE_IS_EDITABLE));
PRBool newEditable = IsEditable();
if (oldEditable != newEditable) {
if (aNotify) {
UpdateState(aNotify);
} else {
// Avoid calling UpdateState in this very common case, because
// this gets called for pretty much every single element on
// insertion into the document and UpdateState can be slow for
// some kinds of elements even when not notifying.
if (oldEditable) {
RemoveStatesSilently(NS_EVENT_STATE_MOZ_READWRITE);
AddStatesSilently(NS_EVENT_STATE_MOZ_READONLY);
} else {
RemoveStatesSilently(NS_EVENT_STATE_MOZ_READONLY);
AddStatesSilently(NS_EVENT_STATE_MOZ_READWRITE);
}
}
}
}
nsIContent*
nsIContent::FindFirstNonNativeAnonymous() const
{
@ -3034,7 +3080,7 @@ nsGenericElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
}
}
UpdateEditableState();
UpdateEditableState(PR_FALSE);
// Now recurse into our kids
for (nsIContent* child = GetFirstChild(); child;
@ -4668,13 +4714,6 @@ nsGenericElement::SetAttrAndNotify(PRInt32 aNamespaceID,
nsIDocument* document = GetCurrentDoc();
mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
// When notifying, make sure to keep track of states whose value
// depends solely on the value of an attribute.
nsEventStates stateMask;
if (aNotify) {
stateMask = IntrinsicState();
}
nsMutationGuard::DidMutate();
if (aNamespaceID == kNameSpaceID_None) {
@ -4706,11 +4745,9 @@ nsGenericElement::SetAttrAndNotify(PRInt32 aNamespaceID,
}
}
UpdateState(aNotify);
if (aNotify) {
stateMask ^= IntrinsicState();
if (document && !stateMask.IsEmpty()) {
document->ContentStateChanged(this, stateMask);
}
nsNodeUtils::AttributeChanged(this, aNamespaceID, aName, aModType);
}
@ -4904,13 +4941,6 @@ nsGenericElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
nsIDOMMutationEvent::REMOVAL);
}
// When notifying, make sure to keep track of states whose value
// depends solely on the value of an attribute.
nsEventStates stateMask;
if (aNotify) {
stateMask = IntrinsicState();
}
PRBool hasMutationListeners = aNotify &&
nsContentUtils::HasMutationListeners(this,
NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
@ -4950,11 +4980,9 @@ nsGenericElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
}
}
UpdateState(aNotify);
if (aNotify) {
stateMask ^= IntrinsicState();
if (document && !stateMask.IsEmpty()) {
document->ContentStateChanged(this, stateMask);
}
nsNodeUtils::AttributeChanged(this, aNameSpaceID, aName,
nsIDOMMutationEvent::REMOVAL);
}
@ -5085,7 +5113,7 @@ nsGenericElement::List(FILE* out, PRInt32 aIndent,
ListAttributes(out);
fprintf(out, " intrinsicstate=[%llx]", IntrinsicState().GetInternalValue());
fprintf(out, " state=[%llx]", State().GetInternalValue());
fprintf(out, " flags=[%08x]", static_cast<unsigned int>(GetFlags()));
fprintf(out, " primaryframe=%p", static_cast<void*>(GetPrimaryFrame()));
fprintf(out, " refcount=%d<", mRefCnt.get());

View File

@ -355,6 +355,8 @@ public:
}
// nsIContent interface methods
virtual void UpdateEditableState(PRBool aNotify);
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
PRBool aCompileEventHandlers);

View File

@ -794,8 +794,6 @@ nsImageLoadingContent::UpdateImageState(PRBool aNotify)
return;
}
nsEventStates oldState = ImageState();
mLoading = mBroken = mUserDisabled = mSuppressed = PR_FALSE;
// If we were blocked by server-based content policy, we claim to be
@ -818,17 +816,8 @@ nsImageLoadingContent::UpdateImageState(PRBool aNotify)
}
}
if (aNotify) {
nsIDocument* doc = thisContent->GetCurrentDoc();
if (doc) {
NS_ASSERTION(thisContent->IsInDoc(), "Something is confused");
nsEventStates changedBits = oldState ^ ImageState();
if (!changedBits.IsEmpty()) {
nsAutoScriptBlocker scriptBlocker;
doc->ContentStateChanged(thisContent, changedBits);
}
}
}
NS_ASSERTION(thisContent->IsElement(), "Not an element?");
thisContent->AsElement()->UpdateState(aNotify);
}
void

View File

@ -337,9 +337,7 @@ class AutoNotifier {
mOldState = aContent->ObjectState();
}
~AutoNotifier() {
if (mNotify) {
mContent->NotifyStateChanged(mOldType, mOldState, PR_FALSE);
}
mContent->NotifyStateChanged(mOldType, mOldState, PR_FALSE, mNotify);
}
/**
@ -350,7 +348,7 @@ class AutoNotifier {
void Notify() {
NS_ASSERTION(mNotify, "Should not notify when notify=false");
mContent->NotifyStateChanged(mOldType, mOldState, PR_TRUE);
mContent->NotifyStateChanged(mOldType, mOldState, PR_TRUE, PR_TRUE);
mOldType = mContent->Type();
mOldState = mContent->ObjectState();
}
@ -1639,7 +1637,9 @@ nsObjectLoadingContent::UnloadContent()
void
nsObjectLoadingContent::NotifyStateChanged(ObjectType aOldType,
nsEventStates aOldState, PRBool aSync)
nsEventStates aOldState,
PRBool aSync,
PRBool aNotify)
{
LOG(("OBJLC [%p]: Notifying about state change: (%u, %llx) -> (%u, %llx) (sync=%i)\n",
this, aOldType, aOldState.GetInternalValue(), mType,
@ -1649,6 +1649,18 @@ nsObjectLoadingContent::NotifyStateChanged(ObjectType aOldType,
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
NS_ASSERTION(thisContent, "must be a content");
NS_ASSERTION(thisContent->IsElement(), "Not an element?");
// Unfortunately, we do some state changes without notifying
// (e.g. in Fallback when canceling image requests), so we have to
// manually notify object state changes.
thisContent->AsElement()->UpdateState(false);
if (!aNotify) {
// We're done here
return;
}
nsIDocument* doc = thisContent->GetCurrentDoc();
if (!doc) {
return; // Nothing to do
@ -1666,8 +1678,7 @@ nsObjectLoadingContent::NotifyStateChanged(ObjectType aOldType,
doc->ContentStateChanged(thisContent, changedBits);
}
if (aSync) {
// Make sure that frames are actually constructed, and do it after
// EndUpdate was called.
// Make sure that frames are actually constructed immediately.
doc->FlushPendingNotifications(Flush_Frames);
}
} else if (aOldType != mType) {

View File

@ -256,9 +256,10 @@ class nsObjectLoadingContent : public nsImageLoadingContent
*
* @param aSync If a synchronous frame construction is required. If false,
* the construction may either be sync or async.
* @param aNotify if false, only need to update the state of our element.
*/
void NotifyStateChanged(ObjectType aOldType, nsEventStates aOldState,
PRBool aSync);
PRBool aSync, PRBool aNotify);
/**
* Fires the "Plugin not found" event. This function doesn't do any checks

View File

@ -939,17 +939,16 @@ nsGenericHTMLElement::InNavQuirksMode(nsIDocument* aDoc)
}
void
nsGenericHTMLElement::UpdateEditableState()
nsGenericHTMLElement::UpdateEditableState(PRBool aNotify)
{
// XXX Should we do this only when in a document?
ContentEditableTristate value = GetContentEditableValue();
if (value != eInherit) {
SetEditableFlag(!!value);
DoSetEditableFlag(!!value, aNotify);
return;
}
nsStyledElement::UpdateEditableState();
nsStyledElement::UpdateEditableState(aNotify);
}
nsresult
@ -1713,27 +1712,26 @@ nsGenericHTMLElement::MapCommonAttributesInto(const nsMappedAttributes* aAttribu
}
void
nsGenericHTMLFormElement::UpdateEditableFormControlState()
nsGenericHTMLFormElement::UpdateEditableFormControlState(PRBool aNotify)
{
// nsCSSFrameConstructor::MaybeConstructLazily is based on the logic of this
// function, so should be kept in sync with that.
ContentEditableTristate value = GetContentEditableValue();
if (value != eInherit) {
SetEditableFlag(!!value);
DoSetEditableFlag(!!value, aNotify);
return;
}
nsIContent *parent = GetParent();
if (parent && parent->HasFlag(NODE_IS_EDITABLE)) {
SetEditableFlag(PR_TRUE);
DoSetEditableFlag(PR_TRUE, aNotify);
return;
}
if (!IsTextControl(PR_FALSE)) {
SetEditableFlag(PR_FALSE);
DoSetEditableFlag(PR_FALSE, aNotify);
return;
}
@ -1741,7 +1739,7 @@ nsGenericHTMLFormElement::UpdateEditableFormControlState()
PRBool roState;
GetBoolAttr(nsGkAtoms::readonly, &roState);
SetEditableFlag(!roState);
DoSetEditableFlag(!roState, aNotify);
}
@ -2410,6 +2408,9 @@ nsGenericHTMLFormElement::nsGenericHTMLFormElement(already_AddRefed<nsINodeInfo>
, mForm(nsnull)
, mFieldSet(nsnull)
{
// We should add the NS_EVENT_STATE_ENABLED bit here as needed, but
// that depends on our type, which is not initialized yet. So we
// have to do this in subclasses.
}
nsGenericHTMLFormElement::~nsGenericHTMLFormElement()
@ -2564,7 +2565,7 @@ nsGenericHTMLFormElement::BindToTree(nsIDocument* aDocument,
}
// Set parent fieldset which should be used for the disabled state.
UpdateFieldSet();
UpdateFieldSet(PR_FALSE);
return NS_OK;
}
@ -2589,6 +2590,11 @@ nsGenericHTMLFormElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
UnsetFlags(MAYBE_ORPHAN_FORM_ELEMENT);
}
}
if (!mForm) {
// Our novalidate state might have changed
UpdateState(false);
}
}
// We have to remove the form id observer if there was one.
@ -2601,7 +2607,7 @@ nsGenericHTMLFormElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
// The element might not have a fieldset anymore.
UpdateFieldSet();
UpdateFieldSet(PR_FALSE);
}
nsresult
@ -2622,8 +2628,6 @@ nsGenericHTMLFormElement::BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
}
if (mForm && aName == nsGkAtoms::type) {
nsIDocument* doc = GetCurrentDoc();
GetAttr(kNameSpaceID_None, nsGkAtoms::name, tmp);
if (!tmp.IsEmpty()) {
@ -2642,10 +2646,8 @@ nsGenericHTMLFormElement::BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
// control anymore. Go ahead and notify on that change, though we might
// end up readding and becoming the default control again in
// AfterSetAttr.
if (doc && aNotify) {
nsAutoScriptBlocker scriptBlocker;
doc->ContentStateChanged(this, NS_EVENT_STATE_DEFAULT);
}
// FIXME: Bug 656197
UpdateState(aNotify);
}
if (aName == nsGkAtoms::form) {
@ -2679,7 +2681,6 @@ nsGenericHTMLFormElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
}
if (mForm && aName == nsGkAtoms::type) {
nsIDocument* doc = GetDocument();
nsAutoString tmp;
GetAttr(kNameSpaceID_None, nsGkAtoms::name, tmp);
@ -2700,9 +2701,7 @@ nsGenericHTMLFormElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
// Go ahead and notify on that change.
// Note: no need to notify on CanBeDisabled(), since type attr
// changes can't affect that.
if (doc && aNotify) {
doc->ContentStateChanged(this, NS_EVENT_STATE_DEFAULT);
}
UpdateState(aNotify);
}
if (aName == nsGkAtoms::form) {
@ -2913,19 +2912,13 @@ nsGenericHTMLFormElement::UpdateFormOwner(bool aBindToTree,
NS_PRECONDITION(!aBindToTree || !aFormIdElement,
"aFormIdElement shouldn't be set if aBindToTree is true!");
PRBool needStateUpdate = PR_FALSE;
if (!aBindToTree) {
PRBool wasDefaultSubmit = mForm && mForm->IsDefaultSubmitElement(this);
needStateUpdate = mForm && mForm->IsDefaultSubmitElement(this);
ClearForm(PR_TRUE);
if (wasDefaultSubmit) {
nsIDocument* doc = GetCurrentDoc();
if (doc) {
nsAutoScriptBlocker scriptBlocker;
doc->ContentStateChanged(this, NS_EVENT_STATE_DEFAULT);
}
}
}
bool hadForm = mForm;
nsHTMLFormElement *oldForm = mForm;
if (!mForm) {
// If @form is set, we have to use that to find the form.
@ -2972,7 +2965,7 @@ nsGenericHTMLFormElement::UpdateFormOwner(bool aBindToTree,
SetFlags(ADDED_TO_FORM);
// Notify only if we just found this mForm.
mForm->AddElement(this, true, !hadForm);
mForm->AddElement(this, true, oldForm == nsnull);
if (!nameVal.IsEmpty()) {
mForm->AddElementToTable(this, nameVal);
@ -2982,10 +2975,14 @@ nsGenericHTMLFormElement::UpdateFormOwner(bool aBindToTree,
mForm->AddElementToTable(this, idVal);
}
}
if (mForm != oldForm || needStateUpdate) {
UpdateState(true);
}
}
void
nsGenericHTMLFormElement::UpdateFieldSet()
nsGenericHTMLFormElement::UpdateFieldSet(PRBool aNotify)
{
nsIContent* parent = nsnull;
nsIContent* prev = nsnull;
@ -2997,11 +2994,19 @@ nsGenericHTMLFormElement::UpdateFieldSet()
static_cast<nsHTMLFieldSetElement*>(parent);
if (!prev || fieldset->GetFirstLegend() != prev) {
if (mFieldSet == fieldset) {
// We already have the right fieldset;
return;
}
if (mFieldSet) {
static_cast<nsHTMLFieldSetElement*>(mFieldSet)->RemoveElement(this);
}
mFieldSet = fieldset;
fieldset->AddElement(this);
// The disabled state may have changed
FieldSetDisabledChanged(aNotify);
return;
}
}
@ -3010,24 +3015,16 @@ nsGenericHTMLFormElement::UpdateFieldSet()
// No fieldset found.
if (mFieldSet) {
static_cast<nsHTMLFieldSetElement*>(mFieldSet)->RemoveElement(this);
mFieldSet = nsnull;
// The disabled state may have changed
FieldSetDisabledChanged(aNotify);
}
mFieldSet = nsnull;
}
void
nsGenericHTMLFormElement::FieldSetDisabledChanged(nsEventStates aStates, PRBool aNotify)
nsGenericHTMLFormElement::FieldSetDisabledChanged(PRBool aNotify)
{
if (!aNotify) {
return;
}
aStates |= NS_EVENT_STATE_DISABLED | NS_EVENT_STATE_ENABLED;
nsIDocument* doc = GetCurrentDoc();
if (doc) {
nsAutoScriptBlocker scriptBlocker;
doc->ContentStateChanged(this, aStates);
}
UpdateState(aNotify);
}
//----------------------------------------------------------------------
@ -3556,20 +3553,13 @@ MakeContentDescendantsEditable(nsIContent *aContent, nsIDocument *aDocument)
// that. For elements, we need to send a ContentStateChanged
// notification.
if (!aContent->IsElement()) {
aContent->UpdateEditableState();
aContent->UpdateEditableState(PR_FALSE);
return;
}
Element *element = aContent->AsElement();
nsEventStates stateBefore = element->State();
element->UpdateEditableState();
if (aDocument && stateBefore != element->State()) {
aDocument->ContentStateChanged(element,
NS_EVENT_STATE_MOZ_READONLY |
NS_EVENT_STATE_MOZ_READWRITE);
}
element->UpdateEditableState(PR_TRUE);
for (nsIContent *child = aContent->GetFirstChild();
child;

View File

@ -199,7 +199,13 @@ public:
// HTML element methods
void Compact() { mAttrsAndChildren.Compact(); }
virtual void UpdateEditableState();
virtual void UpdateEditableState(PRBool aNotify);
// Helper for setting our editable flag and notifying
void DoSetEditableFlag(PRBool aEditable, bool aNotify) {
SetEditableFlag(aEditable);
UpdateState(aNotify);
}
virtual PRBool ParseAttribute(PRInt32 aNamespaceID,
nsIAtom* aAttribute,
@ -870,22 +876,18 @@ public:
}
/**
* This callback is called by a fieldest on all it's elements whenever it's
* disabled attribute is changed so the element knows it's disabled state
* This callback is called by a fieldest on all its elements whenever its
* disabled attribute is changed so the element knows its disabled state
* might have changed.
*
* @param aStates States for which a change should be notified.
* @note Classes redefining this method should not call ContentStatesChanged
* but they should pass aStates instead.
* @note Classes redefining this method should not do any content
* state updates themselves but should just make sure to call into
* nsGenericHTMLFormElement::FieldSetDisabledChanged.
*/
virtual void FieldSetDisabledChanged(nsEventStates aStates, PRBool aNotify);
virtual void FieldSetDisabledChanged(PRBool aNotify);
void FieldSetFirstLegendChanged(PRBool aNotify) {
UpdateFieldSet();
// The disabled state may have change because the element might not be in
// the first legend anymore.
FieldSetDisabledChanged(nsEventStates(), aNotify);
UpdateFieldSet(aNotify);
}
/**
@ -916,7 +918,7 @@ protected:
virtual nsresult AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
const nsAString* aValue, PRBool aNotify);
void UpdateEditableFormControlState();
void UpdateEditableFormControlState(PRBool aNotify);
/**
* This method will update the form owner, using @form or looking to a parent.
@ -934,7 +936,7 @@ protected:
/**
* This method will update mFieldset and set it to the first fieldset parent.
*/
void UpdateFieldSet();
void UpdateFieldSet(PRBool aNotify);
/**
* Add a form id observer which will observe when the element with the id in

View File

@ -134,6 +134,12 @@ public:
virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
virtual nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor);
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
PRBool aCompileEventHandlers);
virtual void UnbindFromTree(PRBool aDeep = PR_TRUE,
PRBool aNullParent = PR_TRUE);
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
virtual void DoneCreatingElement();
virtual nsXPCClassInfo* GetClassInfo();
@ -167,6 +173,9 @@ nsHTMLButtonElement::nsHTMLButtonElement(already_AddRefed<nsINodeInfo> aNodeInfo
{
// <button> is always barred from constraint validation.
SetBarredFromConstraintValidation(PR_TRUE);
// Set up our default state: enabled
AddStatesSilently(NS_EVENT_STATE_ENABLED);
}
nsHTMLButtonElement::~nsHTMLButtonElement()
@ -486,6 +495,31 @@ nsHTMLButtonElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
return rv;
}
nsresult
nsHTMLButtonElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
PRBool aCompileEventHandlers)
{
nsresult rv = nsGenericHTMLFormElement::BindToTree(aDocument, aParent,
aBindingParent,
aCompileEventHandlers);
NS_ENSURE_SUCCESS(rv, rv);
// Update our state; we may now be the default submit element
UpdateState(false);
return NS_OK;
}
void
nsHTMLButtonElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
{
nsGenericHTMLFormElement::UnbindFromTree(aDeep, aNullParent);
// Update our state; we may no longer be the default submit element
UpdateState(false);
}
nsresult
nsHTMLButtonElement::GetDefaultValue(nsAString& aDefaultValue)
{
@ -574,22 +608,13 @@ nsresult
nsHTMLButtonElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
const nsAString* aValue, PRBool aNotify)
{
nsEventStates states;
if (aNameSpaceID == kNameSpaceID_None) {
if (aName == nsGkAtoms::type) {
if (!aValue) {
mType = kButtonDefaultType->value;
}
states |= NS_EVENT_STATE_MOZ_SUBMITINVALID;
}
if (aNotify && !states.IsEmpty()) {
nsIDocument* doc = GetCurrentDoc();
if (doc) {
doc->ContentStateChanged(this, states);
}
UpdateState(aNotify);
}
}

View File

@ -54,6 +54,9 @@ nsHTMLFieldSetElement::nsHTMLFieldSetElement(already_AddRefed<nsINodeInfo> aNode
{
// <fieldset> is always barred from constraint validation.
SetBarredFromConstraintValidation(PR_TRUE);
// We start out enabled
AddStatesSilently(NS_EVENT_STATE_ENABLED);
}
nsHTMLFieldSetElement::~nsHTMLFieldSetElement()
@ -127,7 +130,7 @@ nsHTMLFieldSetElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
PRUint32 length = mElements->Length(PR_TRUE);
for (PRUint32 i=0; i<length; ++i) {
static_cast<nsGenericHTMLFormElement*>(mElements->GetNodeAt(i))
->FieldSetDisabledChanged(nsEventStates(), aNotify);
->FieldSetDisabledChanged(aNotify);
}
}

View File

@ -382,21 +382,14 @@ nsHTMLFormElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
if (aName == nsGkAtoms::novalidate && aNameSpaceID == kNameSpaceID_None) {
// Update all form elements states because they might be [no longer]
// affected by :-moz-ui-valid or :-moz-ui-invalid.
nsIDocument* doc = GetCurrentDoc();
if (doc) {
for (PRUint32 i = 0, length = mControls->mElements.Length();
i < length; ++i) {
doc->ContentStateChanged(mControls->mElements[i],
NS_EVENT_STATE_MOZ_UI_VALID |
NS_EVENT_STATE_MOZ_UI_INVALID);
}
for (PRUint32 i = 0, length = mControls->mElements.Length();
i < length; ++i) {
mControls->mElements[i]->UpdateState(true);
}
for (PRUint32 i = 0, length = mControls->mNotInElements.Length();
i < length; ++i) {
doc->ContentStateChanged(mControls->mNotInElements[i],
NS_EVENT_STATE_MOZ_UI_VALID |
NS_EVENT_STATE_MOZ_UI_INVALID);
}
for (PRUint32 i = 0, length = mControls->mNotInElements.Length();
i < length; ++i) {
mControls->mNotInElements[i]->UpdateState(true);
}
}
@ -505,8 +498,7 @@ CollectOrphans(nsINode* aRemovalRoot, nsTArray<nsGenericHTMLFormElement*> aArray
#endif
)
{
// Prepare document update batch.
nsIDocument* doc = aArray.IsEmpty() ? nsnull : aArray[0]->GetCurrentDoc();
// Put a script blocker around all the notifications we're about to do.
nsAutoScriptBlocker scriptBlocker;
// Walk backwards so that if we remove elements we can just keep iterating
@ -527,20 +519,8 @@ CollectOrphans(nsINode* aRemovalRoot, nsTArray<nsGenericHTMLFormElement*> aArray
if (!nsContentUtils::ContentIsDescendantOf(node, aRemovalRoot)) {
node->ClearForm(PR_TRUE);
// When a form control loses its form owner, :-moz-ui-invalid and
// :-moz-ui-valid might not apply any more.
nsEventStates states = NS_EVENT_STATE_MOZ_UI_VALID |
NS_EVENT_STATE_MOZ_UI_INVALID;
// In addition, submit controls shouldn't have
// NS_EVENT_STATE_MOZ_SUBMITINVALID applying if they do not have a form.
if (node->IsSubmitControl()) {
states |= NS_EVENT_STATE_MOZ_SUBMITINVALID;
}
if (doc) {
doc->ContentStateChanged(node, states);
}
// When a form control loses its form owner, its state can change.
node->UpdateState(true);
#ifdef DEBUG
removed = PR_TRUE;
#endif
@ -1203,7 +1183,7 @@ nsHTMLFormElement::AddElement(nsGenericHTMLFormElement* aChild,
// unless it replaces what's in the slot. If it _does_ replace what's in
// the slot, it becomes the default submit if either the default submit is
// what's in the slot or the child is earlier than the default submit.
nsIFormControl* oldDefaultSubmit = mDefaultSubmitElement;
nsGenericHTMLFormElement* oldDefaultSubmit = mDefaultSubmitElement;
if (!*firstSubmitSlot ||
(!lastElement &&
CompareFormControlPosition(aChild, *firstSubmitSlot, this) < 0)) {
@ -1226,16 +1206,9 @@ nsHTMLFormElement::AddElement(nsGenericHTMLFormElement* aChild,
// Notify that the state of the previous default submit element has changed
// if the element which is the default submit element has changed. The new
// default submit element is responsible for its own ContentStateChanged
// call.
if (aNotify && oldDefaultSubmit &&
oldDefaultSubmit != mDefaultSubmitElement) {
nsIDocument* document = GetCurrentDoc();
if (document) {
nsAutoScriptBlocker scriptBlocker;
nsCOMPtr<nsIContent> oldElement(do_QueryInterface(oldDefaultSubmit));
document->ContentStateChanged(oldElement, NS_EVENT_STATE_DEFAULT);
}
// default submit element is responsible for its own state update.
if (oldDefaultSubmit && oldDefaultSubmit != mDefaultSubmitElement) {
oldDefaultSubmit->UpdateState(aNotify);
}
}
@ -1368,12 +1341,7 @@ nsHTMLFormElement::HandleDefaultSubmitRemoval()
// Notify about change if needed.
if (mDefaultSubmitElement) {
nsIDocument* document = GetCurrentDoc();
if (document) {
nsAutoScriptBlocker scriptBlocker;
document->ContentStateChanged(mDefaultSubmitElement,
NS_EVENT_STATE_DEFAULT);
}
mDefaultSubmitElement->UpdateState(true);
}
}
@ -1742,40 +1710,33 @@ nsHTMLFormElement::CheckValidFormSubmission()
if (!mEverTriedInvalidSubmit) {
mEverTriedInvalidSubmit = true;
nsIDocument* doc = GetCurrentDoc();
if (doc) {
/*
* We are going to call ContentStateChanged assuming elements want to
* be notified because we can't know.
* Submissions shouldn't happen during parsing so it _should_ be safe.
*/
/*
* We are going to call update states assuming elements want to
* be notified because we can't know.
* Submissions shouldn't happen during parsing so it _should_ be safe.
*/
nsAutoScriptBlocker scriptBlocker;
nsAutoScriptBlocker scriptBlocker;
for (PRUint32 i = 0, length = mControls->mElements.Length();
i < length; ++i) {
// Input elements can trigger a form submission and we want to
// update the style in that case.
if (mControls->mElements[i]->IsHTML(nsGkAtoms::input) &&
nsContentUtils::IsFocusedContent(mControls->mElements[i])) {
static_cast<nsHTMLInputElement*>(mControls->mElements[i])
->UpdateValidityUIBits(true);
}
doc->ContentStateChanged(mControls->mElements[i],
NS_EVENT_STATE_MOZ_UI_VALID |
NS_EVENT_STATE_MOZ_UI_INVALID);
for (PRUint32 i = 0, length = mControls->mElements.Length();
i < length; ++i) {
// Input elements can trigger a form submission and we want to
// update the style in that case.
if (mControls->mElements[i]->IsHTML(nsGkAtoms::input) &&
nsContentUtils::IsFocusedContent(mControls->mElements[i])) {
static_cast<nsHTMLInputElement*>(mControls->mElements[i])
->UpdateValidityUIBits(true);
}
// Because of backward compatibility, <input type='image'> is not in
// elements but can be invalid.
// TODO: should probably be removed when bug 606491 will be fixed.
for (PRUint32 i = 0, length = mControls->mNotInElements.Length();
i < length; ++i) {
doc->ContentStateChanged(mControls->mNotInElements[i],
NS_EVENT_STATE_MOZ_UI_VALID |
NS_EVENT_STATE_MOZ_UI_INVALID);
}
mControls->mElements[i]->UpdateState(true);
}
// Because of backward compatibility, <input type='image'> is not in
// elements but can be invalid.
// TODO: should probably be removed when bug 606491 will be fixed.
for (PRUint32 i = 0, length = mControls->mNotInElements.Length();
i < length; ++i) {
mControls->mNotInElements[i]->UpdateState(true);
}
}
@ -1823,13 +1784,8 @@ nsHTMLFormElement::UpdateValidity(PRBool aElementValidity)
return;
}
nsIDocument* doc = GetCurrentDoc();
if (!doc) {
return;
}
/*
* We are going to call ContentStateChanged assuming submit controls want to
* We are going to update states assuming submit controls want to
* be notified because we can't know.
* UpdateValidity shouldn't be called so much during parsing so it _should_
* be safe.
@ -1841,8 +1797,7 @@ nsHTMLFormElement::UpdateValidity(PRBool aElementValidity)
for (PRUint32 i = 0, length = mControls->mElements.Length();
i < length; ++i) {
if (mControls->mElements[i]->IsSubmitControl()) {
doc->ContentStateChanged(mControls->mElements[i],
NS_EVENT_STATE_MOZ_SUBMITINVALID);
mControls->mElements[i]->UpdateState(true);
}
}
@ -1851,8 +1806,7 @@ nsHTMLFormElement::UpdateValidity(PRBool aElementValidity)
PRUint32 length = mControls->mNotInElements.Length();
for (PRUint32 i = 0; i < length; ++i) {
if (mControls->mNotInElements[i]->IsSubmitControl()) {
doc->ContentStateChanged(mControls->mNotInElements[i],
NS_EVENT_STATE_MOZ_SUBMITINVALID);
mControls->mNotInElements[i]->UpdateState(true);
}
}
}

View File

@ -180,6 +180,8 @@ NS_NewHTMLImageElement(already_AddRefed<nsINodeInfo> aNodeInfo,
nsHTMLImageElement::nsHTMLImageElement(already_AddRefed<nsINodeInfo> aNodeInfo)
: nsGenericHTMLElement(aNodeInfo)
{
// We start out broken
AddStatesSilently(NS_EVENT_STATE_BROKEN);
}
nsHTMLImageElement::~nsHTMLImageElement()
@ -506,7 +508,10 @@ nsHTMLImageElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
NS_ENSURE_SUCCESS(rv, rv);
if (HasAttr(kNameSpaceID_None, nsGkAtoms::src)) {
// FIXME: Bug 660963 it would be nice if we could just have
// ClearBrokenState update our state and do it fast...
ClearBrokenState();
RemoveStatesSilently(NS_EVENT_STATE_BROKEN);
// If loading is temporarily disabled, don't even launch MaybeLoadImage.
// Otherwise MaybeLoadImage may run later when someone has reenabled
// loading.

View File

@ -631,6 +631,15 @@ nsHTMLInputElement::nsHTMLInputElement(already_AddRefed<nsINodeInfo> aNodeInfo,
if (!gUploadLastDir)
nsHTMLInputElement::InitUploadLastDir();
// Set up our default state. By default we're enabled (since we're
// a control type that can be disabled but not actually disabled
// right now), optional, and valid. We are NOT readwrite by default
// until someone calls UpdateEditableState on us, apparently! Also
// by default we don't have to show validity UI and so forth.
AddStatesSilently(NS_EVENT_STATE_ENABLED |
NS_EVENT_STATE_OPTIONAL |
NS_EVENT_STATE_VALID);
}
nsHTMLInputElement::~nsHTMLInputElement()
@ -800,9 +809,6 @@ nsHTMLInputElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
const nsAString* aValue,
PRBool aNotify)
{
// States changes that have to be passed to ContentStateChanged().
nsEventStates states;
if (aNameSpaceID == kNameSpaceID_None) {
//
// When name or type changes, radio should be added to radio group.
@ -815,8 +821,6 @@ nsHTMLInputElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
(mForm || !(GET_BOOLBIT(mBitField, BF_PARSER_CREATING)))) {
AddedToRadioGroup();
UpdateValueMissingValidityStateForRadio(false);
states |= NS_EVENT_STATE_VALID | NS_EVENT_STATE_INVALID |
NS_EVENT_STATE_REQUIRED | NS_EVENT_STATE_OPTIONAL;
}
// If @value is changed and BF_VALUE_CHANGED is false, @value is the value
@ -883,30 +887,6 @@ nsHTMLInputElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
LoadImage(src, PR_FALSE, aNotify);
}
}
// Changing type affects the applicability of some states. Just notify
// on them all now, just in case. Note that we can't rely on the
// notifications LoadImage or CancelImageRequests might have sent, because
// those didn't include all the possibly-changed states in the mask. We
// have to do this here because we just updated mType, so the code in
// nsGenericElement::SetAttrAndNotify didn't see the new states.
states |= NS_EVENT_STATE_CHECKED |
NS_EVENT_STATE_DEFAULT |
NS_EVENT_STATE_BROKEN |
NS_EVENT_STATE_USERDISABLED |
NS_EVENT_STATE_SUPPRESSED |
NS_EVENT_STATE_LOADING |
NS_EVENT_STATE_MOZ_READONLY |
NS_EVENT_STATE_MOZ_READWRITE |
NS_EVENT_STATE_REQUIRED |
NS_EVENT_STATE_OPTIONAL |
NS_EVENT_STATE_VALID |
NS_EVENT_STATE_INVALID |
NS_EVENT_STATE_MOZ_UI_VALID |
NS_EVENT_STATE_MOZ_UI_INVALID |
NS_EVENT_STATE_INDETERMINATE |
NS_EVENT_STATE_MOZ_PLACEHOLDER |
NS_EVENT_STATE_MOZ_SUBMITINVALID;
}
if (mType == NS_FORM_INPUT_RADIO && aName == nsGkAtoms::required) {
@ -929,34 +909,14 @@ nsHTMLInputElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
if (aName == nsGkAtoms::readonly || aName == nsGkAtoms::disabled) {
UpdateBarredFromConstraintValidation();
}
states |= NS_EVENT_STATE_REQUIRED | NS_EVENT_STATE_OPTIONAL |
NS_EVENT_STATE_VALID | NS_EVENT_STATE_INVALID |
NS_EVENT_STATE_MOZ_UI_VALID | NS_EVENT_STATE_MOZ_UI_INVALID;
} else if (MaxLengthApplies() && aName == nsGkAtoms::maxlength) {
UpdateTooLongValidityState();
states |= NS_EVENT_STATE_VALID | NS_EVENT_STATE_INVALID |
NS_EVENT_STATE_MOZ_UI_VALID | NS_EVENT_STATE_MOZ_UI_INVALID;
} else if (aName == nsGkAtoms::pattern) {
UpdatePatternMismatchValidityState();
states |= NS_EVENT_STATE_VALID | NS_EVENT_STATE_INVALID |
NS_EVENT_STATE_MOZ_UI_VALID | NS_EVENT_STATE_MOZ_UI_INVALID;
}
if (aNotify) {
nsIDocument* doc = GetCurrentDoc();
if (aName == nsGkAtoms::type) {
UpdateEditableState();
} else if (IsSingleLineTextControl(PR_FALSE) && aName == nsGkAtoms::readonly) {
UpdateEditableState();
states |= NS_EVENT_STATE_MOZ_READONLY | NS_EVENT_STATE_MOZ_READWRITE;
}
if (doc && !states.IsEmpty()) {
doc->ContentStateChanged(this, states);
}
}
UpdateEditableState(aNotify);
UpdateState(aNotify);
}
return nsGenericHTMLFormElement::AfterSetAttr(aNameSpaceID, aName,
@ -1023,12 +983,7 @@ nsHTMLInputElement::SetIndeterminateInternal(PRBool aValue,
frame->InvalidateFrameSubtree();
}
// Notify the document so it can update :indeterminate pseudoclass rules
nsIDocument* document = GetCurrentDoc();
if (document) {
nsAutoScriptBlocker scriptBlocker;
document->ContentStateChanged(this, NS_EVENT_STATE_INDETERMINATE);
}
UpdateState(true);
return NS_OK;
}
@ -1441,11 +1396,7 @@ nsHTMLInputElement::SetValueInternal(const nsAString& aValue,
if (PlaceholderApplies() &&
HasAttr(kNameSpaceID_None, nsGkAtoms::placeholder)) {
nsIDocument* doc = GetCurrentDoc();
if (doc) {
nsAutoScriptBlocker scriptBlocker;
doc->ContentStateChanged(this, NS_EVENT_STATE_MOZ_PLACEHOLDER);
}
UpdateState(true);
}
return NS_OK;
@ -1480,12 +1431,7 @@ nsHTMLInputElement::SetValueChanged(PRBool aValueChanged)
}
if (valueChangedBefore != aValueChanged) {
nsIDocument* doc = GetCurrentDoc();
if (doc) {
nsAutoScriptBlocker scriptBlocker;
doc->ContentStateChanged(this, NS_EVENT_STATE_MOZ_UI_VALID |
NS_EVENT_STATE_MOZ_UI_INVALID);
}
UpdateState(true);
}
return NS_OK;
@ -1529,13 +1475,7 @@ nsHTMLInputElement::SetCheckedChangedInternal(PRBool aCheckedChanged)
// This method can't be called when we are not authorized to notify
// so we do not need a aNotify parameter.
if (checkedChangedBefore != aCheckedChanged) {
nsIDocument* document = GetCurrentDoc();
if (document) {
nsAutoScriptBlocker scriptBlocker;
document->ContentStateChanged(this,
NS_EVENT_STATE_MOZ_UI_VALID |
NS_EVENT_STATE_MOZ_UI_INVALID);
}
UpdateState(true);
}
}
@ -1729,17 +1669,11 @@ nsHTMLInputElement::SetCheckedInternal(PRBool aChecked, PRBool aNotify)
}
}
UpdateAllValidityStates(aNotify);
// Notify the document that the CSS :checked pseudoclass for this element
// has changed state.
if (aNotify) {
nsIDocument* document = GetCurrentDoc();
if (document) {
nsAutoScriptBlocker scriptBlocker;
document->ContentStateChanged(this, NS_EVENT_STATE_CHECKED);
}
}
UpdateAllValidityStates(aNotify);
UpdateState(aNotify);
}
NS_IMETHODIMP
@ -2057,30 +1991,10 @@ nsHTMLInputElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
if (aVisitor.mEvent->message == NS_FOCUS_CONTENT ||
aVisitor.mEvent->message == NS_BLUR_CONTENT) {
nsEventStates states;
if (aVisitor.mEvent->message == NS_FOCUS_CONTENT) {
UpdateValidityUIBits(true);
UpdateValidityUIBits(aVisitor.mEvent->message == NS_FOCUS_CONTENT);
// We don't have to update NS_EVENT_STATE_MOZ_UI_INVALID nor
// NS_EVENT_STATE_MOZ_UI_VALID given that the states should not change.
} else { // NS_BLUR_CONTENT
UpdateValidityUIBits(false);
states |= NS_EVENT_STATE_MOZ_UI_VALID | NS_EVENT_STATE_MOZ_UI_INVALID;
}
if (PlaceholderApplies() &&
HasAttr(kNameSpaceID_None, nsGkAtoms::placeholder)) {
// TODO: checking if the value is empty could be a good idea but we do not
// have a simple way to do that, see bug 585100
states |= NS_EVENT_STATE_MOZ_PLACEHOLDER;
}
nsIDocument* doc = GetCurrentDoc();
if (doc) {
nsAutoScriptBlocker scriptBlocker;
doc->ContentStateChanged(this, states);
}
UpdateState(true);
}
// ignore the activate event fired by the "Browse..." button
@ -2455,7 +2369,10 @@ nsHTMLInputElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
// Our base URI may have changed; claim that our URI changed, and the
// nsImageLoadingContent will decide whether a new image load is warranted.
if (HasAttr(kNameSpaceID_None, nsGkAtoms::src)) {
// FIXME: Bug 660963 it would be nice if we could just have
// ClearBrokenState update our state and do it fast...
ClearBrokenState();
RemoveStatesSilently(NS_EVENT_STATE_BROKEN);
nsContentUtils::AddScriptRunner(
NS_NewRunnableMethod(this, &nsHTMLInputElement::MaybeLoadImage));
}
@ -2476,6 +2393,9 @@ nsHTMLInputElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
// (call done before).
UpdateBarredFromConstraintValidation();
// And now make sure our state is up to date
UpdateState(false);
return rv;
}
@ -2498,6 +2418,9 @@ nsHTMLInputElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
UpdateValueMissingValidityState();
// We might be no longer disabled because of parent chain changed.
UpdateBarredFromConstraintValidation();
// And now make sure our state is up to date
UpdateState(false);
}
void
@ -3654,14 +3577,7 @@ nsHTMLInputElement::SetCustomValidity(const nsAString& aError)
{
nsIConstraintValidation::SetCustomValidity(aError);
nsIDocument* doc = GetCurrentDoc();
if (doc) {
nsAutoScriptBlocker scriptBlocker;
doc->ContentStateChanged(this, NS_EVENT_STATE_INVALID |
NS_EVENT_STATE_VALID |
NS_EVENT_STATE_MOZ_UI_INVALID |
NS_EVENT_STATE_MOZ_UI_VALID);
}
UpdateState(true);
return NS_OK;
}
@ -3872,15 +3788,8 @@ nsHTMLInputElement::UpdateAllValidityStates(PRBool aNotify)
UpdateTypeMismatchValidityState();
UpdatePatternMismatchValidityState();
if (validBefore != IsValid() && aNotify) {
nsIDocument* doc = GetCurrentDoc();
if (doc) {
nsAutoScriptBlocker scriptBlocker;
doc->ContentStateChanged(this,
NS_EVENT_STATE_VALID | NS_EVENT_STATE_INVALID |
NS_EVENT_STATE_MOZ_UI_VALID |
NS_EVENT_STATE_MOZ_UI_INVALID);
}
if (validBefore != IsValid()) {
UpdateState(aNotify);
}
}
@ -4173,26 +4082,20 @@ nsHTMLInputElement::OnValueChanged(PRBool aNotify)
// :-moz-placeholder pseudo-class may change when the value changes.
// However, we don't want to waste cycles if the state doesn't apply.
if (aNotify && PlaceholderApplies()
if (PlaceholderApplies()
&& HasAttr(kNameSpaceID_None, nsGkAtoms::placeholder)
&& !nsContentUtils::IsFocusedContent((nsIContent*)(this))) {
nsIDocument* doc = GetCurrentDoc();
if (doc) {
nsAutoScriptBlocker scriptBlocker;
doc->ContentStateChanged(this, NS_EVENT_STATE_MOZ_PLACEHOLDER);
}
UpdateState(aNotify);
}
}
void
nsHTMLInputElement::FieldSetDisabledChanged(nsEventStates aStates, PRBool aNotify)
nsHTMLInputElement::FieldSetDisabledChanged(PRBool aNotify)
{
UpdateValueMissingValidityState();
UpdateBarredFromConstraintValidation();
aStates |= NS_EVENT_STATE_VALID | NS_EVENT_STATE_INVALID |
NS_EVENT_STATE_MOZ_UI_VALID | NS_EVENT_STATE_MOZ_UI_INVALID;
nsGenericHTMLFormElement::FieldSetDisabledChanged(aStates, aNotify);
nsGenericHTMLFormElement::FieldSetDisabledChanged(aNotify);
}
PRInt32

View File

@ -161,7 +161,7 @@ public:
virtual PRBool RestoreState(nsPresState* aState);
virtual PRBool AllowDrop();
virtual void FieldSetDisabledChanged(nsEventStates aStates, PRBool aNotify);
virtual void FieldSetDisabledChanged(PRBool aNotify);
// nsIContent
virtual PRBool IsHTMLFocusable(PRBool aWithMouse, PRBool *aIsFocusable, PRInt32 *aTabIndex);
@ -239,9 +239,9 @@ public:
NS_IMETHOD FireAsyncClickHandler();
virtual void UpdateEditableState()
virtual void UpdateEditableState(PRBool aNotify)
{
return UpdateEditableFormControlState();
return UpdateEditableFormControlState(aNotify);
}
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsHTMLInputElement,

View File

@ -163,6 +163,9 @@ nsHTMLObjectElement::nsHTMLObjectElement(already_AddRefed<nsINodeInfo> aNodeInfo
// <object> is always barred from constraint validation.
SetBarredFromConstraintValidation(PR_TRUE);
// By default we're in the loading state
AddStatesSilently(NS_EVENT_STATE_LOADING);
}
nsHTMLObjectElement::~nsHTMLObjectElement()

View File

@ -101,6 +101,8 @@ NS_IMPL_NS_NEW_HTML_ELEMENT(OptGroup)
nsHTMLOptGroupElement::nsHTMLOptGroupElement(already_AddRefed<nsINodeInfo> aNodeInfo)
: nsGenericHTMLElement(aNodeInfo)
{
// We start off enabled
AddStatesSilently(NS_EVENT_STATE_ENABLED);
}
nsHTMLOptGroupElement::~nsHTMLOptGroupElement()

View File

@ -120,6 +120,8 @@ nsHTMLOptionElement::nsHTMLOptionElement(already_AddRefed<nsINodeInfo> aNodeInfo
mIsSelected(PR_FALSE),
mIsInSetDefaultSelected(PR_FALSE)
{
// We start off enabled
AddStatesSilently(NS_EVENT_STATE_ENABLED);
}
nsHTMLOptionElement::~nsHTMLOptionElement()
@ -169,14 +171,10 @@ nsHTMLOptionElement::SetSelectedInternal(PRBool aValue, PRBool aNotify)
mSelectedChanged = PR_TRUE;
mIsSelected = aValue;
// When mIsInSetDefaultSelected is true, the notification will be handled by
// When mIsInSetDefaultSelected is true, the state change will be handled by
// SetAttr/UnsetAttr.
if (aNotify && !mIsInSetDefaultSelected) {
nsIDocument* document = GetCurrentDoc();
if (document) {
nsAutoScriptBlocker scriptBlocker;
document->ContentStateChanged(this, NS_EVENT_STATE_CHECKED);
}
if (!mIsInSetDefaultSelected) {
UpdateState(aNotify);
}
}

View File

@ -86,6 +86,10 @@ public:
nsEventStates IntrinsicState() const;
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
PRBool aCompileEventHandlers);
// This function is called when a callback function from nsIMutationObserver
// has to be used to update the defaultValue attribute.
void DescendantsChanged();
@ -120,6 +124,9 @@ nsHTMLOutputElement::nsHTMLOutputElement(already_AddRefed<nsINodeInfo> aNodeInfo
, mValueModeFlag(eModeDefault)
{
AddMutationObserver(this);
// We start out valid and ui-valid (since we have no form).
AddStatesSilently(NS_EVENT_STATE_VALID | NS_EVENT_STATE_MOZ_UI_VALID);
}
nsHTMLOutputElement::~nsHTMLOutputElement()
@ -157,14 +164,7 @@ nsHTMLOutputElement::SetCustomValidity(const nsAString& aError)
{
nsIConstraintValidation::SetCustomValidity(aError);
nsIDocument* doc = GetCurrentDoc();
if (doc) {
nsAutoScriptBlocker scriptBlocker;
doc->ContentStateChanged(this, NS_EVENT_STATE_INVALID |
NS_EVENT_STATE_VALID |
NS_EVENT_STATE_MOZ_UI_INVALID |
NS_EVENT_STATE_MOZ_UI_VALID);
}
UpdateState(true);
return NS_OK;
}
@ -222,6 +222,26 @@ nsHTMLOutputElement::IntrinsicState() const
return states;
}
nsresult
nsHTMLOutputElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
PRBool aCompileEventHandlers)
{
nsresult rv = nsGenericHTMLFormElement::BindToTree(aDocument, aParent,
aBindingParent,
aCompileEventHandlers);
NS_ENSURE_SUCCESS(rv, rv);
// Unfortunately, we can actually end up having to change our state
// as a result of being bound to a tree even from the parser: we
// might end up a in a novalidate form, and unlike other form
// controls that on its own is enough to make change ui-valid state.
// So just go ahead and update our state now.
UpdateState(false);
return rv;
}
NS_IMETHODIMP
nsHTMLOutputElement::GetForm(nsIDOMHTMLFormElement** aForm)
{

View File

@ -102,6 +102,8 @@ NS_IMPL_NS_NEW_HTML_ELEMENT(Progress)
nsHTMLProgressElement::nsHTMLProgressElement(already_AddRefed<nsINodeInfo> aNodeInfo)
: nsGenericHTMLFormElement(aNodeInfo)
{
// We start out indeterminate
AddStatesSilently(NS_EVENT_STATE_INDETERMINATE);
}
nsHTMLProgressElement::~nsHTMLProgressElement()

View File

@ -156,6 +156,11 @@ nsHTMLSelectElement::nsHTMLSelectElement(already_AddRefed<nsINodeInfo> aNodeInfo
// DoneAddingChildren() will be called later if it's from the parser,
// otherwise it is
// Set up our default state: enabled, optional, and valid.
AddStatesSilently(NS_EVENT_STATE_ENABLED |
NS_EVENT_STATE_OPTIONAL |
NS_EVENT_STATE_VALID);
}
nsHTMLSelectElement::~nsHTMLSelectElement()
@ -203,14 +208,7 @@ nsHTMLSelectElement::SetCustomValidity(const nsAString& aError)
{
nsIConstraintValidation::SetCustomValidity(aError);
nsIDocument* doc = GetCurrentDoc();
if (doc) {
nsAutoScriptBlocker scriptBlocker;
doc->ContentStateChanged(this, NS_EVENT_STATE_INVALID |
NS_EVENT_STATE_VALID |
NS_EVENT_STATE_MOZ_UI_INVALID |
NS_EVENT_STATE_MOZ_UI_VALID);
}
UpdateState(true);
return NS_OK;
}
@ -355,16 +353,7 @@ nsHTMLSelectElement::RemoveOptionsFromList(nsIContent* aOptions,
// option.
UpdateValueMissingValidityState();
if (aNotify) {
nsIDocument* doc = GetCurrentDoc();
if (doc) {
nsAutoScriptBlocker scriptBlocker;
doc->ContentStateChanged(this, NS_EVENT_STATE_VALID |
NS_EVENT_STATE_INVALID |
NS_EVENT_STATE_MOZ_UI_INVALID |
NS_EVENT_STATE_MOZ_UI_VALID);
}
}
UpdateState(aNotify);
}
}
@ -888,16 +877,7 @@ nsHTMLSelectElement::OnOptionSelected(nsISelectControlFrame* aSelectFrame,
}
UpdateValueMissingValidityState();
if (aNotify) {
nsIDocument* doc = GetCurrentDoc();
if (doc) {
nsAutoScriptBlocker scriptBlocker;
doc->ContentStateChanged(this, NS_EVENT_STATE_VALID |
NS_EVENT_STATE_INVALID |
NS_EVENT_STATE_MOZ_UI_INVALID |
NS_EVENT_STATE_MOZ_UI_VALID);
}
}
UpdateState(aNotify);
}
void
@ -1321,16 +1301,7 @@ nsHTMLSelectElement::SelectSomething(PRBool aNotify)
NS_ENSURE_SUCCESS(rv, PR_FALSE);
UpdateValueMissingValidityState();
if (aNotify) {
nsIDocument* doc = GetCurrentDoc();
if (doc) {
nsAutoScriptBlocker scriptBlocker;
doc->ContentStateChanged(this, NS_EVENT_STATE_VALID |
NS_EVENT_STATE_INVALID |
NS_EVENT_STATE_MOZ_UI_INVALID |
NS_EVENT_STATE_MOZ_UI_VALID);
}
}
UpdateState(aNotify);
return PR_TRUE;
}
@ -1351,8 +1322,13 @@ nsHTMLSelectElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
// If there is a disabled fieldset in the parent chain, the element is now
// barred from constraint validation.
// XXXbz is this still needed now that fieldset changes always call
// FieldSetDisabledChanged?
UpdateBarredFromConstraintValidation();
// And now make sure our state is up to date
UpdateState(false);
return rv;
}
@ -1362,7 +1338,12 @@ nsHTMLSelectElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
nsGenericHTMLFormElement::UnbindFromTree(aDeep, aNullParent);
// We might be no longer disabled because our parent chain changed.
// XXXbz is this still needed now that fieldset changes always call
// FieldSetDisabledChanged?
UpdateBarredFromConstraintValidation();
// And now make sure our state is up to date
UpdateState(false);
}
nsresult
@ -1382,26 +1363,14 @@ nsresult
nsHTMLSelectElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
const nsAString* aValue, PRBool aNotify)
{
nsEventStates states;
if (aNameSpaceID == kNameSpaceID_None) {
if (aName == nsGkAtoms::disabled) {
UpdateBarredFromConstraintValidation();
states |= NS_EVENT_STATE_VALID | NS_EVENT_STATE_INVALID |
NS_EVENT_STATE_MOZ_UI_VALID | NS_EVENT_STATE_MOZ_UI_INVALID;
} else if (aName == nsGkAtoms::required) {
UpdateValueMissingValidityState();
states |= NS_EVENT_STATE_VALID | NS_EVENT_STATE_INVALID |
NS_EVENT_STATE_MOZ_UI_VALID | NS_EVENT_STATE_MOZ_UI_INVALID;
}
}
if (aNotify && !states.IsEmpty()) {
nsIDocument* doc = GetCurrentDoc();
if (doc) {
nsAutoScriptBlocker scriptBlocker;
doc->ContentStateChanged(this, states);
}
UpdateState(aNotify);
}
return nsGenericHTMLFormElement::AfterSetAttr(aNameSpaceID, aName,
@ -1470,6 +1439,9 @@ nsHTMLSelectElement::DoneAddingChildren(PRBool aHaveNotified)
// with an empty value. We have to make sure the select element updates it's
// validity state to take this into account.
UpdateValueMissingValidityState();
// And now make sure we update our content state too
UpdateState(aHaveNotified);
}
mDefaultSelectionSet = PR_TRUE;
@ -1573,12 +1545,7 @@ nsHTMLSelectElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
mCanShowInvalidUI = PR_TRUE;
mCanShowValidUI = PR_TRUE;
nsIDocument* doc = GetCurrentDoc();
if (doc) {
nsAutoScriptBlocker scriptBlocker;
doc->ContentStateChanged(this, NS_EVENT_STATE_MOZ_UI_VALID |
NS_EVENT_STATE_MOZ_UI_INVALID);
}
UpdateState(true);
}
return nsGenericHTMLFormElement::PostHandleEvent(aVisitor);
@ -2287,13 +2254,11 @@ nsHTMLSelectElement::UpdateBarredFromConstraintValidation()
}
void
nsHTMLSelectElement::FieldSetDisabledChanged(nsEventStates aStates, PRBool aNotify)
nsHTMLSelectElement::FieldSetDisabledChanged(PRBool aNotify)
{
UpdateBarredFromConstraintValidation();
aStates |= NS_EVENT_STATE_VALID | NS_EVENT_STATE_INVALID |
NS_EVENT_STATE_MOZ_UI_VALID | NS_EVENT_STATE_MOZ_UI_INVALID;
nsGenericHTMLFormElement::FieldSetDisabledChanged(aStates, aNotify);
nsGenericHTMLFormElement::FieldSetDisabledChanged(aNotify);
}
void
@ -2306,13 +2271,8 @@ nsHTMLSelectElement::SetSelectionChanged(PRBool aValue, PRBool aNotify)
PRBool previousSelectionChangedValue = mSelectionHasChanged;
mSelectionHasChanged = aValue;
if (aNotify && mSelectionHasChanged != previousSelectionChangedValue) {
nsIDocument* doc = GetCurrentDoc();
if (doc) {
nsAutoScriptBlocker scriptBlocker;
doc->ContentStateChanged(this, NS_EVENT_STATE_MOZ_UI_INVALID |
NS_EVENT_STATE_MOZ_UI_VALID);
}
if (mSelectionHasChanged != previousSelectionChangedValue) {
UpdateState(aNotify);
}
}

View File

@ -289,7 +289,7 @@ public:
NS_IMETHOD SaveState();
virtual PRBool RestoreState(nsPresState* aState);
virtual void FieldSetDisabledChanged(nsEventStates aStates, PRBool aNotify);
virtual void FieldSetDisabledChanged(PRBool aNotify);
nsEventStates IntrinsicState() const;

View File

@ -180,6 +180,9 @@ nsHTMLSharedObjectElement::nsHTMLSharedObjectElement(already_AddRefed<nsINodeInf
{
RegisterFreezableElement();
SetIsNetworkCreated(aFromParser == FROM_PARSER_NETWORK);
// By default we're in the loading state
AddStatesSilently(NS_EVENT_STATE_LOADING);
}
nsHTMLSharedObjectElement::~nsHTMLSharedObjectElement()

View File

@ -134,7 +134,7 @@ public:
NS_IMETHOD SaveState();
virtual PRBool RestoreState(nsPresState* aState);
virtual void FieldSetDisabledChanged(nsEventStates aStates, PRBool aNotify);
virtual void FieldSetDisabledChanged(PRBool aNotify);
virtual nsEventStates IntrinsicState() const;
@ -204,9 +204,9 @@ public:
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
virtual void UpdateEditableState()
virtual void UpdateEditableState(PRBool aNotify)
{
return UpdateEditableFormControlState();
return UpdateEditableFormControlState(aNotify);
}
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsHTMLTextAreaElement,
@ -321,6 +321,15 @@ nsHTMLTextAreaElement::nsHTMLTextAreaElement(already_AddRefed<nsINodeInfo> aNode
mState(new nsTextEditorState(this))
{
AddMutationObserver(this);
// Set up our default state. By default we're enabled (since we're
// a control type that can be disabled but not actually disabled
// right now), optional, and valid. We are NOT readwrite by default
// until someone calls UpdateEditableState on us, apparently! Also
// by default we don't have to show validity UI and so forth.
AddStatesSilently(NS_EVENT_STATE_ENABLED |
NS_EVENT_STATE_OPTIONAL |
NS_EVENT_STATE_VALID);
}
@ -587,18 +596,7 @@ nsHTMLTextAreaElement::SetValueChanged(PRBool aValueChanged)
}
if (mValueChanged != previousValue) {
nsEventStates states = NS_EVENT_STATE_MOZ_UI_VALID |
NS_EVENT_STATE_MOZ_UI_INVALID;
if (HasAttr(kNameSpaceID_None, nsGkAtoms::placeholder)) {
states |= NS_EVENT_STATE_MOZ_PLACEHOLDER;
}
nsIDocument* doc = GetCurrentDoc();
if (doc) {
nsAutoScriptBlocker scriptBlocker;
doc->ContentStateChanged(this, states);
}
UpdateState(true);
}
return NS_OK;
@ -747,8 +745,6 @@ nsHTMLTextAreaElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
if (aVisitor.mEvent->message == NS_FOCUS_CONTENT ||
aVisitor.mEvent->message == NS_BLUR_CONTENT) {
nsEventStates states;
if (aVisitor.mEvent->message == NS_FOCUS_CONTENT) {
// If the invalid UI is shown, we should show it while focusing (and
// update). Otherwise, we should not.
@ -757,26 +753,12 @@ nsHTMLTextAreaElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
// If neither invalid UI nor valid UI is shown, we shouldn't show the valid
// UI while typing.
mCanShowValidUI = ShouldShowValidityUI();
// We don't have to update NS_EVENT_STATE_MOZ_UI_INVALID nor
// NS_EVENT_STATE_MOZ_UI_VALID given that the states should not change.
} else { // NS_BLUR_CONTENT
mCanShowInvalidUI = PR_TRUE;
mCanShowValidUI = PR_TRUE;
states |= NS_EVENT_STATE_MOZ_UI_VALID | NS_EVENT_STATE_MOZ_UI_INVALID;
}
if (HasAttr(kNameSpaceID_None, nsGkAtoms::placeholder)) {
// TODO: checking if the value is empty could be a good idea but we do not
// have a simple way to do that, see bug 585100
states |= NS_EVENT_STATE_MOZ_PLACEHOLDER;
}
nsIDocument* doc = GetCurrentDoc();
if (doc) {
nsAutoScriptBlocker scriptBlocker;
doc->ContentStateChanged(this, states);
}
UpdateState(true);
}
// Reset the flag for other content besides this text field
@ -1116,6 +1098,9 @@ nsHTMLTextAreaElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
UpdateValueMissingValidityState();
UpdateBarredFromConstraintValidation();
// And now make sure our state is up to date
UpdateState(false);
return rv;
}
@ -1127,6 +1112,9 @@ nsHTMLTextAreaElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
// We might be no longer disabled because of parent chain changed.
UpdateValueMissingValidityState();
UpdateBarredFromConstraintValidation();
// And now make sure our state is up to date
UpdateState(false);
}
nsresult
@ -1194,8 +1182,6 @@ nsresult
nsHTMLTextAreaElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
const nsAString* aValue, PRBool aNotify)
{
nsEventStates states;
if (aNameSpaceID == kNameSpaceID_None) {
if (aName == nsGkAtoms::required || aName == nsGkAtoms::disabled ||
aName == nsGkAtoms::readonly) {
@ -1205,28 +1191,14 @@ nsHTMLTextAreaElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
if (aName == nsGkAtoms::readonly || aName == nsGkAtoms::disabled) {
UpdateBarredFromConstraintValidation();
}
states |= NS_EVENT_STATE_VALID | NS_EVENT_STATE_INVALID |
NS_EVENT_STATE_MOZ_UI_VALID | NS_EVENT_STATE_MOZ_UI_INVALID |
NS_EVENT_STATE_MOZ_SUBMITINVALID;
} else if (aName == nsGkAtoms::maxlength) {
UpdateTooLongValidityState();
states |= NS_EVENT_STATE_VALID | NS_EVENT_STATE_INVALID |
NS_EVENT_STATE_MOZ_UI_VALID | NS_EVENT_STATE_MOZ_UI_INVALID;
}
if (aNotify) {
nsIDocument* doc = GetCurrentDoc();
if (aName == nsGkAtoms::readonly) {
UpdateEditableState();
states |= NS_EVENT_STATE_MOZ_READONLY | NS_EVENT_STATE_MOZ_READWRITE;
}
if (doc && !states.IsEmpty()) {
doc->ContentStateChanged(this, states);
}
if (aName == nsGkAtoms::readonly) {
UpdateEditableState(aNotify);
}
UpdateState(aNotify);
}
return nsGenericHTMLFormElement::AfterSetAttr(aNameSpaceID, aName, aValue,
@ -1269,14 +1241,7 @@ nsHTMLTextAreaElement::SetCustomValidity(const nsAString& aError)
{
nsIConstraintValidation::SetCustomValidity(aError);
nsIDocument* doc = GetCurrentDoc();
if (doc) {
nsAutoScriptBlocker scriptBlocker;
doc->ContentStateChanged(this, NS_EVENT_STATE_INVALID |
NS_EVENT_STATE_VALID |
NS_EVENT_STATE_MOZ_UI_INVALID |
NS_EVENT_STATE_MOZ_UI_VALID);
}
UpdateState(true);
return NS_OK;
}
@ -1487,36 +1452,19 @@ nsHTMLTextAreaElement::OnValueChanged(PRBool aNotify)
UpdateTooLongValidityState();
UpdateValueMissingValidityState();
if (aNotify) {
nsEventStates states;
if (validBefore != IsValid()) {
states |= NS_EVENT_STATE_VALID | NS_EVENT_STATE_INVALID |
NS_EVENT_STATE_MOZ_UI_VALID | NS_EVENT_STATE_MOZ_UI_INVALID;
}
if (HasAttr(kNameSpaceID_None, nsGkAtoms::placeholder)
&& !nsContentUtils::IsFocusedContent((nsIContent*)(this))) {
states |= NS_EVENT_STATE_MOZ_PLACEHOLDER;
}
if (!states.IsEmpty()) {
nsIDocument* doc = GetCurrentDoc();
if (doc) {
nsAutoScriptBlocker scriptBlocker;
doc->ContentStateChanged(this, states);
}
}
if (validBefore != IsValid() ||
(HasAttr(kNameSpaceID_None, nsGkAtoms::placeholder)
&& !nsContentUtils::IsFocusedContent((nsIContent*)(this)))) {
UpdateState(aNotify);
}
}
void
nsHTMLTextAreaElement::FieldSetDisabledChanged(nsEventStates aStates, PRBool aNotify)
nsHTMLTextAreaElement::FieldSetDisabledChanged(PRBool aNotify)
{
UpdateValueMissingValidityState();
UpdateBarredFromConstraintValidation();
aStates |= NS_EVENT_STATE_VALID | NS_EVENT_STATE_INVALID |
NS_EVENT_STATE_MOZ_UI_VALID | NS_EVENT_STATE_MOZ_UI_INVALID;
nsGenericHTMLFormElement::FieldSetDisabledChanged(aStates, aNotify);
nsGenericHTMLFormElement::FieldSetDisabledChanged(aNotify);
}

View File

@ -83,13 +83,7 @@ nsRadioSetValueMissingState::Visit(nsIFormControl* aRadio)
input->SetValidityState(nsIConstraintValidation::VALIDITY_STATE_VALUE_MISSING,
mValidity);
nsIDocument* doc = input->GetCurrentDoc();
if (mNotify && doc) {
doc->ContentStateChanged(input, NS_EVENT_STATE_VALID |
NS_EVENT_STATE_INVALID |
NS_EVENT_STATE_MOZ_UI_VALID |
NS_EVENT_STATE_MOZ_UI_INVALID);
}
input->UpdateState(true);
return PR_TRUE;
}

View File

@ -63,7 +63,7 @@ function checkNotSufferingFromBeingMissing(element, doNotApply)
if (element.type != 'radio' && element.type != 'checkbox') {
is(window.getComputedStyle(element, null).getPropertyValue('background-color'),
doNotApply ? "rgb(0, 0, 0)" : "rgb(0, 255, 0)",
"The pseudo-class is not correctly applied");
"The pseudo-class is not correctly applied to " + element.localName);
}
}

View File

@ -2732,10 +2732,9 @@ NotifyEditableStateChange(nsINode *aNode, nsIDocument *aDocument,
PRUint32 i, n = aNode->GetChildCount();
for (i = 0; i < n; ++i) {
nsIContent *child = aNode->GetChildAt(i);
if (child->HasFlag(NODE_IS_EDITABLE) != aEditable) {
aDocument->ContentStateChanged(child,
NS_EVENT_STATE_MOZ_READONLY |
NS_EVENT_STATE_MOZ_READWRITE);
if (child->HasFlag(NODE_IS_EDITABLE) != aEditable &&
child->IsElement()) {
child->AsElement()->UpdateState(true);
}
NotifyEditableStateChange(child, aDocument, aEditable);
}

View File

@ -463,10 +463,5 @@ nsMathMLElement::SetIncrementScriptLevel(PRBool aIncrementScriptLevel,
NS_ASSERTION(aNotify, "We always notify!");
nsIDocument* doc = GetCurrentDoc();
if (!doc)
return;
nsAutoScriptBlocker scriptBlocker;
doc->ContentStateChanged(this, NS_EVENT_STATE_INCREMENT_SCRIPT_LEVEL);
UpdateState(true);
}

View File

@ -5377,6 +5377,8 @@ NS_INTERFACE_MAP_END_INHERITING(nsSVGFEImageElementBase)
nsSVGFEImageElement::nsSVGFEImageElement(already_AddRefed<nsINodeInfo> aNodeInfo)
: nsSVGFEImageElementBase(aNodeInfo)
{
// We start out broken
AddStatesSilently(NS_EVENT_STATE_BROKEN);
}
nsSVGFEImageElement::~nsSVGFEImageElement()
@ -5466,7 +5468,10 @@ nsSVGFEImageElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
NS_ENSURE_SUCCESS(rv, rv);
if (HasAttr(kNameSpaceID_XLink, nsGkAtoms::href)) {
// FIXME: Bug 660963 it would be nice if we could just have
// ClearBrokenState update our state and do it fast...
ClearBrokenState();
RemoveStatesSilently(NS_EVENT_STATE_BROKEN);
nsContentUtils::AddScriptRunner(
NS_NewRunnableMethod(this, &nsSVGFEImageElement::MaybeLoadSVGImage));
}

View File

@ -84,6 +84,8 @@ NS_INTERFACE_MAP_END_INHERITING(nsSVGImageElementBase)
nsSVGImageElement::nsSVGImageElement(already_AddRefed<nsINodeInfo> aNodeInfo)
: nsSVGImageElementBase(aNodeInfo)
{
// We start out broken
AddStatesSilently(NS_EVENT_STATE_BROKEN);
}
nsSVGImageElement::~nsSVGImageElement()
@ -207,7 +209,10 @@ nsSVGImageElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
NS_ENSURE_SUCCESS(rv, rv);
if (HasAttr(kNameSpaceID_XLink, nsGkAtoms::href)) {
// FIXME: Bug 660963 it would be nice if we could just have
// ClearBrokenState update our state and do it fast...
ClearBrokenState();
RemoveStatesSilently(NS_EVENT_STATE_BROKEN);
nsContentUtils::AddScriptRunner(
NS_NewRunnableMethod(this, &nsSVGImageElement::MaybeLoadSVGImage));
}

View File

@ -914,8 +914,7 @@ nsXTFElementWrapper::SetIntrinsicState(nsEventStates::InternalType aNewState)
"Both READONLY and READWRITE are being set. Yikes!!!");
mIntrinsicState = newStates;
nsAutoScriptBlocker scriptBlocker;
doc->ContentStateChanged(this, bits);
UpdateState(true);
return NS_OK;
}

View File

@ -245,6 +245,12 @@ nsXULElement::nsXULElement(already_AddRefed<nsINodeInfo> aNodeInfo)
mBindingParent(nsnull)
{
XUL_PROTOTYPE_ATTRIBUTE_METER(gNumElements);
// We may be READWRITE by default; check.
if (IsReadWriteTextElement()) {
AddStatesSilently(NS_EVENT_STATE_MOZ_READWRITE);
RemoveStatesSilently(NS_EVENT_STATE_MOZ_READONLY);
}
}
nsXULElement::nsXULSlots::nsXULSlots()
@ -892,6 +898,16 @@ nsXULElement::MaybeAddPopupListener(nsIAtom* aLocalName)
//
// nsIContent interface
//
void
nsXULElement::UpdateEditableState(PRBool aNotify)
{
// Don't call through to nsGenericElement here because the things
// it does don't work for cases when we're an editable control.
nsIContent *parent = GetParent();
SetEditableFlag(parent && parent->HasFlag(NODE_IS_EDITABLE));
UpdateState(aNotify);
}
nsresult
nsXULElement::BindToTree(nsIDocument* aDocument,
@ -1362,12 +1378,7 @@ nsXULElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, PRBool aNotify)
nsAutoString oldValue;
GetAttr(aNameSpaceID, aName, oldValue);
// When notifying, make sure to keep track of states whose value
// depends solely on the value of an attribute.
nsEventStates stateMask;
if (aNotify) {
stateMask = IntrinsicState();
nsNodeUtils::AttributeWillChange(this, aNameSpaceID, aName,
nsIDOMMutationEvent::REMOVAL);
}
@ -1467,11 +1478,9 @@ nsXULElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, PRBool aNotify)
}
UpdateState(aNotify);
if (aNotify) {
stateMask ^= IntrinsicState();
if (doc && !stateMask.IsEmpty()) {
doc->ContentStateChanged(this, stateMask);
}
nsNodeUtils::AttributeChanged(this, aNameSpaceID, aName,
nsIDOMMutationEvent::REMOVAL);
}
@ -2248,10 +2257,7 @@ nsXULElement::IntrinsicState() const
{
nsEventStates state = nsStyledElement::IntrinsicState();
const nsIAtom* tag = Tag();
if (GetNameSpaceID() == kNameSpaceID_XUL &&
(tag == nsGkAtoms::textbox || tag == nsGkAtoms::textarea) &&
!HasAttr(kNameSpaceID_None, nsGkAtoms::readonly)) {
if (IsReadWriteTextElement()) {
state |= NS_EVENT_STATE_MOZ_READWRITE;
state &= ~NS_EVENT_STATE_MOZ_READONLY;
}

View File

@ -651,6 +651,8 @@ protected:
virtual nsresult AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
const nsAString* aValue, PRBool aNotify);
virtual void UpdateEditableState(PRBool aNotify);
virtual PRBool ParseAttribute(PRInt32 aNamespaceID,
nsIAtom* aAttribute,
const nsAString& aValue,
@ -708,6 +710,15 @@ protected:
PRBool aIsScriptable);
friend class nsScriptEventHandlerOwnerTearoff;
bool IsReadWriteTextElement() const
{
const nsIAtom* tag = Tag();
return
GetNameSpaceID() == kNameSpaceID_XUL &&
(tag == nsGkAtoms::textbox || tag == nsGkAtoms::textarea) &&
!HasAttr(kNameSpaceID_None, nsGkAtoms::readonly);
}
};
#endif // nsXULElement_h__

View File

@ -66,6 +66,7 @@
using namespace mozilla;
using namespace mozilla::layers;
using namespace mozilla::dom;
nsIFrame*
NS_NewHTMLVideoFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
@ -101,7 +102,8 @@ nsVideoFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
nsnull,
kNameSpaceID_XHTML);
NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
mPosterImage = NS_NewHTMLImageElement(nodeInfo.forget());
Element* element = NS_NewHTMLImageElement(nodeInfo.forget());
mPosterImage = element;
NS_ENSURE_TRUE(mPosterImage, NS_ERROR_OUT_OF_MEMORY);
// Push a null JSContext on the stack so that code that runs
@ -118,6 +120,8 @@ nsVideoFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
NS_ENSURE_TRUE(imgContent, NS_ERROR_FAILURE);
imgContent->ForceImageState(PR_TRUE, 0);
// And now have it update its internal state
element->UpdateState(false);
nsresult res = UpdatePosterSource(PR_FALSE);
NS_ENSURE_SUCCESS(res,res);