Bug 366200: Fix problems with mRootContent being out of sync with mChildren by removing mRootContent. r/sr=bz

This commit is contained in:
jonas@sicking.cc 2007-12-11 18:26:09 -08:00
parent 754ec000fb
commit 5d4f2a4212
13 changed files with 187 additions and 287 deletions

View File

@ -396,8 +396,12 @@ public:
*/
nsIContent *GetRootContent() const
{
return mRootContent;
return (mCachedRootContent &&
mCachedRootContent->GetNodeParent() == this) ?
reinterpret_cast<nsIContent*>(mCachedRootContent.get()) :
GetRootContentInternal();
}
virtual nsIContent *GetRootContentInternal() const = 0;
/**
* Accessors to the collection of stylesheets owned by this document.
@ -941,9 +945,10 @@ protected:
// This is just a weak pointer; the parent document owns its children.
nsIDocument* mParentDocument;
// A weak reference to the only child element, or null if no
// such element exists.
nsIContent* mRootContent;
// A reference to the content last returned from GetRootContent().
// This should be an nsIContent, but that would force us to pull in
// nsIContent.h
nsCOMPtr<nsINode> mCachedRootContent;
// We'd like these to be nsRefPtrs, but that'd require us to include
// additional headers that we don't want to expose.

View File

@ -818,27 +818,17 @@ nsDocument::~nsDocument()
mSubDocuments = nsnull;
}
PRInt32 indx;
if (mRootContent) {
if (mRootContent->GetCurrentDoc()) {
NS_ASSERTION(mRootContent->GetCurrentDoc() == this,
"Unexpected current doc in root content");
// The root content still has a pointer back to the document,
// clear the document pointer in all children.
// Destroy link map now so we don't waste time removing
// links one by one
DestroyLinkMap();
// Destroy link map now so we don't waste time removing
// links one by one
DestroyLinkMap();
PRUint32 count = mChildren.ChildCount();
for (indx = PRInt32(count) - 1; indx >= 0; --indx) {
mChildren.ChildAt(indx)->UnbindFromTree();
mChildren.RemoveChildAt(indx);
}
}
PRInt32 indx; // must be signed
PRUint32 count = mChildren.ChildCount();
for (indx = PRInt32(count) - 1; indx >= 0; --indx) {
mChildren.ChildAt(indx)->UnbindFromTree();
mChildren.RemoveChildAt(indx);
}
mRootContent = nsnull;
mCachedRootContent = nsnull;
// Let the stylesheets know we're going away
indx = mStyleSheets.Count();
@ -1020,6 +1010,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDocument)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_USERDATA
// Traverse all nsIDocument pointer members.
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCachedRootContent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mBindingManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mSecurityInfo)
@ -1078,13 +1069,14 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
tmp->mChildren.RemoveChildAt(indx);
}
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCachedRootContent)
NS_IMPL_CYCLE_COLLECTION_UNLINK_USERDATA
// Unlink any associated preserved wrapper.
tmp->RemoveReference(tmp);
tmp->mParentDocument = nsnull;
tmp->mRootContent = nsnull;
// nsDocument has a pretty complex destructor, so we're going to
// assume that *most* cycles you actually want to break somewhere
@ -1218,7 +1210,6 @@ nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
// links one by one
DestroyLinkMap();
mRootContent = nsnull;
PRUint32 count = mChildren.ChildCount();
for (PRInt32 i = PRInt32(count) - 1; i >= 0; i--) {
nsCOMPtr<nsIContent> content = mChildren.ChildAt(i);
@ -1227,6 +1218,7 @@ nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
content->UnbindFromTree();
mChildren.RemoveChildAt(i);
}
mCachedRootContent = nsnull;
// Reset our stylesheets
ResetStylesheetsToURI(aURI);
@ -2207,6 +2199,24 @@ nsDocument::IsNodeOfType(PRUint32 aFlags) const
return !(aFlags & ~eDOCUMENT);
}
nsIContent*
nsDocument::GetRootContentInternal() const
{
// Loop backwards because any non-elements, such as doctypes and PIs
// are likely to appear before the root element.
PRUint32 i;
for (i = mChildren.ChildCount(); i > 0; --i) {
nsIContent* child = mChildren.ChildAt(i - 1);
if (child->IsNodeOfType(nsINode::eELEMENT)) {
const_cast<nsDocument*>(this)->mCachedRootContent = child;
return child;
}
}
const_cast<nsDocument*>(this)->mCachedRootContent = nsnull;
return nsnull;
}
nsIContent *
nsDocument::GetChildAt(PRUint32 aIndex) const
{
@ -2229,37 +2239,14 @@ nsresult
nsDocument::InsertChildAt(nsIContent* aKid, PRUint32 aIndex,
PRBool aNotify)
{
if (aKid->IsNodeOfType(nsINode::eELEMENT)) {
if (mRootContent) {
NS_ERROR("Inserting element child when we already have one");
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
}
mRootContent = aKid;
}
nsresult rv = nsGenericElement::doInsertChildAt(aKid, aIndex, aNotify,
nsnull, this, mChildren);
if (NS_FAILED(rv) && mRootContent == aKid) {
PRInt32 kidIndex = mChildren.IndexOfChild(aKid);
NS_ASSERTION(kidIndex == -1,
"Error result and still have same root content but it's in "
"our child list?");
// Check to make sure that we're keeping mRootContent in sync with our
// child list... but really, if kidIndex != -1 we have major problems
// coming up; hence the assert above. This check is just a feeble attempt
// to not die due to mRootContent being bogus.
if (kidIndex == -1) {
mRootContent = nsnull;
}
if (aKid->IsNodeOfType(nsINode::eELEMENT) &&
GetRootContent()) {
NS_ERROR("Inserting element child when we already have one");
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
}
#ifdef DEBUG
VerifyRootContentState();
#endif
return rv;
return nsGenericElement::doInsertChildAt(aKid, aIndex, aNotify,
nsnull, this, mChildren);
}
nsresult
@ -2277,58 +2264,21 @@ nsresult
nsDocument::RemoveChildAt(PRUint32 aIndex, PRBool aNotify)
{
nsCOMPtr<nsIContent> oldKid = GetChildAt(aIndex);
nsresult rv = NS_OK;
if (oldKid) {
if (oldKid == mRootContent) {
NS_ASSERTION(oldKid->IsNodeOfType(nsINode::eELEMENT),
"Non-element root content?");
// Destroy the link map up front and null out mRootContent before we mess
// with the child list. Hopefully no one in doRemoveChildAt will compare
// the content being removed to GetRootContent().... Need to do this
// before calling doRemoveChildAt because DOM events might fire while
// we're inside the doInsertChildAt call and want to set a new
// mRootContent; if they do that, setting mRootContent after the
// doRemoveChildAt call would clobber state. If we ever fix the issue of
// DOM events firing at inconvenient times, consider changing the order
// here. Just make sure we DestroyLinkMap() before unbinding the
// content.
DestroyLinkMap();
mRootContent = nsnull;
}
rv = nsGenericElement::doRemoveChildAt(aIndex, aNotify, oldKid,
nsnull, this, mChildren);
if (NS_FAILED(rv) && mChildren.IndexOfChild(oldKid) != -1) {
mRootContent = oldKid;
}
if (!oldKid) {
return NS_OK;
}
#ifdef DEBUG
VerifyRootContentState();
#endif
if (oldKid->IsNodeOfType(nsINode::eELEMENT)) {
// Destroy the link map up front before we mess with the child list.
DestroyLinkMap();
}
nsresult rv = nsGenericElement::doRemoveChildAt(aIndex, aNotify, oldKid,
nsnull, this, mChildren);
mCachedRootContent = nsnull;
return rv;
}
#ifdef DEBUG
void
nsDocument::VerifyRootContentState()
{
nsIContent* elementChild = nsnull;
for (PRUint32 i = 0; i < GetChildCount(); ++i) {
nsIContent* kid = GetChildAt(i);
NS_ASSERTION(kid, "Must have kid here");
if (kid->IsNodeOfType(nsINode::eELEMENT)) {
NS_ASSERTION(!elementChild, "Multiple element kids?");
elementChild = kid;
}
}
NS_ASSERTION(mRootContent == elementChild, "Incorrect mRootContent");
}
#endif // DEBUG
PRInt32
nsDocument::GetNumberOfStyleSheets() const
{
@ -2959,28 +2909,11 @@ nsDocument::GetDoctype(nsIDOMDocumentType** aDoctype)
*aDoctype = nsnull;
PRInt32 i, count;
count = mChildren.ChildCount();
nsCOMPtr<nsIDOMNode> rootContentNode(do_QueryInterface(mRootContent) );
nsCOMPtr<nsIDOMNode> node;
for (i = 0; i < count; i++) {
node = do_QueryInterface(mChildren.ChildAt(i));
CallQueryInterface(mChildren.ChildAt(i), aDoctype);
NS_ASSERTION(node, "null element of mChildren");
// doctype can't be after the root
// XXX Do we really want to enforce this when we don't enforce
// anything else?
if (node == rootContentNode)
if (*aDoctype) {
return NS_OK;
if (node) {
PRUint16 nodeType;
node->GetNodeType(&nodeType);
if (nodeType == nsIDOMNode::DOCUMENT_TYPE_NODE) {
return CallQueryInterface(node, aDoctype);
}
}
}
@ -3015,16 +2948,14 @@ nsDocument::GetDocumentElement(nsIDOMElement** aDocumentElement)
{
NS_ENSURE_ARG_POINTER(aDocumentElement);
nsresult rv = NS_OK;
if (mRootContent) {
rv = CallQueryInterface(mRootContent, aDocumentElement);
NS_ASSERTION(NS_OK == rv, "Must be a DOM Element");
} else {
*aDocumentElement = nsnull;
nsIContent* root = GetRootContent();
if (root) {
return CallQueryInterface(root, aDocumentElement);
}
return rv;
*aDocumentElement = nsnull;
return NS_OK;
}
NS_IMETHODIMP
@ -4304,7 +4235,7 @@ NS_IMETHODIMP
nsDocument::LookupPrefix(const nsAString& aNamespaceURI,
nsAString& aPrefix)
{
nsCOMPtr<nsIDOM3Node> root(do_QueryInterface(mRootContent));
nsCOMPtr<nsIDOM3Node> root(do_QueryInterface(GetRootContent()));
if (root) {
return root->LookupPrefix(aNamespaceURI, aPrefix);
}
@ -4317,7 +4248,7 @@ NS_IMETHODIMP
nsDocument::LookupNamespaceURI(const nsAString& aNamespacePrefix,
nsAString& aNamespaceURI)
{
if (NS_FAILED(nsContentUtils::LookupNamespaceURI(mRootContent,
if (NS_FAILED(nsContentUtils::LookupNamespaceURI(GetRootContent(),
aNamespacePrefix,
aNamespaceURI))) {
SetDOMStringToNull(aNamespaceURI);
@ -5753,9 +5684,10 @@ nsDocument::OnPageShow(PRBool aPersisted)
mVisible = PR_TRUE;
UpdateLinkMap();
if (aPersisted && mRootContent) {
nsIContent* root = GetRootContent();
if (aPersisted && root) {
// Send out notifications that our <link> elements are attached.
nsRefPtr<nsContentList> links = NS_GetContentList(mRootContent,
nsRefPtr<nsContentList> links = NS_GetContentList(root,
nsGkAtoms::link,
kNameSpaceID_Unknown);
@ -5779,8 +5711,9 @@ nsDocument::OnPageHide(PRBool aPersisted)
{
// Send out notifications that our <link> elements are detached,
// but only if this is not a full unload.
if (aPersisted && mRootContent) {
nsRefPtr<nsContentList> links = NS_GetContentList(mRootContent,
nsIContent* root = GetRootContent();
if (aPersisted && root) {
nsRefPtr<nsContentList> links = NS_GetContentList(root,
nsGkAtoms::link,
kNameSpaceID_Unknown);

View File

@ -380,6 +380,7 @@ public:
nsIDocument* aSubDoc);
virtual nsIDocument* GetSubDocumentFor(nsIContent *aContent) const;
virtual nsIContent* FindContentForSubDocument(nsIDocument *aDocument) const;
virtual nsIContent* GetRootContentInternal() const;
/**
* Get the style sheets owned by this document.

View File

@ -382,7 +382,6 @@ IdAndNameMapEntryTraverse(PLDHashTable *table, PLDHashEntryHdr *hdr,
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsHTMLDocument, nsDocument)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mBodyContent)
if (tmp->mIdAndNameHashTable.ops) {
PL_DHashTableEnumerate(&tmp->mIdAndNameHashTable,
IdAndNameMapEntryTraverse,
@ -479,8 +478,6 @@ nsHTMLDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
mLinks = nsnull;
mAnchors = nsnull;
mBodyContent = nsnull;
mImageMaps.Clear();
mForms = nsnull;
@ -1373,12 +1370,6 @@ nsHTMLDocument::ContentRemoved(nsIDocument* aDocument,
NS_ABORT_IF_FALSE(aChild, "Null content!");
if (aContainer == mRootContent) {
// Reset mBodyContent in case we got a new body.
mBodyContent = nsnull;
}
UnregisterNamedItems(aChild);
}
@ -1791,66 +1782,62 @@ nsHTMLDocument::GetURL(nsAString& aURL)
NS_IMETHODIMP
nsHTMLDocument::GetBody(nsIDOMHTMLElement** aBody)
{
NS_ENSURE_ARG_POINTER(aBody);
*aBody = nsnull;
nsISupports* element = nsnull;
nsCOMPtr<nsIDOMNode> node;
nsIContent* body = GetBodyContent();
if (mBodyContent || GetBodyContent()) {
if (body) {
// There is a body element, return that as the body.
element = mBodyContent;
} else {
// The document is most likely a frameset document so look for the
// outer most frameset element
nsCOMPtr<nsIDOMNodeList> nodeList;
nsresult rv;
if (IsXHTML()) {
rv = GetElementsByTagNameNS(NS_LITERAL_STRING("http://www.w3.org/1999/xhtml"),
NS_LITERAL_STRING("frameset"),
getter_AddRefs(nodeList));
} else {
rv = GetElementsByTagName(NS_LITERAL_STRING("frameset"),
getter_AddRefs(nodeList));
}
if (nodeList) {
rv |= nodeList->Item(0, getter_AddRefs(node));
element = node;
}
NS_ENSURE_SUCCESS(rv, rv);
return CallQueryInterface(body, aBody);
}
return element ? CallQueryInterface(element, aBody) : NS_OK;
// The document is most likely a frameset document so look for the
// outer most frameset element
nsCOMPtr<nsIDOMNodeList> nodeList;
nsresult rv;
if (IsXHTML()) {
rv = GetElementsByTagNameNS(NS_LITERAL_STRING("http://www.w3.org/1999/xhtml"),
NS_LITERAL_STRING("frameset"),
getter_AddRefs(nodeList));
} else {
rv = GetElementsByTagName(NS_LITERAL_STRING("frameset"),
getter_AddRefs(nodeList));
}
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDOMNode> node;
nodeList->Item(0, getter_AddRefs(node));
return node ? CallQueryInterface(node, aBody) : NS_OK;
}
NS_IMETHODIMP
nsHTMLDocument::SetBody(nsIDOMHTMLElement* aBody)
{
nsCOMPtr<nsIContent> body(do_QueryInterface(aBody));
nsCOMPtr<nsIDOMElement> root(do_QueryInterface(mRootContent));
nsCOMPtr<nsIContent> newBody = do_QueryInterface(aBody);
nsIContent* root = GetRootContent();
// The body element must be either a body tag or a frameset tag.
if (!body || !root || !(body->Tag() == nsGkAtoms::body ||
body->Tag() == nsGkAtoms::frameset)) {
// The body element must be either a body tag or a frameset tag. And we must
// have a html root tag, otherwise GetBody will not return the newly set
// body.
if (!newBody || !(newBody->Tag() == nsGkAtoms::body ||
newBody->Tag() == nsGkAtoms::frameset) ||
!root || !root->IsNodeOfType(nsINode::eHTML) ||
root->Tag() != nsGkAtoms::html) {
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
}
nsCOMPtr<nsIDOMElement> rootElem = do_QueryInterface(root);
nsCOMPtr<nsIDOMNode> tmp;
if (mBodyContent || GetBodyContent()) {
root->ReplaceChild(aBody, mBodyContent, getter_AddRefs(tmp));
} else {
root->AppendChild(aBody, getter_AddRefs(tmp));
// Use DOM methods so that we pass through the appropriate security checks.
nsCOMPtr<nsIDOMNode> currentBody = do_QueryInterface(GetBodyContent());
if (currentBody) {
return rootElem->ReplaceChild(aBody, currentBody, getter_AddRefs(tmp));
}
mBodyContent = aBody;
return PR_FALSE;
return rootElem->AppendChild(aBody, getter_AddRefs(tmp));
}
NS_IMETHODIMP
@ -2188,10 +2175,10 @@ nsHTMLDocument::OpenCommon(const nsACString& aContentType, PRBool aReplace)
// (http://bugzilla.mozilla.org/show_bug.cgi?id=55334).
// Hold on to our root element
nsCOMPtr<nsIContent> root(mRootContent);
nsCOMPtr<nsIContent> root = GetRootContent();
if (root) {
PRInt32 rootIndex = mChildren.IndexOfChild(mRootContent);
PRInt32 rootIndex = mChildren.IndexOfChild(root);
NS_ASSERTION(rootIndex >= 0, "Root must be in list!");
PRUint32 count = root->GetChildCount();
@ -2201,7 +2188,7 @@ nsHTMLDocument::OpenCommon(const nsACString& aContentType, PRBool aReplace)
root->RemoveChildAt(count, PR_TRUE);
}
count = mRootContent->GetAttrCount();
count = root->GetAttrCount();
// Remove all attributes from the root element
while (count-- > 0) {
@ -2211,8 +2198,7 @@ nsHTMLDocument::OpenCommon(const nsACString& aContentType, PRBool aReplace)
// Remove the root from the childlist
mChildren.RemoveChildAt(rootIndex);
mRootContent = nsnull;
mCachedRootContent = nsnull;
}
// Call Reset(), this will now do the full reset, except removing
@ -2235,7 +2221,6 @@ nsHTMLDocument::OpenCommon(const nsACString& aContentType, PRBool aReplace)
// element was never set to null)
mChildren.AppendChild(root);
mRootContent = root;
}
if (IsEditingOn()) {
@ -2615,18 +2600,19 @@ nsHTMLDocument::GetElementById(const nsAString& aElementId,
if (!e) {
// If IdTableIsLive(), no need to look for the element in the document,
// since we're fully maintaining our table's state as the DOM mutates.
nsIContent* root = GetRootContent();
if (!IdTableIsLive()) {
if (IdTableShouldBecomeLive()) {
// Just make sure our table is up to date and call this method again
// to look up in the hashtable.
if (mRootContent) {
RegisterNamedItems(mRootContent);
if (root) {
RegisterNamedItems(root);
}
return GetElementById(aElementId, aReturn);
}
if (mRootContent && CheckGetElementByIdArg(aElementId)) {
e = nsContentUtils::MatchElementId(mRootContent, idAtom);
if (root && CheckGetElementByIdArg(aElementId)) {
e = nsContentUtils::MatchElementId(root, idAtom);
}
}
@ -2634,9 +2620,9 @@ nsHTMLDocument::GetElementById(const nsAString& aElementId,
#ifdef DEBUG
// No reason to call MatchElementId if !IdTableIsLive, since
// we'd have done just that already
if (IdTableIsLive() && mRootContent && !aElementId.IsEmpty()) {
if (IdTableIsLive() && root && !aElementId.IsEmpty()) {
nsIContent* eDebug =
nsContentUtils::MatchElementId(mRootContent, idAtom);
nsContentUtils::MatchElementId(root, idAtom);
NS_ASSERTION(!eDebug,
"We got null for |e| but MatchElementId found something?");
}
@ -2773,12 +2759,11 @@ nsHTMLDocument::GetBodySize(PRInt32* aWidth,
// Find the <body> element: this is what we'll want to use for the
// document's width and height values.
if (!mBodyContent && !GetBodyContent()) {
nsIContent* body = GetBodyContent();
if (!body) {
return NS_OK;
}
nsCOMPtr<nsIContent> body = do_QueryInterface(mBodyContent);
// Now grab its frame
nsIFrame* frame = shell->GetPrimaryFrameFor(body);
if (!frame)
@ -2815,8 +2800,7 @@ nsHTMLDocument::GetAlinkColor(nsAString& aAlinkColor)
{
aAlinkColor.Truncate();
nsCOMPtr<nsIDOMHTMLBodyElement> body;
GetBodyElement(getter_AddRefs(body));
nsCOMPtr<nsIDOMHTMLBodyElement> body = do_QueryInterface(GetBodyContent());
if (body) {
body->GetALink(aAlinkColor);
@ -2834,8 +2818,7 @@ nsHTMLDocument::GetAlinkColor(nsAString& aAlinkColor)
NS_IMETHODIMP
nsHTMLDocument::SetAlinkColor(const nsAString& aAlinkColor)
{
nsCOMPtr<nsIDOMHTMLBodyElement> body;
GetBodyElement(getter_AddRefs(body));
nsCOMPtr<nsIDOMHTMLBodyElement> body = do_QueryInterface(GetBodyContent());
if (body) {
body->SetALink(aAlinkColor);
@ -2856,8 +2839,7 @@ nsHTMLDocument::GetLinkColor(nsAString& aLinkColor)
{
aLinkColor.Truncate();
nsCOMPtr<nsIDOMHTMLBodyElement> body;
GetBodyElement(getter_AddRefs(body));
nsCOMPtr<nsIDOMHTMLBodyElement> body = do_QueryInterface(GetBodyContent());
if (body) {
body->GetLink(aLinkColor);
@ -2875,8 +2857,7 @@ nsHTMLDocument::GetLinkColor(nsAString& aLinkColor)
NS_IMETHODIMP
nsHTMLDocument::SetLinkColor(const nsAString& aLinkColor)
{
nsCOMPtr<nsIDOMHTMLBodyElement> body;
GetBodyElement(getter_AddRefs(body));
nsCOMPtr<nsIDOMHTMLBodyElement> body = do_QueryInterface(GetBodyContent());
if (body) {
body->SetLink(aLinkColor);
@ -2897,8 +2878,7 @@ nsHTMLDocument::GetVlinkColor(nsAString& aVlinkColor)
{
aVlinkColor.Truncate();
nsCOMPtr<nsIDOMHTMLBodyElement> body;
GetBodyElement(getter_AddRefs(body));
nsCOMPtr<nsIDOMHTMLBodyElement> body = do_QueryInterface(GetBodyContent());
if (body) {
body->GetVLink(aVlinkColor);
@ -2916,8 +2896,7 @@ nsHTMLDocument::GetVlinkColor(nsAString& aVlinkColor)
NS_IMETHODIMP
nsHTMLDocument::SetVlinkColor(const nsAString& aVlinkColor)
{
nsCOMPtr<nsIDOMHTMLBodyElement> body;
GetBodyElement(getter_AddRefs(body));
nsCOMPtr<nsIDOMHTMLBodyElement> body = do_QueryInterface(GetBodyContent());
if (body) {
body->SetVLink(aVlinkColor);
@ -2938,8 +2917,7 @@ nsHTMLDocument::GetBgColor(nsAString& aBgColor)
{
aBgColor.Truncate();
nsCOMPtr<nsIDOMHTMLBodyElement> body;
GetBodyElement(getter_AddRefs(body));
nsCOMPtr<nsIDOMHTMLBodyElement> body = do_QueryInterface(GetBodyContent());
if (body) {
body->GetBgColor(aBgColor);
@ -2951,8 +2929,7 @@ nsHTMLDocument::GetBgColor(nsAString& aBgColor)
NS_IMETHODIMP
nsHTMLDocument::SetBgColor(const nsAString& aBgColor)
{
nsCOMPtr<nsIDOMHTMLBodyElement> body;
GetBodyElement(getter_AddRefs(body));
nsCOMPtr<nsIDOMHTMLBodyElement> body = do_QueryInterface(GetBodyContent());
if (body) {
body->SetBgColor(aBgColor);
@ -2967,8 +2944,7 @@ nsHTMLDocument::GetFgColor(nsAString& aFgColor)
{
aFgColor.Truncate();
nsCOMPtr<nsIDOMHTMLBodyElement> body;
GetBodyElement(getter_AddRefs(body));
nsCOMPtr<nsIDOMHTMLBodyElement> body = do_QueryInterface(GetBodyContent());
if (body) {
body->GetText(aFgColor);
@ -2980,8 +2956,7 @@ nsHTMLDocument::GetFgColor(nsAString& aFgColor)
NS_IMETHODIMP
nsHTMLDocument::SetFgColor(const nsAString& aFgColor)
{
nsCOMPtr<nsIDOMHTMLBodyElement> body;
GetBodyElement(getter_AddRefs(body));
nsCOMPtr<nsIDOMHTMLBodyElement> body = do_QueryInterface(GetBodyContent());
if (body) {
body->SetText(aFgColor);
@ -3474,10 +3449,11 @@ nsHTMLDocument::ResolveName(const nsAString& aName,
entry->mNameContentList = list;
NS_ADDREF(entry->mNameContentList);
if (mRootContent && !aName.IsEmpty()) {
nsIContent* root = GetRootContent();
if (root && !aName.IsEmpty()) {
// We'll never get here if !IsXHTML(), so we can just pass
// PR_FALSE to FindNamedItems().
FindNamedItems(name, mRootContent, *entry, PR_FALSE);
FindNamedItems(name, root, *entry, PR_FALSE);
}
}
@ -3566,42 +3542,31 @@ nsHTMLDocument::ResolveName(const nsAString& aName,
//----------------------------
PRBool
nsIContent*
nsHTMLDocument::GetBodyContent()
{
if (!mRootContent) {
return PR_FALSE;
}
// Loop backwards because any non-elements, such as doctypes and PIs
// are likely to appear before the root element.
PRUint32 i;
for (i = mChildren.ChildCount(); i > 0; --i) {
nsIContent* html = mChildren.ChildAt(i - 1);
if (html->Tag() == nsGkAtoms::html &&
html->IsNodeOfType(nsINode::eHTML)) {
PRUint32 i, child_count = mRootContent->GetChildCount();
// Look for body inside html
for (i = html->GetChildCount(); i > 0; --i) {
nsIContent* body = html->GetChildAt(i - 1);
if (body->Tag() == nsGkAtoms::body &&
body->IsNodeOfType(nsINode::eHTML)) {
return body;
}
}
for (i = 0; i < child_count; ++i) {
nsIContent *child = mRootContent->GetChildAt(i);
NS_ENSURE_TRUE(child, NS_ERROR_UNEXPECTED);
if (child->NodeInfo()->Equals(nsGkAtoms::body, mDefaultNamespaceID) &&
child->IsNodeOfType(nsINode::eHTML)) {
mBodyContent = do_QueryInterface(child);
return PR_TRUE;
break;
}
}
return PR_FALSE;
}
void
nsHTMLDocument::GetBodyElement(nsIDOMHTMLBodyElement** aBody)
{
*aBody = nsnull;
if (!mBodyContent && !GetBodyContent()) {
// No body in this document.
return;
}
CallQueryInterface(mBodyContent, aBody);
return nsnull;
}
// forms related stuff
@ -3868,12 +3833,13 @@ nsHTMLDocument::GetDocumentAllResult(const nsAString& aID, nsISupports** aResult
return NS_OK;
}
if (!mRootContent) {
nsIContent* root = GetRootContent();
if (!root) {
return NS_OK;
}
if (!entry->mDocAllList) {
entry->mDocAllList = new nsContentList(mRootContent, DocAllResultMatch,
entry->mDocAllList = new nsContentList(root, DocAllResultMatch,
nsnull, nsnull, PR_TRUE, id);
NS_ENSURE_TRUE(entry->mDocAllList, NS_ERROR_OUT_OF_MEMORY);
}

View File

@ -241,8 +241,7 @@ protected:
static void DocumentWriteTerminationFunc(nsISupports *aRef);
PRBool GetBodyContent();
void GetBodyElement(nsIDOMHTMLBodyElement** aBody);
nsIContent* GetBodyContent();
void GetDomainURI(nsIURI **uri);
@ -332,8 +331,6 @@ protected:
// Load flags of the document's channel
PRUint32 mLoadFlags;
nsCOMPtr<nsIDOMNode> mBodyContent;
PRPackedBool mIsFrameset;
PRPackedBool mTooDeepWriteRecursion;

View File

@ -354,7 +354,7 @@ nsImageDocument::SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObjec
nsHTMLDocument::SetScriptGlobalObject(aScriptGlobalObject);
if (aScriptGlobalObject) {
if (!mRootContent) {
if (!GetRootContent()) {
// Create synthetic document
nsresult rv = CreateSyntheticDocument();
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to create synthetic document");
@ -568,7 +568,7 @@ nsImageDocument::CreateSyntheticDocument()
nsresult rv = nsMediaDocument::CreateSyntheticDocument();
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIContent> body = do_QueryInterface(mBodyContent);
nsIContent* body = GetBodyContent();
if (!body) {
NS_WARNING("no body on image document!");
return NS_ERROR_FAILURE;
@ -618,7 +618,7 @@ nsImageDocument::CheckOverflowing(PRBool changeState)
nsPresContext *context = shell->GetPresContext();
nsRect visibleArea = context->GetVisibleArea();
nsCOMPtr<nsIContent> content = do_QueryInterface(mBodyContent);
nsIContent* content = GetBodyContent();
if (!content) {
NS_WARNING("no body on image document!");
return NS_ERROR_FAILURE;

View File

@ -256,7 +256,6 @@ nsMediaDocument::CreateSyntheticDocument()
if (!body) {
return NS_ERROR_OUT_OF_MEMORY;
}
mBodyContent = do_QueryInterface(body);
root->AppendChildTo(body, PR_FALSE);

View File

@ -227,7 +227,7 @@ nsPluginDocument::CreateSyntheticPluginDocument()
NS_ENSURE_SUCCESS(rv, rv);
// then attach our plugin
nsCOMPtr<nsIContent> body = do_QueryInterface(mBodyContent);
nsIContent* body = GetBodyContent();
if (!body) {
NS_WARNING("no body on plugin document!");
return NS_ERROR_FAILURE;

View File

@ -757,8 +757,7 @@ nsSVGSVGElement::GetCTM(nsIDOMSVGMatrix **_retval)
if (!ancestorCTM) {
// we didn't find an SVG ancestor
float s=1, x=0, y=0;
if (ownerDoc &&
ownerDoc->GetRootContent() == static_cast<nsIContent*>(this)) {
if (IsRoot()) {
// we're the root element. get our currentScale and currentTranslate vals
mCurrentScale->GetValue(&s);
mCurrentTranslate->GetX(&x);
@ -867,8 +866,7 @@ nsSVGSVGElement::GetScreenCTM(nsIDOMSVGMatrix **_retval)
if (!ancestorScreenCTM) {
// we didn't find an SVG ancestor
float s=1, x=0, y=0;
if (ownerDoc &&
ownerDoc->GetRootContent() == static_cast<nsIContent*>(this)) {
if (IsRoot()) {
// we're the root element. get our currentScale and currentTranslate vals
mCurrentScale->GetValue(&s);
mCurrentTranslate->GetX(&x);
@ -996,8 +994,7 @@ nsSVGSVGElement::SetCurrentScaleTranslate(float s, float x, float y)
if (doc) {
nsCOMPtr<nsIPresShell> presShell = doc->GetPrimaryShell();
NS_ASSERTION(presShell, "no presShell");
if (presShell &&
doc->GetRootContent() == static_cast<nsIContent*>(this)) {
if (presShell && IsRoot()) {
nsEventStatus status = nsEventStatus_eIgnore;
nsGUIEvent event(PR_TRUE, NS_SVG_ZOOM, 0);
event.eventStructType = NS_SVGZOOM_EVENT;
@ -1021,8 +1018,7 @@ nsSVGSVGElement::SetCurrentTranslate(float x, float y)
if (doc) {
nsCOMPtr<nsIPresShell> presShell = doc->GetPrimaryShell();
NS_ASSERTION(presShell, "no presShell");
if (presShell &&
doc->GetRootContent() == static_cast<nsIContent*>(this)) {
if (presShell && IsRoot()) {
nsEventStatus status = nsEventStatus_eIgnore;
nsEvent event(PR_TRUE, NS_SVG_SCROLL);
event.eventStructType = NS_SVG_EVENT;
@ -1160,8 +1156,7 @@ nsSVGSVGElement::DidModifySVGObservable (nsISVGValue* observable,
// dispatch an SVGZoom or SVGScroll DOM event before repainting
nsCOMPtr<nsIDOMSVGNumber> n = do_QueryInterface(observable);
if (n && n==mCurrentScale) {
if (mDispatchEvent &&
doc->GetRootContent() == static_cast<nsIContent*>(this)) {
if (mDispatchEvent && IsRoot()) {
nsEventStatus status = nsEventStatus_eIgnore;
nsGUIEvent event(PR_TRUE, NS_SVG_ZOOM, 0);
event.eventStructType = NS_SVGZOOM_EVENT;
@ -1174,8 +1169,7 @@ nsSVGSVGElement::DidModifySVGObservable (nsISVGValue* observable,
else {
nsCOMPtr<nsIDOMSVGPoint> p = do_QueryInterface(observable);
if (p && p==mCurrentTranslate) {
if (mDispatchEvent &&
doc->GetRootContent() == static_cast<nsIContent*>(this)) {
if (mDispatchEvent && IsRoot()) {
nsEventStatus status = nsEventStatus_eIgnore;
nsEvent event(PR_TRUE, NS_SVG_SCROLL);
event.eventStructType = NS_SVG_EVENT;

View File

@ -172,6 +172,12 @@ protected:
// implementation helpers:
void GetOffsetToAncestor(nsIContent* ancestor, float &x, float &y);
PRBool IsRoot() {
NS_ASSERTION((IsInDoc() && !GetParent()) ==
(GetOwnerDoc() && (GetOwnerDoc()->GetRootContent() == this)),
"Can't determine if we're root");
return IsInDoc() && !GetParent();
}
// invalidate viewbox -> viewport xform & inform frames
void InvalidateTransformNotifyFrame();

View File

@ -121,13 +121,10 @@ nsSVGDocument::GetURL(nsAString& aURL)
NS_IMETHODIMP
nsSVGDocument::GetRootElement(nsIDOMSVGSVGElement** aRootElement)
{
NS_ENSURE_ARG_POINTER(aRootElement);
if (mRootContent)
return CallQueryInterface(mRootContent, aRootElement);
*aRootElement = nsnull;
return NS_OK;
nsIContent* root = GetRootContent();
return root ? CallQueryInterface(root, aRootElement) : NS_OK;
}
////////////////////////////////////////////////////////////////////////

View File

@ -535,7 +535,7 @@ nsXMLDocument::Load(const nsAString& aUrl, PRBool *aReturn)
}
// We set return to true unless there was a parsing error
nsCOMPtr<nsIDOMNode> node = do_QueryInterface(mRootContent);
nsCOMPtr<nsIDOMNode> node = do_QueryInterface(GetRootContent());
if (node) {
nsAutoString name, ns;
if (NS_SUCCEEDED(node->GetLocalName(name)) &&
@ -660,14 +660,15 @@ nsXMLDocument::GetElementById(const nsAString& aElementId,
// If we tried to load a document and something went wrong, we might not have
// root content. This can happen when you do document.load() and the document
// to load is not XML, for example.
if (!mRootContent)
nsIContent* root = GetRootContent();
if (!root)
return NS_OK;
// XXX For now, we do a brute force search of the content tree.
// We should come up with a more efficient solution.
// Note that content is *not* refcounted here, so do *not* release it!
nsIContent *content =
nsContentUtils::MatchElementId(mRootContent, aElementId);
nsContentUtils::MatchElementId(root, aElementId);
if (!content) {
return NS_OK;

View File

@ -1875,7 +1875,7 @@ nsXULDocument::Init()
nsresult
nsXULDocument::StartLayout(void)
{
if (!mRootContent) {
if (!GetRootContent()) {
#ifdef PR_LOGGING
if (PR_LOG_TEST(gXULLog, PR_LOG_WARNING)) {
nsCAutoString urlspec;
@ -3046,9 +3046,9 @@ nsXULDocument::DoneWalking()
mDocumentLoaded = PR_TRUE;
nsAutoString title;
if (mRootContent) {
mRootContent->GetAttr(kNameSpaceID_None, nsGkAtoms::title,
title);
nsIContent* root = GetRootContent();
if (root) {
root->GetAttr(kNameSpaceID_None, nsGkAtoms::title, title);
}
SetTitle(title);
@ -3729,11 +3729,12 @@ nsXULDocument::OverlayForwardReference::Resolve()
if (id.IsEmpty()) {
// mOverlay is a direct child of <overlay> and has no id.
// Insert it under the root element in the base document.
if (!mDocument->mRootContent) {
nsIContent* root = mDocument->GetRootContent();
if (!root) {
return eResolve_Error;
}
rv = mDocument->InsertElement(mDocument->mRootContent, mOverlay, notify);
rv = mDocument->InsertElement(root, mOverlay, notify);
if (NS_FAILED(rv)) return eResolve_Error;
target = mOverlay;