mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
Bug 403549: Avoid memory churn from nsContentUtils::CreateContextualFragment by giving nsIParser::ParseFragment a better signature. r/sr=stuart
This commit is contained in:
parent
f6b0191adc
commit
0e1c530ce2
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user