From b8893ea45ec78b1c3ca73859c353a51a3cd5595f Mon Sep 17 00:00:00 2001 From: "jfrancis%netscape.com" Date: Sun, 23 Mar 2003 20:45:47 +0000 Subject: [PATCH] fix for 187955: improvements to html fragment sink and paste code. Fixes problems seen with "Create table From Selection" and also with CF_HTML paste. r=brade; sr=kin --- .../src/nsHTMLFragmentContentSink.cpp | 6 +- editor/libeditor/html/nsHTMLDataTransfer.cpp | 86 +++++++++++++++++-- editor/libeditor/html/nsHTMLEditor.h | 4 +- 3 files changed, 83 insertions(+), 13 deletions(-) diff --git a/content/html/document/src/nsHTMLFragmentContentSink.cpp b/content/html/document/src/nsHTMLFragmentContentSink.cpp index ce80d0e64c4..e0dabf4427f 100644 --- a/content/html/document/src/nsHTMLFragmentContentSink.cpp +++ b/content/html/document/src/nsHTMLFragmentContentSink.cpp @@ -163,8 +163,6 @@ class nsHTMLFragmentContentSink2 : public nsHTMLFragmentContentSink public: nsHTMLFragmentContentSink2() { mHitSentinel = PR_TRUE; mSeenBody = PR_FALSE;} virtual ~nsHTMLFragmentContentSink2() {} - NS_IMETHODIMP OpenHead(const nsIParserNode& aNode) { return OpenContainer(aNode); } - NS_IMETHODIMP CloseHead() { return CloseContainer(eHTMLTag_head); } }; nsresult @@ -389,13 +387,13 @@ nsHTMLFragmentContentSink::CloseHTML() NS_IMETHODIMP nsHTMLFragmentContentSink::OpenHead(const nsIParserNode& aNode) { - return NS_OK; + return OpenContainer(aNode); } NS_IMETHODIMP nsHTMLFragmentContentSink::CloseHead() { - return NS_OK; + return CloseContainer(eHTMLTag_head); } NS_IMETHODIMP diff --git a/editor/libeditor/html/nsHTMLDataTransfer.cpp b/editor/libeditor/html/nsHTMLDataTransfer.cpp index 5fb86af1a20..5ae55b4a0a6 100644 --- a/editor/libeditor/html/nsHTMLDataTransfer.cpp +++ b/editor/libeditor/html/nsHTMLDataTransfer.cpp @@ -2112,11 +2112,13 @@ nsresult nsHTMLEditor::CreateDOMFragmentFromPaste(nsIDOMNSRange *aNSRange, nsresult res = NS_OK; // if we have context info, create a fragment for that + nsVoidArray tagStack; + nsCOMPtr contextfrag; nsCOMPtr contextLeaf, junk; PRInt32 contextDepth = 0; if (aContextStr.Length()) { - res = ParseFragment(aContextStr, address_of(contextAsNode)); + res = ParseFragment(aContextStr, tagStack, address_of(contextAsNode)); NS_ENSURE_SUCCESS(res, res); NS_ENSURE_TRUE(contextAsNode, NS_ERROR_FAILURE); @@ -2135,14 +2137,21 @@ nsresult nsHTMLEditor::CreateDOMFragmentFromPaste(nsIDOMNSRange *aNSRange, } } - + // get the tagstack for the context + res = CreateTagStack(tagStack, contextLeaf); + if (NS_FAILED(res)) + { + FreeTagStackStrings(tagStack); + return res; + } // create fragment for pasted html - res = ParseFragment(aInputString, outFragNode); + res = ParseFragment(aInputString, tagStack, outFragNode); + FreeTagStackStrings(tagStack); NS_ENSURE_SUCCESS(res, res); NS_ENSURE_TRUE(*outFragNode, NS_ERROR_FAILURE); RemoveBodyAndHead(*outFragNode); - + if (contextAsNode) { // unite the two trees @@ -2174,8 +2183,12 @@ nsresult nsHTMLEditor::CreateDOMFragmentFromPaste(nsIDOMNSRange *aNSRange, return res; } -nsresult nsHTMLEditor::ParseFragment(const nsAString &aFragStr, nsCOMPtr *outNode) + +nsresult nsHTMLEditor::ParseFragment(const nsAString & aFragStr, nsVoidArray &aTagStack, nsCOMPtr *outNode) { + // figure out if we are parsing full context or not + PRBool bContext = (aTagStack.Count()==0); + // create the parser to do the conversion. nsCOMPtr parser; nsresult res = nsComponentManager::CreateInstance(kCParserCID, nsnull, NS_GET_IID(nsIParser), @@ -2185,15 +2198,21 @@ nsresult nsHTMLEditor::ParseFragment(const nsAString &aFragStr, nsCOMPtr sink; - sink = do_CreateInstance(NS_HTMLFRAGMENTSINK2_CONTRACTID); + if (bContext) + sink = do_CreateInstance(NS_HTMLFRAGMENTSINK2_CONTRACTID); + else + sink = do_CreateInstance(NS_HTMLFRAGMENTSINK_CONTRACTID); + NS_ENSURE_TRUE(sink, NS_ERROR_FAILURE); nsCOMPtr fragSink(do_QueryInterface(sink)); NS_ENSURE_TRUE(fragSink, NS_ERROR_FAILURE); // parse the fragment parser->SetContentSink(sink); - parser->Parse(aFragStr, 0, NS_LITERAL_CSTRING("text/html"), PR_FALSE, PR_TRUE, eDTDMode_fragment); - + if (bContext) + parser->Parse(aFragStr, (void*)0, NS_LITERAL_CSTRING("text/html"), PR_FALSE, PR_TRUE, eDTDMode_fragment); + else + parser->ParseFragment(aFragStr, 0, aTagStack, 0, NS_LITERAL_CSTRING("text/html"), eDTDMode_quirks); // get the fragment node nsCOMPtr contextfrag; res = fragSink->GetFragment(getter_AddRefs(contextfrag)); @@ -2203,6 +2222,57 @@ nsresult nsHTMLEditor::ParseFragment(const nsAString &aFragStr, nsCOMPtr node= aNode; + PRBool bSeenBody = PR_FALSE; + + while (node) + { + if (nsTextEditUtils::IsBody(node)) + bSeenBody = PR_TRUE; + nsCOMPtr temp = node; + PRUint16 nodeType; + + 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; + + aTagStack.AppendElement(name); + // printf("%s\n",NS_LossyConvertUCS2toASCII(tagName).get()); + } + + res = temp->GetParentNode(getter_AddRefs(node)); + NS_ENSURE_SUCCESS(res, res); + } + + if (!bSeenBody) + { + PRUnichar* bodyname = ToNewUnicode(NS_LITERAL_STRING("BODY")); + aTagStack.AppendElement(bodyname); + } + 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) { + nsCRT::free(str); + } + } +} nsresult nsHTMLEditor::CreateListOfNodesToPaste(nsIDOMNode *aFragmentAsNode, nsCOMArray& outNodeList, diff --git a/editor/libeditor/html/nsHTMLEditor.h b/editor/libeditor/html/nsHTMLEditor.h index fb9542822d7..6ffaf3fcce3 100644 --- a/editor/libeditor/html/nsHTMLEditor.h +++ b/editor/libeditor/html/nsHTMLEditor.h @@ -680,11 +680,13 @@ protected: nsCOMPtr *outFragNode, PRInt32 *outRangeStartHint, PRInt32 *outRangeEndHint); - nsresult ParseFragment(const nsAString & aFragStr, nsCOMPtr *outNode); + nsresult ParseFragment(const nsAString & aStr, nsVoidArray &aTagStack, nsCOMPtr *outNode); nsresult CreateListOfNodesToPaste(nsIDOMNode *aFragmentAsNode, nsCOMArray& outNodeList, PRInt32 aRangeStartHint, PRInt32 aRangeEndHint); + nsresult CreateTagStack(nsVoidArray &aTagStack, nsIDOMNode *aNode); + void FreeTagStackStrings(nsVoidArray &tagStack); nsresult GetListAndTableParents( PRBool aEnd, nsCOMArray& aListOfNodes, nsCOMArray& outArray);