mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 542592 - Change how we use/store nsDocument::mLinkMap
This makes changes nsDocument::mLinkMap in a number of ways: 1) renamed to mStyledLinks to better reflect its new nature. 2) change it to an nsTHashtable of Link*. It no longer has a strong reference 3) add some assertions to make sure we call ForgetLink and AddStyleRelevantLink in pairs. This also makes mozilla::dom::Link::ResetLinkState take a boolean indicating if we should notify or not. r=bz
This commit is contained in:
parent
17cfa3d578
commit
149f5aac0a
@ -72,8 +72,8 @@ enum nsLinkState {
|
||||
|
||||
// IID for the nsIContent interface
|
||||
#define NS_ICONTENT_IID \
|
||||
{ 0xe88a767e, 0x1ca1, 0x4855, \
|
||||
{ 0xa7, 0xa4, 0x37, 0x9f, 0x07, 0x89, 0x45, 0xef } }
|
||||
{ 0xc19d6f16, 0xab13, 0x4dde, \
|
||||
{ 0x99, 0x7a, 0x51, 0x04, 0xc3, 0x64, 0xd2, 0x51 } }
|
||||
|
||||
/**
|
||||
* A node of content in a document's content model. This interface
|
||||
@ -668,17 +668,6 @@ public:
|
||||
*/
|
||||
virtual PRBool IsLink(nsIURI** aURI) const = 0;
|
||||
|
||||
/**
|
||||
* If the implementing element is a link, calling this method forces it to
|
||||
* clear its cached href, if it has one.
|
||||
*
|
||||
* This function does not notify the document that it may need to restyle the
|
||||
* link.
|
||||
*/
|
||||
virtual void DropCachedHref()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cached state of the link. If the state is unknown,
|
||||
* return eLinkState_Unknown.
|
||||
@ -690,17 +679,6 @@ public:
|
||||
return eLinkState_NotLink;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cached state of the link.
|
||||
*
|
||||
* @param aState The cached link state of the link.
|
||||
*/
|
||||
virtual void SetLinkState(nsLinkState aState)
|
||||
{
|
||||
NS_ASSERTION(aState == eLinkState_NotLink,
|
||||
"Need to override SetLinkState?");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a pointer to the full href URI (fully resolved and canonicalized,
|
||||
* since it's an nsIURI object) for link elements.
|
||||
|
@ -104,10 +104,16 @@ struct JSObject;
|
||||
class nsFrameLoader;
|
||||
class nsIBoxObject;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class Link;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
// IID for the nsIDocument interface
|
||||
#define NS_IDOCUMENT_IID \
|
||||
{ 0x7d1ff787, 0x8c35, 0x45f3, \
|
||||
{ 0xa6, 0x7c, 0x8d, 0x7f, 0x36, 0xbd, 0x4e, 0x68 } }
|
||||
{ 0xd7978655, 0x9b7d, 0x41e6, \
|
||||
{ 0xad, 0x48, 0xdf, 0x32, 0x0b, 0x06, 0xb4, 0xda } }
|
||||
|
||||
// Flag for AddStyleSheet().
|
||||
#define NS_STYLESHEET_FROM_CATALOG (1 << 0)
|
||||
@ -907,17 +913,16 @@ public:
|
||||
* style.
|
||||
*/
|
||||
/**
|
||||
* Notification that an element is a link with a given URI that is
|
||||
* relevant to style.
|
||||
* Notification that an element is a link that is relevant to style.
|
||||
*/
|
||||
virtual void AddStyleRelevantLink(nsIContent* aContent, nsIURI* aURI) = 0;
|
||||
virtual void AddStyleRelevantLink(mozilla::dom::Link* aLink) = 0;
|
||||
/**
|
||||
* Notification that an element is a link and its URI might have been
|
||||
* changed or the element removed. If the element is still a link relevant
|
||||
* to style, then someone must ensure that AddStyleRelevantLink is
|
||||
* (eventually) called on it again.
|
||||
*/
|
||||
virtual void ForgetLink(nsIContent* aContent) = 0;
|
||||
virtual void ForgetLink(mozilla::dom::Link* aLink) = 0;
|
||||
|
||||
/**
|
||||
* Resets and removes a box object from the document's box object cache
|
||||
|
@ -78,14 +78,6 @@ Link::GetLinkState() const
|
||||
void
|
||||
Link::SetLinkState(nsLinkState aState)
|
||||
{
|
||||
// Other code may try to reset our state by passing in eLinkState_Unknown. In
|
||||
// these situations, we want to call ResetLinkState and return since we may
|
||||
// not be registered, and we may already be in an unknown state.
|
||||
if (aState == eLinkState_Unknown) {
|
||||
ResetLinkState();
|
||||
return;
|
||||
}
|
||||
|
||||
NS_ASSERTION(mRegistered,
|
||||
"Setting the link state of an unregistered Link!");
|
||||
NS_ASSERTION(mLinkState != aState,
|
||||
@ -147,7 +139,7 @@ Link::LinkState() const
|
||||
// And make sure we are in the document's link map.
|
||||
nsIDocument *doc = content->GetCurrentDoc();
|
||||
if (doc) {
|
||||
doc->AddStyleRelevantLink(content, hrefURI);
|
||||
doc->AddStyleRelevantLink(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -470,16 +462,25 @@ Link::GetHash(nsAString &_hash)
|
||||
}
|
||||
|
||||
void
|
||||
Link::ResetLinkState()
|
||||
Link::ResetLinkState(bool aNotify)
|
||||
{
|
||||
// If we are in our default state, bail early.
|
||||
if (mLinkState == defaultState) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we are not a link, revert to the default state and do no more work.
|
||||
if (mLinkState == eLinkState_NotLink) {
|
||||
mLinkState = defaultState;
|
||||
return;
|
||||
}
|
||||
|
||||
nsIContent *content = Content();
|
||||
|
||||
// Tell the document to forget about this link, but only if we are registered.
|
||||
if (mRegistered) {
|
||||
nsIDocument *doc = content->GetCurrentDoc();
|
||||
if (doc) {
|
||||
doc->ForgetLink(content);
|
||||
}
|
||||
// Tell the document to forget about this link.
|
||||
nsIDocument *doc = content->GetCurrentDoc();
|
||||
if (doc) {
|
||||
doc->ForgetLink(this);
|
||||
}
|
||||
|
||||
UnregisterFromHistory();
|
||||
@ -489,6 +490,17 @@ Link::ResetLinkState()
|
||||
|
||||
// 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) {
|
||||
PRUint32 changedState = NS_EVENT_STATE_VISITED ^ NS_EVENT_STATE_UNVISITED;
|
||||
MOZ_AUTO_DOC_UPDATE(doc, UPDATE_STYLE, aNotify);
|
||||
doc->ContentStatesChanged(content, nsnull, changedState);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -87,12 +87,16 @@ public:
|
||||
nsresult GetPort(nsAString &_port);
|
||||
nsresult GetHash(nsAString &_hash);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Invalidates any link caching, and resets the state to the default.
|
||||
*
|
||||
* @param aNotify
|
||||
* true if ResetLinkState should notify the owning document about style
|
||||
* changes or false if it should not.
|
||||
*/
|
||||
virtual void ResetLinkState();
|
||||
virtual void ResetLinkState(bool aNotify);
|
||||
|
||||
protected:
|
||||
virtual ~Link();
|
||||
|
||||
private:
|
||||
|
@ -189,6 +189,10 @@ static NS_DEFINE_CID(kDOMEventGroupCID, NS_DOMEVENTGROUP_CID);
|
||||
// FOR CSP (autogenerated by xpidl)
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
|
||||
#include "mozilla/dom/Link.h"
|
||||
using namespace mozilla::dom;
|
||||
|
||||
|
||||
/* Keeps track of whether or not CSP is enabled */
|
||||
static PRBool gCSPEnabled = PR_TRUE;
|
||||
|
||||
@ -197,122 +201,6 @@ static PRLogModuleInfo* gDocumentLeakPRLog;
|
||||
static PRLogModuleInfo* gCspPRLog;
|
||||
#endif
|
||||
|
||||
void
|
||||
nsUint32ToContentHashEntry::Destroy()
|
||||
{
|
||||
HashSet* set = GetHashSet();
|
||||
if (set) {
|
||||
delete set;
|
||||
} else {
|
||||
nsIContent* content = GetContent();
|
||||
NS_IF_RELEASE(content);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsUint32ToContentHashEntry::PutContent(nsIContent* aVal)
|
||||
{
|
||||
// Add the value to the hash if it is there
|
||||
HashSet* set = GetHashSet();
|
||||
if (set) {
|
||||
nsISupportsHashKey* entry = set->PutEntry(aVal);
|
||||
return entry ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// If an element is already there, create a hashtable and both of these to it
|
||||
nsIContent* oldVal = GetContent();
|
||||
if (oldVal) {
|
||||
nsresult rv = InitHashSet(&set);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsISupportsHashKey* entry = set->PutEntry(oldVal);
|
||||
if (!entry) {
|
||||
// OOM - we can't insert aVal, but we can at least put oldVal back (even
|
||||
// if we didn't, we'd still have to release oldVal so that we don't leak)
|
||||
delete set;
|
||||
SetContent(oldVal);
|
||||
// SetContent adds another reference, so release the one we had
|
||||
NS_RELEASE(oldVal);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
// The hashset adds its own reference, so release the one we had
|
||||
NS_RELEASE(oldVal);
|
||||
|
||||
entry = set->PutEntry(aVal);
|
||||
return entry ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Nothing exists in the hash right now, so just set the single pointer
|
||||
return SetContent(aVal);
|
||||
}
|
||||
|
||||
void
|
||||
nsUint32ToContentHashEntry::RemoveContent(nsIContent* aVal)
|
||||
{
|
||||
// Remove from the hash if the hash is there
|
||||
HashSet* set = GetHashSet();
|
||||
if (set) {
|
||||
set->RemoveEntry(aVal);
|
||||
if (set->Count() == 0) {
|
||||
delete set;
|
||||
mValOrHash = nsnull;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove the ptr if there is just a ptr
|
||||
nsIContent* v = GetContent();
|
||||
if (v == aVal) {
|
||||
NS_IF_RELEASE(v);
|
||||
mValOrHash = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsUint32ToContentHashEntry::InitHashSet(HashSet** aSet)
|
||||
{
|
||||
HashSet* newSet = new HashSet();
|
||||
if (!newSet) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsresult rv = newSet->Init();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mValOrHash = newSet;
|
||||
*aSet = newSet;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
nsUint32ToContentHashEntryVisitorCallback(nsISupportsHashKey* aEntry,
|
||||
void* aClosure)
|
||||
{
|
||||
nsUint32ToContentHashEntry::Visitor* visitor =
|
||||
static_cast<nsUint32ToContentHashEntry::Visitor*>(aClosure);
|
||||
visitor->Visit(static_cast<nsIContent*>(aEntry->GetKey()));
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
nsUint32ToContentHashEntry::VisitContent(Visitor* aVisitor)
|
||||
{
|
||||
HashSet* set = GetHashSet();
|
||||
if (set) {
|
||||
set->EnumerateEntries(nsUint32ToContentHashEntryVisitorCallback, aVisitor);
|
||||
if (set->Count() == 0) {
|
||||
delete set;
|
||||
mValOrHash = nsnull;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
nsIContent* v = GetContent();
|
||||
if (v) {
|
||||
aVisitor->Visit(v);
|
||||
}
|
||||
}
|
||||
|
||||
#define NAME_NOT_VALID ((nsBaseContentList*)1)
|
||||
|
||||
nsIdentifierMapEntry::~nsIdentifierMapEntry()
|
||||
@ -1716,26 +1604,6 @@ BoxObjectTraverser(const void* key, nsPIBoxObject* boxObject, void* userArg)
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
class LinkMapTraversalVisitor : public nsUint32ToContentHashEntry::Visitor
|
||||
{
|
||||
public:
|
||||
nsCycleCollectionTraversalCallback *mCb;
|
||||
virtual void Visit(nsIContent* aContent)
|
||||
{
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*mCb, "mLinkMap entry");
|
||||
mCb->NoteXPCOMChild(aContent);
|
||||
}
|
||||
};
|
||||
|
||||
static PLDHashOperator
|
||||
LinkMapTraverser(nsUint32ToContentHashEntry* aEntry, void* userArg)
|
||||
{
|
||||
LinkMapTraversalVisitor visitor;
|
||||
visitor.mCb = static_cast<nsCycleCollectionTraversalCallback*>(userArg);
|
||||
aEntry->VisitContent(&visitor);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
IdentifierMapEntryTraverse(nsIdentifierMapEntry *aEntry, void *aArg)
|
||||
{
|
||||
@ -1800,12 +1668,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDocument)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDOMImplementation)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOriginalDocument)
|
||||
|
||||
// An element will only be in the linkmap as long as it's in the
|
||||
// document, so we'll traverse the table here instead of from the element.
|
||||
if (tmp->mLinkMap.IsInitialized()) {
|
||||
tmp->mLinkMap.EnumerateEntries(LinkMapTraverser, &cb);
|
||||
}
|
||||
|
||||
// Traverse all our nsCOMArrays.
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mStyleSheets)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mCatalogSheets)
|
||||
@ -1830,11 +1692,6 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
|
||||
// Tear down linkmap. This is a performance optimization so that we
|
||||
// don't waste time removing links one by one as they are removed
|
||||
// from the doc.
|
||||
tmp->DestroyLinkMap();
|
||||
|
||||
// Clear out our external resources
|
||||
tmp->mExternalResourceMap.Shutdown();
|
||||
|
||||
@ -1876,7 +1733,7 @@ nsDocument::Init()
|
||||
}
|
||||
|
||||
mIdentifierMap.Init();
|
||||
mLinkMap.Init();
|
||||
(void)mStyledLinks.Init();
|
||||
mRadioGroups.Init();
|
||||
|
||||
// Force initialization.
|
||||
@ -7488,107 +7345,60 @@ static PRUint32 GetURIHash(nsIURI* aURI)
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::AddStyleRelevantLink(nsIContent* aContent, nsIURI* aURI)
|
||||
nsDocument::AddStyleRelevantLink(Link* aLink)
|
||||
{
|
||||
nsUint32ToContentHashEntry* entry = mLinkMap.PutEntry(GetURIHash(aURI));
|
||||
if (!entry) // out of memory?
|
||||
return;
|
||||
entry->PutContent(aContent);
|
||||
NS_ASSERTION(aLink, "Passing in a null link. Expect crashes RSN!");
|
||||
#ifdef DEBUG
|
||||
nsPtrHashKey<Link>* entry = mStyledLinks.GetEntry(aLink);
|
||||
NS_ASSERTION(!entry, "Document already knows about this Link!");
|
||||
mStyledLinksCleared = false;
|
||||
#endif
|
||||
(void)mStyledLinks.PutEntry(aLink);
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::ForgetLink(nsIContent* aContent)
|
||||
nsDocument::ForgetLink(Link* aLink)
|
||||
{
|
||||
// Important optimization! If the link map is empty (as it will be
|
||||
// during teardown because we destroy the map early), then stop
|
||||
// now before we waste time constructing a URI object.
|
||||
if (mLinkMap.Count() == 0)
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
if (!aContent->IsLink(getter_AddRefs(uri)))
|
||||
return;
|
||||
PRUint32 hash = GetURIHash(uri);
|
||||
nsUint32ToContentHashEntry* entry = mLinkMap.GetEntry(hash);
|
||||
if (!entry)
|
||||
return;
|
||||
|
||||
entry->RemoveContent(aContent);
|
||||
if (entry->IsEmpty()) {
|
||||
// Remove the entry and allow the table to resize, in case
|
||||
// a lot of links are being removed from the document or modified
|
||||
mLinkMap.RemoveEntry(hash);
|
||||
}
|
||||
NS_ASSERTION(aLink, "Passing in a null link. Expect crashes RSN!");
|
||||
#ifdef DEBUG
|
||||
nsPtrHashKey<Link>* entry = mStyledLinks.GetEntry(aLink);
|
||||
NS_ASSERTION(entry || mStyledLinksCleared,
|
||||
"Document knows nothing about this Link!");
|
||||
#endif
|
||||
(void)mStyledLinks.RemoveEntry(aLink);
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::DestroyLinkMap()
|
||||
{
|
||||
mLinkMap.Clear();
|
||||
#ifdef DEBUG
|
||||
mStyledLinksCleared = true;
|
||||
#endif
|
||||
mStyledLinks.Clear();
|
||||
}
|
||||
|
||||
class RefreshLinkStateVisitor : public nsUint32ToContentHashEntry::Visitor
|
||||
static
|
||||
PLDHashOperator
|
||||
EnumerateStyledLinks(nsPtrHashKey<Link>* aEntry, void* aArray)
|
||||
{
|
||||
public:
|
||||
nsCOMArray<nsIContent> contentVisited;
|
||||
|
||||
virtual void Visit(nsIContent* aContent) {
|
||||
// We can't call ContentStatesChanged here, because that may modify the link
|
||||
// map. Instead, we just add to an array and call ContentStatesChanged
|
||||
// later.
|
||||
aContent->SetLinkState(eLinkState_Unknown);
|
||||
contentVisited.AppendObject(aContent);
|
||||
}
|
||||
};
|
||||
|
||||
static PLDHashOperator
|
||||
RefreshLinkStateTraverser(nsUint32ToContentHashEntry* aEntry,
|
||||
void* userArg)
|
||||
{
|
||||
RefreshLinkStateVisitor *visitor =
|
||||
static_cast<RefreshLinkStateVisitor*>(userArg);
|
||||
|
||||
aEntry->VisitContent(visitor);
|
||||
nsTArray<Link*>* array = static_cast<nsTArray<Link*>*>(aArray);
|
||||
(void)array->AppendElement(aEntry->GetKey());
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
|
||||
// Helper function for nsDocument::RefreshLinkHrefs
|
||||
static void
|
||||
DropCachedHrefsRecursive(nsIContent * const elem)
|
||||
{
|
||||
// Drop the element's cached href, if it has one. (If it doesn't have
|
||||
// one, this call does nothing.) We could check first that elem is an <a>
|
||||
// tag to avoid making a virtual call, but it turns out not to make a
|
||||
// substantial perf difference either way. This doesn't restyle the link,
|
||||
// but we do that later.
|
||||
elem->DropCachedHref();
|
||||
|
||||
PRUint32 childCount;
|
||||
nsIContent * const * child = elem->GetChildArray(&childCount);
|
||||
nsIContent * const * end = child + childCount;
|
||||
for ( ; child != end; ++child) {
|
||||
DropCachedHrefsRecursive(*child);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::RefreshLinkHrefs()
|
||||
{
|
||||
if (!GetRootContent())
|
||||
return;
|
||||
|
||||
// First, walk the DOM and clear the cached hrefs of all the <a> tags.
|
||||
DropCachedHrefsRecursive(GetRootContent());
|
||||
|
||||
// Now update the styles of everything in the linkmap.
|
||||
RefreshLinkStateVisitor visitor;
|
||||
mLinkMap.EnumerateEntries(RefreshLinkStateTraverser, &visitor);
|
||||
// Get a list of all links we know about. We will reset them, which will
|
||||
// remove them from the document, so we need a copy of what is in the
|
||||
// hashtable.
|
||||
nsTArray<Link*> linksToNotify(mStyledLinks.Count());
|
||||
(void)mStyledLinks.EnumerateEntries(EnumerateStyledLinks, &linksToNotify);
|
||||
|
||||
// Reset all of our styled links.
|
||||
MOZ_AUTO_DOC_UPDATE(this, UPDATE_CONTENT_STATE, PR_TRUE);
|
||||
for (PRUint32 count = visitor.contentVisited.Count(), i = 0; i < count; i++) {
|
||||
ContentStatesChanged(visitor.contentVisited[i],
|
||||
nsnull, NS_EVENT_STATE_VISITED);
|
||||
for (nsTArray_base::size_type i = 0; i < linksToNotify.Length(); i++) {
|
||||
linksToNotify[i]->ResetLinkState(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,83 +140,6 @@ class nsChildContentList;
|
||||
class nsSMILAnimationController;
|
||||
#endif // MOZ_SMIL
|
||||
|
||||
/**
|
||||
* Hashentry using a PRUint32 key and a cheap set of nsIContent* owning
|
||||
* pointers for the value.
|
||||
*
|
||||
* @see nsTHashtable::EntryType for specification
|
||||
*/
|
||||
class nsUint32ToContentHashEntry : public PLDHashEntryHdr
|
||||
{
|
||||
public:
|
||||
typedef const PRUint32& KeyType;
|
||||
typedef const PRUint32* KeyTypePointer;
|
||||
|
||||
nsUint32ToContentHashEntry(const KeyTypePointer key) :
|
||||
mValue(*key), mValOrHash(nsnull) { }
|
||||
nsUint32ToContentHashEntry(const nsUint32ToContentHashEntry& toCopy) :
|
||||
mValue(toCopy.mValue), mValOrHash(toCopy.mValOrHash)
|
||||
{
|
||||
// Pathetic attempt to not die: clear out the other mValOrHash so we're
|
||||
// effectively stealing it. If toCopy is destroyed right after this,
|
||||
// we'll be OK.
|
||||
const_cast<nsUint32ToContentHashEntry&>(toCopy).mValOrHash = nsnull;
|
||||
NS_ERROR("Copying not supported. Fasten your seat belt.");
|
||||
}
|
||||
~nsUint32ToContentHashEntry() { Destroy(); }
|
||||
|
||||
KeyType GetKey() const { return mValue; }
|
||||
|
||||
PRBool KeyEquals(KeyTypePointer aKey) const { return mValue == *aKey; }
|
||||
|
||||
static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
|
||||
static PLDHashNumber HashKey(KeyTypePointer aKey) { return *aKey; }
|
||||
enum { ALLOW_MEMMOVE = PR_TRUE };
|
||||
|
||||
// Content set methods
|
||||
nsresult PutContent(nsIContent* aContent);
|
||||
|
||||
void RemoveContent(nsIContent* aContent);
|
||||
|
||||
struct Visitor {
|
||||
virtual void Visit(nsIContent* aContent) = 0;
|
||||
};
|
||||
void VisitContent(Visitor* aVisitor);
|
||||
|
||||
PRBool IsEmpty() { return mValOrHash == nsnull; }
|
||||
|
||||
private:
|
||||
typedef PRUptrdiff PtrBits;
|
||||
typedef nsTHashtable<nsISupportsHashKey> HashSet;
|
||||
/** Get the hash pointer (or null if we're not a hash) */
|
||||
HashSet* GetHashSet()
|
||||
{
|
||||
return (PtrBits(mValOrHash) & 0x1) ? nsnull : (HashSet*)mValOrHash;
|
||||
}
|
||||
/** Find out whether it is an nsIContent (returns weak) */
|
||||
nsIContent* GetContent()
|
||||
{
|
||||
return (PtrBits(mValOrHash) & 0x1)
|
||||
? (nsIContent*)(PtrBits(mValOrHash) & ~0x1)
|
||||
: nsnull;
|
||||
}
|
||||
/** Set the single element, adding a reference */
|
||||
nsresult SetContent(nsIContent* aVal)
|
||||
{
|
||||
NS_IF_ADDREF(aVal);
|
||||
mValOrHash = (void*)(PtrBits(aVal) | 0x1);
|
||||
return NS_OK;
|
||||
}
|
||||
/** Initialize the hash */
|
||||
nsresult InitHashSet(HashSet** aSet);
|
||||
|
||||
void Destroy();
|
||||
|
||||
private:
|
||||
const PRUint32 mValue;
|
||||
/** A hash or nsIContent ptr, depending on the lower bit (0=hash, 1=ptr) */
|
||||
void* mValOrHash;
|
||||
};
|
||||
|
||||
/**
|
||||
* Right now our identifier map entries contain information for 'name'
|
||||
@ -943,8 +866,8 @@ public:
|
||||
virtual NS_HIDDEN_(void) BlockOnload();
|
||||
virtual NS_HIDDEN_(void) UnblockOnload(PRBool aFireSync);
|
||||
|
||||
virtual NS_HIDDEN_(void) AddStyleRelevantLink(nsIContent* aContent, nsIURI* aURI);
|
||||
virtual NS_HIDDEN_(void) ForgetLink(nsIContent* aContent);
|
||||
virtual NS_HIDDEN_(void) AddStyleRelevantLink(mozilla::dom::Link* aLink);
|
||||
virtual NS_HIDDEN_(void) ForgetLink(mozilla::dom::Link* aLink);
|
||||
|
||||
NS_HIDDEN_(void) ClearBoxObjectFor(nsIContent* aContent);
|
||||
NS_IMETHOD GetBoxObjectFor(nsIDOMElement* aElement, nsIBoxObject** aResult);
|
||||
@ -1242,8 +1165,14 @@ private:
|
||||
nsCOMPtr<nsIRequest> mOnloadBlocker;
|
||||
ReadyState mReadyState;
|
||||
|
||||
// A map from unvisited URI hashes to content elements
|
||||
nsTHashtable<nsUint32ToContentHashEntry> mLinkMap;
|
||||
// A hashtable of styled links keyed by address pointer.
|
||||
nsTHashtable<nsPtrHashKey<mozilla::dom::Link> > mStyledLinks;
|
||||
#ifdef DEBUG
|
||||
// Indicates whether mStyledLinks was cleared or not. This is used to track
|
||||
// state so we can provide useful assertions to consumers of ForgetLink and
|
||||
// AddStyleRelevantLink.
|
||||
bool mStyledLinksCleared;
|
||||
#endif
|
||||
|
||||
// Member to store out last-selected stylesheet set.
|
||||
nsString mLastStyleSheetSet;
|
||||
|
@ -2646,10 +2646,6 @@ nsGenericElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
|
||||
// anonymous content that the document is changing.
|
||||
document->BindingManager()->ChangeDocumentFor(this, document, nsnull);
|
||||
|
||||
if (HasAttr(kNameSpaceID_XLink, nsGkAtoms::href)) {
|
||||
document->ForgetLink(this);
|
||||
}
|
||||
|
||||
document->ClearBoxObjectFor(this);
|
||||
}
|
||||
|
||||
@ -4299,20 +4295,6 @@ nsGenericElement::SetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
|
||||
NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
|
||||
"Don't call SetAttr with unknown namespace");
|
||||
|
||||
nsIDocument* doc = GetCurrentDoc();
|
||||
if (kNameSpaceID_XLink == aNamespaceID && nsGkAtoms::href == aName) {
|
||||
// XLink URI(s) might be changing. Drop the link from the map. If it
|
||||
// is still style relevant it will be re-added by
|
||||
// nsStyleUtil::IsLink. Make sure to keep the style system
|
||||
// consistent so this remains true! In particular if the style system
|
||||
// were to get smarter and not restyling an XLink element if the href
|
||||
// doesn't change in a "significant" way, we'd need to do the same
|
||||
// significance check here.
|
||||
if (doc) {
|
||||
doc->ForgetLink(this);
|
||||
}
|
||||
}
|
||||
|
||||
nsAutoString oldValue;
|
||||
PRBool modification = PR_FALSE;
|
||||
PRBool hasListeners = aNotify &&
|
||||
@ -4629,12 +4611,6 @@ nsGenericElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
|
||||
nsIDOMMutationEvent::REMOVAL);
|
||||
}
|
||||
|
||||
if (document && kNameSpaceID_XLink == aNameSpaceID &&
|
||||
nsGkAtoms::href == aName) {
|
||||
// XLink URI might be changing.
|
||||
document->ForgetLink(this);
|
||||
}
|
||||
|
||||
// When notifying, make sure to keep track of states whose value
|
||||
// depends solely on the value of an attribute.
|
||||
PRUint32 stateMask;
|
||||
|
@ -111,7 +111,6 @@ public:
|
||||
virtual PRBool IsLink(nsIURI** aURI) const;
|
||||
virtual void GetLinkTarget(nsAString& aTarget);
|
||||
virtual nsLinkState GetLinkState() const;
|
||||
virtual void SetLinkState(nsLinkState aState);
|
||||
virtual already_AddRefed<nsIURI> GetHrefURI() const;
|
||||
|
||||
nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
|
||||
@ -131,8 +130,6 @@ public:
|
||||
|
||||
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
|
||||
|
||||
virtual void DropCachedHref();
|
||||
|
||||
virtual PRInt32 IntrinsicState() const;
|
||||
};
|
||||
|
||||
@ -200,7 +197,7 @@ nsHTMLAnchorElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
PRBool aCompileEventHandlers)
|
||||
{
|
||||
Link::ResetLinkState();
|
||||
Link::ResetLinkState(false);
|
||||
|
||||
nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
|
||||
aBindingParent,
|
||||
@ -223,7 +220,7 @@ nsHTMLAnchorElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
|
||||
{
|
||||
// If this link is ever reinserted into a document, it might
|
||||
// be under a different xml:base, so forget the cached state now.
|
||||
Link::ResetLinkState();
|
||||
Link::ResetLinkState(false);
|
||||
|
||||
if (IsInDoc()) {
|
||||
RegUnRegAccessKey(PR_FALSE);
|
||||
@ -422,12 +419,6 @@ nsHTMLAnchorElement::GetLinkState() const
|
||||
return Link::GetLinkState();
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLAnchorElement::SetLinkState(nsLinkState aState)
|
||||
{
|
||||
Link::SetLinkState(aState);
|
||||
}
|
||||
|
||||
already_AddRefed<nsIURI>
|
||||
nsHTMLAnchorElement::GetHrefURI() const
|
||||
{
|
||||
@ -443,7 +434,7 @@ nsHTMLAnchorElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
|
||||
nsAutoString val;
|
||||
GetHref(val);
|
||||
if (!val.Equals(aValue)) {
|
||||
Link::ResetLinkState();
|
||||
Link::ResetLinkState(!!aNotify);
|
||||
}
|
||||
}
|
||||
|
||||
@ -467,7 +458,7 @@ nsHTMLAnchorElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
|
||||
PRBool aNotify)
|
||||
{
|
||||
if (aAttribute == nsGkAtoms::href && kNameSpaceID_None == aNameSpaceID) {
|
||||
Link::ResetLinkState();
|
||||
Link::ResetLinkState(!!aNotify);
|
||||
}
|
||||
|
||||
if (aAttribute == nsGkAtoms::accesskey &&
|
||||
@ -488,12 +479,6 @@ nsHTMLAnchorElement::ParseAttribute(PRInt32 aNamespaceID,
|
||||
aResult);
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLAnchorElement::DropCachedHref()
|
||||
{
|
||||
Link::ResetLinkState();
|
||||
}
|
||||
|
||||
PRInt32
|
||||
nsHTMLAnchorElement::IntrinsicState() const
|
||||
{
|
||||
|
@ -93,7 +93,6 @@ public:
|
||||
virtual PRBool IsLink(nsIURI** aURI) const;
|
||||
virtual void GetLinkTarget(nsAString& aTarget);
|
||||
virtual nsLinkState GetLinkState() const;
|
||||
virtual void SetLinkState(nsLinkState aState);
|
||||
virtual already_AddRefed<nsIURI> GetHrefURI() const;
|
||||
|
||||
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
@ -206,7 +205,7 @@ nsHTMLAreaElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
PRBool aCompileEventHandlers)
|
||||
{
|
||||
Link::ResetLinkState();
|
||||
Link::ResetLinkState(false);
|
||||
|
||||
nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
|
||||
aBindingParent,
|
||||
@ -225,7 +224,7 @@ nsHTMLAreaElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
|
||||
{
|
||||
// If this link is ever reinserted into a document, it might
|
||||
// be under a different xml:base, so forget the cached state now.
|
||||
Link::ResetLinkState();
|
||||
Link::ResetLinkState(false);
|
||||
|
||||
if (IsInDoc()) {
|
||||
RegUnRegAccessKey(PR_FALSE);
|
||||
@ -244,7 +243,7 @@ nsHTMLAreaElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
|
||||
}
|
||||
|
||||
if (aName == nsGkAtoms::href && aNameSpaceID == kNameSpaceID_None) {
|
||||
Link::ResetLinkState();
|
||||
Link::ResetLinkState(!!aNotify);
|
||||
}
|
||||
|
||||
nsresult rv =
|
||||
@ -263,7 +262,7 @@ nsHTMLAreaElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
|
||||
PRBool aNotify)
|
||||
{
|
||||
if (aAttribute == nsGkAtoms::href && kNameSpaceID_None == aNameSpaceID) {
|
||||
Link::ResetLinkState();
|
||||
Link::ResetLinkState(!!aNotify);
|
||||
}
|
||||
|
||||
if (aAttribute == nsGkAtoms::accesskey &&
|
||||
@ -320,12 +319,6 @@ nsHTMLAreaElement::GetLinkState() const
|
||||
return Link::GetLinkState();
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLAreaElement::SetLinkState(nsLinkState aState)
|
||||
{
|
||||
Link::SetLinkState(aState);
|
||||
}
|
||||
|
||||
already_AddRefed<nsIURI>
|
||||
nsHTMLAreaElement::GetHrefURI() const
|
||||
{
|
||||
|
@ -114,7 +114,6 @@ public:
|
||||
virtual PRBool IsLink(nsIURI** aURI) const;
|
||||
virtual void GetLinkTarget(nsAString& aTarget);
|
||||
virtual nsLinkState GetLinkState() const;
|
||||
virtual void SetLinkState(nsLinkState aState);
|
||||
virtual already_AddRefed<nsIURI> GetHrefURI() const;
|
||||
|
||||
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
|
||||
@ -205,7 +204,7 @@ nsHTMLLinkElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
PRBool aCompileEventHandlers)
|
||||
{
|
||||
Link::ResetLinkState();
|
||||
Link::ResetLinkState(false);
|
||||
|
||||
nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
|
||||
aBindingParent,
|
||||
@ -240,7 +239,7 @@ nsHTMLLinkElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
|
||||
{
|
||||
// If this link is ever reinserted into a document, it might
|
||||
// be under a different xml:base, so forget the cached state now.
|
||||
Link::ResetLinkState();
|
||||
Link::ResetLinkState(false);
|
||||
|
||||
// Once we have XPCOMGC we shouldn't need to call UnbindFromTree during Unlink
|
||||
// and so this messy event dispatch can go away.
|
||||
@ -286,7 +285,7 @@ nsHTMLLinkElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
|
||||
PRBool aNotify)
|
||||
{
|
||||
if (aName == nsGkAtoms::href && kNameSpaceID_None == aNameSpaceID) {
|
||||
Link::ResetLinkState();
|
||||
Link::ResetLinkState(!!aNotify);
|
||||
}
|
||||
|
||||
nsresult rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix,
|
||||
@ -316,7 +315,7 @@ nsHTMLLinkElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
|
||||
PRBool aNotify)
|
||||
{
|
||||
if (aAttribute == nsGkAtoms::href && kNameSpaceID_None == aNameSpaceID) {
|
||||
Link::ResetLinkState();
|
||||
Link::ResetLinkState(!!aNotify);
|
||||
}
|
||||
|
||||
nsresult rv = nsGenericHTMLElement::UnsetAttr(aNameSpaceID, aAttribute,
|
||||
@ -366,12 +365,6 @@ nsHTMLLinkElement::GetLinkState() const
|
||||
return Link::GetLinkState();
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLLinkElement::SetLinkState(nsLinkState aState)
|
||||
{
|
||||
Link::SetLinkState(aState);
|
||||
}
|
||||
|
||||
already_AddRefed<nsIURI>
|
||||
nsHTMLLinkElement::GetHrefURI() const
|
||||
{
|
||||
|
@ -126,7 +126,7 @@ nsSVGAElement::BindToTree(nsIDocument *aDocument, nsIContent *aParent,
|
||||
nsIContent *aBindingParent,
|
||||
PRBool aCompileEventHandlers)
|
||||
{
|
||||
Link::ResetLinkState();
|
||||
Link::ResetLinkState(false);
|
||||
|
||||
nsresult rv = nsSVGAElementBase::BindToTree(aDocument, aParent,
|
||||
aBindingParent,
|
||||
@ -141,7 +141,7 @@ nsSVGAElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
|
||||
{
|
||||
// If this link is ever reinserted into a document, it might
|
||||
// be under a different xml:base, so forget the cached state now.
|
||||
Link::ResetLinkState();
|
||||
Link::ResetLinkState(false);
|
||||
|
||||
nsSVGAElementBase::UnbindFromTree(aDeep, aNullParent);
|
||||
}
|
||||
@ -152,12 +152,6 @@ nsSVGAElement::GetLinkState() const
|
||||
return Link::GetLinkState();
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGAElement::SetLinkState(nsLinkState aState)
|
||||
{
|
||||
Link::SetLinkState(aState);
|
||||
}
|
||||
|
||||
already_AddRefed<nsIURI>
|
||||
nsSVGAElement::GetHrefURI() const
|
||||
{
|
||||
@ -269,7 +263,7 @@ nsSVGAElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
|
||||
PRBool aNotify)
|
||||
{
|
||||
if (aName == nsGkAtoms::href && aNameSpaceID == kNameSpaceID_XLink) {
|
||||
Link::ResetLinkState();
|
||||
Link::ResetLinkState(!!aNotify);
|
||||
}
|
||||
|
||||
return nsSVGAElementBase::SetAttr(aNameSpaceID, aName, aPrefix, aValue,
|
||||
@ -281,7 +275,7 @@ nsSVGAElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttr,
|
||||
PRBool aNotify)
|
||||
{
|
||||
if (aAttr == nsGkAtoms::href && aNameSpaceID == kNameSpaceID_XLink) {
|
||||
Link::ResetLinkState();
|
||||
Link::ResetLinkState(!!aNotify);
|
||||
}
|
||||
|
||||
return nsSVGAElementBase::UnsetAttr(aNameSpaceID, aAttr, aNotify);
|
||||
|
@ -87,7 +87,6 @@ public:
|
||||
virtual PRBool IsLink(nsIURI** aURI) const;
|
||||
virtual void GetLinkTarget(nsAString& aTarget);
|
||||
virtual nsLinkState GetLinkState() const;
|
||||
virtual void SetLinkState(nsLinkState aState);
|
||||
virtual already_AddRefed<nsIURI> GetHrefURI() const;
|
||||
virtual PRInt32 IntrinsicState() const;
|
||||
nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
|
||||
|
@ -112,7 +112,7 @@ Link::SetLinkState(nsLinkState aState)
|
||||
}
|
||||
|
||||
void
|
||||
Link::ResetLinkState()
|
||||
Link::ResetLinkState(bool aNotify)
|
||||
{
|
||||
NS_NOTREACHED("Unexpected call to Link::ResetLinkState");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user