Bug 403549: Avoid memory churn from nsContentUtils::CreateContextualFragment by giving nsIParser::ParseFragment a better signature. r/sr=stuart

This commit is contained in:
jonas@sicking.cc 2007-11-12 17:41:40 -08:00
parent f6b0191adc
commit 0e1c530ce2
6 changed files with 108 additions and 168 deletions

View File

@ -3206,146 +3206,107 @@ nsContentUtils::CreateContextualFragment(nsIDOMNode* aContextNode,
nsCOMPtr<nsIParser> parser = do_CreateInstance(kCParserCID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocument> document;
nsCOMPtr<nsIDOMDocument> domDocument;
aContextNode->GetOwnerDocument(getter_AddRefs(domDocument));
document = do_QueryInterface(domDocument);
nsCOMPtr<nsIContent> content = do_QueryInterface(aContextNode);
NS_ENSURE_TRUE(content, NS_ERROR_NOT_AVAILABLE);
// If we don't have a document here, we can't get the right security context
// for compiling event handlers... so just bail out.
nsCOMPtr<nsIDocument> document = content->GetOwnerDoc();
NS_ENSURE_TRUE(document, NS_ERROR_NOT_AVAILABLE);
nsVoidArray tagStack;
nsCOMPtr<nsIDOMNode> parent = aContextNode;
while (parent && (parent != domDocument)) {
PRUint16 nodeType;
parent->GetNodeType(&nodeType);
if (nsIDOMNode::ELEMENT_NODE == nodeType) {
nsAutoString tagName, uriStr;
parent->GetNodeName(tagName);
nsAutoTArray<nsAutoString, 32> tagStack;
nsAutoString uriStr, nameStr;
// see if we need to add xmlns declarations
nsCOMPtr<nsIContent> content = do_QueryInterface(parent);
if (!content) {
rv = NS_ERROR_FAILURE;
break;
}
while (content && content->IsNodeOfType(nsINode::eELEMENT)) {
nsAutoString& tagName = *tagStack.AppendElement();
NS_ENSURE_TRUE(&tagName, NS_ERROR_OUT_OF_MEMORY);
PRUint32 count = content->GetAttrCount();
PRBool setDefaultNamespace = PR_FALSE;
if (count > 0) {
PRUint32 index;
nsAutoString nameStr, prefixStr, valueStr;
content->NodeInfo()->GetQualifiedName(tagName);
for (index = 0; index < count; index++) {
const nsAttrName* name = content->GetAttrNameAt(index);
if (name->NamespaceEquals(kNameSpaceID_XMLNS)) {
content->GetAttr(kNameSpaceID_XMLNS, name->LocalName(), uriStr);
// see if we need to add xmlns declarations
PRUint32 count = content->GetAttrCount();
PRBool setDefaultNamespace = PR_FALSE;
if (count > 0) {
PRUint32 index;
// really want something like nsXMLContentSerializer::SerializeAttr
tagName.Append(NS_LITERAL_STRING(" xmlns")); // space important
if (name->GetPrefix()) {
tagName.Append(PRUnichar(':'));
name->LocalName()->ToString(nameStr);
tagName.Append(nameStr);
} else {
setDefaultNamespace = PR_TRUE;
}
tagName.Append(NS_LITERAL_STRING("=\"") + uriStr +
NS_LITERAL_STRING("\""));
for (index = 0; index < count; index++) {
const nsAttrName* name = content->GetAttrNameAt(index);
if (name->NamespaceEquals(kNameSpaceID_XMLNS)) {
content->GetAttr(kNameSpaceID_XMLNS, name->LocalName(), uriStr);
// really want something like nsXMLContentSerializer::SerializeAttr
tagName.Append(NS_LITERAL_STRING(" xmlns")); // space important
if (name->GetPrefix()) {
tagName.Append(PRUnichar(':'));
name->LocalName()->ToString(nameStr);
tagName.Append(nameStr);
} else {
setDefaultNamespace = PR_TRUE;
}
tagName.Append(NS_LITERAL_STRING("=\"") + uriStr +
NS_LITERAL_STRING("\""));
}
}
if (!setDefaultNamespace) {
nsINodeInfo* info = content->NodeInfo();
if (!info->GetPrefixAtom() &&
info->NamespaceID() != kNameSpaceID_None) {
// We have no namespace prefix, but have a namespace ID. Push
// default namespace attr in, so that our kids will be in our
// namespace.
nsAutoString uri;
info->GetNamespaceURI(uri);
tagName.Append(NS_LITERAL_STRING(" xmlns=\"") + uri +
NS_LITERAL_STRING("\""));
}
}
// XXX Wish we didn't have to allocate here
PRUnichar* name = ToNewUnicode(tagName);
if (name) {
tagStack.AppendElement(name);
nsCOMPtr<nsIDOMNode> temp = parent;
rv = temp->GetParentNode(getter_AddRefs(parent));
if (NS_FAILED(rv)) {
break;
}
} else {
rv = NS_ERROR_OUT_OF_MEMORY;
break;
}
} else {
nsCOMPtr<nsIDOMNode> temp = parent;
rv = temp->GetParentNode(getter_AddRefs(parent));
if (NS_FAILED(rv)) {
break;
}
}
if (!setDefaultNamespace) {
nsINodeInfo* info = content->NodeInfo();
if (!info->GetPrefixAtom() &&
info->NamespaceID() != kNameSpaceID_None) {
// We have no namespace prefix, but have a namespace ID. Push
// default namespace attr in, so that our kids will be in our
// namespace.
info->GetNamespaceURI(uriStr);
tagName.Append(NS_LITERAL_STRING(" xmlns=\"") + uriStr +
NS_LITERAL_STRING("\""));
}
}
content = content->GetParent();
}
nsCAutoString contentType;
PRBool bCaseSensitive = PR_TRUE;
nsAutoString buf;
document->GetContentType(buf);
LossyCopyUTF16toASCII(buf, contentType);
bCaseSensitive = document->IsCaseSensitive();
nsCOMPtr<nsIHTMLDocument> htmlDoc(do_QueryInterface(document));
PRBool bHTML = htmlDoc && !bCaseSensitive;
nsCOMPtr<nsIFragmentContentSink> sink;
if (bHTML) {
rv = NS_NewHTMLFragmentContentSink(getter_AddRefs(sink));
} else {
rv = NS_NewXMLFragmentContentSink(getter_AddRefs(sink));
}
NS_ENSURE_SUCCESS(rv, rv);
sink->SetTargetDocument(document);
nsCOMPtr<nsIContentSink> contentsink(do_QueryInterface(sink));
parser->SetContentSink(contentsink);
nsDTDMode mode = eDTDMode_autodetect;
switch (document->GetCompatibilityMode()) {
case eCompatibility_NavQuirks:
mode = eDTDMode_quirks;
break;
case eCompatibility_AlmostStandards:
mode = eDTDMode_almost_standards;
break;
case eCompatibility_FullStandards:
mode = eDTDMode_full_standards;
break;
default:
NS_NOTREACHED("unknown mode");
break;
}
// XXX Shouldn't we be returning rv if it's a failure code?
rv = parser->ParseFragment(aFragment, nsnull, tagStack,
!bHTML, contentType, mode);
if (NS_SUCCEEDED(rv)) {
nsCAutoString contentType;
PRBool bCaseSensitive = PR_TRUE;
nsAutoString buf;
document->GetContentType(buf);
LossyCopyUTF16toASCII(buf, contentType);
bCaseSensitive = document->IsCaseSensitive();
nsCOMPtr<nsIHTMLDocument> htmlDoc(do_QueryInterface(domDocument));
PRBool bHTML = htmlDoc && !bCaseSensitive;
nsCOMPtr<nsIFragmentContentSink> sink;
if (bHTML) {
rv = NS_NewHTMLFragmentContentSink(getter_AddRefs(sink));
} else {
rv = NS_NewXMLFragmentContentSink(getter_AddRefs(sink));
}
if (NS_SUCCEEDED(rv)) {
sink->SetTargetDocument(document);
nsCOMPtr<nsIContentSink> contentsink(do_QueryInterface(sink));
parser->SetContentSink(contentsink);
nsDTDMode mode = eDTDMode_autodetect;
switch (document->GetCompatibilityMode()) {
case eCompatibility_NavQuirks:
mode = eDTDMode_quirks;
break;
case eCompatibility_AlmostStandards:
mode = eDTDMode_almost_standards;
break;
case eCompatibility_FullStandards:
mode = eDTDMode_full_standards;
break;
default:
NS_NOTREACHED("unknown mode");
break;
}
rv = parser->ParseFragment(aFragment, nsnull, tagStack,
!bHTML, contentType, mode);
if (NS_SUCCEEDED(rv)) {
rv = sink->GetFragment(aReturn);
}
}
}
// XXX Ick! Delete strings we allocated above.
PRInt32 count = tagStack.Count();
for (PRInt32 i = 0; i < count; i++) {
PRUnichar* str = (PRUnichar*)tagStack.ElementAt(i);
if (str) {
NS_Free(str);
}
rv = sink->GetFragment(aReturn);
}
return NS_OK;

View File

@ -2546,7 +2546,7 @@ nsresult nsHTMLEditor::CreateDOMFragmentFromPaste(const nsAString &aInputString,
NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
// if we have context info, create a fragment for that
nsVoidArray tagStack;
nsAutoTArray<nsAutoString, 32> tagStack;
nsCOMPtr<nsIDOMDocumentFragment> contextfrag;
nsCOMPtr<nsIDOMNode> contextLeaf, junk;
if (!aContextStr.IsEmpty())
@ -2568,15 +2568,10 @@ nsresult nsHTMLEditor::CreateDOMFragmentFromPaste(const nsAString &aInputString,
// get the tagstack for the context
res = CreateTagStack(tagStack, contextLeaf);
if (NS_FAILED(res))
{
FreeTagStackStrings(tagStack);
return res;
}
NS_ENSURE_SUCCESS(res, res);
// create fragment for pasted html
res = ParseFragment(aInputString, tagStack, doc, outFragNode);
FreeTagStackStrings(tagStack);
NS_ENSURE_SUCCESS(res, res);
NS_ENSURE_TRUE(*outFragNode, NS_ERROR_FAILURE);
@ -2636,12 +2631,12 @@ nsresult nsHTMLEditor::CreateDOMFragmentFromPaste(const nsAString &aInputString,
nsresult nsHTMLEditor::ParseFragment(const nsAString & aFragStr,
nsVoidArray &aTagStack,
nsTArray<nsAutoString> &aTagStack,
nsIDocument* aTargetDocument,
nsCOMPtr<nsIDOMNode> *outNode)
{
// figure out if we are parsing full context or not
PRBool bContext = (aTagStack.Count()==0);
PRBool bContext = !aTagStack.IsEmpty();
// create the parser to do the conversion.
nsresult res;
@ -2677,7 +2672,7 @@ nsresult nsHTMLEditor::ParseFragment(const nsAString & aFragStr,
return res;
}
nsresult nsHTMLEditor::CreateTagStack(nsVoidArray &aTagStack, nsIDOMNode *aNode)
nsresult nsHTMLEditor::CreateTagStack(nsTArray<nsAutoString> &aTagStack, nsIDOMNode *aNode)
{
nsresult res = NS_OK;
nsCOMPtr<nsIDOMNode> node= aNode;
@ -2693,14 +2688,10 @@ nsresult nsHTMLEditor::CreateTagStack(nsVoidArray &aTagStack, nsIDOMNode *aNode)
node->GetNodeType(&nodeType);
if (nsIDOMNode::ELEMENT_NODE == nodeType)
{
nsAutoString tagName;
node->GetNodeName(tagName);
// XXX Wish we didn't have to allocate here
PRUnichar* name = ToNewUnicode(tagName);
if (!name)
return NS_ERROR_OUT_OF_MEMORY;
nsAutoString* tagName = aTagStack.AppendElement();
NS_ENSURE_TRUE(tagName, NS_ERROR_OUT_OF_MEMORY);
aTagStack.AppendElement(name);
node->GetNodeName(*tagName);
// printf("%s\n",NS_LossyConvertUTF16toASCII(tagName).get());
}
@ -2710,25 +2701,12 @@ nsresult nsHTMLEditor::CreateTagStack(nsVoidArray &aTagStack, nsIDOMNode *aNode)
if (!bSeenBody)
{
PRUnichar* bodyname = ToNewUnicode(NS_LITERAL_STRING("BODY"));
aTagStack.AppendElement(bodyname);
aTagStack.AppendElement(NS_LITERAL_STRING("BODY"));
}
return res;
}
void nsHTMLEditor::FreeTagStackStrings(nsVoidArray &tagStack)
{
PRInt32 count = tagStack.Count();
for (PRInt32 i = 0; i < count; i++)
{
PRUnichar* str = (PRUnichar*)tagStack.ElementAt(i);
if (str) {
NS_Free(str);
}
}
}
nsresult nsHTMLEditor::CreateListOfNodesToPaste(nsIDOMNode *aFragmentAsNode,
nsCOMArray<nsIDOMNode>& outNodeList,
nsIDOMNode *aStartNode,

View File

@ -72,6 +72,7 @@
#include "nsIDocumentObserver.h"
#include "nsPoint.h"
#include "nsTArray.h"
class nsIDOMKeyEvent;
class nsITransferable;
@ -633,7 +634,7 @@ protected:
nsCOMPtr<nsIDOMNode> *outEndNode,
PRInt32 *outStartOffset,
PRInt32 *outEndOffset);
nsresult ParseFragment(const nsAString & aStr, nsVoidArray &aTagStack,
nsresult ParseFragment(const nsAString & aStr, nsTArray<nsAutoString> &aTagStack,
nsIDocument* aTargetDoc,
nsCOMPtr<nsIDOMNode> *outNode);
nsresult CreateListOfNodesToPaste(nsIDOMNode *aFragmentAsNode,
@ -642,8 +643,8 @@ protected:
PRInt32 aStartOffset,
nsIDOMNode *aEndNode,
PRInt32 aEndOffset);
nsresult CreateTagStack(nsVoidArray &aTagStack, nsIDOMNode *aNode);
void FreeTagStackStrings(nsVoidArray &tagStack);
nsresult CreateTagStack(nsTArray<nsAutoString> &aTagStack,
nsIDOMNode *aNode);
nsresult GetListAndTableParents( PRBool aEnd,
nsCOMArray<nsIDOMNode>& aListOfNodes,
nsCOMArray<nsIDOMNode>& outArray);

View File

@ -51,12 +51,12 @@
#include "nsIStreamListener.h"
#include "nsIDTD.h"
#include "nsStringGlue.h"
#include "nsVoidArray.h"
#include "nsTArray.h"
// {d49b492c-1bdb-4b41-a138-9495a72fc11c}
// {506527cc-d832-420b-ba3a-80c05aa105f4}
#define NS_IPARSER_IID \
{ 0xd49b492c, 0x1bdb, 0x4b41, \
{ 0xa1, 0x38, 0x94, 0x95, 0xa7, 0x2f, 0xc1, 0x1c } }
{ 0x506527cc, 0xd832, 0x420b, \
{ 0xba, 0x3a, 0x80, 0xc0, 0x5a, 0xa1, 0x05, 0xf4 } }
// {41421C60-310A-11d4-816F-000064657374}
@ -254,7 +254,7 @@ class nsIParser : public nsISupports {
*/
NS_IMETHOD ParseFragment(const nsAString& aSourceBuffer,
void* aKey,
nsVoidArray& aTagStack,
nsTArray<nsAutoString>& aTagStack,
PRBool aXMLMode,
const nsACString& aContentType,
nsDTDMode aMode = eDTDMode_autodetect) = 0;

View File

@ -1423,14 +1423,14 @@ nsParser::Parse(const nsAString& aSourceBuffer,
NS_IMETHODIMP
nsParser::ParseFragment(const nsAString& aSourceBuffer,
void* aKey,
nsVoidArray& aTagStack,
nsTArray<nsAutoString>& aTagStack,
PRBool aXMLMode,
const nsACString& aMimeType,
nsDTDMode aMode)
{
nsresult result = NS_OK;
nsAutoString theContext;
PRUint32 theCount = aTagStack.Count();
PRUint32 theCount = aTagStack.Length();
PRUint32 theIndex = 0;
// Disable observers for fragments
@ -1438,7 +1438,7 @@ nsParser::ParseFragment(const nsAString& aSourceBuffer,
for (theIndex = 0; theIndex < theCount; theIndex++) {
theContext.AppendLiteral("<");
theContext.Append((PRUnichar*)aTagStack.ElementAt(theCount - theIndex - 1));
theContext.Append(aTagStack[theCount - theIndex - 1]);
theContext.AppendLiteral(">");
}
@ -1515,7 +1515,7 @@ nsParser::ParseFragment(const nsAString& aSourceBuffer,
endContext.AppendLiteral("</");
}
nsAutoString thisTag( (PRUnichar*)aTagStack.ElementAt(theIndex) );
nsAutoString& thisTag = aTagStack[theIndex];
// was there an xmlns=?
PRInt32 endOfTag = thisTag.FindChar(PRUnichar(' '));
if (endOfTag == -1) {

View File

@ -219,7 +219,7 @@ class nsParser : public nsIParser,
*/
NS_IMETHOD ParseFragment(const nsAString& aSourceBuffer,
void* aKey,
nsVoidArray& aTagStack,
nsTArray<nsAutoString>& aTagStack,
PRBool aXMLMode,
const nsACString& aContentType,
nsDTDMode aMode = eDTDMode_autodetect);