diff --git a/mozilla/editor/libeditor/html/nsHTMLDataTransfer.cpp b/mozilla/editor/libeditor/html/nsHTMLDataTransfer.cpp
index 0bc6cf9b54e..37949c89e9b 100644
--- a/mozilla/editor/libeditor/html/nsHTMLDataTransfer.cpp
+++ b/mozilla/editor/libeditor/html/nsHTMLDataTransfer.cpp
@@ -176,6 +176,69 @@ static nsCOMPtr GetTableParent(nsIDOMNode* aNode)
}
+NS_IMETHODIMP nsHTMLEditor::LoadHTML(const nsAReadableString & aInString)
+{
+ nsAutoString charset;
+ return LoadHTMLWithCharset(aInString, charset);
+}
+
+NS_IMETHODIMP nsHTMLEditor::LoadHTMLWithCharset(const nsAReadableString & aInputString, const nsAReadableString & aCharset)
+{
+ nsresult res = NS_OK;
+ if (!mRules) return NS_ERROR_NOT_INITIALIZED;
+
+ // force IME commit; set up rules sniffing and batching
+ ForceCompositionEnd();
+ nsAutoEditBatch beginBatching(this);
+ nsAutoRules beginRulesSniffing(this, kOpHTMLLoad, nsIEditor::eNext);
+
+ // Get selection
+ nsCOMPtrselection;
+ res = GetSelection(getter_AddRefs(selection));
+ if (NS_FAILED(res)) return res;
+
+ // Delete Selection
+ res = DeleteSelection(eNone);
+ if (NS_FAILED(res)) return res;
+
+ // Get the first range in the selection, for context:
+ nsCOMPtr range, clone;
+ res = selection->GetRangeAt(0, getter_AddRefs(range));
+ NS_ENSURE_SUCCESS(res, res);
+ if (!range)
+ return NS_ERROR_NULL_POINTER;
+ nsCOMPtr nsrange (do_QueryInterface(range));
+ if (!nsrange)
+ return NS_ERROR_NO_INTERFACE;
+
+ // create fragment for pasted html
+ nsCOMPtr docfrag;
+ {
+ res = nsrange->CreateContextualFragment(aInputString, getter_AddRefs(docfrag));
+ NS_ENSURE_SUCCESS(res, res);
+ }
+ // put the fragment into the document
+ nsCOMPtr parent, junk;
+ res = range->GetStartContainer(getter_AddRefs(parent));
+ NS_ENSURE_SUCCESS(res, res);
+ if (!parent)
+ return NS_ERROR_NULL_POINTER;
+ PRInt32 childOffset;
+ res = range->GetStartOffset(&childOffset);
+ NS_ENSURE_SUCCESS(res, res);
+
+ nsCOMPtr nodeToInsert;
+ docfrag->GetFirstChild(getter_AddRefs(nodeToInsert));
+ while (nodeToInsert)
+ {
+ res = InsertNode(nodeToInsert, parent, childOffset++);
+ NS_ENSURE_SUCCESS(res, res);
+ docfrag->GetFirstChild(getter_AddRefs(nodeToInsert));
+ }
+ return res;
+}
+
+
NS_IMETHODIMP nsHTMLEditor::InsertHTML(const nsAReadableString & aInString)
{
nsAutoString charset;
@@ -761,6 +824,44 @@ NS_IMETHODIMP nsHTMLEditor::InsertFromDrop(nsIDOMEvent* aDropEvent)
if (NS_FAILED(rv)) return rv;
if (!trans) return NS_OK; // NS_ERROR_FAILURE; Should we fail?
+ // get additional html copy hints, if present
+ nsAutoString contextStr, infoStr;
+ nsCOMPtr contextDataObj, infoDataObj;
+ PRUint32 contextLen, infoLen;
+ nsCOMPtr textDataObj;
+
+ nsCOMPtr contextTrans = do_CreateInstance(kCTransferableCID);
+ NS_ENSURE_TRUE(contextTrans, NS_ERROR_NULL_POINTER);
+ contextTrans->AddDataFlavor(kHTMLContext);
+ dragSession->GetData(contextTrans, i);
+ contextTrans->GetTransferData(kHTMLContext, getter_AddRefs(contextDataObj), &contextLen);
+
+ nsCOMPtr infoTrans = do_CreateInstance(kCTransferableCID);
+ NS_ENSURE_TRUE(infoTrans, NS_ERROR_NULL_POINTER);
+ infoTrans->AddDataFlavor(kHTMLInfo);
+ dragSession->GetData(infoTrans, i);
+ infoTrans->GetTransferData(kHTMLInfo, getter_AddRefs(infoDataObj), &infoLen);
+
+ if (contextDataObj)
+ {
+ PRUnichar* text = nsnull;
+ textDataObj = do_QueryInterface(contextDataObj);
+ textDataObj->ToString ( &text );
+ contextStr.Assign ( text, contextLen / 2 );
+ if (text)
+ nsMemory::Free(text);
+ }
+
+ if (infoDataObj)
+ {
+ PRUnichar* text = nsnull;
+ textDataObj = do_QueryInterface(infoDataObj);
+ textDataObj->ToString ( &text );
+ infoStr.Assign ( text, infoLen / 2 );
+ if (text)
+ nsMemory::Free(text);
+ }
+
if ( doPlaceCaret )
{
// check if the user pressed the key to force a copy rather than a move
@@ -898,7 +999,7 @@ NS_IMETHODIMP nsHTMLEditor::InsertFromDrop(nsIDOMEvent* aDropEvent)
doPlaceCaret = PR_FALSE;
}
- rv = InsertFromTransferable(trans, nsAutoString(), nsAutoString());
+ rv = InsertFromTransferable(trans, contextStr, infoStr);
}
return rv;
@@ -1022,16 +1123,28 @@ NS_IMETHODIMP nsHTMLEditor::DoDrag(nsIDOMEvent *aDragEvent)
if (NS_FAILED(rv)) return rv;
// grab a string
- nsAutoString buffer;
- rv = docEncoder->EncodeToString(buffer);
- if (NS_FAILED(rv)) return rv;
+ nsAutoString buffer, parents, info;
+
+ if (!bIsPlainTextControl)
+ {
+ // encode the selection as html with contextual info
+ rv = docEncoder->EncodeToStringWithContext(buffer, parents, info);
+ if (NS_FAILED(rv)) return rv;
+ }
+ else
+ {
+ // encode the selection
+ rv = docEncoder->EncodeToString(buffer);
+ if (NS_FAILED(rv)) return rv;
+ }
// if we have an empty string, we're done; otherwise continue
if ( !buffer.IsEmpty() )
{
- nsCOMPtr dataWrapper = do_CreateInstance(NS_SUPPORTS_WSTRING_CONTRACTID);
- NS_ENSURE_TRUE(dataWrapper, NS_ERROR_FAILURE);
+ nsCOMPtr dataWrapper, contextWrapper, infoWrapper;
+ dataWrapper = do_CreateInstance(NS_SUPPORTS_WSTRING_CONTRACTID);
+ NS_ENSURE_TRUE(dataWrapper, NS_ERROR_FAILURE);
rv = dataWrapper->SetData( NS_CONST_CAST(PRUnichar*, buffer.get()) );
if (NS_FAILED(rv)) return rv;
@@ -1040,9 +1153,23 @@ NS_IMETHODIMP nsHTMLEditor::DoDrag(nsIDOMEvent *aDragEvent)
// Add the unicode flavor to the transferable
rv = trans->AddDataFlavor(kUnicodeMime);
if (NS_FAILED(rv)) return rv;
+
+ // QI the data object an |nsISupports| so that when the transferable holds
+ // onto it, it will addref the correct interface.
+ nsCOMPtr genericDataObj ( do_QueryInterface(dataWrapper) );
+ rv = trans->SetTransferData(kUnicodeMime, genericDataObj, buffer.Length() * 2);
+ if (NS_FAILED(rv)) return rv;
}
else
{
+ contextWrapper = do_CreateInstance(NS_SUPPORTS_WSTRING_CONTRACTID);
+ NS_ENSURE_TRUE(contextWrapper, NS_ERROR_FAILURE);
+ infoWrapper = do_CreateInstance(NS_SUPPORTS_WSTRING_CONTRACTID);
+ NS_ENSURE_TRUE(infoWrapper, NS_ERROR_FAILURE);
+
+ contextWrapper->SetData ( NS_CONST_CAST(PRUnichar*,parents.get()) );
+ infoWrapper->SetData ( NS_CONST_CAST(PRUnichar*,info.get()) );
+
rv = trans->AddDataFlavor(kHTMLMime);
if (NS_FAILED(rv)) return rv;
@@ -1051,14 +1178,26 @@ NS_IMETHODIMP nsHTMLEditor::DoDrag(nsIDOMEvent *aDragEvent)
rv = trans->SetConverter(htmlConverter);
if (NS_FAILED(rv)) return rv;
- }
- // QI the data object an |nsISupports| so that when the transferable holds
- // onto it, it will addref the correct interface.
- nsCOMPtr nsisupportsDataWrapper ( do_QueryInterface(dataWrapper) );
- rv = trans->SetTransferData(bIsPlainTextControl ? kUnicodeMime : kHTMLMime,
- nsisupportsDataWrapper, buffer.Length() * 2);
- if (NS_FAILED(rv)) return rv;
+ nsCOMPtr genericDataObj ( do_QueryInterface(dataWrapper) );
+ rv = trans->SetTransferData(kHTMLMime, genericDataObj, buffer.Length() * 2);
+ if (NS_FAILED(rv)) return rv;
+
+ if (parents.Length())
+ {
+ // Add the htmlcontext DataFlavor to the transferable
+ trans->AddDataFlavor(kHTMLContext);
+ genericDataObj = do_QueryInterface(contextWrapper);
+ trans->SetTransferData(kHTMLContext, genericDataObj, parents.Length()*2);
+ }
+ if (info.Length())
+ {
+ // Add the htmlinfo DataFlavor to the transferable
+ trans->AddDataFlavor(kHTMLInfo);
+ genericDataObj = do_QueryInterface(infoWrapper);
+ trans->SetTransferData(kHTMLInfo, genericDataObj, info.Length()*2);
+ }
+ }
/* add the transferable to the array */
rv = transferableArray->AppendElement(trans);
@@ -1067,7 +1206,7 @@ NS_IMETHODIMP nsHTMLEditor::DoDrag(nsIDOMEvent *aDragEvent)
/* invoke drag */
unsigned int flags;
// in some cases we'll want to cut rather than copy... hmmmmm...
- flags = nsIDragService::DRAGDROP_ACTION_COPY + nsIDragService::DRAGDROP_ACTION_MOVE;
+ flags = nsIDragService::DRAGDROP_ACTION_COPY + nsIDragService::DRAGDROP_ACTION_MOVE;
rv = dragService->InvokeDragSession( domnode, transferableArray, nsnull, flags);
if (NS_FAILED(rv)) return rv;
@@ -1481,7 +1620,7 @@ nsHTMLEditor::InsertAsCitedQuotation(const nsAReadableString & aQuotedText,
}
if (aInsertHTML)
- res = InsertHTMLWithCharset(aQuotedText, aCharset);
+ res = LoadHTMLWithCharset(aQuotedText, aCharset);
else
res = InsertText(aQuotedText); // XXX ignore charset
diff --git a/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp b/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp
index 80dfaceb2bf..bf767629bf4 100644
--- a/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp
+++ b/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp
@@ -403,7 +403,9 @@ nsHTMLEditRules::AfterEditInner(PRInt32 action, nsIEditor::EDirection aDirection
// (action == nsEditor::kOpInsertIMEText) ||
(action == nsHTMLEditor::kOpInsertElement) ||
(action == nsHTMLEditor::kOpInsertQuotation) ||
- (action == nsEditor::kOpInsertNode))
+ (action == nsEditor::kOpInsertNode) ||
+ (action == nsHTMLEditor::kOpHTMLPaste ||
+ (action == nsHTMLEditor::kOpHTMLLoad)))
{
res = ReplaceNewlines(mDocChangeRange);
}
@@ -431,7 +433,8 @@ nsHTMLEditRules::AfterEditInner(PRInt32 action, nsIEditor::EDirection aDirection
(action == nsEditor::kOpInsertIMEText) ||
(action == nsEditor::kOpDeleteSelection) ||
(action == nsEditor::kOpInsertBreak) ||
- (action == nsHTMLEditor::kOpHTMLPaste))
+ (action == nsHTMLEditor::kOpHTMLPaste ||
+ (action == nsHTMLEditor::kOpHTMLLoad)))
{
res = AdjustSelection(selection, aDirection);
if (NS_FAILED(res)) return res;
@@ -760,9 +763,18 @@ nsHTMLEditRules::GetIndentState(PRBool *aCanIndent, PRBool *aCanOutdent)
return NS_ERROR_FAILURE;
*aCanIndent = PR_TRUE;
*aCanOutdent = PR_FALSE;
-
+
+ // get selection
+ nsCOMPtrselection;
+ nsresult res = mHTMLEditor->GetSelection(getter_AddRefs(selection));
+ if (NS_FAILED(res)) return res;
+ nsCOMPtr selPriv(do_QueryInterface(selection));
+ if (!selPriv)
+ return NS_ERROR_FAILURE;
+
+ // contruct a list of nodes to act on.
nsCOMPtr arrayOfNodes;
- nsresult res = GetListActionNodes(address_of(arrayOfNodes), PR_FALSE, PR_TRUE);
+ res = GetNodesFromSelection(selection, kIndent, address_of(arrayOfNodes), PR_TRUE);
if (NS_FAILED(res)) return res;
// examine nodes in selection for blockquotes or list elements;
@@ -1082,7 +1094,8 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction,
if (aAction == kInsertTextIME)
{
- res = mHTMLEditor->InsertTextImpl(*inString, address_of(selNode), &selOffset, doc);
+ nsWSRunObject wsObj(mHTMLEditor, selNode, selOffset);
+ res = wsObj.InsertText(*inString, address_of(selNode), &selOffset, doc);
if (NS_FAILED(res)) return res;
}
else // aAction == kInsertText
@@ -1183,7 +1196,6 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction,
// is it a tab?
if (subStr.Equals(tabStr))
{
-// res = mHTMLEditor->InsertTextImpl(tabString, address_of(curNode), &curOffset, doc);
res = wsObj.InsertText(tabString, address_of(curNode), &curOffset, doc);
if (NS_FAILED(res)) return res;
pos++;
@@ -1191,14 +1203,12 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction,
// is it a return?
else if (subStr.Equals(newlineStr))
{
-// res = mHTMLEditor->CreateBRImpl(address_of(curNode), &curOffset, address_of(unused), nsIEditor::eNone);
res = wsObj.InsertBreak(address_of(curNode), &curOffset, address_of(unused), nsIEditor::eNone);
if (NS_FAILED(res)) return res;
pos++;
}
else
{
-// res = mHTMLEditor->InsertTextImpl(subStr, address_of(curNode), &curOffset, doc);
res = wsObj.InsertText(subStr, address_of(curNode), &curOffset, doc);
if (NS_FAILED(res)) return res;
}
@@ -2513,14 +2523,10 @@ nsHTMLEditRules::WillMakeBasicBlock(nsISelection *aSelection,
nsAutoTxnsConserveSelection dontSpazMySelection(mHTMLEditor);
*aHandled = PR_TRUE;
- nsCOMPtr arrayOfRanges;
- res = GetPromotedRanges(aSelection, address_of(arrayOfRanges), kMakeBasicBlock);
- if (NS_FAILED(res)) return res;
-
- // use these ranges to contruct a list of nodes to act on.
+ // contruct a list of nodes to act on.
nsCOMPtr arrayOfNodes;
- res = GetNodesForOperation(arrayOfRanges, address_of(arrayOfNodes), kMakeBasicBlock);
- if (NS_FAILED(res)) return res;
+ res = GetNodesFromSelection(aSelection, kMakeBasicBlock, address_of(arrayOfNodes));
+ if (NS_FAILED(res)) return res;
nsString tString(*aBlockType);
@@ -2702,13 +2708,8 @@ nsHTMLEditRules::WillIndent(nsISelection *aSelection, PRBool *aCancel, PRBool *
// this basically just expands the range to include the immediate
// block parent, and then further expands to include any ancestors
// whose children are all in the range
-
- res = GetPromotedRanges(aSelection, address_of(arrayOfRanges), kIndent);
+ res = GetNodesFromSelection(aSelection, kIndent, address_of(arrayOfNodes));
if (NS_FAILED(res)) return res;
-
- // use these ranges to contruct a list of nodes to act on.
- res = GetNodesForOperation(arrayOfRanges, address_of(arrayOfNodes), kIndent);
- if (NS_FAILED(res)) return res;
}
// if nothing visible in list, make an empty block
@@ -2847,17 +2848,10 @@ nsHTMLEditRules::WillOutdent(nsISelection *aSelection, PRBool *aCancel, PRBool *
// this basically just expands the range to include the immediate
// block parent, and then further expands to include any ancestors
// whose children are all in the range
-
- nsCOMPtr arrayOfRanges;
- res = GetPromotedRanges(aSelection, address_of(arrayOfRanges), kOutdent);
- if (NS_FAILED(res)) return res;
-
- // use these ranges to contruct a list of nodes to act on.
-
nsCOMPtr arrayOfNodes;
- res = GetNodesForOperation(arrayOfRanges, address_of(arrayOfNodes), kOutdent);
- if (NS_FAILED(res)) return res;
-
+ res = GetNodesFromSelection(aSelection, kOutdent, address_of(arrayOfNodes));
+ if (NS_FAILED(res)) return res;
+
// Ok, now go through all the nodes and remove a level of blockquoting,
// or whatever is appropriate. Wohoo!
@@ -3284,15 +3278,9 @@ nsHTMLEditRules::WillAlign(nsISelection *aSelection,
// block parent, and then further expands to include any ancestors
// whose children are all in the range
*aHandled = PR_TRUE;
-
- nsCOMPtr arrayOfRanges;
- res = GetPromotedRanges(aSelection, address_of(arrayOfRanges), kAlign);
- if (NS_FAILED(res)) return res;
-
- // use these ranges to contruct a list of nodes to act on.
nsCOMPtr arrayOfNodes;
- res = GetNodesForOperation(arrayOfRanges, address_of(arrayOfNodes), kAlign);
- if (NS_FAILED(res)) return res;
+ res = GetNodesFromSelection(aSelection, kAlign, address_of(arrayOfNodes));
+ if (NS_FAILED(res)) return res;
// if we don't have any nodes, or we have only a single br, then we are
// creating an empty alignment div. We have to do some different things for these.
@@ -4432,12 +4420,8 @@ nsHTMLEditRules::GetListActionNodes(nsCOMPtr *outArrayOfNodes,
}
}
- nsCOMPtr arrayOfRanges;
- res = GetPromotedRanges(selection, address_of(arrayOfRanges), kMakeList);
- if (NS_FAILED(res)) return res;
-
- // use these ranges to contruct a list of nodes to act on.
- res = GetNodesForOperation(arrayOfRanges, outArrayOfNodes, kMakeList, aDontTouchContent);
+ // contruct a list of nodes to act on.
+ res = GetNodesFromSelection(selection, kMakeList, outArrayOfNodes, aDontTouchContent);
if (NS_FAILED(res)) return res;
// pre process our list of nodes...
@@ -4564,14 +4548,10 @@ nsHTMLEditRules::GetParagraphFormatNodes(nsCOMPtr *outArrayOfN
nsresult res = mHTMLEditor->GetSelection(getter_AddRefs(selection));
if (NS_FAILED(res)) return res;
- nsCOMPtr arrayOfRanges;
- res = GetPromotedRanges(selection, address_of(arrayOfRanges), kMakeList);
+ // contruct a list of nodes to act on.
+ res = GetNodesFromSelection(selection, kMakeBasicBlock, outArrayOfNodes, aDontTouchContent);
if (NS_FAILED(res)) return res;
-
- // use these ranges to contruct a list of nodes to act on.
- res = GetNodesForOperation(arrayOfRanges, outArrayOfNodes, kMakeBasicBlock, aDontTouchContent);
- if (NS_FAILED(res)) return res;
-
+
// pre process our list of nodes...
PRUint32 listCount;
PRInt32 i;
@@ -4746,6 +4726,31 @@ nsHTMLEditRules::GetHighestInlineParent(nsIDOMNode* aNode)
return inlineNode;
}
+
+///////////////////////////////////////////////////////////////////////////
+// GetNodesFromSelection: given a particular operation, construct a list
+// of nodes from the selection that will be operated on.
+//
+nsresult
+nsHTMLEditRules::GetNodesFromSelection(nsISelection *selection,
+ PRInt32 operation,
+ nsCOMPtr *arrayOfNodes,
+ PRBool dontTouchContent)
+{
+ if (!selection || !arrayOfNodes) return NS_ERROR_NULL_POINTER;
+ nsresult res;
+
+ // promote selection ranges
+ nsCOMPtr arrayOfRanges;
+ res = GetPromotedRanges(selection, address_of(arrayOfRanges), operation);
+ if (NS_FAILED(res)) return res;
+
+ // use these ranges to contruct a list of nodes to act on.
+ res = GetNodesForOperation(arrayOfRanges, arrayOfNodes, operation, dontTouchContent);
+ return res;
+}
+
+
///////////////////////////////////////////////////////////////////////////
// MakeTransitionList: detect all the transitions in the array, where a
// transition means that adjacent nodes in the array
diff --git a/mozilla/editor/libeditor/html/nsHTMLEditRules.h b/mozilla/editor/libeditor/html/nsHTMLEditRules.h
index 9627d53ad62..2d364aa2f52 100644
--- a/mozilla/editor/libeditor/html/nsHTMLEditRules.h
+++ b/mozilla/editor/libeditor/html/nsHTMLEditRules.h
@@ -171,6 +171,10 @@ protected:
PRBool aDontTouchContent=PR_FALSE);
nsresult GetChildNodesForOperation(nsIDOMNode *inNode,
nsCOMPtr *outArrayOfNodes);
+ nsresult GetNodesFromSelection(nsISelection *selection,
+ PRInt32 operation,
+ nsCOMPtr *arrayOfNodes,
+ PRBool aDontTouchContent=PR_FALSE);
nsresult GetListActionNodes(nsCOMPtr *outArrayOfNodes, PRBool aEntireList, PRBool aDontTouchContent=PR_FALSE);
nsresult GetDefinitionListItemTypes(nsIDOMNode *aNode, PRBool &aDT, PRBool &aDD);
nsresult GetParagraphFormatNodes(nsCOMPtr *outArrayOfNodes, PRBool aDontTouchContent=PR_FALSE);
diff --git a/mozilla/editor/libeditor/html/nsHTMLEditor.cpp b/mozilla/editor/libeditor/html/nsHTMLEditor.cpp
index 1cf848b21bb..3e5a60d4a3e 100644
--- a/mozilla/editor/libeditor/html/nsHTMLEditor.cpp
+++ b/mozilla/editor/libeditor/html/nsHTMLEditor.cpp
@@ -1684,7 +1684,7 @@ nsHTMLEditor::RebuildDocumentFromSource(const nsAReadableString& aSourceString)
nsReadingIterator endtotal;
aSourceString.EndReading(endtotal);
- res = InsertHTML(Substring(beginbody,endtotal));
+ res = LoadHTML(Substring(beginbody,endtotal));
if (NS_FAILED(res)) return res;
selection->Collapse(bodyElement, 0);
diff --git a/mozilla/editor/libeditor/html/nsHTMLEditor.h b/mozilla/editor/libeditor/html/nsHTMLEditor.h
index 0c3e5703452..65aef6919c3 100644
--- a/mozilla/editor/libeditor/html/nsHTMLEditor.h
+++ b/mozilla/editor/libeditor/html/nsHTMLEditor.h
@@ -95,7 +95,8 @@ public:
kOpInsertQuotation = 3009,
kOpSetTextProperty = 3010,
kOpRemoveTextProperty = 3011,
- kOpHTMLPaste = 3012
+ kOpHTMLPaste = 3012,
+ kOpHTMLLoad = 3013
};
@@ -140,6 +141,9 @@ public:
NS_IMETHOD InsertHTML(const nsAReadableString &aInputString);
NS_IMETHOD InsertHTMLWithCharset(const nsAReadableString& aInputString,
const nsAReadableString& aCharset);
+ NS_IMETHOD LoadHTML(const nsAReadableString &aInputString);
+ NS_IMETHOD LoadHTMLWithCharset(const nsAReadableString& aInputString,
+ const nsAReadableString& aCharset);
NS_IMETHOD RebuildDocumentFromSource(const nsAReadableString& aSourceString);
NS_IMETHOD InsertElementAtSelection(nsIDOMElement* aElement, PRBool aDeleteSelection);
@@ -621,6 +625,8 @@ protected:
PRInt32 aEndOffset);
nsresult RelativeFontChangeOnNode( PRInt32 aSizeChange,
nsIDOMNode *aNode);
+ nsresult RelativeFontChangeHelper( PRInt32 aSizeChange,
+ nsIDOMNode *aNode);
/* helper routines for inline style */
nsresult SetInlinePropertyOnTextNode( nsIDOMCharacterData *aTextNode,
diff --git a/mozilla/editor/libeditor/html/nsHTMLEditorStyle.cpp b/mozilla/editor/libeditor/html/nsHTMLEditorStyle.cpp
index 944ec5d7139..9ebcf088570 100644
--- a/mozilla/editor/libeditor/html/nsHTMLEditorStyle.cpp
+++ b/mozilla/editor/libeditor/html/nsHTMLEditorStyle.cpp
@@ -336,6 +336,28 @@ nsHTMLEditor::SetInlinePropertyOnTextNode( nsIDOMCharacterData *aTextNode,
if (NS_FAILED(res)) return res;
}
+ // look for siblings that are correct type of node
+ nsCOMPtr sibling;
+ GetPriorHTMLSibling(node, address_of(sibling));
+ if (sibling && NodeIsType(sibling, aProperty) &&
+ HasAttrVal(sibling, aAttribute, aValue) &&
+ IsOnlyAttribute(sibling, aAttribute) )
+ {
+ // previous sib is already right kind of inline node; slide this over into it
+ res = MoveNode(node, sibling, -1);
+ return res;
+ }
+ sibling = nsnull;
+ GetNextHTMLSibling(node, address_of(sibling));
+ if (sibling && NodeIsType(sibling, aProperty) &&
+ HasAttrVal(sibling, aAttribute, aValue) &&
+ IsOnlyAttribute(sibling, aAttribute) )
+ {
+ // following sib is already right kind of inline node; slide this over into it
+ res = MoveNode(node, sibling, 0);
+ return res;
+ }
+
// reparent the node inside inline node with appropriate {attribute,value}
res = SetInlinePropertyOnNode(node, aProperty, aAttribute, aValue);
return res;
@@ -558,9 +580,9 @@ nsresult nsHTMLEditor::RemoveStyleInside(nsIDOMNode *aNode,
// then process the node itself
if ( !aChildrenOnly &&
- ((aProperty && NodeIsType(aNode, aProperty)) || // node is prop we asked for
+ (aProperty && NodeIsType(aNode, aProperty) || // node is prop we asked for
(aProperty == nsIEditProperty::href && nsHTMLEditUtils::IsLink(aNode))) || // but check for link ( tmp, node = do_QueryInterface(aTextNode);
-
+
// do we need to split the text node?
PRUint32 textLen;
aTextNode->GetLength(&textLen);
@@ -1427,12 +1456,98 @@ nsHTMLEditor::RelativeFontChangeOnTextNode( PRInt32 aSizeChange,
if (NS_FAILED(res)) return res;
}
- // reparent the node inside font node with appropriate relative size
+ // look for siblings that are correct type of node
+ nsCOMPtr sibling;
+ GetPriorHTMLSibling(node, address_of(sibling));
+ if (sibling && NodeIsType(sibling, NS_ConvertASCIItoUCS2(aSizeChange==1 ? "big" : "small")))
+ {
+ // previous sib is already right kind of inline node; slide this over into it
+ res = MoveNode(node, sibling, -1);
+ return res;
+ }
+ sibling = nsnull;
+ GetNextHTMLSibling(node, address_of(sibling));
+ if (sibling && NodeIsType(sibling, NS_ConvertASCIItoUCS2(aSizeChange==1 ? "big" : "small")))
+ {
+ // following sib is already right kind of inline node; slide this over into it
+ res = MoveNode(node, sibling, 0);
+ return res;
+ }
+
+ // else reparent the node inside font node with appropriate relative size
res = InsertContainerAbove(node, address_of(tmp), NS_ConvertASCIItoUCS2(aSizeChange==1 ? "big" : "small"));
return res;
}
+nsresult
+nsHTMLEditor::RelativeFontChangeHelper( PRInt32 aSizeChange,
+ nsIDOMNode *aNode)
+{
+ /* This routine looks for all the font nodes in the tree rooted by aNode,
+ including aNode itself, looking for font nodes that have the size attr
+ set. Any such nodes need to have big or small put inside them, since
+ they override any big/small that are above them.
+ */
+
+ // Can only change font size by + or - 1
+ if ( !( (aSizeChange==1) || (aSizeChange==-1) ) )
+ return NS_ERROR_ILLEGAL_VALUE;
+ if (!aNode) return NS_ERROR_NULL_POINTER;
+
+ nsresult res = NS_OK;
+ nsAutoString tag;
+ if (aSizeChange == 1) tag.AssignWithConversion("big");
+ else tag.AssignWithConversion("small");
+ nsCOMPtr childNodes;
+ PRInt32 j;
+ PRUint32 childCount;
+ nsCOMPtr childNode;
+ nsAutoString attr;
+ attr.AssignWithConversion("size");
+
+ // if this is a font node with size, put big/small inside it
+ if (NodeIsType(aNode, nsIEditProperty::font) && HasAttr(aNode, &attr))
+ {
+ // cycle through children and adjust relative font size
+ res = aNode->GetChildNodes(getter_AddRefs(childNodes));
+ if (NS_FAILED(res)) return res;
+ if (childNodes)
+ {
+ childNodes->GetLength(&childCount);
+ for (j=childCount-1; j>=0; j--)
+ {
+ res = childNodes->Item(j, getter_AddRefs(childNode));
+ if ((NS_SUCCEEDED(res)) && (childNode))
+ {
+ res = RelativeFontChangeOnNode(aSizeChange, childNode);
+ if (NS_FAILED(res)) return res;
+ }
+ }
+ }
+ }
+
+ childNodes = nsnull;
+ // now cycle through the children.
+ res = aNode->GetChildNodes(getter_AddRefs(childNodes));
+ if (NS_FAILED(res)) return res;
+ if (childNodes)
+ {
+ childNodes->GetLength(&childCount);
+ for (j=childCount-1; j>=0; j--)
+ {
+ res = childNodes->Item(j, getter_AddRefs(childNode));
+ if ((NS_SUCCEEDED(res)) && (childNode))
+ {
+ res = RelativeFontChangeHelper(aSizeChange, childNode);
+ if (NS_FAILED(res)) return res;
+ }
+ }
+ }
+ return res;
+}
+
+
nsresult
nsHTMLEditor::RelativeFontChangeOnNode( PRInt32 aSizeChange,
nsIDOMNode *aNode)
@@ -1448,16 +1563,13 @@ nsHTMLEditor::RelativeFontChangeOnNode( PRInt32 aSizeChange,
if (aSizeChange == 1) tag.Assign(NS_LITERAL_STRING("big"));
else tag.Assign(NS_LITERAL_STRING("small"));
- // is this node a text node?
- if (IsTextNode(aNode))
- {
- res = InsertContainerAbove(aNode, address_of(tmp), tag);
- return res;
- }
// is it the opposite of what we want?
if ( ((aSizeChange == 1) && nsHTMLEditUtils::IsSmall(aNode)) ||
((aSizeChange == -1) && nsHTMLEditUtils::IsBig(aNode)) )
{
+ // first populate any nested font tags that have the size attr set
+ res = RelativeFontChangeHelper(aSizeChange, aNode);
+ if (NS_FAILED(res)) return res;
// in that case, just remove this node and pull up the children
res = RemoveContainer(aNode);
return res;
@@ -1465,7 +1577,29 @@ nsHTMLEditor::RelativeFontChangeOnNode( PRInt32 aSizeChange,
// can it be put inside a "big" or "small"?
if (TagCanContain(tag, aNode))
{
+ // first populate any nested font tags that have the size attr set
+ res = RelativeFontChangeHelper(aSizeChange, aNode);
+ if (NS_FAILED(res)) return res;
// ok, chuck it in.
+ // first look at siblings of aNode for matching bigs or smalls.
+ // if we find one, move aNode into it.
+ nsCOMPtr sibling;
+ GetPriorHTMLSibling(aNode, address_of(sibling));
+ if (sibling && NodeIsType(sibling, NS_ConvertASCIItoUCS2(aSizeChange==1 ? "big" : "small")))
+ {
+ // previous sib is already right kind of inline node; slide this over into it
+ res = MoveNode(aNode, sibling, -1);
+ return res;
+ }
+ sibling = nsnull;
+ GetNextHTMLSibling(aNode, address_of(sibling));
+ if (sibling && NodeIsType(sibling, NS_ConvertASCIItoUCS2(aSizeChange==1 ? "big" : "small")))
+ {
+ // following sib is already right kind of inline node; slide this over into it
+ res = MoveNode(aNode, sibling, 0);
+ return res;
+ }
+ // else insert it above aNode
res = InsertContainerAbove(aNode, address_of(tmp), tag);
return res;
}
@@ -1481,7 +1615,7 @@ nsHTMLEditor::RelativeFontChangeOnNode( PRInt32 aSizeChange,
PRInt32 j;
PRUint32 childCount;
childNodes->GetLength(&childCount);
- for (j=0 ; j < (PRInt32)childCount; j++)
+ for (j=childCount-1; j>=0; j--)
{
nsCOMPtr childNode;
res = childNodes->Item(j, getter_AddRefs(childNode));
diff --git a/mozilla/editor/libeditor/html/nsWSRunObject.cpp b/mozilla/editor/libeditor/html/nsWSRunObject.cpp
index fd33a7d0fcc..e51db7f6a6e 100644
--- a/mozilla/editor/libeditor/html/nsWSRunObject.cpp
+++ b/mozilla/editor/libeditor/html/nsWSRunObject.cpp
@@ -242,11 +242,11 @@ nsWSRunObject::InsertBreak(nsCOMPtr *aInOutParent,
// convert run to nbsp.
WSPoint thePoint;
res = GetCharAfter(*aInOutParent, *aInOutOffset, &thePoint);
- if ( (NS_SUCCEEDED(res)) && (nsCRT::IsAsciiSpace(thePoint.mChar)) )
+ if ( (NS_SUCCEEDED(res)) && thePoint.mTextNode && (nsCRT::IsAsciiSpace(thePoint.mChar)) )
{
WSPoint prevPoint;
res = GetCharBefore(thePoint, &prevPoint);
- if ( (NS_FAILED(res)) || (!nsCRT::IsAsciiSpace(prevPoint.mChar)) )
+ if ( (NS_FAILED(res)) || (prevPoint.mTextNode && !nsCRT::IsAsciiSpace(prevPoint.mChar)) )
{
// we are at start of non-nbsps. convert to a single nbsp.
res = ConvertToNBSP(thePoint);
@@ -372,7 +372,7 @@ nsWSRunObject::InsertText(const nsAReadableString& aStringToInsert,
{
WSPoint wspoint;
res = GetCharBefore(*aInOutParent, *aInOutOffset, &wspoint);
- if (NS_SUCCEEDED(res) && nsCRT::IsAsciiSpace(wspoint.mChar))
+ if (NS_SUCCEEDED(res) && wspoint.mTextNode && nsCRT::IsAsciiSpace(wspoint.mChar))
{
theString.SetCharAt(nbsp, 0);
}
@@ -403,7 +403,7 @@ nsWSRunObject::InsertText(const nsAReadableString& aStringToInsert,
{
WSPoint wspoint;
res = GetCharAfter(*aInOutParent, *aInOutOffset, &wspoint);
- if (NS_SUCCEEDED(res) && nsCRT::IsAsciiSpace(wspoint.mChar))
+ if (NS_SUCCEEDED(res) && wspoint.mTextNode && nsCRT::IsAsciiSpace(wspoint.mChar))
{
theString.SetCharAt(nbsp, lastCharIndex);
}
@@ -455,6 +455,7 @@ nsWSRunObject::DeleteWSBackward()
WSPoint point;
res = GetCharBefore(mNode, mOffset, &point);
NS_ENSURE_SUCCESS(res, res);
+ if (!point.mTextNode) return NS_OK; // nothing to delete
// callers job to insure that previous char is really ws.
// If it is normal ws, we need to delete the whole run
@@ -498,6 +499,7 @@ nsWSRunObject::DeleteWSForward()
WSPoint point;
res = GetCharAfter(mNode, mOffset, &point);
NS_ENSURE_SUCCESS(res, res);
+ if (!point.mTextNode) return NS_OK; // nothing to delete
// callers job to insure that next char is really ws.
// If it is normal ws, we need to delete the whole run
@@ -555,8 +557,7 @@ nsWSRunObject::PriorVisibleNode(nsIDOMNode *aNode,
if (run->mType == eNormalWS)
{
WSPoint point;
- res = GetCharBefore(aNode, aOffset, &point);
- NS_ENSURE_SUCCESS(res, res);
+ GetCharBefore(aNode, aOffset, &point);
if (point.mTextNode)
{
*outVisNode = do_QueryInterface(point.mTextNode);
@@ -597,7 +598,7 @@ nsWSRunObject::NextVisibleNode (nsIDOMNode *aNode,
PRInt32 *outVisOffset,
PRInt16 *outType)
{
- // Find first visible thing before the point. position outVisNode/outVisOffset
+ // Find first visible thing after the point. position outVisNode/outVisOffset
// just _before_ that thing. If we don't find anything return end of ws.
if (!aNode || !outVisNode || !outVisOffset || !outType)
return NS_ERROR_NULL_POINTER;
@@ -611,8 +612,7 @@ nsWSRunObject::NextVisibleNode (nsIDOMNode *aNode,
if (run->mType == eNormalWS)
{
WSPoint point;
- res = GetCharAfter(aNode, aOffset, &point);
- NS_ENSURE_SUCCESS(res, res);
+ GetCharAfter(aNode, aOffset, &point);
if (point.mTextNode)
{
*outVisNode = do_QueryInterface(point.mTextNode);
@@ -1458,7 +1458,7 @@ nsWSRunObject::PrepareToDeleteRangePriv(nsWSRunObject* aEndObject)
// make sure leading char of following ws is an nbsp, so that it will show up
WSPoint point;
aEndObject->GetCharAfter(aEndObject->mNode, aEndObject->mOffset, &point);
- if (nsCRT::IsAsciiSpace(point.mChar))
+ if (point.mTextNode && nsCRT::IsAsciiSpace(point.mChar))
{
res = ConvertToNBSP(point);
NS_ENSURE_SUCCESS(res, res);
@@ -1480,7 +1480,7 @@ nsWSRunObject::PrepareToDeleteRangePriv(nsWSRunObject* aEndObject)
// make sure trailing char of starting ws is an nbsp, so that it will show up
WSPoint point;
GetCharBefore(mNode, mOffset, &point);
- if (nsCRT::IsAsciiSpace(point.mChar))
+ if (point.mTextNode && nsCRT::IsAsciiSpace(point.mChar))
{
nsCOMPtr wsStartNode, wsEndNode;
PRInt32 wsStartOffset, wsEndOffset;
@@ -1518,7 +1518,7 @@ nsWSRunObject::PrepareToSplitAcrossBlocksPriv()
// make sure leading char of following ws is an nbsp, so that it will show up
WSPoint point;
GetCharAfter(mNode, mOffset, &point);
- if (nsCRT::IsAsciiSpace(point.mChar))
+ if (point.mTextNode && nsCRT::IsAsciiSpace(point.mChar))
{
res = ConvertToNBSP(point);
NS_ENSURE_SUCCESS(res, res);
@@ -1531,7 +1531,7 @@ nsWSRunObject::PrepareToSplitAcrossBlocksPriv()
// make sure trailing char of starting ws is an nbsp, so that it will show up
WSPoint point;
GetCharBefore(mNode, mOffset, &point);
- if (nsCRT::IsAsciiSpace(point.mChar))
+ if (point.mTextNode && nsCRT::IsAsciiSpace(point.mChar))
{
nsCOMPtr wsStartNode, wsEndNode;
PRInt32 wsStartOffset, wsEndOffset;
@@ -1696,7 +1696,7 @@ nsWSRunObject::GetCharAfter(WSPoint &aPoint, WSPoint *outPoint)
nsCOMPtr isupps(do_QueryInterface(aPoint.mTextNode));
PRInt32 idx = mNodeArray->IndexOf(isupps);
- if (idx == -1) return NS_ERROR_FAILURE;
+ if (idx == -1) return NS_OK; // can't find point, but it's not an error
PRUint32 numNodes;
mNodeArray->Count(&numNodes);
@@ -1718,7 +1718,6 @@ nsWSRunObject::GetCharAfter(WSPoint &aPoint, WSPoint *outPoint)
outPoint->mOffset = 0;
outPoint->mChar = GetCharAt(outPoint->mTextNode, 0);
}
- else return NS_ERROR_FAILURE;
return NS_OK;
}
@@ -1735,7 +1734,7 @@ nsWSRunObject::GetCharBefore(WSPoint &aPoint, WSPoint *outPoint)
nsresult res = NS_OK;
nsCOMPtr isupps(do_QueryInterface(aPoint.mTextNode));
PRInt32 idx = mNodeArray->IndexOf(isupps);
- if (idx == -1) return NS_ERROR_FAILURE;
+ if (idx == -1) return NS_OK; // can't find point, but it's not an error
if (aPoint.mOffset != 0)
{
@@ -1757,8 +1756,7 @@ nsWSRunObject::GetCharBefore(WSPoint &aPoint, WSPoint *outPoint)
outPoint->mChar = GetCharAt(outPoint->mTextNode, len-1);
}
}
- else return NS_ERROR_FAILURE;
- return res;
+ return NS_OK;
}
nsresult
@@ -1829,7 +1827,7 @@ nsWSRunObject::GetAsciiWSBounds(PRInt16 aDir, nsIDOMNode *aNode, PRInt32 aOffset
endOffset = point.mOffset;
tmp = point;
res = GetCharAfter(tmp, &point);
- if (NS_FAILED(res)) break;
+ if (NS_FAILED(res) || !point.mTextNode) break;
}
}
}
@@ -1855,7 +1853,7 @@ nsWSRunObject::GetAsciiWSBounds(PRInt16 aDir, nsIDOMNode *aNode, PRInt32 aOffset
startOffset = point.mOffset;
tmp = point;
res = GetCharBefore(tmp, &point);
- if (NS_FAILED(res)) break;
+ if (NS_FAILED(res) || !point.mTextNode) break;
}
}
}
@@ -2091,12 +2089,12 @@ nsWSRunObject::CheckTrailingNBSPOfRun(WSFragment *aRun)
// first check for trailing nbsp
nsresult res = GetCharBefore(aRun->mEndNode, aRun->mEndOffset, &thePoint);
- if (NS_SUCCEEDED(res) && thePoint.mChar == nbsp)
+ if (NS_SUCCEEDED(res) && thePoint.mTextNode && thePoint.mChar == nbsp)
{
// now check that what is to the left of it is compatible with replacing nbsp with space
WSPoint prevPoint;
res = GetCharBefore(thePoint, &prevPoint);
- if (NS_SUCCEEDED(res))
+ if (NS_SUCCEEDED(res) && prevPoint.mTextNode)
{
if (!nsCRT::IsAsciiSpace(prevPoint.mChar)) leftCheck = PR_TRUE;
}
@@ -2141,11 +2139,11 @@ nsWSRunObject::CheckTrailingNBSP(WSFragment *aRun, nsIDOMNode *aNode, PRInt32 aO
WSPoint thePoint;
PRBool canConvert = PR_FALSE;
nsresult res = GetCharBefore(aNode, aOffset, &thePoint);
- if (NS_SUCCEEDED(res) && thePoint.mChar == nbsp)
+ if (NS_SUCCEEDED(res) && thePoint.mTextNode && thePoint.mChar == nbsp)
{
WSPoint prevPoint;
res = GetCharBefore(thePoint, &prevPoint);
- if (NS_SUCCEEDED(res))
+ if (NS_SUCCEEDED(res) && prevPoint.mTextNode)
{
if (!nsCRT::IsAsciiSpace(prevPoint.mChar)) canConvert = PR_TRUE;
}
@@ -2186,7 +2184,7 @@ nsWSRunObject::CheckLeadingNBSP(WSFragment *aRun, nsIDOMNode *aNode, PRInt32 aOf
WSPoint nextPoint, tmp=thePoint;
tmp.mOffset++; // we want to be after thePoint
res = GetCharAfter(tmp, &nextPoint);
- if (NS_SUCCEEDED(res))
+ if (NS_SUCCEEDED(res) && nextPoint.mTextNode)
{
if (!nsCRT::IsAsciiSpace(nextPoint.mChar)) canConvert = PR_TRUE;
}