forked from mirrors/gecko-dev
Rolling in the last of the NOXIF changes from the Netscape 6 branch, code mostly written by jfrancis. Fixes bugs 50742, 55806, 56000 and 55669. sr=kin, scc. r=kandrot, jst.
This commit is contained in:
parent
292cb40883
commit
17691505d4
14 changed files with 774 additions and 415 deletions
|
|
@ -84,8 +84,8 @@ public:
|
|||
// (Probably not well tested for HTML output.)
|
||||
OutputFormatted = 2,
|
||||
|
||||
// OutputNoDoctype is obsolete, flag 4 available for other uses
|
||||
//OutputNoDoctype = 4,
|
||||
// OutputRaw is used by copying text from widgets
|
||||
OutputRaw = 4,
|
||||
|
||||
// No html head tags
|
||||
OutputBodyOnly = 8,
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "nsIComponentManager.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIHTMLDocument.h"
|
||||
#include "nsISelection.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIContentSerializer.h"
|
||||
|
|
@ -48,6 +49,7 @@
|
|||
#include "nsITextContent.h"
|
||||
#include "nsIEnumerator.h"
|
||||
#include "nsISelectionPrivate.h"
|
||||
#include "nsIFrameSelection.h"
|
||||
#include "nsIContentIterator.h"
|
||||
#include "nsISupportsArray.h"
|
||||
#include "nsIParserService.h"
|
||||
|
|
@ -58,6 +60,7 @@ static NS_DEFINE_CID(kCharsetConverterManagerCID,
|
|||
static NS_DEFINE_CID(kParserServiceCID, NS_PARSERSERVICE_CID);
|
||||
|
||||
nsresult NS_NewContentSubtreeIterator(nsIContentIterator** aInstancePtrResult);
|
||||
nsresult NS_NewDomSelection(nsISelection **aDomSelection);
|
||||
|
||||
enum nsRangeIterationDirection {
|
||||
kDirectionOut = -1,
|
||||
|
|
@ -104,8 +107,9 @@ protected:
|
|||
nsresult SerializeRangeToString(nsIDOMRange *aRange,
|
||||
nsAWritableString& aOutputString);
|
||||
nsresult SerializeRangeNodes(nsIDOMRange* aRange,
|
||||
nsIDOMNode* aCommonParent,
|
||||
nsAWritableString& aString);
|
||||
nsIDOMNode* aNode,
|
||||
nsAWritableString& aString,
|
||||
PRInt32 aDepth);
|
||||
nsresult SerializeRangeContextStart(const nsVoidArray& aAncestorArray,
|
||||
nsAWritableString& aString);
|
||||
nsresult SerializeRangeContextEnd(const nsVoidArray& aAncestorArray,
|
||||
|
|
@ -124,6 +128,7 @@ protected:
|
|||
nsCOMPtr<nsIOutputStream> mStream;
|
||||
nsCOMPtr<nsIContentSerializer> mSerializer;
|
||||
nsCOMPtr<nsIUnicodeEncoder> mUnicodeEncoder;
|
||||
nsCOMPtr<nsIDOMNode> mCommonParent;
|
||||
|
||||
nsString mMimeType;
|
||||
nsString mCharset;
|
||||
|
|
@ -131,8 +136,14 @@ protected:
|
|||
PRUint32 mWrapColumn;
|
||||
PRUint32 mStartDepth;
|
||||
PRUint32 mEndDepth;
|
||||
PRInt32 mStartRootIndex;
|
||||
PRInt32 mEndRootIndex;
|
||||
PRBool mHaltRangeHint;
|
||||
nsVoidArray mCommonAncestors;
|
||||
nsVoidArray mStartNodes;
|
||||
nsVoidArray mStartOffsets;
|
||||
nsVoidArray mEndNodes;
|
||||
nsVoidArray mEndOffsets;
|
||||
};
|
||||
|
||||
#ifdef XP_MAC
|
||||
|
|
@ -566,25 +577,33 @@ static nsresult GetLengthOfDOMNode(nsIDOMNode *aNode, PRUint32 &aCount)
|
|||
nsresult
|
||||
nsDocumentEncoder::SerializeRangeNodes(nsIDOMRange* aRange,
|
||||
nsIDOMNode* aNode,
|
||||
nsAWritableString& aString)
|
||||
nsAWritableString& aString,
|
||||
PRInt32 aDepth)
|
||||
{
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
|
||||
NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
|
||||
|
||||
if (IsNodeIntersectsRange(content, aRange))
|
||||
{
|
||||
PRBool nodeBefore, nodeAfter;
|
||||
nsresult rv = CompareNodeToRange(content, aRange, &nodeBefore, &nodeAfter);
|
||||
if (!nodeBefore && !nodeAfter) // node completely contained
|
||||
nsresult rv=NS_OK;
|
||||
|
||||
// get start and end nodes for this recursion level
|
||||
nsCOMPtr<nsIContent> startNode, endNode;
|
||||
startNode = NS_STATIC_CAST(nsIContent *, mStartNodes[mStartRootIndex - aDepth]);
|
||||
endNode = NS_STATIC_CAST(nsIContent *, mEndNodes[mEndRootIndex - aDepth]);
|
||||
|
||||
if ((startNode != content) && (endNode != content))
|
||||
{
|
||||
// node is completely contained in range. Serialize the whole subtree
|
||||
// rooted by this node.
|
||||
rv = SerializeToStringRecursive(aNode, aString);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
else // node intersects range, but is not contained. recurse if needed.
|
||||
else
|
||||
{
|
||||
// due to implementation it is impossible for text node to be both start and end of
|
||||
// range. We would have handled that case without getting here.
|
||||
if (IsTextNode(aNode))
|
||||
{
|
||||
if (nodeBefore)
|
||||
if (startNode == content)
|
||||
{
|
||||
PRInt32 startOffset;
|
||||
aRange->GetStartOffset(&startOffset);
|
||||
|
|
@ -600,6 +619,8 @@ nsDocumentEncoder::SerializeRangeNodes(nsIDOMRange* aRange,
|
|||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (aNode != mCommonParent.get())
|
||||
{
|
||||
if (IncludeInContext(aNode))
|
||||
{
|
||||
|
|
@ -607,22 +628,59 @@ nsDocumentEncoder::SerializeRangeNodes(nsIDOMRange* aRange,
|
|||
// so paste client will include this node in paste.
|
||||
mHaltRangeHint = PR_TRUE;
|
||||
}
|
||||
if (nodeBefore && !mHaltRangeHint) mStartDepth++;
|
||||
if (nodeAfter && !mHaltRangeHint) mEndDepth++;
|
||||
if ((startNode == content) && !mHaltRangeHint) mStartDepth++;
|
||||
if ((endNode == content) && !mHaltRangeHint) mEndDepth++;
|
||||
|
||||
// serialize the start of this node
|
||||
rv = SerializeNodeStart(aNode, 0, -1, aString);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIDOMNode> child, tmp;
|
||||
aNode->GetFirstChild(getter_AddRefs(child));
|
||||
while (child)
|
||||
{
|
||||
rv = SerializeRangeNodes(aRange, child, aString);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
child->GetNextSibling(getter_AddRefs(tmp));
|
||||
child = tmp;
|
||||
}
|
||||
|
||||
// do some calculations that will tell us which children of this node are in the range.
|
||||
nsCOMPtr<nsIContent> child;
|
||||
nsCOMPtr<nsIDOMNode> childAsNode;
|
||||
PRInt32 startOffset = 0, endOffset = -1;
|
||||
if (startNode == content)
|
||||
startOffset = NS_REINTERPRET_CAST(PRInt32, mStartOffsets[mStartRootIndex - aDepth]);
|
||||
if (endNode == content)
|
||||
endOffset = NS_REINTERPRET_CAST(PRInt32, mEndOffsets[mEndRootIndex - aDepth]);
|
||||
// generated content will cause offset values of -1 to be returned.
|
||||
PRInt32 j, childCount=0;
|
||||
rv = content->ChildCount(childCount);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (startOffset == -1) startOffset = 0;
|
||||
if (endOffset == -1) endOffset = childCount;
|
||||
else
|
||||
{
|
||||
// if we are at the "tip" of the selection, endOffset is fine.
|
||||
// otherwise, we need to add one. This is because of the semantics
|
||||
// of the offset list created by GetAncestorsAndOffsets(). The
|
||||
// intermediate points on the list use the endOffset of the
|
||||
// location of the ancestor, rather than just past it. So we need
|
||||
// to add one here in order to include it in the children we serialize.
|
||||
nsCOMPtr<nsIDOMNode> endParent;
|
||||
aRange->GetEndContainer(getter_AddRefs(endParent));
|
||||
if (aNode != endParent.get())
|
||||
{
|
||||
endOffset++;
|
||||
}
|
||||
}
|
||||
// serialize the children of this node that are in the range
|
||||
for (j=startOffset; j<endOffset; j++)
|
||||
{
|
||||
rv = content->ChildAt(j, *getter_AddRefs(child));
|
||||
childAsNode = do_QueryInterface(child);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if ((j==startOffset) || (j==endOffset-1))
|
||||
rv = SerializeRangeNodes(aRange, childAsNode, aString, aDepth+1);
|
||||
else
|
||||
rv = SerializeToStringRecursive(childAsNode, aString);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// serialize the end of this node
|
||||
if (aNode != mCommonParent.get())
|
||||
{
|
||||
rv = SerializeNodeEnd(aNode, aString);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
|
@ -693,15 +751,15 @@ nsDocumentEncoder::SerializeRangeToString(nsIDOMRange *aRange,
|
|||
if (collapsed)
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> commonParent, startParent, endParent;
|
||||
nsCOMPtr<nsIDOMNode> startParent, endParent;
|
||||
PRInt32 startOffset, endOffset;
|
||||
|
||||
aRange->GetCommonAncestorContainer(getter_AddRefs(commonParent));
|
||||
aRange->GetCommonAncestorContainer(getter_AddRefs(mCommonParent));
|
||||
|
||||
if (!commonParent)
|
||||
if (!mCommonParent)
|
||||
return NS_OK;
|
||||
|
||||
AdjustCommonParent(&commonParent);
|
||||
AdjustCommonParent(&mCommonParent);
|
||||
|
||||
aRange->GetStartContainer(getter_AddRefs(startParent));
|
||||
NS_ENSURE_TRUE(startParent, NS_ERROR_FAILURE);
|
||||
|
|
@ -712,8 +770,17 @@ nsDocumentEncoder::SerializeRangeToString(nsIDOMRange *aRange,
|
|||
aRange->GetEndOffset(&endOffset);
|
||||
|
||||
mCommonAncestors.Clear();
|
||||
mStartNodes.Clear();
|
||||
mStartOffsets.Clear();
|
||||
mEndNodes.Clear();
|
||||
mEndOffsets.Clear();
|
||||
|
||||
nsRange::FillArrayWithAncestors(&mCommonAncestors, commonParent);
|
||||
nsRange::FillArrayWithAncestors(&mCommonAncestors, mCommonParent);
|
||||
nsRange::GetAncestorsAndOffsets(startParent, startOffset, &mStartNodes, &mStartOffsets);
|
||||
nsRange::GetAncestorsAndOffsets(endParent, endOffset, &mEndNodes, &mEndOffsets);
|
||||
nsCOMPtr<nsIContent> commonContent = do_QueryInterface(mCommonParent);
|
||||
mStartRootIndex = mStartNodes.IndexOf(commonContent);
|
||||
mEndRootIndex = mEndNodes.IndexOf(commonContent);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
|
|
@ -727,17 +794,9 @@ nsDocumentEncoder::SerializeRangeToString(nsIDOMRange *aRange,
|
|||
}
|
||||
else
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> child, tmp;
|
||||
commonParent->GetFirstChild(getter_AddRefs(child));
|
||||
while (child)
|
||||
{
|
||||
rv = SerializeRangeNodes(aRange, child, aOutputString);
|
||||
rv = SerializeRangeNodes(aRange, mCommonParent, aOutputString, 0);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
child->GetNextSibling(getter_AddRefs(tmp));
|
||||
child = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
rv = SerializeRangeContextEnd(mCommonAncestors, aOutputString);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
|
@ -888,12 +947,14 @@ protected:
|
|||
nsCOMPtr<nsIDOMNode> GetChildAt(nsIDOMNode *aParent, PRInt32 aOffset);
|
||||
PRBool IsMozBR(nsIDOMNode* aNode);
|
||||
nsresult GetNodeLocation(nsIDOMNode *inChild, nsCOMPtr<nsIDOMNode> *outParent, PRInt32 *outOffset);
|
||||
PRBool IsRoot(nsIDOMNode* aNode);
|
||||
PRBool IsFirstNode(nsIDOMNode *aNode);
|
||||
PRBool IsLastNode(nsIDOMNode *aNode);
|
||||
PRBool IsEmptyTextContent(nsIDOMNode* aNode);
|
||||
virtual PRBool IncludeInContext(nsIDOMNode *aNode);
|
||||
|
||||
nsCOMPtr<nsIParserService> mParserService;
|
||||
PRBool mIsTextWidget;
|
||||
};
|
||||
|
||||
#ifdef XP_MAC
|
||||
|
|
@ -903,6 +964,7 @@ protected:
|
|||
|
||||
nsHTMLCopyEncoder::nsHTMLCopyEncoder()
|
||||
{
|
||||
mIsTextWidget = PR_FALSE;
|
||||
}
|
||||
|
||||
nsHTMLCopyEncoder::~nsHTMLCopyEncoder()
|
||||
|
|
@ -911,7 +973,7 @@ nsHTMLCopyEncoder::~nsHTMLCopyEncoder()
|
|||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLCopyEncoder::Init(nsIDocument* aDocument,
|
||||
const nsAReadableString& aIgnored,
|
||||
const nsAReadableString& aMimetype,
|
||||
PRUint32 aFlags)
|
||||
{
|
||||
if (!aDocument)
|
||||
|
|
@ -931,19 +993,50 @@ nsHTMLCopyEncoder::Init(nsIDocument* aDocument,
|
|||
NS_IMETHODIMP
|
||||
nsHTMLCopyEncoder::SetSelection(nsISelection* aSelection)
|
||||
{
|
||||
// normalize selection
|
||||
// check for text widgets: we need to recognize these so that
|
||||
// we don't tweak the selection to be outside of the magic
|
||||
// div that ender-lite text widgets are embedded in.
|
||||
nsCOMPtr<nsIDOMNode> selNode;
|
||||
nsresult rv = aSelection->GetFocusNode(getter_AddRefs(selNode));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIContent> tmp, selContent( do_QueryInterface(selNode) );
|
||||
while (selContent)
|
||||
{
|
||||
nsCOMPtr<nsIAtom> atom;
|
||||
selContent->GetTag(*getter_AddRefs(atom));
|
||||
if (atom.get() == nsHTMLAtoms::input ||
|
||||
atom.get() == nsHTMLAtoms::textarea)
|
||||
{
|
||||
mIsTextWidget = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
selContent->GetParent(*getter_AddRefs(tmp));
|
||||
selContent = tmp;
|
||||
}
|
||||
|
||||
// also consider ourselves in a text widget if we can't find an html document
|
||||
nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(mDocument);
|
||||
if (!htmlDoc) mIsTextWidget = PR_TRUE;
|
||||
|
||||
// normalize selection if we are not in a widget
|
||||
if (mIsTextWidget)
|
||||
{
|
||||
mSelection = aSelection;
|
||||
mFlags |= OutputRaw;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// there's no Clone() for selection! fix...
|
||||
//nsresult rv = aSelection->Clone(getter_AddRefs(mSelection);
|
||||
//NS_ENSURE_SUCCESS(rv, rv);
|
||||
mSelection = aSelection;
|
||||
|
||||
nsCOMPtr<nsISelectionPrivate> privSelection = do_QueryInterface(mSelection);
|
||||
NS_NewDomSelection(getter_AddRefs(mSelection));
|
||||
NS_ENSURE_TRUE(mSelection, NS_ERROR_FAILURE);
|
||||
nsCOMPtr<nsISelectionPrivate> privSelection( do_QueryInterface(aSelection) );
|
||||
NS_ENSURE_TRUE(privSelection, NS_ERROR_FAILURE);
|
||||
|
||||
// get selection range enumerator
|
||||
nsCOMPtr<nsIEnumerator> enumerator;
|
||||
nsresult rv = privSelection->GetEnumerator(getter_AddRefs(enumerator));
|
||||
rv = privSelection->GetEnumerator(getter_AddRefs(enumerator));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(enumerator, NS_ERROR_FAILURE);
|
||||
|
||||
|
|
@ -957,9 +1050,16 @@ nsHTMLCopyEncoder::SetSelection(nsISelection* aSelection)
|
|||
NS_ENSURE_TRUE(currentItem, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
|
||||
NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
|
||||
nsCOMPtr<nsIDOMRange> myRange;
|
||||
range->CloneRange(getter_AddRefs(myRange));
|
||||
NS_ENSURE_TRUE(myRange, NS_ERROR_FAILURE);
|
||||
|
||||
// adjust range to include any ancestors who's children are entirely selected
|
||||
rv = PromoteRange(range);
|
||||
rv = PromoteRange(myRange);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mSelection->AddRange(myRange);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
enumerator->Next();
|
||||
|
|
@ -976,6 +1076,16 @@ nsHTMLCopyEncoder::EncodeToStringWithContext(nsAWritableString& aEncodedString,
|
|||
nsresult rv = EncodeToString(aEncodedString);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (mIsTextWidget) {
|
||||
aEncodedString.Insert(NS_LITERAL_STRING("<pre>"), 0);
|
||||
aEncodedString.Append(NS_LITERAL_STRING("</pre>"));
|
||||
}
|
||||
|
||||
// do not encode any context info or range hints if we are not in an html document.
|
||||
|
||||
// do not encode any context info or range hints if we are in a text widget.
|
||||
if (mIsTextWidget) return NS_OK;
|
||||
|
||||
// now encode common ancestors into aContextString. Note that the common ancestors
|
||||
// will be for the last range in the selection in the case of multirange selections.
|
||||
// encoding ancestors every range in a multirange selection in a way that could be
|
||||
|
|
@ -1126,12 +1236,12 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, PRInt32
|
|||
|
||||
// finding the real start for this point. look up the tree for as long as we are the
|
||||
// first node in the container, and as long as we haven't hit the body node.
|
||||
if (!IsTag(node, nsHTMLAtoms::body))
|
||||
if (!IsRoot(node))
|
||||
{
|
||||
rv = GetNodeLocation(node, &parent, &offset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (offset == -1) return NS_OK; // we hit generated content; STOP
|
||||
while ((IsFirstNode(node)) && (!IsTag(parent, nsHTMLAtoms::body)))
|
||||
while ((IsFirstNode(node)) && (!IsRoot(parent)))
|
||||
{
|
||||
if (bResetPromotion)
|
||||
{
|
||||
|
|
@ -1211,12 +1321,12 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, PRInt32
|
|||
|
||||
// finding the real end for this point. look up the tree for as long as we are the
|
||||
// last node in the container, and as long as we haven't hit the body node.
|
||||
if (!IsTag(node, nsHTMLAtoms::body))
|
||||
if (!IsRoot(node))
|
||||
{
|
||||
rv = GetNodeLocation(node, &parent, &offset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (offset == -1) return NS_OK; // we hit generated content; STOP
|
||||
while ((IsLastNode(node)) && (!IsTag(parent, nsHTMLAtoms::body)))
|
||||
while ((IsLastNode(node)) && (!IsRoot(parent)))
|
||||
{
|
||||
if (bResetPromotion)
|
||||
{
|
||||
|
|
@ -1325,6 +1435,19 @@ nsHTMLCopyEncoder::GetNodeLocation(nsIDOMNode *inChild, nsCOMPtr<nsIDOMNode> *ou
|
|||
return result;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsHTMLCopyEncoder::IsRoot(nsIDOMNode* aNode)
|
||||
{
|
||||
if (aNode)
|
||||
{
|
||||
if (mIsTextWidget)
|
||||
return (IsTag(aNode, nsHTMLAtoms::div));
|
||||
else
|
||||
return (IsTag(aNode, nsHTMLAtoms::body));
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsHTMLCopyEncoder::IsFirstNode(nsIDOMNode *aNode)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include "nsHTMLAtoms.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsEscape.h"
|
||||
|
||||
static NS_DEFINE_CID(kParserServiceCID, NS_PARSERSERVICE_CID);
|
||||
static NS_DEFINE_CID(kEntityConverterCID, NS_ENTITYCONVERTER_CID);
|
||||
|
|
@ -68,21 +69,6 @@ nsHTMLContentSerializer::~nsHTMLContentSerializer()
|
|||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLContentSerializer::GetEntityConverter(nsIEntityConverter** aConverter)
|
||||
{
|
||||
if (!mEntityConverter) {
|
||||
nsresult rv;
|
||||
rv = nsComponentManager::CreateInstance(kEntityConverterCID, NULL,
|
||||
NS_GET_IID(nsIEntityConverter),
|
||||
getter_AddRefs(mEntityConverter));
|
||||
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
CallQueryInterface(mEntityConverter.get(), aConverter);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLContentSerializer::GetParserService(nsIParserService** aParserService)
|
||||
{
|
||||
|
|
@ -149,7 +135,8 @@ nsHTMLContentSerializer::AppendText(nsIDOMText* aText,
|
|||
PRInt32 lastNewlineOffset = kNotFound;
|
||||
PRBool hasLongLines = HasLongLines(data, lastNewlineOffset);
|
||||
|
||||
if (mPreLevel || (!mDoFormat && !hasLongLines)) {
|
||||
if (mPreLevel || (!mDoFormat && !hasLongLines) ||
|
||||
(mFlags & nsIDocumentEncoder::OutputRaw)) {
|
||||
AppendToString(data, aStr);
|
||||
|
||||
if (lastNewlineOffset != kNotFound) {
|
||||
|
|
@ -378,7 +365,6 @@ nsHTMLContentSerializer::AppendToStringWrapped(const nsAReadableString& aStr,
|
|||
PRBool done = PR_FALSE;
|
||||
PRInt32 indx = 0;
|
||||
PRInt32 strOffset = 0;
|
||||
PRInt32 oldLineOffset = 0;
|
||||
PRInt32 lineLength, oldLineEnd;
|
||||
|
||||
// Make sure we haven't gone too far already
|
||||
|
|
@ -468,28 +454,19 @@ nsHTMLContentSerializer::AppendToString(const nsAReadableString& aStr,
|
|||
return;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
|
||||
if (aIncrColumn) {
|
||||
mColPos += aStr.Length();
|
||||
}
|
||||
|
||||
if (aTranslateEntities) {
|
||||
nsCOMPtr<nsIEntityConverter> converter;
|
||||
|
||||
GetEntityConverter(getter_AddRefs(converter));
|
||||
if (converter) {
|
||||
PRUnichar *encodedBuffer;
|
||||
rv = mEntityConverter->ConvertToEntities(nsPromiseFlatString(aStr),
|
||||
nsIEntityConverter::html40Latin1,
|
||||
&encodedBuffer);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
encodedBuffer = nsEscapeHTML2(nsPromiseFlatString(aStr), aStr.Length());
|
||||
if (encodedBuffer) {
|
||||
aOutputStr.Append(encodedBuffer);
|
||||
nsCRT::free(encodedBuffer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aOutputStr.Append(aStr);
|
||||
}
|
||||
|
|
@ -513,7 +490,8 @@ PRBool
|
|||
nsHTMLContentSerializer::LineBreakBeforeOpen(nsIAtom* aName,
|
||||
PRBool aHasDirtyAttr)
|
||||
{
|
||||
if ((!mDoFormat && !aHasDirtyAttr) || mPreLevel || !mColPos) {
|
||||
if ((!mDoFormat && !aHasDirtyAttr) || mPreLevel || !mColPos ||
|
||||
(mFlags & nsIDocumentEncoder::OutputRaw)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
|
@ -548,7 +526,8 @@ PRBool
|
|||
nsHTMLContentSerializer::LineBreakAfterOpen(nsIAtom* aName,
|
||||
PRBool aHasDirtyAttr)
|
||||
{
|
||||
if ((!mDoFormat && !aHasDirtyAttr) || mPreLevel) {
|
||||
if ((!mDoFormat && !aHasDirtyAttr) || mPreLevel ||
|
||||
(mFlags & nsIDocumentEncoder::OutputRaw)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
|
@ -576,7 +555,8 @@ PRBool
|
|||
nsHTMLContentSerializer::LineBreakBeforeClose(nsIAtom* aName,
|
||||
PRBool aHasDirtyAttr)
|
||||
{
|
||||
if ((!mDoFormat && !aHasDirtyAttr) || mPreLevel || !mColPos) {
|
||||
if ((!mDoFormat && !aHasDirtyAttr) || mPreLevel || !mColPos ||
|
||||
(mFlags & nsIDocumentEncoder::OutputRaw)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
|
@ -598,7 +578,8 @@ PRBool
|
|||
nsHTMLContentSerializer::LineBreakAfterClose(nsIAtom* aName,
|
||||
PRBool aHasDirtyAttr)
|
||||
{
|
||||
if ((!mDoFormat && !aHasDirtyAttr) || mPreLevel) {
|
||||
if ((!mDoFormat && !aHasDirtyAttr) || mPreLevel ||
|
||||
(mFlags & nsIDocumentEncoder::OutputRaw)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -281,6 +281,9 @@ nsPlainTextSerializer::AppendElementStart(nsIDOMElement *aElement,
|
|||
mContent = 0;
|
||||
mOutputString = nsnull;
|
||||
|
||||
if (!mInHead && id == eHTMLTag_head)
|
||||
mInHead = PR_TRUE;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
|
@ -310,6 +313,9 @@ nsPlainTextSerializer::AppendElementEnd(nsIDOMElement *aElement,
|
|||
mContent = 0;
|
||||
mOutputString = nsnull;
|
||||
|
||||
if (mInHead && id == eHTMLTag_head)
|
||||
mInHead = PR_FALSE;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
|
@ -326,8 +332,6 @@ NS_IMETHODIMP
|
|||
nsPlainTextSerializer::OpenContainer(const nsIParserNode& aNode)
|
||||
{
|
||||
PRInt32 type = aNode.GetNodeType();
|
||||
const nsString& namestr = aNode.GetText();
|
||||
nsCOMPtr<nsIAtom> name = dont_AddRef(NS_NewAtom(namestr));
|
||||
|
||||
mParserNode = NS_CONST_CAST(nsIParserNode *, &aNode);
|
||||
return DoOpenContainer(type);
|
||||
|
|
|
|||
|
|
@ -150,6 +150,8 @@ public:
|
|||
static PRBool InSameDoc(nsIDOMNode* aNode1, nsIDOMNode* aNode2);
|
||||
static PRInt32 IndexOf(nsIDOMNode* aNode);
|
||||
static PRInt32 FillArrayWithAncestors(nsVoidArray* aArray,nsIDOMNode* aNode);
|
||||
static PRInt32 GetAncestorsAndOffsets(nsIDOMNode* aNode, PRInt32 aOffset,
|
||||
nsVoidArray* aAncestorNodes, nsVoidArray* aAncestorOffsets);
|
||||
static nsCOMPtr<nsIDOMNode> CommonParent(nsIDOMNode* aNode1, nsIDOMNode* aNode2);
|
||||
static nsresult GetDOMNodeFromContent(nsIContent* inContentNode, nsCOMPtr<nsIDOMNode>* outDomNode);
|
||||
static nsresult GetContentFromDOMNode(nsIDOMNode* inDomNode, nsCOMPtr<nsIContent>* outContentNode);
|
||||
|
|
@ -173,9 +175,6 @@ public:
|
|||
nsresult ComparePointToRange(nsIDOMNode* aParent, PRInt32 aOffset, PRInt32* aResult);
|
||||
|
||||
|
||||
PRInt32 GetAncestorsAndOffsets(nsIDOMNode* aNode, PRInt32 aOffset,
|
||||
nsVoidArray* aAncestorNodes, nsVoidArray* aAncestorOffsets);
|
||||
|
||||
nsresult AddToListOf(nsIDOMNode* aNode);
|
||||
|
||||
nsresult RemoveFromListOf(nsIDOMNode* aNode);
|
||||
|
|
|
|||
|
|
@ -2417,6 +2417,36 @@ NS_IMETHODIMP nsHTMLEditor::InsertText(const nsString& aStringToInsert)
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
static nsCOMPtr<nsIDOMNode> GetListParent(nsIDOMNode* aNode)
|
||||
{
|
||||
if (!aNode) return nsnull;
|
||||
nsCOMPtr<nsIDOMNode> parent, tmp;
|
||||
aNode->GetParentNode(getter_AddRefs(parent));
|
||||
while (parent)
|
||||
{
|
||||
if (nsHTMLEditUtils::IsList(parent)) return parent;
|
||||
parent->GetParentNode(getter_AddRefs(tmp));
|
||||
parent = tmp;
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
static nsCOMPtr<nsIDOMNode> GetTableParent(nsIDOMNode* aNode)
|
||||
{
|
||||
if (!aNode) return nsnull;
|
||||
nsCOMPtr<nsIDOMNode> parent, tmp;
|
||||
aNode->GetParentNode(getter_AddRefs(parent));
|
||||
while (parent)
|
||||
{
|
||||
if (nsHTMLEditUtils::IsTable(parent)) return parent;
|
||||
parent->GetParentNode(getter_AddRefs(tmp));
|
||||
parent = tmp;
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsHTMLEditor::InsertHTML(const nsString& aInputString)
|
||||
{
|
||||
nsAutoString charset;
|
||||
|
|
@ -2476,8 +2506,7 @@ nsresult nsHTMLEditor::InsertHTMLWithCharsetAndContext(const nsString& aInputStr
|
|||
nsCOMPtr<nsIDOMNSRange> nsrange (do_QueryInterface(range));
|
||||
if (!nsrange)
|
||||
return NS_ERROR_NO_INTERFACE;
|
||||
nsCAutoString foo; foo.AssignWithConversion(inputString);
|
||||
printf ("fff = '%s'\n", (const char *)foo);
|
||||
|
||||
// create a dom document fragment that represents the structure to paste
|
||||
nsCOMPtr<nsIDOMDocumentFragment> docfrag;
|
||||
res = nsrange->CreateContextualFragment(inputString,
|
||||
|
|
@ -2485,11 +2514,6 @@ printf ("fff = '%s'\n", (const char *)foo);
|
|||
NS_ENSURE_SUCCESS(res, res);
|
||||
nsCOMPtr<nsIDOMNode> fragmentAsNode (do_QueryInterface(docfrag));
|
||||
|
||||
PRInt32 bar;
|
||||
nsCOMPtr<nsIContent> f(do_QueryInterface(docfrag));
|
||||
f->ChildCount(bar);
|
||||
printf ("Child count %d\n", bar);
|
||||
|
||||
res = StripFormattingNodes(fragmentAsNode);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
|
||||
|
|
@ -2657,10 +2681,34 @@ printf ("Child count %d\n", bar);
|
|||
parentNode = temp;
|
||||
}
|
||||
|
||||
// scan insertion list for table elements (other than table).
|
||||
PRBool bHaveTableGuts = PR_FALSE;
|
||||
PRBool bHaveListGuts = PR_FALSE;
|
||||
// build up list of parents of first node in lst that are either:
|
||||
// lists, or tables.
|
||||
nsCOMPtr<nsISupports> isup = nodeList->ElementAt(0);
|
||||
nsCOMPtr<nsIDOMNode> pNode( do_QueryInterface(isup) );
|
||||
nsCOMPtr<nsISupportsArray> listAndTableArray;
|
||||
res = NS_NewISupportsArray(getter_AddRefs(listAndTableArray));
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
while (pNode)
|
||||
{
|
||||
if (nsHTMLEditUtils::IsList(pNode) || nsHTMLEditUtils::IsTable(pNode))
|
||||
{
|
||||
isup = do_QueryInterface(pNode);
|
||||
listAndTableArray->AppendElement(isup);
|
||||
}
|
||||
nsCOMPtr<nsIDOMNode> parent;
|
||||
pNode->GetParentNode(getter_AddRefs(parent));
|
||||
pNode = parent;
|
||||
}
|
||||
|
||||
// remember number of lists and tables above us
|
||||
PRUint32 listAndTableParents;
|
||||
PRInt32 highWaterMark = -1;
|
||||
listAndTableArray->Count(&listAndTableParents);
|
||||
|
||||
PRUint32 listCount, j;
|
||||
if (listAndTableParents)
|
||||
{
|
||||
// scan insertion list for table elements (other than table).
|
||||
nodeList->Count(&listCount);
|
||||
for (j=0; j<listCount; j++)
|
||||
{
|
||||
|
|
@ -2670,31 +2718,96 @@ printf ("Child count %d\n", bar);
|
|||
NS_ENSURE_TRUE(curNode, NS_ERROR_FAILURE);
|
||||
if (nsHTMLEditUtils::IsTableElement(curNode) && !nsHTMLEditUtils::IsTable(curNode))
|
||||
{
|
||||
bHaveTableGuts = PR_TRUE;
|
||||
nsCOMPtr<nsIDOMNode> theTable = GetTableParent(curNode);
|
||||
if (theTable)
|
||||
{
|
||||
nsCOMPtr<nsISupports> isupTable(do_QueryInterface(theTable));
|
||||
PRInt32 indexT = listAndTableArray->IndexOf(isupTable);
|
||||
if (indexT >= 0)
|
||||
{
|
||||
highWaterMark = indexT;
|
||||
if ((PRUint32)highWaterMark == listAndTableParents-1) break;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nsHTMLEditUtils::IsListItem(curNode))
|
||||
{
|
||||
bHaveListGuts = PR_TRUE;
|
||||
nsCOMPtr<nsIDOMNode> theList = GetListParent(curNode);
|
||||
if (theList)
|
||||
{
|
||||
nsCOMPtr<nsISupports> isupList(do_QueryInterface(theList));
|
||||
PRInt32 indexL = listAndTableArray->IndexOf(isupList);
|
||||
if (indexL >= 0)
|
||||
{
|
||||
highWaterMark = indexL;
|
||||
if ((PRUint32)highWaterMark == listAndTableParents-1) break;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// if we have pieces of tables or lists to be inserted, let's force the paste
|
||||
// to deal with table elements right away, so that it doesn't orphan some
|
||||
// table or list contents outside the table or list.
|
||||
if (highWaterMark >= 0)
|
||||
{
|
||||
nsCOMPtr<nsISupports> isupports = listAndTableArray->ElementAt(highWaterMark);
|
||||
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports) );
|
||||
nsCOMPtr<nsIDOMNode> replaceNode;
|
||||
if (nsHTMLEditUtils::IsTable(curNode))
|
||||
{
|
||||
// look upward from curNode for a piece of this table
|
||||
isup = nodeList->ElementAt(0);
|
||||
pNode = do_QueryInterface(isup);
|
||||
while (pNode)
|
||||
{
|
||||
if (nsHTMLEditUtils::IsTableElement(pNode) && !nsHTMLEditUtils::IsTable(pNode))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> tableP = GetTableParent(pNode);
|
||||
if (tableP == curNode)
|
||||
{
|
||||
replaceNode = pNode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
nsCOMPtr<nsIDOMNode> parent;
|
||||
pNode->GetParentNode(getter_AddRefs(parent));
|
||||
pNode = parent;
|
||||
}
|
||||
}
|
||||
else // list case
|
||||
{
|
||||
// look upward from curNode for a piece of this list
|
||||
isup = nodeList->ElementAt(0);
|
||||
pNode = do_QueryInterface(isup);
|
||||
while (pNode)
|
||||
{
|
||||
if (nsHTMLEditUtils::IsListItem(pNode))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> listP = GetListParent(pNode);
|
||||
if (listP == curNode)
|
||||
{
|
||||
replaceNode = pNode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
nsCOMPtr<nsIDOMNode> parent;
|
||||
pNode->GetParentNode(getter_AddRefs(parent));
|
||||
pNode = parent;
|
||||
}
|
||||
if (bHaveTableGuts && bHaveListGuts) break; // no need to continue
|
||||
}
|
||||
|
||||
// if we have pieces of tables to be inserted, then make sure beginning content
|
||||
// is not in a table. If it is, let's force the paste to deal with table elements
|
||||
// right away, so that it doesn't orphan some table contents outside the table.
|
||||
if (bHaveTableGuts)
|
||||
if (replaceNode)
|
||||
{
|
||||
nsCOMPtr<nsISupports> isupports = nodeList->ElementAt(0);
|
||||
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports) );
|
||||
if (!nsHTMLEditUtils::IsTableElement(curNode))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> parent, tmp;
|
||||
curNode->GetParentNode(getter_AddRefs(parent));
|
||||
while (parent)
|
||||
{
|
||||
if (nsHTMLEditUtils::IsTableElement(parent))
|
||||
{
|
||||
isupports = do_QueryInterface(parent);
|
||||
isupports = do_QueryInterface(replaceNode);
|
||||
nodeList->ReplaceElementAt(isupports, 0);
|
||||
// postprocess list to remove any descendants of this node
|
||||
// so that we dont insert them twice.
|
||||
|
|
@ -2702,55 +2815,18 @@ printf ("Child count %d\n", bar);
|
|||
{
|
||||
isupports = nodeList->ElementAt(1);
|
||||
tmp = do_QueryInterface(isupports);
|
||||
if (nsHTMLEditUtils::IsDescendantOf(tmp, parent))
|
||||
if (tmp && nsHTMLEditUtils::IsDescendantOf(tmp, replaceNode))
|
||||
nodeList->RemoveElementAt(1);
|
||||
else
|
||||
break;
|
||||
} while(tmp);
|
||||
break;
|
||||
}
|
||||
parent->GetParentNode(getter_AddRefs(curNode));
|
||||
parent = curNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
// same story as above, only for pieces of lists.
|
||||
if (bHaveListGuts)
|
||||
{
|
||||
nsCOMPtr<nsISupports> isupports = nodeList->ElementAt(0);
|
||||
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports) );
|
||||
if (!nsHTMLEditUtils::IsListItem(curNode))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> parent;
|
||||
curNode->GetParentNode(getter_AddRefs(parent));
|
||||
while (parent)
|
||||
{
|
||||
if (nsHTMLEditUtils::IsListItem(parent))
|
||||
{
|
||||
isupports = do_QueryInterface(parent);
|
||||
nodeList->ReplaceElementAt(isupports, 0);
|
||||
// postprocess list to remove any descendants of this node
|
||||
// so that we dont insert them twice.
|
||||
do
|
||||
{
|
||||
isupports = nodeList->ElementAt(1);
|
||||
tmp = do_QueryInterface(isupports);
|
||||
if (nsHTMLEditUtils::IsDescendantOf(tmp, parent))
|
||||
nodeList->RemoveElementAt(1);
|
||||
else
|
||||
break;
|
||||
} while(tmp);
|
||||
break;
|
||||
}
|
||||
parent->GetParentNode(getter_AddRefs(curNode));
|
||||
parent = curNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Loop over the node list and paste the nodes:
|
||||
PRBool bDidInsert = PR_FALSE;
|
||||
nsCOMPtr<nsIDOMNode> lastInsertNode, insertedContextParent;
|
||||
nodeList->Count(&listCount);
|
||||
for (j=0; j<listCount; j++)
|
||||
{
|
||||
nsCOMPtr<nsISupports> isupports = nodeList->ElementAt(j);
|
||||
|
|
@ -6147,8 +6223,6 @@ NS_IMETHODIMP nsHTMLEditor::OutputToString(nsAWritableString& aOutputString,
|
|||
}
|
||||
else if (nsHTMLEditUtils::IsBody(rootElement))
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
nsCOMPtr<nsIDocumentEncoder> encoder;
|
||||
nsCAutoString formatType(NS_DOC_ENCODER_CONTRACTID_BASE);
|
||||
formatType.AppendWithConversion(aFormatType);
|
||||
|
|
|
|||
|
|
@ -2417,6 +2417,36 @@ NS_IMETHODIMP nsHTMLEditor::InsertText(const nsString& aStringToInsert)
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
static nsCOMPtr<nsIDOMNode> GetListParent(nsIDOMNode* aNode)
|
||||
{
|
||||
if (!aNode) return nsnull;
|
||||
nsCOMPtr<nsIDOMNode> parent, tmp;
|
||||
aNode->GetParentNode(getter_AddRefs(parent));
|
||||
while (parent)
|
||||
{
|
||||
if (nsHTMLEditUtils::IsList(parent)) return parent;
|
||||
parent->GetParentNode(getter_AddRefs(tmp));
|
||||
parent = tmp;
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
static nsCOMPtr<nsIDOMNode> GetTableParent(nsIDOMNode* aNode)
|
||||
{
|
||||
if (!aNode) return nsnull;
|
||||
nsCOMPtr<nsIDOMNode> parent, tmp;
|
||||
aNode->GetParentNode(getter_AddRefs(parent));
|
||||
while (parent)
|
||||
{
|
||||
if (nsHTMLEditUtils::IsTable(parent)) return parent;
|
||||
parent->GetParentNode(getter_AddRefs(tmp));
|
||||
parent = tmp;
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsHTMLEditor::InsertHTML(const nsString& aInputString)
|
||||
{
|
||||
nsAutoString charset;
|
||||
|
|
@ -2476,8 +2506,7 @@ nsresult nsHTMLEditor::InsertHTMLWithCharsetAndContext(const nsString& aInputStr
|
|||
nsCOMPtr<nsIDOMNSRange> nsrange (do_QueryInterface(range));
|
||||
if (!nsrange)
|
||||
return NS_ERROR_NO_INTERFACE;
|
||||
nsCAutoString foo; foo.AssignWithConversion(inputString);
|
||||
printf ("fff = '%s'\n", (const char *)foo);
|
||||
|
||||
// create a dom document fragment that represents the structure to paste
|
||||
nsCOMPtr<nsIDOMDocumentFragment> docfrag;
|
||||
res = nsrange->CreateContextualFragment(inputString,
|
||||
|
|
@ -2485,11 +2514,6 @@ printf ("fff = '%s'\n", (const char *)foo);
|
|||
NS_ENSURE_SUCCESS(res, res);
|
||||
nsCOMPtr<nsIDOMNode> fragmentAsNode (do_QueryInterface(docfrag));
|
||||
|
||||
PRInt32 bar;
|
||||
nsCOMPtr<nsIContent> f(do_QueryInterface(docfrag));
|
||||
f->ChildCount(bar);
|
||||
printf ("Child count %d\n", bar);
|
||||
|
||||
res = StripFormattingNodes(fragmentAsNode);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
|
||||
|
|
@ -2657,10 +2681,34 @@ printf ("Child count %d\n", bar);
|
|||
parentNode = temp;
|
||||
}
|
||||
|
||||
// scan insertion list for table elements (other than table).
|
||||
PRBool bHaveTableGuts = PR_FALSE;
|
||||
PRBool bHaveListGuts = PR_FALSE;
|
||||
// build up list of parents of first node in lst that are either:
|
||||
// lists, or tables.
|
||||
nsCOMPtr<nsISupports> isup = nodeList->ElementAt(0);
|
||||
nsCOMPtr<nsIDOMNode> pNode( do_QueryInterface(isup) );
|
||||
nsCOMPtr<nsISupportsArray> listAndTableArray;
|
||||
res = NS_NewISupportsArray(getter_AddRefs(listAndTableArray));
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
while (pNode)
|
||||
{
|
||||
if (nsHTMLEditUtils::IsList(pNode) || nsHTMLEditUtils::IsTable(pNode))
|
||||
{
|
||||
isup = do_QueryInterface(pNode);
|
||||
listAndTableArray->AppendElement(isup);
|
||||
}
|
||||
nsCOMPtr<nsIDOMNode> parent;
|
||||
pNode->GetParentNode(getter_AddRefs(parent));
|
||||
pNode = parent;
|
||||
}
|
||||
|
||||
// remember number of lists and tables above us
|
||||
PRUint32 listAndTableParents;
|
||||
PRInt32 highWaterMark = -1;
|
||||
listAndTableArray->Count(&listAndTableParents);
|
||||
|
||||
PRUint32 listCount, j;
|
||||
if (listAndTableParents)
|
||||
{
|
||||
// scan insertion list for table elements (other than table).
|
||||
nodeList->Count(&listCount);
|
||||
for (j=0; j<listCount; j++)
|
||||
{
|
||||
|
|
@ -2670,31 +2718,96 @@ printf ("Child count %d\n", bar);
|
|||
NS_ENSURE_TRUE(curNode, NS_ERROR_FAILURE);
|
||||
if (nsHTMLEditUtils::IsTableElement(curNode) && !nsHTMLEditUtils::IsTable(curNode))
|
||||
{
|
||||
bHaveTableGuts = PR_TRUE;
|
||||
nsCOMPtr<nsIDOMNode> theTable = GetTableParent(curNode);
|
||||
if (theTable)
|
||||
{
|
||||
nsCOMPtr<nsISupports> isupTable(do_QueryInterface(theTable));
|
||||
PRInt32 indexT = listAndTableArray->IndexOf(isupTable);
|
||||
if (indexT >= 0)
|
||||
{
|
||||
highWaterMark = indexT;
|
||||
if ((PRUint32)highWaterMark == listAndTableParents-1) break;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nsHTMLEditUtils::IsListItem(curNode))
|
||||
{
|
||||
bHaveListGuts = PR_TRUE;
|
||||
nsCOMPtr<nsIDOMNode> theList = GetListParent(curNode);
|
||||
if (theList)
|
||||
{
|
||||
nsCOMPtr<nsISupports> isupList(do_QueryInterface(theList));
|
||||
PRInt32 indexL = listAndTableArray->IndexOf(isupList);
|
||||
if (indexL >= 0)
|
||||
{
|
||||
highWaterMark = indexL;
|
||||
if ((PRUint32)highWaterMark == listAndTableParents-1) break;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// if we have pieces of tables or lists to be inserted, let's force the paste
|
||||
// to deal with table elements right away, so that it doesn't orphan some
|
||||
// table or list contents outside the table or list.
|
||||
if (highWaterMark >= 0)
|
||||
{
|
||||
nsCOMPtr<nsISupports> isupports = listAndTableArray->ElementAt(highWaterMark);
|
||||
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports) );
|
||||
nsCOMPtr<nsIDOMNode> replaceNode;
|
||||
if (nsHTMLEditUtils::IsTable(curNode))
|
||||
{
|
||||
// look upward from curNode for a piece of this table
|
||||
isup = nodeList->ElementAt(0);
|
||||
pNode = do_QueryInterface(isup);
|
||||
while (pNode)
|
||||
{
|
||||
if (nsHTMLEditUtils::IsTableElement(pNode) && !nsHTMLEditUtils::IsTable(pNode))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> tableP = GetTableParent(pNode);
|
||||
if (tableP == curNode)
|
||||
{
|
||||
replaceNode = pNode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
nsCOMPtr<nsIDOMNode> parent;
|
||||
pNode->GetParentNode(getter_AddRefs(parent));
|
||||
pNode = parent;
|
||||
}
|
||||
}
|
||||
else // list case
|
||||
{
|
||||
// look upward from curNode for a piece of this list
|
||||
isup = nodeList->ElementAt(0);
|
||||
pNode = do_QueryInterface(isup);
|
||||
while (pNode)
|
||||
{
|
||||
if (nsHTMLEditUtils::IsListItem(pNode))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> listP = GetListParent(pNode);
|
||||
if (listP == curNode)
|
||||
{
|
||||
replaceNode = pNode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
nsCOMPtr<nsIDOMNode> parent;
|
||||
pNode->GetParentNode(getter_AddRefs(parent));
|
||||
pNode = parent;
|
||||
}
|
||||
if (bHaveTableGuts && bHaveListGuts) break; // no need to continue
|
||||
}
|
||||
|
||||
// if we have pieces of tables to be inserted, then make sure beginning content
|
||||
// is not in a table. If it is, let's force the paste to deal with table elements
|
||||
// right away, so that it doesn't orphan some table contents outside the table.
|
||||
if (bHaveTableGuts)
|
||||
if (replaceNode)
|
||||
{
|
||||
nsCOMPtr<nsISupports> isupports = nodeList->ElementAt(0);
|
||||
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports) );
|
||||
if (!nsHTMLEditUtils::IsTableElement(curNode))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> parent, tmp;
|
||||
curNode->GetParentNode(getter_AddRefs(parent));
|
||||
while (parent)
|
||||
{
|
||||
if (nsHTMLEditUtils::IsTableElement(parent))
|
||||
{
|
||||
isupports = do_QueryInterface(parent);
|
||||
isupports = do_QueryInterface(replaceNode);
|
||||
nodeList->ReplaceElementAt(isupports, 0);
|
||||
// postprocess list to remove any descendants of this node
|
||||
// so that we dont insert them twice.
|
||||
|
|
@ -2702,55 +2815,18 @@ printf ("Child count %d\n", bar);
|
|||
{
|
||||
isupports = nodeList->ElementAt(1);
|
||||
tmp = do_QueryInterface(isupports);
|
||||
if (nsHTMLEditUtils::IsDescendantOf(tmp, parent))
|
||||
if (tmp && nsHTMLEditUtils::IsDescendantOf(tmp, replaceNode))
|
||||
nodeList->RemoveElementAt(1);
|
||||
else
|
||||
break;
|
||||
} while(tmp);
|
||||
break;
|
||||
}
|
||||
parent->GetParentNode(getter_AddRefs(curNode));
|
||||
parent = curNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
// same story as above, only for pieces of lists.
|
||||
if (bHaveListGuts)
|
||||
{
|
||||
nsCOMPtr<nsISupports> isupports = nodeList->ElementAt(0);
|
||||
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports) );
|
||||
if (!nsHTMLEditUtils::IsListItem(curNode))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> parent;
|
||||
curNode->GetParentNode(getter_AddRefs(parent));
|
||||
while (parent)
|
||||
{
|
||||
if (nsHTMLEditUtils::IsListItem(parent))
|
||||
{
|
||||
isupports = do_QueryInterface(parent);
|
||||
nodeList->ReplaceElementAt(isupports, 0);
|
||||
// postprocess list to remove any descendants of this node
|
||||
// so that we dont insert them twice.
|
||||
do
|
||||
{
|
||||
isupports = nodeList->ElementAt(1);
|
||||
tmp = do_QueryInterface(isupports);
|
||||
if (nsHTMLEditUtils::IsDescendantOf(tmp, parent))
|
||||
nodeList->RemoveElementAt(1);
|
||||
else
|
||||
break;
|
||||
} while(tmp);
|
||||
break;
|
||||
}
|
||||
parent->GetParentNode(getter_AddRefs(curNode));
|
||||
parent = curNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Loop over the node list and paste the nodes:
|
||||
PRBool bDidInsert = PR_FALSE;
|
||||
nsCOMPtr<nsIDOMNode> lastInsertNode, insertedContextParent;
|
||||
nodeList->Count(&listCount);
|
||||
for (j=0; j<listCount; j++)
|
||||
{
|
||||
nsCOMPtr<nsISupports> isupports = nodeList->ElementAt(j);
|
||||
|
|
@ -6147,8 +6223,6 @@ NS_IMETHODIMP nsHTMLEditor::OutputToString(nsAWritableString& aOutputString,
|
|||
}
|
||||
else if (nsHTMLEditUtils::IsBody(rootElement))
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
nsCOMPtr<nsIDocumentEncoder> encoder;
|
||||
nsCAutoString formatType(NS_DOC_ENCODER_CONTRACTID_BASE);
|
||||
formatType.AppendWithConversion(aFormatType);
|
||||
|
|
|
|||
|
|
@ -84,8 +84,8 @@ public:
|
|||
// (Probably not well tested for HTML output.)
|
||||
OutputFormatted = 2,
|
||||
|
||||
// OutputNoDoctype is obsolete, flag 4 available for other uses
|
||||
//OutputNoDoctype = 4,
|
||||
// OutputRaw is used by copying text from widgets
|
||||
OutputRaw = 4,
|
||||
|
||||
// No html head tags
|
||||
OutputBodyOnly = 8,
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "nsIComponentManager.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIHTMLDocument.h"
|
||||
#include "nsISelection.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIContentSerializer.h"
|
||||
|
|
@ -48,6 +49,7 @@
|
|||
#include "nsITextContent.h"
|
||||
#include "nsIEnumerator.h"
|
||||
#include "nsISelectionPrivate.h"
|
||||
#include "nsIFrameSelection.h"
|
||||
#include "nsIContentIterator.h"
|
||||
#include "nsISupportsArray.h"
|
||||
#include "nsIParserService.h"
|
||||
|
|
@ -58,6 +60,7 @@ static NS_DEFINE_CID(kCharsetConverterManagerCID,
|
|||
static NS_DEFINE_CID(kParserServiceCID, NS_PARSERSERVICE_CID);
|
||||
|
||||
nsresult NS_NewContentSubtreeIterator(nsIContentIterator** aInstancePtrResult);
|
||||
nsresult NS_NewDomSelection(nsISelection **aDomSelection);
|
||||
|
||||
enum nsRangeIterationDirection {
|
||||
kDirectionOut = -1,
|
||||
|
|
@ -104,8 +107,9 @@ protected:
|
|||
nsresult SerializeRangeToString(nsIDOMRange *aRange,
|
||||
nsAWritableString& aOutputString);
|
||||
nsresult SerializeRangeNodes(nsIDOMRange* aRange,
|
||||
nsIDOMNode* aCommonParent,
|
||||
nsAWritableString& aString);
|
||||
nsIDOMNode* aNode,
|
||||
nsAWritableString& aString,
|
||||
PRInt32 aDepth);
|
||||
nsresult SerializeRangeContextStart(const nsVoidArray& aAncestorArray,
|
||||
nsAWritableString& aString);
|
||||
nsresult SerializeRangeContextEnd(const nsVoidArray& aAncestorArray,
|
||||
|
|
@ -124,6 +128,7 @@ protected:
|
|||
nsCOMPtr<nsIOutputStream> mStream;
|
||||
nsCOMPtr<nsIContentSerializer> mSerializer;
|
||||
nsCOMPtr<nsIUnicodeEncoder> mUnicodeEncoder;
|
||||
nsCOMPtr<nsIDOMNode> mCommonParent;
|
||||
|
||||
nsString mMimeType;
|
||||
nsString mCharset;
|
||||
|
|
@ -131,8 +136,14 @@ protected:
|
|||
PRUint32 mWrapColumn;
|
||||
PRUint32 mStartDepth;
|
||||
PRUint32 mEndDepth;
|
||||
PRInt32 mStartRootIndex;
|
||||
PRInt32 mEndRootIndex;
|
||||
PRBool mHaltRangeHint;
|
||||
nsVoidArray mCommonAncestors;
|
||||
nsVoidArray mStartNodes;
|
||||
nsVoidArray mStartOffsets;
|
||||
nsVoidArray mEndNodes;
|
||||
nsVoidArray mEndOffsets;
|
||||
};
|
||||
|
||||
#ifdef XP_MAC
|
||||
|
|
@ -566,25 +577,33 @@ static nsresult GetLengthOfDOMNode(nsIDOMNode *aNode, PRUint32 &aCount)
|
|||
nsresult
|
||||
nsDocumentEncoder::SerializeRangeNodes(nsIDOMRange* aRange,
|
||||
nsIDOMNode* aNode,
|
||||
nsAWritableString& aString)
|
||||
nsAWritableString& aString,
|
||||
PRInt32 aDepth)
|
||||
{
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
|
||||
NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
|
||||
|
||||
if (IsNodeIntersectsRange(content, aRange))
|
||||
{
|
||||
PRBool nodeBefore, nodeAfter;
|
||||
nsresult rv = CompareNodeToRange(content, aRange, &nodeBefore, &nodeAfter);
|
||||
if (!nodeBefore && !nodeAfter) // node completely contained
|
||||
nsresult rv=NS_OK;
|
||||
|
||||
// get start and end nodes for this recursion level
|
||||
nsCOMPtr<nsIContent> startNode, endNode;
|
||||
startNode = NS_STATIC_CAST(nsIContent *, mStartNodes[mStartRootIndex - aDepth]);
|
||||
endNode = NS_STATIC_CAST(nsIContent *, mEndNodes[mEndRootIndex - aDepth]);
|
||||
|
||||
if ((startNode != content) && (endNode != content))
|
||||
{
|
||||
// node is completely contained in range. Serialize the whole subtree
|
||||
// rooted by this node.
|
||||
rv = SerializeToStringRecursive(aNode, aString);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
else // node intersects range, but is not contained. recurse if needed.
|
||||
else
|
||||
{
|
||||
// due to implementation it is impossible for text node to be both start and end of
|
||||
// range. We would have handled that case without getting here.
|
||||
if (IsTextNode(aNode))
|
||||
{
|
||||
if (nodeBefore)
|
||||
if (startNode == content)
|
||||
{
|
||||
PRInt32 startOffset;
|
||||
aRange->GetStartOffset(&startOffset);
|
||||
|
|
@ -600,6 +619,8 @@ nsDocumentEncoder::SerializeRangeNodes(nsIDOMRange* aRange,
|
|||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (aNode != mCommonParent.get())
|
||||
{
|
||||
if (IncludeInContext(aNode))
|
||||
{
|
||||
|
|
@ -607,22 +628,59 @@ nsDocumentEncoder::SerializeRangeNodes(nsIDOMRange* aRange,
|
|||
// so paste client will include this node in paste.
|
||||
mHaltRangeHint = PR_TRUE;
|
||||
}
|
||||
if (nodeBefore && !mHaltRangeHint) mStartDepth++;
|
||||
if (nodeAfter && !mHaltRangeHint) mEndDepth++;
|
||||
if ((startNode == content) && !mHaltRangeHint) mStartDepth++;
|
||||
if ((endNode == content) && !mHaltRangeHint) mEndDepth++;
|
||||
|
||||
// serialize the start of this node
|
||||
rv = SerializeNodeStart(aNode, 0, -1, aString);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIDOMNode> child, tmp;
|
||||
aNode->GetFirstChild(getter_AddRefs(child));
|
||||
while (child)
|
||||
{
|
||||
rv = SerializeRangeNodes(aRange, child, aString);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
child->GetNextSibling(getter_AddRefs(tmp));
|
||||
child = tmp;
|
||||
}
|
||||
|
||||
// do some calculations that will tell us which children of this node are in the range.
|
||||
nsCOMPtr<nsIContent> child;
|
||||
nsCOMPtr<nsIDOMNode> childAsNode;
|
||||
PRInt32 startOffset = 0, endOffset = -1;
|
||||
if (startNode == content)
|
||||
startOffset = NS_REINTERPRET_CAST(PRInt32, mStartOffsets[mStartRootIndex - aDepth]);
|
||||
if (endNode == content)
|
||||
endOffset = NS_REINTERPRET_CAST(PRInt32, mEndOffsets[mEndRootIndex - aDepth]);
|
||||
// generated content will cause offset values of -1 to be returned.
|
||||
PRInt32 j, childCount=0;
|
||||
rv = content->ChildCount(childCount);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (startOffset == -1) startOffset = 0;
|
||||
if (endOffset == -1) endOffset = childCount;
|
||||
else
|
||||
{
|
||||
// if we are at the "tip" of the selection, endOffset is fine.
|
||||
// otherwise, we need to add one. This is because of the semantics
|
||||
// of the offset list created by GetAncestorsAndOffsets(). The
|
||||
// intermediate points on the list use the endOffset of the
|
||||
// location of the ancestor, rather than just past it. So we need
|
||||
// to add one here in order to include it in the children we serialize.
|
||||
nsCOMPtr<nsIDOMNode> endParent;
|
||||
aRange->GetEndContainer(getter_AddRefs(endParent));
|
||||
if (aNode != endParent.get())
|
||||
{
|
||||
endOffset++;
|
||||
}
|
||||
}
|
||||
// serialize the children of this node that are in the range
|
||||
for (j=startOffset; j<endOffset; j++)
|
||||
{
|
||||
rv = content->ChildAt(j, *getter_AddRefs(child));
|
||||
childAsNode = do_QueryInterface(child);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if ((j==startOffset) || (j==endOffset-1))
|
||||
rv = SerializeRangeNodes(aRange, childAsNode, aString, aDepth+1);
|
||||
else
|
||||
rv = SerializeToStringRecursive(childAsNode, aString);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// serialize the end of this node
|
||||
if (aNode != mCommonParent.get())
|
||||
{
|
||||
rv = SerializeNodeEnd(aNode, aString);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
|
@ -693,15 +751,15 @@ nsDocumentEncoder::SerializeRangeToString(nsIDOMRange *aRange,
|
|||
if (collapsed)
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> commonParent, startParent, endParent;
|
||||
nsCOMPtr<nsIDOMNode> startParent, endParent;
|
||||
PRInt32 startOffset, endOffset;
|
||||
|
||||
aRange->GetCommonAncestorContainer(getter_AddRefs(commonParent));
|
||||
aRange->GetCommonAncestorContainer(getter_AddRefs(mCommonParent));
|
||||
|
||||
if (!commonParent)
|
||||
if (!mCommonParent)
|
||||
return NS_OK;
|
||||
|
||||
AdjustCommonParent(&commonParent);
|
||||
AdjustCommonParent(&mCommonParent);
|
||||
|
||||
aRange->GetStartContainer(getter_AddRefs(startParent));
|
||||
NS_ENSURE_TRUE(startParent, NS_ERROR_FAILURE);
|
||||
|
|
@ -712,8 +770,17 @@ nsDocumentEncoder::SerializeRangeToString(nsIDOMRange *aRange,
|
|||
aRange->GetEndOffset(&endOffset);
|
||||
|
||||
mCommonAncestors.Clear();
|
||||
mStartNodes.Clear();
|
||||
mStartOffsets.Clear();
|
||||
mEndNodes.Clear();
|
||||
mEndOffsets.Clear();
|
||||
|
||||
nsRange::FillArrayWithAncestors(&mCommonAncestors, commonParent);
|
||||
nsRange::FillArrayWithAncestors(&mCommonAncestors, mCommonParent);
|
||||
nsRange::GetAncestorsAndOffsets(startParent, startOffset, &mStartNodes, &mStartOffsets);
|
||||
nsRange::GetAncestorsAndOffsets(endParent, endOffset, &mEndNodes, &mEndOffsets);
|
||||
nsCOMPtr<nsIContent> commonContent = do_QueryInterface(mCommonParent);
|
||||
mStartRootIndex = mStartNodes.IndexOf(commonContent);
|
||||
mEndRootIndex = mEndNodes.IndexOf(commonContent);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
|
|
@ -727,17 +794,9 @@ nsDocumentEncoder::SerializeRangeToString(nsIDOMRange *aRange,
|
|||
}
|
||||
else
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> child, tmp;
|
||||
commonParent->GetFirstChild(getter_AddRefs(child));
|
||||
while (child)
|
||||
{
|
||||
rv = SerializeRangeNodes(aRange, child, aOutputString);
|
||||
rv = SerializeRangeNodes(aRange, mCommonParent, aOutputString, 0);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
child->GetNextSibling(getter_AddRefs(tmp));
|
||||
child = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
rv = SerializeRangeContextEnd(mCommonAncestors, aOutputString);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
|
@ -888,12 +947,14 @@ protected:
|
|||
nsCOMPtr<nsIDOMNode> GetChildAt(nsIDOMNode *aParent, PRInt32 aOffset);
|
||||
PRBool IsMozBR(nsIDOMNode* aNode);
|
||||
nsresult GetNodeLocation(nsIDOMNode *inChild, nsCOMPtr<nsIDOMNode> *outParent, PRInt32 *outOffset);
|
||||
PRBool IsRoot(nsIDOMNode* aNode);
|
||||
PRBool IsFirstNode(nsIDOMNode *aNode);
|
||||
PRBool IsLastNode(nsIDOMNode *aNode);
|
||||
PRBool IsEmptyTextContent(nsIDOMNode* aNode);
|
||||
virtual PRBool IncludeInContext(nsIDOMNode *aNode);
|
||||
|
||||
nsCOMPtr<nsIParserService> mParserService;
|
||||
PRBool mIsTextWidget;
|
||||
};
|
||||
|
||||
#ifdef XP_MAC
|
||||
|
|
@ -903,6 +964,7 @@ protected:
|
|||
|
||||
nsHTMLCopyEncoder::nsHTMLCopyEncoder()
|
||||
{
|
||||
mIsTextWidget = PR_FALSE;
|
||||
}
|
||||
|
||||
nsHTMLCopyEncoder::~nsHTMLCopyEncoder()
|
||||
|
|
@ -911,7 +973,7 @@ nsHTMLCopyEncoder::~nsHTMLCopyEncoder()
|
|||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLCopyEncoder::Init(nsIDocument* aDocument,
|
||||
const nsAReadableString& aIgnored,
|
||||
const nsAReadableString& aMimetype,
|
||||
PRUint32 aFlags)
|
||||
{
|
||||
if (!aDocument)
|
||||
|
|
@ -931,19 +993,50 @@ nsHTMLCopyEncoder::Init(nsIDocument* aDocument,
|
|||
NS_IMETHODIMP
|
||||
nsHTMLCopyEncoder::SetSelection(nsISelection* aSelection)
|
||||
{
|
||||
// normalize selection
|
||||
// check for text widgets: we need to recognize these so that
|
||||
// we don't tweak the selection to be outside of the magic
|
||||
// div that ender-lite text widgets are embedded in.
|
||||
nsCOMPtr<nsIDOMNode> selNode;
|
||||
nsresult rv = aSelection->GetFocusNode(getter_AddRefs(selNode));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIContent> tmp, selContent( do_QueryInterface(selNode) );
|
||||
while (selContent)
|
||||
{
|
||||
nsCOMPtr<nsIAtom> atom;
|
||||
selContent->GetTag(*getter_AddRefs(atom));
|
||||
if (atom.get() == nsHTMLAtoms::input ||
|
||||
atom.get() == nsHTMLAtoms::textarea)
|
||||
{
|
||||
mIsTextWidget = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
selContent->GetParent(*getter_AddRefs(tmp));
|
||||
selContent = tmp;
|
||||
}
|
||||
|
||||
// also consider ourselves in a text widget if we can't find an html document
|
||||
nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(mDocument);
|
||||
if (!htmlDoc) mIsTextWidget = PR_TRUE;
|
||||
|
||||
// normalize selection if we are not in a widget
|
||||
if (mIsTextWidget)
|
||||
{
|
||||
mSelection = aSelection;
|
||||
mFlags |= OutputRaw;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// there's no Clone() for selection! fix...
|
||||
//nsresult rv = aSelection->Clone(getter_AddRefs(mSelection);
|
||||
//NS_ENSURE_SUCCESS(rv, rv);
|
||||
mSelection = aSelection;
|
||||
|
||||
nsCOMPtr<nsISelectionPrivate> privSelection = do_QueryInterface(mSelection);
|
||||
NS_NewDomSelection(getter_AddRefs(mSelection));
|
||||
NS_ENSURE_TRUE(mSelection, NS_ERROR_FAILURE);
|
||||
nsCOMPtr<nsISelectionPrivate> privSelection( do_QueryInterface(aSelection) );
|
||||
NS_ENSURE_TRUE(privSelection, NS_ERROR_FAILURE);
|
||||
|
||||
// get selection range enumerator
|
||||
nsCOMPtr<nsIEnumerator> enumerator;
|
||||
nsresult rv = privSelection->GetEnumerator(getter_AddRefs(enumerator));
|
||||
rv = privSelection->GetEnumerator(getter_AddRefs(enumerator));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(enumerator, NS_ERROR_FAILURE);
|
||||
|
||||
|
|
@ -957,9 +1050,16 @@ nsHTMLCopyEncoder::SetSelection(nsISelection* aSelection)
|
|||
NS_ENSURE_TRUE(currentItem, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
|
||||
NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
|
||||
nsCOMPtr<nsIDOMRange> myRange;
|
||||
range->CloneRange(getter_AddRefs(myRange));
|
||||
NS_ENSURE_TRUE(myRange, NS_ERROR_FAILURE);
|
||||
|
||||
// adjust range to include any ancestors who's children are entirely selected
|
||||
rv = PromoteRange(range);
|
||||
rv = PromoteRange(myRange);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mSelection->AddRange(myRange);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
enumerator->Next();
|
||||
|
|
@ -976,6 +1076,16 @@ nsHTMLCopyEncoder::EncodeToStringWithContext(nsAWritableString& aEncodedString,
|
|||
nsresult rv = EncodeToString(aEncodedString);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (mIsTextWidget) {
|
||||
aEncodedString.Insert(NS_LITERAL_STRING("<pre>"), 0);
|
||||
aEncodedString.Append(NS_LITERAL_STRING("</pre>"));
|
||||
}
|
||||
|
||||
// do not encode any context info or range hints if we are not in an html document.
|
||||
|
||||
// do not encode any context info or range hints if we are in a text widget.
|
||||
if (mIsTextWidget) return NS_OK;
|
||||
|
||||
// now encode common ancestors into aContextString. Note that the common ancestors
|
||||
// will be for the last range in the selection in the case of multirange selections.
|
||||
// encoding ancestors every range in a multirange selection in a way that could be
|
||||
|
|
@ -1126,12 +1236,12 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, PRInt32
|
|||
|
||||
// finding the real start for this point. look up the tree for as long as we are the
|
||||
// first node in the container, and as long as we haven't hit the body node.
|
||||
if (!IsTag(node, nsHTMLAtoms::body))
|
||||
if (!IsRoot(node))
|
||||
{
|
||||
rv = GetNodeLocation(node, &parent, &offset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (offset == -1) return NS_OK; // we hit generated content; STOP
|
||||
while ((IsFirstNode(node)) && (!IsTag(parent, nsHTMLAtoms::body)))
|
||||
while ((IsFirstNode(node)) && (!IsRoot(parent)))
|
||||
{
|
||||
if (bResetPromotion)
|
||||
{
|
||||
|
|
@ -1211,12 +1321,12 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, PRInt32
|
|||
|
||||
// finding the real end for this point. look up the tree for as long as we are the
|
||||
// last node in the container, and as long as we haven't hit the body node.
|
||||
if (!IsTag(node, nsHTMLAtoms::body))
|
||||
if (!IsRoot(node))
|
||||
{
|
||||
rv = GetNodeLocation(node, &parent, &offset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (offset == -1) return NS_OK; // we hit generated content; STOP
|
||||
while ((IsLastNode(node)) && (!IsTag(parent, nsHTMLAtoms::body)))
|
||||
while ((IsLastNode(node)) && (!IsRoot(parent)))
|
||||
{
|
||||
if (bResetPromotion)
|
||||
{
|
||||
|
|
@ -1325,6 +1435,19 @@ nsHTMLCopyEncoder::GetNodeLocation(nsIDOMNode *inChild, nsCOMPtr<nsIDOMNode> *ou
|
|||
return result;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsHTMLCopyEncoder::IsRoot(nsIDOMNode* aNode)
|
||||
{
|
||||
if (aNode)
|
||||
{
|
||||
if (mIsTextWidget)
|
||||
return (IsTag(aNode, nsHTMLAtoms::div));
|
||||
else
|
||||
return (IsTag(aNode, nsHTMLAtoms::body));
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsHTMLCopyEncoder::IsFirstNode(nsIDOMNode *aNode)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include "nsHTMLAtoms.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsEscape.h"
|
||||
|
||||
static NS_DEFINE_CID(kParserServiceCID, NS_PARSERSERVICE_CID);
|
||||
static NS_DEFINE_CID(kEntityConverterCID, NS_ENTITYCONVERTER_CID);
|
||||
|
|
@ -68,21 +69,6 @@ nsHTMLContentSerializer::~nsHTMLContentSerializer()
|
|||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLContentSerializer::GetEntityConverter(nsIEntityConverter** aConverter)
|
||||
{
|
||||
if (!mEntityConverter) {
|
||||
nsresult rv;
|
||||
rv = nsComponentManager::CreateInstance(kEntityConverterCID, NULL,
|
||||
NS_GET_IID(nsIEntityConverter),
|
||||
getter_AddRefs(mEntityConverter));
|
||||
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
CallQueryInterface(mEntityConverter.get(), aConverter);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLContentSerializer::GetParserService(nsIParserService** aParserService)
|
||||
{
|
||||
|
|
@ -149,7 +135,8 @@ nsHTMLContentSerializer::AppendText(nsIDOMText* aText,
|
|||
PRInt32 lastNewlineOffset = kNotFound;
|
||||
PRBool hasLongLines = HasLongLines(data, lastNewlineOffset);
|
||||
|
||||
if (mPreLevel || (!mDoFormat && !hasLongLines)) {
|
||||
if (mPreLevel || (!mDoFormat && !hasLongLines) ||
|
||||
(mFlags & nsIDocumentEncoder::OutputRaw)) {
|
||||
AppendToString(data, aStr);
|
||||
|
||||
if (lastNewlineOffset != kNotFound) {
|
||||
|
|
@ -378,7 +365,6 @@ nsHTMLContentSerializer::AppendToStringWrapped(const nsAReadableString& aStr,
|
|||
PRBool done = PR_FALSE;
|
||||
PRInt32 indx = 0;
|
||||
PRInt32 strOffset = 0;
|
||||
PRInt32 oldLineOffset = 0;
|
||||
PRInt32 lineLength, oldLineEnd;
|
||||
|
||||
// Make sure we haven't gone too far already
|
||||
|
|
@ -468,28 +454,19 @@ nsHTMLContentSerializer::AppendToString(const nsAReadableString& aStr,
|
|||
return;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
|
||||
if (aIncrColumn) {
|
||||
mColPos += aStr.Length();
|
||||
}
|
||||
|
||||
if (aTranslateEntities) {
|
||||
nsCOMPtr<nsIEntityConverter> converter;
|
||||
|
||||
GetEntityConverter(getter_AddRefs(converter));
|
||||
if (converter) {
|
||||
PRUnichar *encodedBuffer;
|
||||
rv = mEntityConverter->ConvertToEntities(nsPromiseFlatString(aStr),
|
||||
nsIEntityConverter::html40Latin1,
|
||||
&encodedBuffer);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
encodedBuffer = nsEscapeHTML2(nsPromiseFlatString(aStr), aStr.Length());
|
||||
if (encodedBuffer) {
|
||||
aOutputStr.Append(encodedBuffer);
|
||||
nsCRT::free(encodedBuffer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aOutputStr.Append(aStr);
|
||||
}
|
||||
|
|
@ -513,7 +490,8 @@ PRBool
|
|||
nsHTMLContentSerializer::LineBreakBeforeOpen(nsIAtom* aName,
|
||||
PRBool aHasDirtyAttr)
|
||||
{
|
||||
if ((!mDoFormat && !aHasDirtyAttr) || mPreLevel || !mColPos) {
|
||||
if ((!mDoFormat && !aHasDirtyAttr) || mPreLevel || !mColPos ||
|
||||
(mFlags & nsIDocumentEncoder::OutputRaw)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
|
@ -548,7 +526,8 @@ PRBool
|
|||
nsHTMLContentSerializer::LineBreakAfterOpen(nsIAtom* aName,
|
||||
PRBool aHasDirtyAttr)
|
||||
{
|
||||
if ((!mDoFormat && !aHasDirtyAttr) || mPreLevel) {
|
||||
if ((!mDoFormat && !aHasDirtyAttr) || mPreLevel ||
|
||||
(mFlags & nsIDocumentEncoder::OutputRaw)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
|
@ -576,7 +555,8 @@ PRBool
|
|||
nsHTMLContentSerializer::LineBreakBeforeClose(nsIAtom* aName,
|
||||
PRBool aHasDirtyAttr)
|
||||
{
|
||||
if ((!mDoFormat && !aHasDirtyAttr) || mPreLevel || !mColPos) {
|
||||
if ((!mDoFormat && !aHasDirtyAttr) || mPreLevel || !mColPos ||
|
||||
(mFlags & nsIDocumentEncoder::OutputRaw)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
|
@ -598,7 +578,8 @@ PRBool
|
|||
nsHTMLContentSerializer::LineBreakAfterClose(nsIAtom* aName,
|
||||
PRBool aHasDirtyAttr)
|
||||
{
|
||||
if ((!mDoFormat && !aHasDirtyAttr) || mPreLevel) {
|
||||
if ((!mDoFormat && !aHasDirtyAttr) || mPreLevel ||
|
||||
(mFlags & nsIDocumentEncoder::OutputRaw)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -281,6 +281,9 @@ nsPlainTextSerializer::AppendElementStart(nsIDOMElement *aElement,
|
|||
mContent = 0;
|
||||
mOutputString = nsnull;
|
||||
|
||||
if (!mInHead && id == eHTMLTag_head)
|
||||
mInHead = PR_TRUE;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
|
@ -310,6 +313,9 @@ nsPlainTextSerializer::AppendElementEnd(nsIDOMElement *aElement,
|
|||
mContent = 0;
|
||||
mOutputString = nsnull;
|
||||
|
||||
if (mInHead && id == eHTMLTag_head)
|
||||
mInHead = PR_FALSE;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
|
@ -326,8 +332,6 @@ NS_IMETHODIMP
|
|||
nsPlainTextSerializer::OpenContainer(const nsIParserNode& aNode)
|
||||
{
|
||||
PRInt32 type = aNode.GetNodeType();
|
||||
const nsString& namestr = aNode.GetText();
|
||||
nsCOMPtr<nsIAtom> name = dont_AddRef(NS_NewAtom(namestr));
|
||||
|
||||
mParserNode = NS_CONST_CAST(nsIParserNode *, &aNode);
|
||||
return DoOpenContainer(type);
|
||||
|
|
|
|||
|
|
@ -150,6 +150,8 @@ public:
|
|||
static PRBool InSameDoc(nsIDOMNode* aNode1, nsIDOMNode* aNode2);
|
||||
static PRInt32 IndexOf(nsIDOMNode* aNode);
|
||||
static PRInt32 FillArrayWithAncestors(nsVoidArray* aArray,nsIDOMNode* aNode);
|
||||
static PRInt32 GetAncestorsAndOffsets(nsIDOMNode* aNode, PRInt32 aOffset,
|
||||
nsVoidArray* aAncestorNodes, nsVoidArray* aAncestorOffsets);
|
||||
static nsCOMPtr<nsIDOMNode> CommonParent(nsIDOMNode* aNode1, nsIDOMNode* aNode2);
|
||||
static nsresult GetDOMNodeFromContent(nsIContent* inContentNode, nsCOMPtr<nsIDOMNode>* outDomNode);
|
||||
static nsresult GetContentFromDOMNode(nsIDOMNode* inDomNode, nsCOMPtr<nsIContent>* outContentNode);
|
||||
|
|
@ -173,9 +175,6 @@ public:
|
|||
nsresult ComparePointToRange(nsIDOMNode* aParent, PRInt32 aOffset, PRInt32* aResult);
|
||||
|
||||
|
||||
PRInt32 GetAncestorsAndOffsets(nsIDOMNode* aNode, PRInt32 aOffset,
|
||||
nsVoidArray* aAncestorNodes, nsVoidArray* aAncestorOffsets);
|
||||
|
||||
nsresult AddToListOf(nsIDOMNode* aNode);
|
||||
|
||||
nsresult RemoveFromListOf(nsIDOMNode* aNode);
|
||||
|
|
|
|||
|
|
@ -224,55 +224,51 @@ nsEscapeHTML(const char * string)
|
|||
}
|
||||
|
||||
NS_COM PRUnichar *
|
||||
nsEscapeHTML2(const PRUnichar * string)
|
||||
nsEscapeHTML2(const PRUnichar *aSourceBuffer, PRInt32 aSourceBufferLen)
|
||||
{
|
||||
PRUnichar *rv = (PRUnichar *) nsMemory::Alloc(nsCRT::strlen(string)*6*sizeof(PRUnichar) + sizeof(PRUnichar));
|
||||
PRUnichar *ptr = rv;
|
||||
// if the caller didn't calculate the length
|
||||
if (aSourceBufferLen == -1) {
|
||||
aSourceBufferLen = nsCRT::strlen(aSourceBuffer); // ...then I will
|
||||
}
|
||||
|
||||
if(rv)
|
||||
{
|
||||
for(; *string != 0; string++)
|
||||
{
|
||||
if(*string == '<')
|
||||
{
|
||||
PRUnichar *resultBuffer = (PRUnichar *)nsMemory::Alloc(aSourceBufferLen*6*sizeof(PRUnichar) + sizeof(PRUnichar('\0')));
|
||||
PRUnichar *ptr = resultBuffer;
|
||||
|
||||
if (resultBuffer) {
|
||||
PRInt32 i;
|
||||
|
||||
for(i = 0; i < aSourceBufferLen; i++) {
|
||||
if(aSourceBuffer[i] == '<') {
|
||||
*ptr++ = '&';
|
||||
*ptr++ = 'l';
|
||||
*ptr++ = 't';
|
||||
*ptr++ = ';';
|
||||
}
|
||||
else if(*string == '>')
|
||||
{
|
||||
} else if(aSourceBuffer[i] == '>') {
|
||||
*ptr++ = '&';
|
||||
*ptr++ = 'g';
|
||||
*ptr++ = 't';
|
||||
*ptr++ = ';';
|
||||
}
|
||||
else if(*string == '&')
|
||||
{
|
||||
} else if(aSourceBuffer[i] == '&') {
|
||||
*ptr++ = '&';
|
||||
*ptr++ = 'a';
|
||||
*ptr++ = 'm';
|
||||
*ptr++ = 'p';
|
||||
*ptr++ = ';';
|
||||
}
|
||||
else if (*string == '"')
|
||||
{
|
||||
} else if (aSourceBuffer[i] == '"') {
|
||||
*ptr++ = '&';
|
||||
*ptr++ = 'q';
|
||||
*ptr++ = 'u';
|
||||
*ptr++ = 'o';
|
||||
*ptr++ = 't';
|
||||
*ptr++ = ';';
|
||||
}
|
||||
else
|
||||
{
|
||||
*ptr++ = *string;
|
||||
} else {
|
||||
*ptr++ = aSourceBuffer[i];
|
||||
}
|
||||
}
|
||||
*ptr = 0;
|
||||
}
|
||||
|
||||
return(rv);
|
||||
return resultBuffer;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,8 @@ NS_COM char *
|
|||
nsEscapeHTML(const char * string);
|
||||
|
||||
NS_COM PRUnichar *
|
||||
nsEscapeHTML2(const PRUnichar * string);
|
||||
nsEscapeHTML2(const PRUnichar *aSourceBuffer,
|
||||
PRInt32 aSourceBufferLen = -1);
|
||||
/*
|
||||
* Escape problem char's for HTML display
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in a new issue