зеркало из https://github.com/mozilla/pjs.git
Bug 564863: Speed up id/name handling by letting elements register/unregister themselves. r=smaug
This commit is contained in:
Родитель
748a8b1979
Коммит
35b6c8ca22
|
@ -1350,12 +1350,6 @@ public:
|
|||
*/
|
||||
static PRBool URIIsLocalFile(nsIURI *aURI);
|
||||
|
||||
/**
|
||||
* If aContent is an HTML element with a DOM level 0 'name', then
|
||||
* return the name. Otherwise return null.
|
||||
*/
|
||||
static nsIAtom* IsNamedItem(Element* aElement);
|
||||
|
||||
/**
|
||||
* Get the application manifest URI for this document. The manifest URI
|
||||
* is specified in the manifest= attribute of the root element of the
|
||||
|
|
|
@ -71,8 +71,8 @@ enum nsLinkState {
|
|||
|
||||
// IID for the nsIContent interface
|
||||
#define NS_ICONTENT_IID \
|
||||
{ 0x9e3b1a15, 0x72d5, 0x4e4f, \
|
||||
{ 0x8f, 0x4b, 0x75, 0xde, 0x07, 0x9c, 0x16, 0xdc } }
|
||||
{ 0x1450010b, 0xcdca, 0x451c, \
|
||||
{ 0xba, 0xdc, 0x07, 0x90, 0x89, 0x7b, 0xce, 0xb8 } }
|
||||
|
||||
/**
|
||||
* A node of content in a document's content model. This interface
|
||||
|
@ -778,7 +778,12 @@ public:
|
|||
* value of the null-namespace attribute whose name is given by
|
||||
* GetIDAttributeName(). This may be null if there is no ID.
|
||||
*/
|
||||
virtual nsIAtom* GetID() const = 0;
|
||||
nsIAtom* GetID() const {
|
||||
if (HasFlag(NODE_HAS_ID)) {
|
||||
return DoGetID();
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the class list of this content node (this corresponds to the
|
||||
|
@ -915,6 +920,13 @@ public:
|
|||
|
||||
virtual PRBool IsEqualNode(nsINode* aOther);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Hook for implementing GetID. This is guaranteed to only be
|
||||
* called if the NODE_HAS_ID flag is set.
|
||||
*/
|
||||
virtual nsIAtom* DoGetID() const = 0;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Hook for implementing GetClasses. This is guaranteed to only be
|
||||
|
|
|
@ -116,8 +116,8 @@ class Element;
|
|||
} // namespace mozilla
|
||||
|
||||
#define NS_IDOCUMENT_IID \
|
||||
{ 0xdf6c0752, 0xe780, 0x4576, \
|
||||
{ 0x95, 0x3c, 0x7e, 0xf1, 0xde, 0x9f, 0xd7, 0xf0 } }
|
||||
{ 0x3ee6a14b, 0x83b5, 0x4629, \
|
||||
{ 0x96, 0x9b, 0xe9, 0x84, 0x7c, 0x57, 0x24, 0x3c } }
|
||||
|
||||
// Flag for AddStyleSheet().
|
||||
#define NS_STYLESHEET_FROM_CATALOG (1 << 0)
|
||||
|
@ -670,6 +670,17 @@ public:
|
|||
*/
|
||||
virtual nsScriptLoader* ScriptLoader() = 0;
|
||||
|
||||
/**
|
||||
* Add/Remove an element to the document's id and name hashes
|
||||
*/
|
||||
virtual void AddToIdTable(mozilla::dom::Element* aElement, nsIAtom* aId) = 0;
|
||||
virtual void RemoveFromIdTable(mozilla::dom::Element* aElement,
|
||||
nsIAtom* aId) = 0;
|
||||
virtual void AddToNameTable(mozilla::dom::Element* aElement,
|
||||
nsIAtom* aName) = 0;
|
||||
virtual void RemoveFromNameTable(mozilla::dom::Element* aElement,
|
||||
nsIAtom* aName) = 0;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
// Document notification API's
|
||||
|
@ -802,6 +813,10 @@ public:
|
|||
{
|
||||
return mIsRegularHTML;
|
||||
}
|
||||
PRBool IsXUL() const
|
||||
{
|
||||
return mIsXUL;
|
||||
}
|
||||
|
||||
virtual PRBool IsScriptEnabled() = 0;
|
||||
|
||||
|
@ -1369,8 +1384,7 @@ public:
|
|||
* It prevents converting nsIDOMElement to mozill:dom::Element which is
|
||||
* already converted from mozilla::dom::Element.
|
||||
*/
|
||||
virtual mozilla::dom::Element* GetElementById(const nsAString& aElementId,
|
||||
nsresult* aResult) = 0;
|
||||
virtual mozilla::dom::Element* GetElementById(const nsAString& aElementId) = 0;
|
||||
|
||||
protected:
|
||||
~nsIDocument()
|
||||
|
@ -1462,6 +1476,7 @@ protected:
|
|||
PRPackedBool mShellIsHidden;
|
||||
|
||||
PRPackedBool mIsRegularHTML;
|
||||
PRPackedBool mIsXUL;
|
||||
|
||||
// True if we're loaded as data and therefor has any dangerous stuff, such
|
||||
// as scripts and plugins, disabled.
|
||||
|
|
|
@ -117,9 +117,10 @@ enum {
|
|||
|
||||
NODE_IS_EDITABLE = 0x00000100U,
|
||||
|
||||
// Optimizations to quickly check whether element may have ID, class or style
|
||||
// attributes. Not all element implementations may use these!
|
||||
NODE_MAY_HAVE_ID = 0x00000200U,
|
||||
// Set to true if the element has a non-empty id attribute. This can in rare
|
||||
// cases lie for nsXMLElement, such as when the node has been moved between
|
||||
// documents with different id mappings.
|
||||
NODE_HAS_ID = 0x00000200U,
|
||||
// For all Element nodes, NODE_MAY_HAVE_CLASS is guaranteed to be set if the
|
||||
// node in fact has a class, but may be set even if it doesn't.
|
||||
NODE_MAY_HAVE_CLASS = 0x00000400U,
|
||||
|
@ -174,8 +175,11 @@ enum {
|
|||
// Set if the node has the accesskey attribute set.
|
||||
NODE_HAS_ACCESSKEY = 0x00400000U,
|
||||
|
||||
// Set if the node has the accesskey attribute set.
|
||||
NODE_HAS_NAME = 0x00800000U,
|
||||
|
||||
// Four bits for the script-type ID
|
||||
NODE_SCRIPT_TYPE_OFFSET = 23,
|
||||
NODE_SCRIPT_TYPE_OFFSET = 24,
|
||||
|
||||
NODE_SCRIPT_TYPE_SIZE = 4,
|
||||
|
||||
|
|
|
@ -4896,35 +4896,6 @@ nsAutoGCRoot::Shutdown()
|
|||
NS_IF_RELEASE(sJSRuntimeService);
|
||||
}
|
||||
|
||||
nsIAtom*
|
||||
nsContentUtils::IsNamedItem(Element* aElement)
|
||||
{
|
||||
// Only the content types reflected in Level 0 with a NAME
|
||||
// attribute are registered. Images, layers and forms always get
|
||||
// reflected up to the document. Applets and embeds only go
|
||||
// to the closest container (which could be a form).
|
||||
nsGenericHTMLElement* elm = nsGenericHTMLElement::FromContent(aElement);
|
||||
if (!elm) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsIAtom* tag = elm->Tag();
|
||||
if (tag != nsGkAtoms::img &&
|
||||
tag != nsGkAtoms::form &&
|
||||
tag != nsGkAtoms::applet &&
|
||||
tag != nsGkAtoms::embed &&
|
||||
tag != nsGkAtoms::object) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
const nsAttrValue* val = elm->GetParsedAttr(nsGkAtoms::name);
|
||||
if (val && val->Type() == nsAttrValue::eAtom) {
|
||||
return val->GetAtomValue();
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsIInterfaceRequestor*
|
||||
nsContentUtils::GetSameOriginChecker()
|
||||
|
|
|
@ -1454,7 +1454,7 @@ nsDocument::~nsDocument()
|
|||
|
||||
// Destroy link map now so we don't waste time removing
|
||||
// links one by one
|
||||
DestroyLinkMap();
|
||||
DestroyElementMaps();
|
||||
|
||||
nsAutoScriptBlocker scriptBlocker;
|
||||
|
||||
|
@ -1883,8 +1883,6 @@ nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
|
|||
}
|
||||
#endif
|
||||
|
||||
mIdentifierMap.Clear();
|
||||
|
||||
SetPrincipal(nsnull);
|
||||
mSecurityInfo = nsnull;
|
||||
|
||||
|
@ -1900,7 +1898,7 @@ nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
|
|||
|
||||
// Destroy link map now so we don't waste time removing
|
||||
// links one by one
|
||||
DestroyLinkMap();
|
||||
DestroyElementMaps();
|
||||
|
||||
PRUint32 count = mChildren.ChildCount();
|
||||
{ // Scope for update
|
||||
|
@ -2334,51 +2332,38 @@ nsDocument::GetLastModified(nsAString& aLastModified)
|
|||
}
|
||||
|
||||
void
|
||||
nsDocument::UpdateNameTableEntry(Element *aElement)
|
||||
nsDocument::AddToNameTable(Element *aElement, nsIAtom* aName)
|
||||
{
|
||||
if (!mIsRegularHTML)
|
||||
return;
|
||||
|
||||
nsIAtom* name = nsContentUtils::IsNamedItem(aElement);
|
||||
if (!name)
|
||||
return;
|
||||
nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aName);
|
||||
|
||||
nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(name);
|
||||
if (!entry) {
|
||||
// We're not tracking the elements with this name
|
||||
return;
|
||||
// entry is null if we're not tracking the elements with this name
|
||||
|
||||
if (entry) {
|
||||
entry->AddNameElement(aElement);
|
||||
}
|
||||
|
||||
entry->AddNameElement(aElement);
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::RemoveFromNameTable(Element *aElement)
|
||||
nsDocument::RemoveFromNameTable(Element *aElement, nsIAtom* aName)
|
||||
{
|
||||
if (!mIsRegularHTML)
|
||||
// Speed up document teardown
|
||||
if (!mIsRegularHTML || mIdentifierMap.Count() == 0)
|
||||
return;
|
||||
|
||||
nsIAtom* name = nsContentUtils::IsNamedItem(aElement);
|
||||
if (!name)
|
||||
nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aName);
|
||||
if (!entry) // Should never be false unless we had OOM when adding the entry
|
||||
return;
|
||||
|
||||
nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(name);
|
||||
if (!entry) {
|
||||
// We're not tracking the elements with this name
|
||||
return;
|
||||
}
|
||||
|
||||
entry->RemoveNameElement(aElement);
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::UpdateIdTableEntry(Element *aElement)
|
||||
nsDocument::AddToIdTable(Element *aElement, nsIAtom* aId)
|
||||
{
|
||||
nsIAtom* id = aElement->GetID();
|
||||
if (!id)
|
||||
return;
|
||||
|
||||
nsIdentifierMapEntry *entry = mIdentifierMap.PutEntry(id);
|
||||
nsIdentifierMapEntry *entry = mIdentifierMap.PutEntry(aId);
|
||||
|
||||
if (entry) { /* True except on OOM */
|
||||
entry->AddIdElement(aElement);
|
||||
|
@ -2386,127 +2371,21 @@ nsDocument::UpdateIdTableEntry(Element *aElement)
|
|||
}
|
||||
|
||||
void
|
||||
nsDocument::RemoveFromIdTable(Element *aElement)
|
||||
nsDocument::RemoveFromIdTable(Element *aElement, nsIAtom* aId)
|
||||
{
|
||||
nsIAtom* id = aElement->GetID();
|
||||
if (!id)
|
||||
return;
|
||||
NS_ASSERTION(aId, "huhwhatnow?");
|
||||
|
||||
nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(id);
|
||||
if (!entry) /* Should be false unless we had OOM when adding the entry */
|
||||
// Speed up document teardown
|
||||
if (mIdentifierMap.Count() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aId);
|
||||
if (!entry) // Can be null for XML elements with changing ids.
|
||||
return;
|
||||
|
||||
if (entry->RemoveIdElement(aElement)) {
|
||||
mIdentifierMap.RemoveEntry(id);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::UnregisterNamedItems(nsIContent *aContent)
|
||||
{
|
||||
if (!aContent->IsElement()) {
|
||||
// non-element nodes are not named items nor can they have children.
|
||||
return;
|
||||
}
|
||||
|
||||
RemoveFromNameTable(aContent->AsElement());
|
||||
RemoveFromIdTable(aContent->AsElement());
|
||||
|
||||
for (nsINode::ChildIterator iter(aContent); !iter.IsDone(); iter.Next()) {
|
||||
UnregisterNamedItems(iter);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::RegisterNamedItems(nsIContent *aContent)
|
||||
{
|
||||
if (!aContent->IsElement()) {
|
||||
// non-element nodes are not named items nor can they have children.
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateNameTableEntry(aContent->AsElement());
|
||||
UpdateIdTableEntry(aContent->AsElement());
|
||||
|
||||
for (nsINode::ChildIterator iter(aContent); !iter.IsDone(); iter.Next()) {
|
||||
RegisterNamedItems(iter);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::ContentAppended(nsIDocument* aDocument,
|
||||
nsIContent* aContainer,
|
||||
nsIContent* aFirstNewContent,
|
||||
PRInt32 aNewIndexInContainer)
|
||||
{
|
||||
NS_ASSERTION(aDocument == this, "unexpected doc");
|
||||
|
||||
for (nsINode::ChildIterator iter(aContainer, aNewIndexInContainer);
|
||||
!iter.IsDone();
|
||||
iter.Next()) {
|
||||
RegisterNamedItems(iter);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::ContentInserted(nsIDocument* aDocument,
|
||||
nsIContent* aContainer,
|
||||
nsIContent* aContent,
|
||||
PRInt32 aIndexInContainer)
|
||||
{
|
||||
NS_ASSERTION(aDocument == this, "unexpected doc");
|
||||
|
||||
NS_ABORT_IF_FALSE(aContent, "Null content!");
|
||||
|
||||
RegisterNamedItems(aContent);
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::ContentRemoved(nsIDocument* aDocument,
|
||||
nsIContent* aContainer,
|
||||
nsIContent* aChild,
|
||||
PRInt32 aIndexInContainer)
|
||||
{
|
||||
NS_ASSERTION(aDocument == this, "unexpected doc");
|
||||
|
||||
NS_ABORT_IF_FALSE(aChild, "Null content!");
|
||||
|
||||
UnregisterNamedItems(aChild);
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::AttributeWillChange(nsIDocument* aDocument,
|
||||
nsIContent* aContent, PRInt32 aNameSpaceID,
|
||||
nsIAtom* aAttribute, PRInt32 aModType)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aContent && aContent->IsElement(), "Null content!");
|
||||
NS_PRECONDITION(aAttribute, "Must have an attribute that's changing!");
|
||||
|
||||
if (aNameSpaceID != kNameSpaceID_None)
|
||||
return;
|
||||
if (aAttribute == nsGkAtoms::name) {
|
||||
RemoveFromNameTable(aContent->AsElement());
|
||||
} else if (aAttribute == aContent->GetIDAttributeName()) {
|
||||
RemoveFromIdTable(aContent->AsElement());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::AttributeChanged(nsIDocument* aDocument,
|
||||
nsIContent* aContent, PRInt32 aNameSpaceID,
|
||||
nsIAtom* aAttribute, PRInt32 aModType)
|
||||
{
|
||||
NS_ASSERTION(aDocument == this, "unexpected doc");
|
||||
|
||||
NS_ABORT_IF_FALSE(aContent && aContent->IsElement(), "Null content!");
|
||||
NS_PRECONDITION(aAttribute, "Must have an attribute that's changing!");
|
||||
|
||||
if (aNameSpaceID != kNameSpaceID_None)
|
||||
return;
|
||||
if (aAttribute == nsGkAtoms::name) {
|
||||
UpdateNameTableEntry(aContent->AsElement());
|
||||
} else if (aAttribute == aContent->GetIDAttributeName()) {
|
||||
UpdateIdTableEntry(aContent->AsElement());
|
||||
mIdentifierMap.RemoveEntry(aId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3325,7 +3204,7 @@ nsDocument::RemoveChildAt(PRUint32 aIndex, PRBool aNotify, PRBool aMutationEvent
|
|||
|
||||
if (oldKid->IsElement()) {
|
||||
// Destroy the link map up front before we mess with the child list.
|
||||
DestroyLinkMap();
|
||||
DestroyElementMaps();
|
||||
}
|
||||
|
||||
nsresult rv =
|
||||
|
@ -3859,80 +3738,35 @@ nsDocument::CheckGetElementByIdArg(const nsIAtom* aId)
|
|||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsIdentifierMapEntry*
|
||||
nsDocument::GetElementByIdInternal(nsIAtom* aID)
|
||||
{
|
||||
// We don't have to flush before we do the initial hashtable lookup, since if
|
||||
// the id is already in the hashtable it couldn't have been removed without
|
||||
// us being notified (all removals notify immediately, as far as I can tell).
|
||||
// So do the lookup first.
|
||||
nsIdentifierMapEntry *entry = mIdentifierMap.PutEntry(aID);
|
||||
NS_ENSURE_TRUE(entry, nsnull);
|
||||
|
||||
if (entry->GetIdElement())
|
||||
return entry;
|
||||
|
||||
// Now we have to flush. It could be that we know nothing about this ID yet
|
||||
// but more content has been added to the document since. Note that we have
|
||||
// to flush notifications, so that the entry will get updated properly.
|
||||
|
||||
// Make sure to stash away the current generation so we can check whether
|
||||
// the table changes when we flush.
|
||||
PRUint32 generation = mIdentifierMap.GetGeneration();
|
||||
|
||||
FlushPendingNotifications(Flush_ContentAndNotify);
|
||||
|
||||
if (generation != mIdentifierMap.GetGeneration()) {
|
||||
// Table changed, so the entry pointer is no longer valid; look up the
|
||||
// entry again, adding if necessary (the adding may be necessary in case
|
||||
// the flush actually deleted entries).
|
||||
entry = mIdentifierMap.PutEntry(aID);
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
Element*
|
||||
nsDocument::GetElementById(const nsAString& aElementId, nsresult *aResult)
|
||||
nsDocument::GetElementById(const nsAString& aElementId)
|
||||
{
|
||||
nsCOMPtr<nsIAtom> idAtom(do_GetAtom(aElementId));
|
||||
if (!idAtom) {
|
||||
*aResult = NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// This can only fail due to OOM when the atom doesn't exist, in which
|
||||
// case there can't be an entry for it.
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
if (!CheckGetElementByIdArg(idAtom)) {
|
||||
*aResult = NS_OK;
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsIdentifierMapEntry *entry = GetElementByIdInternal(idAtom);
|
||||
if (!entry) {
|
||||
*aResult = NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
*aResult = NS_OK;
|
||||
|
||||
return entry->GetIdElement();
|
||||
nsIdentifierMapEntry *entry = mIdentifierMap.PutEntry(idAtom);
|
||||
return entry ? entry->GetIdElement() : nsnull;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocument::GetElementById(const nsAString& aId, nsIDOMElement** aReturn)
|
||||
{
|
||||
nsresult rv;
|
||||
Element *content = GetElementById(aId, &rv);
|
||||
Element *content = GetElementById(aId);
|
||||
if (content) {
|
||||
rv = CallQueryInterface(content, aReturn);
|
||||
}
|
||||
else {
|
||||
*aReturn = nsnull;
|
||||
return CallQueryInterface(content, aReturn);
|
||||
}
|
||||
|
||||
return rv;
|
||||
*aReturn = nsnull;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
Element*
|
||||
|
@ -3942,7 +3776,7 @@ nsDocument::AddIDTargetObserver(nsIAtom* aID, IDTargetObserver aObserver,
|
|||
if (!CheckGetElementByIdArg(aID))
|
||||
return nsnull;
|
||||
|
||||
nsIdentifierMapEntry *entry = GetElementByIdInternal(aID);
|
||||
nsIdentifierMapEntry *entry = mIdentifierMap.PutEntry(aID);
|
||||
NS_ENSURE_TRUE(entry, nsnull);
|
||||
|
||||
entry->AddContentChangeCallback(aObserver, aData);
|
||||
|
@ -3958,9 +3792,6 @@ nsDocument::RemoveIDTargetObserver(nsIAtom* aID,
|
|||
|
||||
nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aID);
|
||||
if (!entry) {
|
||||
// We don't need to do the stuff that GetElementByIdInternal does;
|
||||
// if there's no entry already in mIdentifierMap, then there's no
|
||||
// callback to remove.
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -7380,12 +7211,13 @@ nsDocument::ForgetLink(Link* aLink)
|
|||
}
|
||||
|
||||
void
|
||||
nsDocument::DestroyLinkMap()
|
||||
nsDocument::DestroyElementMaps()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
mStyledLinksCleared = true;
|
||||
#endif
|
||||
mStyledLinks.Clear();
|
||||
mIdentifierMap.Clear();
|
||||
}
|
||||
|
||||
static
|
||||
|
|
|
@ -650,6 +650,17 @@ public:
|
|||
*/
|
||||
virtual nsScriptLoader* ScriptLoader();
|
||||
|
||||
/**
|
||||
* Add/Remove an element to the document's id and name hashes
|
||||
*/
|
||||
virtual void AddToIdTable(mozilla::dom::Element* aElement, nsIAtom* aId);
|
||||
virtual void RemoveFromIdTable(mozilla::dom::Element* aElement,
|
||||
nsIAtom* aId);
|
||||
virtual void AddToNameTable(mozilla::dom::Element* aElement,
|
||||
nsIAtom* aName);
|
||||
virtual void RemoveFromNameTable(mozilla::dom::Element* aElement,
|
||||
nsIAtom* aName);
|
||||
|
||||
/**
|
||||
* Add a new observer of document change notifications. Whenever
|
||||
* content is changed, appended, inserted or removed the observers are
|
||||
|
@ -807,13 +818,6 @@ public:
|
|||
// nsIDOMNSEventTarget
|
||||
NS_DECL_NSIDOMNSEVENTTARGET
|
||||
|
||||
// nsIMutationObserver
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTEWILLCHANGE
|
||||
|
||||
// nsIScriptObjectPrincipal
|
||||
virtual nsIPrincipal* GetPrincipal();
|
||||
|
||||
|
@ -937,17 +941,10 @@ public:
|
|||
GetElementsByTagNameNS(const nsAString& aNamespaceURI,
|
||||
const nsAString& aLocalName);
|
||||
|
||||
virtual mozilla::dom::Element *GetElementById(const nsAString& aElementId,
|
||||
nsresult *aResult);
|
||||
virtual mozilla::dom::Element *GetElementById(const nsAString& aElementId);
|
||||
|
||||
protected:
|
||||
friend class nsNodeUtils;
|
||||
void RegisterNamedItems(nsIContent *aContent);
|
||||
void UnregisterNamedItems(nsIContent *aContent);
|
||||
void UpdateNameTableEntry(Element *aElement);
|
||||
void UpdateIdTableEntry(Element *aElement);
|
||||
void RemoveFromNameTable(Element *aElement);
|
||||
void RemoveFromIdTable(Element *aElement);
|
||||
|
||||
/**
|
||||
* Check that aId is not empty and log a message to the console
|
||||
|
@ -966,8 +963,8 @@ protected:
|
|||
nsACString& aCharset);
|
||||
|
||||
// Call this before the document does something that will unbind all content.
|
||||
// That will stop us from resolving URIs for all links as they are removed.
|
||||
void DestroyLinkMap();
|
||||
// That will stop us from doing a lot of work as each element is removed.
|
||||
void DestroyElementMaps();
|
||||
|
||||
// Refreshes the hrefs of all the links in the document.
|
||||
void RefreshLinkHrefs();
|
||||
|
|
|
@ -154,6 +154,9 @@ public:
|
|||
|
||||
virtual PRBool IsNodeOfType(PRUint32 aFlags) const;
|
||||
|
||||
virtual nsIAtom* DoGetID() const;
|
||||
virtual nsIAtom *GetIDAttributeName() const;
|
||||
|
||||
protected:
|
||||
nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
|
||||
};
|
||||
|
@ -195,6 +198,18 @@ nsDocumentFragment::IsNodeOfType(PRUint32 aFlags) const
|
|||
return !(aFlags & ~(eCONTENT | eDOCUMENT_FRAGMENT));
|
||||
}
|
||||
|
||||
nsIAtom*
|
||||
nsDocumentFragment::DoGetID() const
|
||||
{
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsIAtom*
|
||||
nsDocumentFragment::GetIDAttributeName() const
|
||||
{
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
DOMCI_DATA(DocumentFragment, nsDocumentFragment)
|
||||
|
||||
// QueryInterface implementation for nsDocumentFragment
|
||||
|
|
|
@ -1108,7 +1108,7 @@ nsGenericDOMDataNode::GetCurrentValueAtom()
|
|||
}
|
||||
|
||||
nsIAtom*
|
||||
nsGenericDOMDataNode::GetID() const
|
||||
nsGenericDOMDataNode::DoGetID() const
|
||||
{
|
||||
return nsnull;
|
||||
}
|
||||
|
|
|
@ -248,7 +248,7 @@ public:
|
|||
virtual already_AddRefed<nsIURI> GetBaseURI() const;
|
||||
virtual PRBool IsLink(nsIURI** aURI) const;
|
||||
|
||||
virtual nsIAtom* GetID() const;
|
||||
virtual nsIAtom* DoGetID() const;
|
||||
virtual const nsAttrValue* DoGetClasses() const;
|
||||
NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker);
|
||||
virtual nsICSSStyleRule* GetInlineStyleRule();
|
||||
|
|
|
@ -3249,38 +3249,6 @@ nsGenericElement::DispatchDOMEvent(nsEvent* aEvent,
|
|||
aPresContext, aEventStatus);
|
||||
}
|
||||
|
||||
nsIAtom*
|
||||
nsGenericElement::GetID() const
|
||||
{
|
||||
if (!HasFlag(NODE_MAY_HAVE_ID)) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsIAtom* IDName = GetIDAttributeName();
|
||||
if (IDName) {
|
||||
const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(IDName);
|
||||
if (attrVal){
|
||||
if (attrVal->Type() == nsAttrValue::eAtom) {
|
||||
return attrVal->GetAtomValue();
|
||||
}
|
||||
if(attrVal->IsEmptyString()){
|
||||
return nsnull;
|
||||
}
|
||||
// Check if the ID has been stored as a string.
|
||||
// This would occur if the ID attribute name changed after
|
||||
// the ID was parsed.
|
||||
if (attrVal->Type() == nsAttrValue::eString) {
|
||||
nsAutoString idVal(attrVal->GetStringValue());
|
||||
|
||||
// Create an atom from the value and set it into the attribute list.
|
||||
const_cast<nsAttrValue*>(attrVal)->ParseAtom(idVal);
|
||||
return attrVal->GetAtomValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
const nsAttrValue*
|
||||
nsGenericElement::DoGetClasses() const
|
||||
{
|
||||
|
@ -3371,12 +3339,6 @@ nsGenericElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
|
|||
return nsChangeHint(0);
|
||||
}
|
||||
|
||||
nsIAtom *
|
||||
nsGenericElement::GetIDAttributeName() const
|
||||
{
|
||||
return mNodeInfo->GetIDAttributeAtom();
|
||||
}
|
||||
|
||||
nsIAtom *
|
||||
nsGenericElement::GetClassAttributeName() const
|
||||
{
|
||||
|
@ -4732,15 +4694,6 @@ nsGenericElement::ParseAttribute(PRInt32 aNamespaceID,
|
|||
const nsAString& aValue,
|
||||
nsAttrValue& aResult)
|
||||
{
|
||||
if (aNamespaceID == kNameSpaceID_None &&
|
||||
aAttribute == GetIDAttributeName() && !aValue.IsEmpty()) {
|
||||
SetFlags(NODE_MAY_HAVE_ID);
|
||||
// Store id as an atom. id="" means that the element has no id,
|
||||
// not that it has an emptystring as the id.
|
||||
aResult.ParseAtom(aValue);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
|
|
@ -379,7 +379,6 @@ public:
|
|||
virtual void UnbindFromTree(PRBool aDeep = PR_TRUE,
|
||||
PRBool aNullParent = PR_TRUE);
|
||||
virtual already_AddRefed<nsINodeList> GetChildren(PRInt32 aChildType);
|
||||
virtual nsIAtom *GetIDAttributeName() const;
|
||||
virtual nsIAtom *GetClassAttributeName() const;
|
||||
virtual already_AddRefed<nsINodeInfo> GetExistingAttrNameFromQName(const nsAString& aStr) const;
|
||||
nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
|
||||
|
@ -451,7 +450,6 @@ public:
|
|||
void ListAttributes(FILE* out) const;
|
||||
#endif
|
||||
|
||||
virtual nsIAtom* GetID() const;
|
||||
virtual const nsAttrValue* DoGetClasses() const;
|
||||
NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker);
|
||||
virtual nsICSSStyleRule* GetInlineStyleRule();
|
||||
|
@ -994,15 +992,29 @@ protected:
|
|||
}
|
||||
|
||||
/**
|
||||
* GetContentsAsText will take all the textnodes that are children
|
||||
* of |this| and concatenate the text in them into aText. It
|
||||
* completely ignores any non-text-node children of |this|; in
|
||||
* particular it does not descend into any children of |this| that
|
||||
* happen to be container elements.
|
||||
*
|
||||
* @param aText the resulting text [OUT]
|
||||
* Add/remove this element to the documents id cache
|
||||
*/
|
||||
void GetContentsAsText(nsAString& aText);
|
||||
void AddToIdTable(nsIAtom* aId) {
|
||||
NS_ASSERTION(HasFlag(NODE_HAS_ID), "Node lacking NODE_HAS_ID flag");
|
||||
nsIDocument* doc = GetCurrentDoc();
|
||||
if (doc && (!IsInAnonymousSubtree() || doc->IsXUL())) {
|
||||
doc->AddToIdTable(this, aId);
|
||||
}
|
||||
}
|
||||
void RemoveFromIdTable() {
|
||||
if (HasFlag(NODE_HAS_ID)) {
|
||||
nsIDocument* doc = GetCurrentDoc();
|
||||
if (doc) {
|
||||
nsIAtom* id = DoGetID();
|
||||
// id can be null during mutation events evilness. Also, XUL elements
|
||||
// loose their proto attributes during cc-unlink, so this can happen
|
||||
// during cc-unlink too.
|
||||
if (id) {
|
||||
doc->RemoveFromIdTable(this, DoGetID());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Functions to carry out event default actions for links of all types
|
||||
|
|
|
@ -578,13 +578,6 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNode, PRBool aClone, PRBool aDeep,
|
|||
aCx, aOldScope, aNewScope, aNodesWithProperties,
|
||||
clone, getter_AddRefs(child));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (isDeepDocumentClone) {
|
||||
NS_ASSERTION(child->IsNodeOfType(nsINode::eCONTENT),
|
||||
"A clone of a child of a node is not nsIContent?");
|
||||
|
||||
nsIContent* content = static_cast<nsIContent*>(child.get());
|
||||
static_cast<nsDocument*>(clone.get())->RegisterNamedItems(content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -71,6 +71,20 @@ nsStyledElement::GetIDAttributeName() const
|
|||
return nsGkAtoms::id;
|
||||
}
|
||||
|
||||
nsIAtom*
|
||||
nsStyledElement::DoGetID() const
|
||||
{
|
||||
NS_ASSERTION(HasFlag(NODE_HAS_ID), "Unexpected call");
|
||||
|
||||
// The nullcheck here is needed because nsGenericElement::UnsetAttr calls
|
||||
// out to various code between removing the attribute and we get a chance to
|
||||
// clear the NODE_HAS_ID flag.
|
||||
|
||||
const nsAttrValue* attr = mAttrsAndChildren.GetAttr(nsGkAtoms::id);
|
||||
|
||||
return attr ? attr->GetAtomValue() : nsnull;
|
||||
}
|
||||
|
||||
const nsAttrValue*
|
||||
nsStyledElement::DoGetClasses() const
|
||||
{
|
||||
|
@ -93,12 +107,45 @@ nsStyledElement::ParseAttribute(PRInt32 aNamespaceID, nsIAtom* aAttribute,
|
|||
aResult.ParseAtomArray(aValue);
|
||||
return PR_TRUE;
|
||||
}
|
||||
if (aAttribute == nsGkAtoms::id) {
|
||||
// Store id as an atom. id="" means that the element has no id,
|
||||
// not that it has an emptystring as the id.
|
||||
RemoveFromIdTable();
|
||||
if (aValue.IsEmpty()) {
|
||||
UnsetFlags(NODE_HAS_ID);
|
||||
return PR_FALSE;
|
||||
}
|
||||
aResult.ParseAtom(aValue);
|
||||
SetFlags(NODE_HAS_ID);
|
||||
AddToIdTable(aResult.GetAtomValue());
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return nsStyledElementBase::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
||||
aResult);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsStyledElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
|
||||
PRBool aNotify)
|
||||
{
|
||||
PRBool isId = PR_FALSE;
|
||||
if (aAttribute == nsGkAtoms::id && aNameSpaceID == kNameSpaceID_None) {
|
||||
// Have to do this before clearing flag. See RemoveFromIdTable
|
||||
RemoveFromIdTable();
|
||||
isId = PR_TRUE;
|
||||
}
|
||||
|
||||
nsresult rv = nsGenericElement::UnsetAttr(aNameSpaceID, aAttribute, aNotify);
|
||||
|
||||
if (isId) {
|
||||
UnsetFlags(NODE_HAS_ID);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStyledElement::SetInlineStyleRule(nsICSSStyleRule* aStyleRule, PRBool aNotify)
|
||||
{
|
||||
|
@ -163,13 +210,28 @@ nsStyledElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
|||
aCompileEventHandlers);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// XXXbz if we already have a style attr parsed, this won't do
|
||||
// anything... need to fix that.
|
||||
ReparseStyleAttribute(PR_FALSE);
|
||||
if (aDocument && HasFlag(NODE_HAS_ID) && !GetBindingParent()) {
|
||||
aDocument->AddToIdTable(this, DoGetID());
|
||||
}
|
||||
|
||||
return rv;
|
||||
if (!IsXUL()) {
|
||||
// XXXbz if we already have a style attr parsed, this won't do
|
||||
// anything... need to fix that.
|
||||
ReparseStyleAttribute(PR_FALSE);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsStyledElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
|
||||
{
|
||||
RemoveFromIdTable();
|
||||
|
||||
nsStyledElementBase::UnbindFromTree(aDeep, aNullParent);
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Others and helpers
|
||||
|
||||
|
|
|
@ -64,9 +64,10 @@ protected:
|
|||
|
||||
public:
|
||||
|
||||
// nsIContent interface methods for styling
|
||||
// nsIContent interface methods
|
||||
virtual nsIAtom* GetClassAttributeName() const;
|
||||
virtual nsIAtom* GetIDAttributeName() const;
|
||||
virtual nsIAtom* DoGetID() const;
|
||||
virtual const nsAttrValue* DoGetClasses() const;
|
||||
|
||||
virtual nsICSSStyleRule* GetInlineStyleRule();
|
||||
|
@ -75,6 +76,10 @@ public:
|
|||
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
PRBool aCompileEventHandlers);
|
||||
virtual void UnbindFromTree(PRBool aDeep, PRBool aNullParent);
|
||||
|
||||
virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
|
||||
PRBool aNotify);
|
||||
|
||||
protected:
|
||||
|
||||
|
|
|
@ -343,6 +343,7 @@ _TEST_FILES2 = \
|
|||
test_bug475156.html \
|
||||
bug475156.sjs \
|
||||
test_bug544642.html \
|
||||
test_bug564863.xhtml \
|
||||
test_copypaste.html \
|
||||
test_bug503481.html \
|
||||
file_bug503481.sjs \
|
||||
|
|
|
@ -0,0 +1,328 @@
|
|||
<!DOCTYPE html [
|
||||
<!ATTLIST ns:x id ID #REQUIRED>
|
||||
<!ATTLIST ns2:x id_2 ID #REQUIRED>
|
||||
]>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:ns="urn:namespace"
|
||||
xmlns:ns2="urn:namespace">
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=564863
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 564863</title>
|
||||
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<style>
|
||||
#div_id {
|
||||
color: rgb(10, 10, 10);
|
||||
}
|
||||
#a_id {
|
||||
color: rgb(20, 20, 20);
|
||||
}
|
||||
#xul_id {
|
||||
color: rgb(30, 30, 30);
|
||||
}
|
||||
#svg_id {
|
||||
color: rgb(40, 40, 40);
|
||||
}
|
||||
#ns_id {
|
||||
color: rgb(50, 50, 50);
|
||||
}
|
||||
#ns2_id {
|
||||
color: rgb(60, 60, 60);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=564863">Mozilla Bug 564863</a>
|
||||
<!-- Elements to ensure we have nodeinfos with id-attribute set -->
|
||||
<div><ns:x id="ns-holder"/><ns2:x id_2="ns2-holder"/></div>
|
||||
|
||||
<!-- DOM to muck around with for tests -->
|
||||
<p id="root">
|
||||
<div id="div_id" />
|
||||
<a id="a_id" />
|
||||
<xul:button id="xul_id" />
|
||||
<svg:svg><svg:g id="svg_id" /></svg:svg>
|
||||
<ns:x id="ns_id" />
|
||||
</p>
|
||||
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
<![CDATA[
|
||||
|
||||
root = $('root');
|
||||
div = root.children[0];
|
||||
a = root.children[1];
|
||||
xul = root.children[2];
|
||||
svg = root.children[3].firstChild;
|
||||
nsx = root.children[4];
|
||||
|
||||
var div_cs = getComputedStyle(div, "");
|
||||
var a_cs = getComputedStyle(a, "");
|
||||
var xul_cs = getComputedStyle(xul, "");
|
||||
var svg_cs = getComputedStyle(svg, "");
|
||||
var nsx_cs = getComputedStyle(nsx, "");
|
||||
|
||||
function checkHasId(test) {
|
||||
// Check computed style first to avoid flushes from hiding problems
|
||||
checkHasIdNoGEBI(test);
|
||||
|
||||
is($("div_id"), div, "div getElementById " + test);
|
||||
is($("a_id"), a, "a getElementById " + test);
|
||||
is($("xul_id"), xul, "xul getElementById " + test);
|
||||
is($("svg_id"), svg, "svg getElementById " + test);
|
||||
is($("ns_id"), nsx, "ns getElementById " + test);
|
||||
}
|
||||
|
||||
function checkHasIdNoGEBI(test) {
|
||||
is(div_cs.color, "rgb(10, 10, 10)", "div color " + test);
|
||||
is(a_cs.color, "rgb(20, 20, 20)", "a color " + test);
|
||||
is(xul_cs.color, "rgb(30, 30, 30)", "xul color " + test);
|
||||
is(svg_cs.color, "rgb(40, 40, 40)", "svg color " + test);
|
||||
is(nsx_cs.color, "rgb(50, 50, 50)", "nsx color " + test);
|
||||
|
||||
is(div.id, "div_id", "div id " + test);
|
||||
is(a.id, "a_id", "a id " + test);
|
||||
is(xul.id, "xul_id", "xul id " + test);
|
||||
is(svg.id, "svg_id", "svg id " + test);
|
||||
is (nsx.getAttribute("id"), "ns_id", "ns id " + test);
|
||||
}
|
||||
|
||||
function checkHasNoId(removed, test) {
|
||||
is(div_cs.color, "rgb(0, 0, 0)", "div color " + test);
|
||||
is(a_cs.color, "rgb(0, 0, 0)", "a color " + test);
|
||||
is(xul_cs.color, "rgb(0, 0, 0)", "xul color " + test);
|
||||
is(svg_cs.color, "rgb(0, 0, 0)", "svg color " + test);
|
||||
is(nsx_cs.color, "rgb(0, 0, 0)", "nsx color " + test);
|
||||
|
||||
attrValue = removed ? null : "";
|
||||
|
||||
is(div.id, "", "div id " + test);
|
||||
is(a.id, "", "a id " + test);
|
||||
is(xul.id, "", "xul id " + test);
|
||||
is(svg.id, "", "svg id " + test);
|
||||
|
||||
is(div.getAttribute("id"), attrValue, "div getAttribute " + test);
|
||||
is(a.getAttribute("id"), attrValue, "a getAttribute " + test);
|
||||
is(xul.getAttribute("id"), "", "xul getAttribute " + test);
|
||||
is(svg.getAttribute("id"), attrValue, "svg getAttribute " + test);
|
||||
is(nsx.getAttribute("id"), attrValue, "ns getAttribute " + test);
|
||||
|
||||
is($("div_id"), null, "div getElementById " + test);
|
||||
is($("a_id"), null, "a getElementById " + test);
|
||||
is($("xul_id"), null, "xul getElementById " + test);
|
||||
is($("svg_id"), null, "svg getElementById " + test);
|
||||
is($("ns_id"), null, "ns getElementById " + test);
|
||||
}
|
||||
|
||||
// Check that dynamic modifications of attribute work
|
||||
|
||||
checkHasId("in markup");
|
||||
|
||||
div.id = "";
|
||||
a.id = "";
|
||||
xul.id = "";
|
||||
svg.id = "";
|
||||
nsx.setAttribute("id", "");
|
||||
|
||||
checkHasNoId(false, "set to empty");
|
||||
|
||||
div.id = "div_id";
|
||||
a.id = "a_id";
|
||||
xul.id = "xul_id";
|
||||
svg.id = "svg_id";
|
||||
nsx.setAttribute("id", "ns_id");
|
||||
|
||||
checkHasId("set using .id");
|
||||
|
||||
div.setAttribute("id", "");
|
||||
a.setAttribute("id", "");
|
||||
xul.setAttribute("id", "");
|
||||
svg.setAttribute("id", "");
|
||||
nsx.setAttribute("id", "");
|
||||
|
||||
checkHasNoId(false, "setAttribute to empty");
|
||||
|
||||
div.id = "div_id";
|
||||
a.id = "a_id";
|
||||
xul.id = "xul_id";
|
||||
svg.id = "svg_id";
|
||||
nsx.setAttribute("id", "ns_id");
|
||||
|
||||
checkHasId("set again using .id");
|
||||
|
||||
div.removeAttribute("id");
|
||||
a.removeAttribute("id");
|
||||
xul.removeAttribute("id");
|
||||
svg.removeAttribute("id");
|
||||
nsx.removeAttribute("id");
|
||||
|
||||
checkHasNoId(true, "removed attribute");
|
||||
|
||||
div.setAttribute("id", "div_id");
|
||||
a.setAttribute("id", "a_id");
|
||||
xul.setAttribute("id", "xul_id");
|
||||
svg.setAttribute("id", "svg_id");
|
||||
nsx.setAttribute("id", "ns_id");
|
||||
|
||||
checkHasId("set using setAttribute");
|
||||
|
||||
t1 = document.createElement("div");
|
||||
t1.id = "div_id";
|
||||
t2 = document.createElement("a");
|
||||
t2.id = "a_id";
|
||||
t3 = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "button");
|
||||
t3.id = "xul_id";
|
||||
t4 = document.createElementNS("http://www.w3.org/2000/svg", "g");
|
||||
t4.id = "svg_id";
|
||||
t5 = document.createElementNS("urn:namespace", "ns:x");
|
||||
t5.setAttribute("id", "ns_id");
|
||||
|
||||
// Check that inserting elements before/after existing work
|
||||
|
||||
function insertAfter(newChild, existing) {
|
||||
existing.parentNode.insertBefore(newChild, existing.nextSibling);
|
||||
}
|
||||
function insertBefore(newChild, existing) {
|
||||
existing.parentNode.insertBefore(newChild, existing);
|
||||
}
|
||||
function removeNode(child) {
|
||||
child.parentNode.removeChild(child);
|
||||
}
|
||||
|
||||
insertAfter(t1, div);
|
||||
insertAfter(t2, a);
|
||||
insertAfter(t3, xul);
|
||||
insertAfter(t4, svg);
|
||||
insertAfter(t5, nsx);
|
||||
|
||||
checkHasId("inserted after");
|
||||
|
||||
insertBefore(t1, div);
|
||||
insertBefore(t2, a);
|
||||
insertBefore(t3, xul);
|
||||
insertBefore(t4, svg);
|
||||
insertBefore(t5, nsx);
|
||||
|
||||
checkHasIdNoGEBI("inserted before");
|
||||
is($("div_id"), t1, "div getElementById inserted before");
|
||||
is($("a_id"), t2, "a getElementById inserted before");
|
||||
is($("xul_id"), t3, "xul getElementById inserted before");
|
||||
is($("svg_id"), t4, "svg getElementById inserted before");
|
||||
is($("ns_id"), t5, "ns getElementById inserted before");
|
||||
|
||||
t1.removeAttribute("id");
|
||||
t2.removeAttribute("id");
|
||||
t3.removeAttribute("id");
|
||||
t4.removeAttribute("id");
|
||||
t5.removeAttribute("id");
|
||||
|
||||
checkHasId("removed tx attribute");
|
||||
|
||||
t1.setAttribute("id", "div_id");
|
||||
t2.setAttribute("id", "a_id");
|
||||
t3.setAttribute("id", "xul_id");
|
||||
t4.setAttribute("id", "svg_id");
|
||||
t5.setAttribute("id", "ns_id");
|
||||
|
||||
checkHasIdNoGEBI("setAttribute before");
|
||||
is($("div_id"), t1, "div getElementById setAttribute before");
|
||||
is($("a_id"), t2, "a getElementById setAttribute before");
|
||||
is($("xul_id"), t3, "xul getElementById setAttribute before");
|
||||
is($("svg_id"), t4, "svg getElementById setAttribute before");
|
||||
is($("ns_id"), t5, "ns getElementById setAttribute before");
|
||||
|
||||
removeNode(t1);
|
||||
removeNode(t2);
|
||||
removeNode(t3);
|
||||
removeNode(t4);
|
||||
removeNode(t5);
|
||||
|
||||
checkHasId("removed temporaries");
|
||||
|
||||
removeNode(div);
|
||||
removeNode(a);
|
||||
removeNode(xul);
|
||||
removeNode(svg);
|
||||
removeNode(nsx);
|
||||
|
||||
checkHasIdNoGEBI("removed node");
|
||||
|
||||
// Check that removing an element during UnsetAttr works
|
||||
is(div.id, "div_id", "div still has id set");
|
||||
var mutateFired = false;
|
||||
root.appendChild(div);
|
||||
var f = function(e) {
|
||||
div.removeEventListener("DOMAttrModified", f, false);
|
||||
is(e.target, div, "target is div");
|
||||
is(div.id, "", "div no longer has id");
|
||||
is(div.getAttribute("id"), null, "div no longer has id attr");
|
||||
removeNode(div);
|
||||
is(div.parentNode, null, "div was removed");
|
||||
mutateFired = true;
|
||||
}
|
||||
div.addEventListener("DOMAttrModified", f, false);
|
||||
div.removeAttribute("id");
|
||||
ok(mutateFired, "mutation event fired");
|
||||
|
||||
// Check same for XML elements
|
||||
is(nsx.getAttribute("id"), "ns_id", "nsx still has id set");
|
||||
mutateFired = false;
|
||||
root.appendChild(nsx);
|
||||
var f2 = function(e) {
|
||||
nsx.removeEventListener("DOMAttrModified", f2, false);
|
||||
is(e.target, nsx, "target is nsx");
|
||||
is(nsx.getAttribute("id"), null, "nsx no longer has id attr");
|
||||
removeNode(nsx);
|
||||
is(nsx.parentNode, null, "nsx was removed");
|
||||
mutateFired = true;
|
||||
}
|
||||
nsx.addEventListener("DOMAttrModified", f2, false);
|
||||
nsx.removeAttribute("id");
|
||||
ok(mutateFired, "mutation event fired");
|
||||
|
||||
|
||||
// Check that modifying the id-name of an XML element works
|
||||
ok($("ns-holder"), "ns-holder exists");
|
||||
ok($("ns2-holder"), "ns2-holder exists");
|
||||
root.appendChild(nsx);
|
||||
nsx.setAttribute("id", "ns_id");
|
||||
is(nsx_cs.color, "rgb(50, 50, 50)", "nsx has initial id");
|
||||
is($("ns_id"), nsx, "gEBI works on old id");
|
||||
nsx.setAttribute("id_2", "ns2_id");
|
||||
nsx.prefix = "ns2";
|
||||
removeNode(nsx);
|
||||
root.appendChild(nsx);
|
||||
is(nsx_cs.color, "rgb(60, 60, 60)", "nsx has new id");
|
||||
is($("ns2_id"), nsx, "gEBI works on new id");
|
||||
|
||||
// Need to change id and then CC to ensure that we don't end up with dangling pointers
|
||||
function gc() {
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
||||
.getInterface(Components.interfaces.nsIDOMWindowUtils)
|
||||
.garbageCollect();
|
||||
}
|
||||
ok($("ns-holder"), "ns-holder exists");
|
||||
ok($("ns2-holder"), "ns2-holder exists");
|
||||
tempNode = document.createElementNS("urn:namespace", "ns:x");
|
||||
tempNode.setAttribute("id", "tempNode_id");
|
||||
document.body.appendChild(tempNode);
|
||||
is($("tempNode_id"), tempNode, "tempNode in gEBI table");
|
||||
tempNode.prefix = "ns2";
|
||||
removeNode(tempNode);
|
||||
tempNode = null;
|
||||
gc();
|
||||
$("tempNode_id");
|
||||
ok(true, "Didn't crash when accessing old id");
|
||||
|
||||
|
||||
]]>
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -913,7 +913,7 @@ nsGenericHTMLElement::UpdateEditableState()
|
|||
return;
|
||||
}
|
||||
|
||||
nsGenericElement::UpdateEditableState();
|
||||
nsStyledElement::UpdateEditableState();
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -927,6 +927,10 @@ nsGenericHTMLElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aDocument) {
|
||||
if (HasFlag(NODE_HAS_NAME)) {
|
||||
aDocument->
|
||||
AddToNameTable(this, GetParsedAttr(nsGkAtoms::name)->GetAtomValue());
|
||||
}
|
||||
if (HasFlag(NODE_IS_EDITABLE) && GetContentEditableValue() == eTrue) {
|
||||
nsCOMPtr<nsIHTMLDocument> htmlDocument = do_QueryInterface(aDocument);
|
||||
if (htmlDocument) {
|
||||
|
@ -948,7 +952,7 @@ nsGenericHTMLElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
|
|||
}
|
||||
}
|
||||
|
||||
nsGenericElement::UnbindFromTree(aDeep, aNullParent);
|
||||
nsStyledElement::UnbindFromTree(aDeep, aNullParent);
|
||||
}
|
||||
|
||||
nsHTMLFormElement*
|
||||
|
@ -1161,8 +1165,8 @@ nsGenericHTMLElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
|
|||
SetFlags(NODE_MAY_HAVE_CONTENT_EDITABLE_ATTR);
|
||||
}
|
||||
|
||||
nsresult rv = nsGenericElement::SetAttr(aNameSpaceID, aName, aPrefix, aValue,
|
||||
aNotify);
|
||||
nsresult rv = nsStyledElement::SetAttr(aNameSpaceID, aName, aPrefix, aValue,
|
||||
aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (contentEditable) {
|
||||
|
@ -1185,7 +1189,12 @@ nsGenericHTMLElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
|
|||
|
||||
// Check for event handlers
|
||||
if (aNameSpaceID == kNameSpaceID_None) {
|
||||
if (aAttribute == nsGkAtoms::contenteditable) {
|
||||
if (aAttribute == nsGkAtoms::name) {
|
||||
// Have to do this before clearing flag. See RemoveFromNameTable
|
||||
RemoveFromNameTable();
|
||||
UnsetFlags(NODE_HAS_NAME);
|
||||
}
|
||||
else if (aAttribute == nsGkAtoms::contenteditable) {
|
||||
contentEditable = PR_TRUE;
|
||||
contentEditableChange = GetContentEditableValue() == eTrue ? -1 : 0;
|
||||
}
|
||||
|
@ -1222,6 +1231,15 @@ nsGenericHTMLElement::GetBaseTarget(nsAString& aBaseTarget) const
|
|||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
static PRBool
|
||||
CanHaveName(nsIAtom* aTag)
|
||||
{
|
||||
return aTag == nsGkAtoms::img ||
|
||||
aTag == nsGkAtoms::form ||
|
||||
aTag == nsGkAtoms::applet ||
|
||||
aTag == nsGkAtoms::embed ||
|
||||
aTag == nsGkAtoms::object;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsGenericHTMLElement::ParseAttribute(PRInt32 aNamespaceID,
|
||||
|
@ -1238,10 +1256,22 @@ nsGenericHTMLElement::ParseAttribute(PRInt32 aNamespaceID,
|
|||
return aResult.ParseIntWithBounds(aValue, -32768, 32767);
|
||||
}
|
||||
|
||||
if (aAttribute == nsGkAtoms::name && !aValue.IsEmpty()) {
|
||||
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();
|
||||
if (aValue.IsEmpty()) {
|
||||
UnsetFlags(NODE_HAS_NAME);
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
aResult.ParseAtom(aValue);
|
||||
|
||||
if (CanHaveName(Tag())) {
|
||||
SetFlags(NODE_HAS_NAME);
|
||||
AddToNameTable(aResult.GetAtomValue());
|
||||
}
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
|
@ -2501,6 +2531,8 @@ nsGenericHTMLFormElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
|
|||
{
|
||||
// Save state before doing anything
|
||||
SaveState();
|
||||
|
||||
RemoveFromNameTable();
|
||||
|
||||
if (mForm) {
|
||||
// Might need to unset mForm
|
||||
|
|
|
@ -498,6 +498,26 @@ public:
|
|||
NS_HIDDEN_(nsresult) GetEditorInternal(nsIEditor** aEditor);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Add/remove this element to the documents name cache
|
||||
*/
|
||||
void AddToNameTable(nsIAtom* aName) {
|
||||
NS_ASSERTION(HasFlag(NODE_HAS_NAME), "Node lacking NODE_HAS_NAME flag");
|
||||
nsIDocument* doc = GetCurrentDoc();
|
||||
if (doc && !IsInAnonymousSubtree()) {
|
||||
doc->AddToNameTable(this, aName);
|
||||
}
|
||||
}
|
||||
void RemoveFromNameTable() {
|
||||
if (HasFlag(NODE_HAS_NAME)) {
|
||||
nsIDocument* doc = GetCurrentDoc();
|
||||
if (doc) {
|
||||
doc->RemoveFromNameTable(this, GetParsedAttr(nsGkAtoms::name)->
|
||||
GetAtomValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register or unregister an access key to this element based on the
|
||||
* accesskey attribute.
|
||||
|
|
|
@ -436,9 +436,7 @@ nsHTMLLabelElement::GetControlContent()
|
|||
return nsnull;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
nsIContent* content = doc->GetElementById(elementId, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, nsnull);
|
||||
nsIContent* content = doc->GetElementById(elementId);
|
||||
if (!content) {
|
||||
return nsnull;
|
||||
}
|
||||
|
|
|
@ -2635,26 +2635,18 @@ FindNamedItems(nsIAtom* aName, nsIContent *aContent,
|
|||
NS_ASSERTION(!aEntry->IsInvalidName(),
|
||||
"Entry that should never have a list passed to FindNamedItems()!");
|
||||
|
||||
if (!aContent->IsElement()) {
|
||||
// non-elements are not named items nor can they have children.
|
||||
return;
|
||||
if (aContent->HasFlag(NODE_HAS_NAME)) {
|
||||
NS_ASSERTION(nsGenericHTMLElement::FromContent(aContent),
|
||||
"Only HTML Elements should have a name");
|
||||
|
||||
nsGenericHTMLElement* elm = static_cast<nsGenericHTMLElement*>(aContent);
|
||||
if (elm->GetParsedAttr(nsGkAtoms::name)->GetAtomValue() == aName) {
|
||||
aEntry->AddNameElement(elm);
|
||||
}
|
||||
}
|
||||
|
||||
Element* element = aContent->AsElement();
|
||||
|
||||
if (aName == nsContentUtils::IsNamedItem(element)) {
|
||||
aEntry->AddNameElement(element);
|
||||
}
|
||||
|
||||
if (!aEntry->GetIdElement() &&
|
||||
// Maybe this node has the right id?
|
||||
aName == element->GetID()) {
|
||||
aEntry->AddIdElement(element);
|
||||
}
|
||||
|
||||
PRUint32 i, count = element->GetChildCount();
|
||||
for (i = 0; i < count; ++i) {
|
||||
FindNamedItems(aName, element->GetChildAt(i), aEntry);
|
||||
for (nsINode::ChildIterator iter(aContent); !iter.IsDone(); iter.Next()) {
|
||||
FindNamedItems(aName, iter, aEntry);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2677,27 +2669,7 @@ nsHTMLDocument::ResolveName(const nsAString& aName,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// Now we know we _might_ have items. Before looking at
|
||||
// entry->mNameContentList, make sure to flush out content (see
|
||||
// bug 69826).
|
||||
// This is a perf killer while the document is loading!
|
||||
|
||||
// Make sure to stash away the current generation so we can check whether the
|
||||
// table changes when we flush.
|
||||
PRUint32 generation = mIdentifierMap.GetGeneration();
|
||||
|
||||
// If we already have an entry->mNameContentList, we need to flush out
|
||||
// notifications too, so that it will get updated properly.
|
||||
FlushPendingNotifications(entry->HasNameContentList() ?
|
||||
Flush_ContentAndNotify : Flush_Content);
|
||||
|
||||
if (generation != mIdentifierMap.GetGeneration()) {
|
||||
// Table changed, so the entry pointer is no longer valid; look up the
|
||||
// entry again, adding if necessary (the adding may be necessary in case
|
||||
// the flush actually deleted entries).
|
||||
entry = mIdentifierMap.PutEntry(name);
|
||||
NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
// Now we know we _might_ have items.
|
||||
|
||||
if (!entry->HasNameContentList()) {
|
||||
#ifdef DEBUG_jst
|
||||
|
|
|
@ -240,10 +240,9 @@ public:
|
|||
|
||||
virtual NS_HIDDEN_(void) RemovedFromDocShell();
|
||||
|
||||
virtual mozilla::dom::Element *GetElementById(const nsAString& aElementId,
|
||||
nsresult *aResult)
|
||||
virtual mozilla::dom::Element *GetElementById(const nsAString& aElementId)
|
||||
{
|
||||
return nsDocument::GetElementById(aElementId, aResult);
|
||||
return nsDocument::GetElementById(aElementId);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
|
|
@ -63,8 +63,113 @@ NS_INTERFACE_TABLE_HEAD(nsXMLElement)
|
|||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Element)
|
||||
NS_ELEMENT_INTERFACE_MAP_END
|
||||
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(nsXMLElement, nsGenericElement)
|
||||
NS_IMPL_RELEASE_INHERITED(nsXMLElement, nsGenericElement)
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(nsXMLElement)
|
||||
|
||||
nsresult
|
||||
nsXMLElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
|
||||
PRBool aNotify)
|
||||
{
|
||||
PRBool isId = PR_FALSE;
|
||||
if (aAttribute == GetIDAttributeName() &&
|
||||
aNameSpaceID == kNameSpaceID_None) {
|
||||
// Have to do this before clearing flag. See RemoveFromIdTable
|
||||
RemoveFromIdTable();
|
||||
isId = PR_TRUE;
|
||||
}
|
||||
|
||||
nsresult rv = nsGenericElement::UnsetAttr(aNameSpaceID, aAttribute, aNotify);
|
||||
|
||||
if (isId) {
|
||||
UnsetFlags(NODE_HAS_ID);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsIAtom *
|
||||
nsXMLElement::GetIDAttributeName() const
|
||||
{
|
||||
return mNodeInfo->GetIDAttributeAtom();
|
||||
}
|
||||
|
||||
nsIAtom*
|
||||
nsXMLElement::DoGetID() const
|
||||
{
|
||||
NS_ASSERTION(HasFlag(NODE_HAS_ID), "Unexpected call");
|
||||
|
||||
nsIAtom* IDName = GetIDAttributeName();
|
||||
if (IDName) {
|
||||
const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(IDName);
|
||||
if (attrVal) {
|
||||
if (attrVal->Type() == nsAttrValue::eAtom) {
|
||||
return attrVal->GetAtomValue();
|
||||
}
|
||||
if (attrVal->IsEmptyString()) {
|
||||
return nsnull;
|
||||
}
|
||||
// Check if the ID has been stored as a string.
|
||||
// This would occur if the ID attribute name changed after
|
||||
// the ID was parsed.
|
||||
if (attrVal->Type() == nsAttrValue::eString) {
|
||||
nsAutoString idVal(attrVal->GetStringValue());
|
||||
|
||||
// Create an atom from the value and set it into the attribute list.
|
||||
const_cast<nsAttrValue*>(attrVal)->ParseAtom(idVal);
|
||||
return attrVal->GetAtomValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsXMLElement::ParseAttribute(PRInt32 aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult)
|
||||
{
|
||||
if (aAttribute == GetIDAttributeName() &&
|
||||
aNamespaceID == kNameSpaceID_None) {
|
||||
// Store id as an atom. id="" means that the element has no id,
|
||||
// not that it has an emptystring as the id.
|
||||
RemoveFromIdTable();
|
||||
if (aValue.IsEmpty()) {
|
||||
UnsetFlags(NODE_HAS_ID);
|
||||
return PR_FALSE;
|
||||
}
|
||||
aResult.ParseAtom(aValue);
|
||||
SetFlags(NODE_HAS_ID);
|
||||
AddToIdTable(aResult.GetAtomValue());
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsXMLElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
PRBool aCompileEventHandlers)
|
||||
{
|
||||
nsresult rv = nsGenericElement::BindToTree(aDocument, aParent,
|
||||
aBindingParent,
|
||||
aCompileEventHandlers);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aDocument && HasFlag(NODE_HAS_ID) && !GetBindingParent()) {
|
||||
aDocument->AddToIdTable(this, DoGetID());
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsXMLElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
|
||||
{
|
||||
RemoveFromIdTable();
|
||||
|
||||
return nsGenericElement::UnbindFromTree(aDeep, aNullParent);
|
||||
}
|
||||
|
|
|
@ -62,6 +62,20 @@ public:
|
|||
|
||||
// nsINode interface methods
|
||||
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
|
||||
|
||||
// nsIContent interface methods
|
||||
virtual nsIAtom *GetIDAttributeName() const;
|
||||
virtual nsIAtom* DoGetID() const;
|
||||
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
PRBool aCompileEventHandlers);
|
||||
virtual void UnbindFromTree(PRBool aDeep, PRBool aNullParent);
|
||||
virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
|
||||
PRBool aNotify);
|
||||
virtual PRBool ParseAttribute(PRInt32 aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult);
|
||||
};
|
||||
|
||||
#endif // nsXMLElement_h___
|
||||
|
|
|
@ -272,7 +272,7 @@ nsXULElement::Create(nsXULPrototypeElement* aPrototype, nsINodeInfo *aNodeInfo,
|
|||
|
||||
element->mPrototype = aPrototype;
|
||||
if (aPrototype->mHasIdAttribute) {
|
||||
element->SetFlags(NODE_MAY_HAVE_ID);
|
||||
element->SetFlags(NODE_HAS_ID);
|
||||
}
|
||||
if (aPrototype->mHasClassAttribute) {
|
||||
element->SetFlags(NODE_MAY_HAVE_CLASS);
|
||||
|
@ -874,12 +874,9 @@ nsXULElement::BindToTree(nsIDocument* aDocument,
|
|||
nsIContent* aBindingParent,
|
||||
PRBool aCompileEventHandlers)
|
||||
{
|
||||
// Calling the nsStyledElementBase method on purpose to skip over
|
||||
// nsStyledElement, since we don't want the style attribute
|
||||
// reparsing it does.
|
||||
nsresult rv = nsStyledElementBase::BindToTree(aDocument, aParent,
|
||||
aBindingParent,
|
||||
aCompileEventHandlers);
|
||||
nsresult rv = nsStyledElement::BindToTree(aDocument, aParent,
|
||||
aBindingParent,
|
||||
aCompileEventHandlers);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aDocument) {
|
||||
|
@ -1306,6 +1303,13 @@ nsXULElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, PRBool aNotify)
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
PRBool isId = PR_FALSE;
|
||||
if (aName == nsGkAtoms::id && aNameSpaceID == kNameSpaceID_None) {
|
||||
// Have to do this before clearing flag. See RemoveFromIdTable
|
||||
RemoveFromIdTable();
|
||||
isId = PR_TRUE;
|
||||
}
|
||||
|
||||
PRInt32 index = mAttrsAndChildren.IndexOfAttr(aName, aNameSpaceID);
|
||||
if (index < 0) {
|
||||
NS_ASSERTION(!protoattr, "we used to have a protoattr, we should now "
|
||||
|
@ -1359,6 +1363,10 @@ nsXULElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, PRBool aNotify)
|
|||
// other things.
|
||||
// XXX Know how to remove POPUP event listeners when an attribute is unset?
|
||||
|
||||
if (isId) {
|
||||
UnsetFlags(NODE_HAS_ID);
|
||||
}
|
||||
|
||||
if (aNameSpaceID == kNameSpaceID_None) {
|
||||
if (aName == nsGkAtoms::hidechrome &&
|
||||
mNodeInfo->Equals(nsGkAtoms::window)) {
|
||||
|
@ -1717,26 +1725,22 @@ nsXULElement::GetBuilder(nsIXULTemplateBuilder** aBuilder)
|
|||
//----------------------------------------------------------------------
|
||||
// Implementation methods
|
||||
|
||||
/// XXX GetID must be defined here because we have proto attrs.
|
||||
// XXX DoGetID and DoGetClasses must be defined here because we have proto
|
||||
// attributes.
|
||||
nsIAtom*
|
||||
nsXULElement::GetID() const
|
||||
nsXULElement::DoGetID() const
|
||||
{
|
||||
if (!HasFlag(NODE_MAY_HAVE_ID)) {
|
||||
return nsnull;
|
||||
}
|
||||
NS_ASSERTION(HasFlag(NODE_HAS_ID), "Unexpected call");
|
||||
const nsAttrValue* attr =
|
||||
FindLocalOrProtoAttr(kNameSpaceID_None, nsGkAtoms::id);
|
||||
|
||||
const nsAttrValue* attrVal = FindLocalOrProtoAttr(kNameSpaceID_None, nsGkAtoms::id);
|
||||
// We need the nullcheck here because during unlink the prototype looses
|
||||
// all of its attributes. We might want to change that.
|
||||
// The nullcheck would also be needed if we make UnsetAttr use
|
||||
// nsGenericElement::UnsetAttr as that calls out to various code between
|
||||
// removing the attribute and clearing the NODE_HAS_ID flag.
|
||||
|
||||
NS_ASSERTION(!attrVal ||
|
||||
attrVal->Type() == nsAttrValue::eAtom ||
|
||||
(attrVal->Type() == nsAttrValue::eString &&
|
||||
attrVal->GetStringValue().IsEmpty()),
|
||||
"unexpected attribute type");
|
||||
|
||||
if (attrVal && attrVal->Type() == nsAttrValue::eAtom) {
|
||||
return attrVal->GetAtomValue();
|
||||
}
|
||||
return nsnull;
|
||||
return attr ? attr->GetAtomValue() : nsnull;
|
||||
}
|
||||
|
||||
const nsAttrValue*
|
||||
|
|
|
@ -528,7 +528,7 @@ public:
|
|||
virtual nsIContent *GetBindingParent() const;
|
||||
virtual PRBool IsNodeOfType(PRUint32 aFlags) const;
|
||||
virtual PRBool IsFocusable(PRInt32 *aTabIndex = nsnull, PRBool aWithMouse = PR_FALSE);
|
||||
virtual nsIAtom* GetID() const;
|
||||
virtual nsIAtom* DoGetID() const;
|
||||
virtual const nsAttrValue* DoGetClasses() const;
|
||||
|
||||
NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker);
|
||||
|
|
|
@ -47,10 +47,10 @@ class nsIContent;
|
|||
class nsIScriptGlobalObjectOwner;
|
||||
|
||||
|
||||
// {E486EA2A-5B37-4107-905F-EE062FB4FF97}
|
||||
// 3e872e97-b678-418e-a7e3-41b8305d4e75
|
||||
#define NS_IXULDOCUMENT_IID \
|
||||
{ 0xe486ea2a, 0x5b37, 0x4107, \
|
||||
{ 0x90, 0x5f, 0xee, 0x06, 0x2f, 0xb4, 0xff, 0x97 }}
|
||||
{ 0x3e872e97, 0xb678, 0x418e, \
|
||||
{ 0xa7, 0xe3, 0x41, 0xb8, 0x30, 0x5d, 0x4e, 0x75 } }
|
||||
|
||||
|
||||
/*
|
||||
|
@ -63,14 +63,6 @@ class nsIXULDocument : public nsISupports
|
|||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IXULDOCUMENT_IID)
|
||||
|
||||
// The resource-to-element map is a one-to-many mapping of RDF
|
||||
// resources to content elements.
|
||||
|
||||
/**
|
||||
* Add an entry to the ID-to-element map.
|
||||
*/
|
||||
NS_IMETHOD AddElementForID(nsIContent* aElement) = 0;
|
||||
|
||||
/**
|
||||
* Get the elements for a particular resource --- all elements whose 'id'
|
||||
* or 'ref' is aID. The nsCOMArray will be truncated and filled in with
|
||||
|
|
|
@ -238,6 +238,7 @@ nsXULDocument::nsXULDocument(void)
|
|||
mCharacterSet.AssignLiteral("UTF-8");
|
||||
|
||||
mDefaultElementType = kNameSpaceID_XUL;
|
||||
mIsXUL = PR_TRUE;
|
||||
|
||||
mDelayFrameLoaderInitialization = PR_TRUE;
|
||||
}
|
||||
|
@ -980,9 +981,6 @@ nsXULDocument::AttributeWillChange(nsIDocument* aDocument,
|
|||
(aAttribute == nsGkAtoms::id && !aContent->GetIDAttributeName())) {
|
||||
RemoveElementFromRefMap(aContent->AsElement());
|
||||
}
|
||||
|
||||
nsXMLDocument::AttributeWillChange(aDocument, aContent, aNameSpaceID,
|
||||
aAttribute, aModType);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -995,10 +993,6 @@ nsXULDocument::AttributeChanged(nsIDocument* aDocument,
|
|||
// XXXbz once we change AttributeChanged to take Element, we can nix this line
|
||||
Element* aElement = aElementContent->AsElement();
|
||||
|
||||
// Do this here so that all the exit paths below don't leave this undone
|
||||
nsXMLDocument::AttributeChanged(aDocument, aElement, aNameSpaceID,
|
||||
aAttribute, aModType);
|
||||
|
||||
// XXXbz check aNameSpaceID, dammit!
|
||||
// See if we need to update our ref map.
|
||||
if (aAttribute == nsGkAtoms::ref ||
|
||||
|
@ -1100,9 +1094,6 @@ nsXULDocument::ContentAppended(nsIDocument* aDocument,
|
|||
cur = cur->GetNextSibling()) {
|
||||
rv = AddSubtreeToDocument(cur);
|
||||
}
|
||||
|
||||
nsXMLDocument::ContentAppended(aDocument, aContainer, aFirstNewContent,
|
||||
aNewIndexInContainer);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1114,8 +1105,6 @@ nsXULDocument::ContentInserted(nsIDocument* aDocument,
|
|||
NS_ASSERTION(aDocument == this, "unexpected doc");
|
||||
|
||||
AddSubtreeToDocument(aChild);
|
||||
|
||||
nsXMLDocument::ContentInserted(aDocument, aContainer, aChild, aIndexInContainer);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1127,8 +1116,6 @@ nsXULDocument::ContentRemoved(nsIDocument* aDocument,
|
|||
NS_ASSERTION(aDocument == this, "unexpected doc");
|
||||
|
||||
RemoveSubtreeFromDocument(aChild);
|
||||
|
||||
nsXMLDocument::ContentRemoved(aDocument, aContainer, aChild, aIndexInContainer);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
@ -1136,19 +1123,6 @@ nsXULDocument::ContentRemoved(nsIDocument* aDocument,
|
|||
// nsIXULDocument interface
|
||||
//
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULDocument::AddElementForID(nsIContent* aElement)
|
||||
{
|
||||
NS_PRECONDITION(aElement != nsnull, "null ptr");
|
||||
if (! aElement)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
if (!aElement->IsElement())
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
UpdateIdTableEntry(aElement->AsElement());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULDocument::GetElementsForID(const nsAString& aID,
|
||||
nsCOMArray<nsIContent>& aElements)
|
||||
|
@ -1661,17 +1635,15 @@ nsXULDocument::GetCommandDispatcher(nsIDOMXULCommandDispatcher** aTracker)
|
|||
}
|
||||
|
||||
Element*
|
||||
nsXULDocument::GetElementById(const nsAString& aId, nsresult *aResult)
|
||||
nsXULDocument::GetElementById(const nsAString& aId)
|
||||
{
|
||||
nsCOMPtr<nsIAtom> atom(do_GetAtom(aId));
|
||||
if (!atom) {
|
||||
*aResult = NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// This can only fail due OOM if the atom doesn't exist, in which
|
||||
// case there couldn't possibly exist an entry for it.
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
*aResult = NS_OK;
|
||||
|
||||
if (!CheckGetElementByIdArg(atom))
|
||||
return nsnull;
|
||||
|
||||
|
@ -1700,7 +1672,10 @@ nsXULDocument::AddElementToDocumentPre(Element* aElement)
|
|||
// 1. Add the element to the resource-to-element map. Also add it to
|
||||
// the id map, since it seems this can be called when creating
|
||||
// elements from prototypes.
|
||||
UpdateIdTableEntry(aElement);
|
||||
nsIAtom* id = aElement->GetID();
|
||||
if (id) {
|
||||
AddToIdTable(aElement, id);
|
||||
}
|
||||
rv = AddElementToRefMap(aElement);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
|
@ -1835,7 +1810,10 @@ nsXULDocument::RemoveSubtreeFromDocument(nsIContent* aContent)
|
|||
// Also remove it from the id map, since we added it in
|
||||
// AddElementToDocumentPre().
|
||||
RemoveElementFromRefMap(aElement);
|
||||
RemoveFromIdTable(aElement);
|
||||
nsIAtom* id = aElement->GetID();
|
||||
if (id) {
|
||||
RemoveFromIdTable(aElement, id);
|
||||
}
|
||||
|
||||
// 3. If the element is a 'command updater', then remove the
|
||||
// element from the document's command dispatcher.
|
||||
|
@ -2472,8 +2450,6 @@ nsXULDocument::PrepareToWalk()
|
|||
rv = AppendChildTo(root, PR_FALSE);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Add the root element to the XUL document's ID-to-element map.
|
||||
UpdateIdTableEntry(root);
|
||||
rv = AddElementToRefMap(root);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
|
|
|
@ -148,7 +148,6 @@ public:
|
|||
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTEWILLCHANGE
|
||||
|
||||
// nsIXULDocument interface
|
||||
NS_IMETHOD AddElementForID(nsIContent* aElement);
|
||||
NS_IMETHOD GetElementsForID(const nsAString& aID,
|
||||
nsCOMArray<nsIContent>& aElements);
|
||||
|
||||
|
@ -170,8 +169,7 @@ public:
|
|||
{
|
||||
return nsDocument::GetElementById(aId, aReturn);
|
||||
}
|
||||
virtual mozilla::dom::Element* GetElementById(const nsAString & elementId,
|
||||
nsresult *aResult);
|
||||
virtual mozilla::dom::Element* GetElementById(const nsAString & elementId);
|
||||
|
||||
// nsIDOMXULDocument interface
|
||||
NS_DECL_NSIDOMXULDOCUMENT
|
||||
|
|
|
@ -634,17 +634,6 @@ nsXULContentBuilder::BuildContentFromTemplate(nsIContent *aTemplateNode,
|
|||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if (! aNotify) {
|
||||
// XUL document will watch us, and take care of making
|
||||
// sure that we get added to or removed from the
|
||||
// element map if aNotify is true. If not, we gotta do
|
||||
// it ourselves. Yay.
|
||||
nsCOMPtr<nsIXULDocument> xuldoc =
|
||||
do_QueryInterface(mRoot->GetDocument());
|
||||
if (xuldoc)
|
||||
xuldoc->AddElementForID(realKid);
|
||||
}
|
||||
|
||||
// Set up the element's 'container' and 'empty' attributes.
|
||||
SetContainerAttrs(realKid, aChild, PR_TRUE, PR_FALSE);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче