fixes following bugs:

77902: toggling from normal to source view and back in composer can leave source in normal view.
101645: big/small tags get seperately wrapped around br nodes
81315: drag and drop doesn't behave same as copy paste
90759: ascii spaces don't behave in IME mode
96328: cant outdent certain indented text
58629: some mail messages cannot be accurately quoted on reply
93088/93477: forward deletion broken
46290: relative font size controls dont play nice with absolute font size
r=various; sr=kin


git-svn-id: svn://10.0.0.236/trunk@105922 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
jfrancis%netscape.com 2001-10-22 06:22:52 +00:00
parent 00fcc38140
commit c64143d012
7 changed files with 391 additions and 105 deletions

View File

@ -176,6 +176,69 @@ static nsCOMPtr<nsIDOMNode> 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
nsCOMPtr<nsISelection>selection;
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<nsIDOMRange> range, clone;
res = selection->GetRangeAt(0, getter_AddRefs(range));
NS_ENSURE_SUCCESS(res, res);
if (!range)
return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMNSRange> nsrange (do_QueryInterface(range));
if (!nsrange)
return NS_ERROR_NO_INTERFACE;
// create fragment for pasted html
nsCOMPtr<nsIDOMDocumentFragment> docfrag;
{
res = nsrange->CreateContextualFragment(aInputString, getter_AddRefs(docfrag));
NS_ENSURE_SUCCESS(res, res);
}
// put the fragment into the document
nsCOMPtr<nsIDOMNode> 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<nsIDOMNode> 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<nsISupports> contextDataObj, infoDataObj;
PRUint32 contextLen, infoLen;
nsCOMPtr<nsISupportsWString> textDataObj;
nsCOMPtr<nsITransferable> 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<nsITransferable> 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<nsISupportsWString> dataWrapper = do_CreateInstance(NS_SUPPORTS_WSTRING_CONTRACTID);
NS_ENSURE_TRUE(dataWrapper, NS_ERROR_FAILURE);
nsCOMPtr<nsISupportsWString> 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<nsISupports> 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<nsISupports> nsisupportsDataWrapper ( do_QueryInterface(dataWrapper) );
rv = trans->SetTransferData(bIsPlainTextControl ? kUnicodeMime : kHTMLMime,
nsisupportsDataWrapper, buffer.Length() * 2);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsISupports> 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

View File

@ -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
nsCOMPtr<nsISelection>selection;
nsresult res = mHTMLEditor->GetSelection(getter_AddRefs(selection));
if (NS_FAILED(res)) return res;
nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
if (!selPriv)
return NS_ERROR_FAILURE;
// contruct a list of nodes to act on.
nsCOMPtr<nsISupportsArray> 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<nsISupportsArray> 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<nsISupportsArray> 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<nsISupportsArray> 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<nsISupportsArray> 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<nsISupportsArray> 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<nsISupportsArray> 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<nsISupportsArray> *outArrayOfNodes,
}
}
nsCOMPtr<nsISupportsArray> 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<nsISupportsArray> *outArrayOfN
nsresult res = mHTMLEditor->GetSelection(getter_AddRefs(selection));
if (NS_FAILED(res)) return res;
nsCOMPtr<nsISupportsArray> 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<nsISupportsArray> *arrayOfNodes,
PRBool dontTouchContent)
{
if (!selection || !arrayOfNodes) return NS_ERROR_NULL_POINTER;
nsresult res;
// promote selection ranges
nsCOMPtr<nsISupportsArray> 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

View File

@ -171,6 +171,10 @@ protected:
PRBool aDontTouchContent=PR_FALSE);
nsresult GetChildNodesForOperation(nsIDOMNode *inNode,
nsCOMPtr<nsISupportsArray> *outArrayOfNodes);
nsresult GetNodesFromSelection(nsISelection *selection,
PRInt32 operation,
nsCOMPtr<nsISupportsArray> *arrayOfNodes,
PRBool aDontTouchContent=PR_FALSE);
nsresult GetListActionNodes(nsCOMPtr<nsISupportsArray> *outArrayOfNodes, PRBool aEntireList, PRBool aDontTouchContent=PR_FALSE);
nsresult GetDefinitionListItemTypes(nsIDOMNode *aNode, PRBool &aDT, PRBool &aDD);
nsresult GetParagraphFormatNodes(nsCOMPtr<nsISupportsArray> *outArrayOfNodes, PRBool aDontTouchContent=PR_FALSE);

View File

@ -1684,7 +1684,7 @@ nsHTMLEditor::RebuildDocumentFromSource(const nsAReadableString& aSourceString)
nsReadingIterator<PRUnichar> endtotal;
aSourceString.EndReading(endtotal);
res = InsertHTML(Substring(beginbody,endtotal));
res = LoadHTML(Substring(beginbody,endtotal));
if (NS_FAILED(res)) return res;
selection->Collapse(bodyElement, 0);

View File

@ -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,

View File

@ -336,6 +336,28 @@ nsHTMLEditor::SetInlinePropertyOnTextNode( nsIDOMCharacterData *aTextNode,
if (NS_FAILED(res)) return res;
}
// look for siblings that are correct type of node
nsCOMPtr<nsIDOMNode> 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 (<a href=...)
(!aProperty && NodeIsProperty(aNode)) ) // or node is any prop and we asked for that
(!aProperty && NodeIsProperty(aNode))) // or node is any prop and we asked for that
{
// if we weren't passed an attribute, then we want to
// remove any matching inlinestyles entirely
@ -588,6 +610,13 @@ nsresult nsHTMLEditor::RemoveStyleInside(nsIDOMNode *aNode,
}
}
}
if ( aProperty == nsIEditProperty::font && // or node is big or small and we are setting font size
(NodeIsType(aNode, nsIEditProperty::big) || NodeIsType(aNode, nsIEditProperty::small)) &&
!Compare(*aAttribute,NS_LITERAL_STRING("size"),nsCaseInsensitiveStringComparator()))
{
res = RemoveContainer(aNode); // if we are setting font size, remove any nested bigs and smalls
}
return res;
}
@ -1405,7 +1434,7 @@ nsHTMLEditor::RelativeFontChangeOnTextNode( PRInt32 aSizeChange,
nsresult res = NS_OK;
nsCOMPtr<nsIDOMNode> 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<nsIDOMNode> 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<nsIDOMNodeList> childNodes;
PRInt32 j;
PRUint32 childCount;
nsCOMPtr<nsIDOMNode> 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<nsIDOMNode> 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<nsIDOMNode> childNode;
res = childNodes->Item(j, getter_AddRefs(childNode));

View File

@ -242,11 +242,11 @@ nsWSRunObject::InsertBreak(nsCOMPtr<nsIDOMNode> *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<nsIDOMNode> 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<nsIDOMNode> wsStartNode, wsEndNode;
PRInt32 wsStartOffset, wsEndOffset;
@ -1696,7 +1696,7 @@ nsWSRunObject::GetCharAfter(WSPoint &aPoint, WSPoint *outPoint)
nsCOMPtr<nsISupports> 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<nsISupports> 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;
}