Fix for bug 457104 (nsTextServicesDocument::FirstSelectedBlock dead?). r/sr=peterv.

--HG--
extra : rebase_source : 73e620aade6618aa90cebe0784754a68d5479a6d
This commit is contained in:
Fred Jendrzejewski 2009-04-08 14:59:06 +02:00
parent 2bef32708b
commit 63abee270a
6 changed files with 3 additions and 1062 deletions

View File

@ -752,29 +752,6 @@ nsHTMLEditor::GetBlockNodeParent(nsIDOMNode *aNode)
return p;
}
///////////////////////////////////////////////////////////////////////////
// HasSameBlockNodeParent: true if nodes have same block level ancestor
//
PRBool
nsHTMLEditor::HasSameBlockNodeParent(nsIDOMNode *aNode1, nsIDOMNode *aNode2)
{
if (!aNode1 || !aNode2)
{
NS_NOTREACHED("null node passed to HasSameBlockNodeParent()");
return PR_FALSE;
}
if (aNode1 == aNode2)
return PR_TRUE;
nsCOMPtr<nsIDOMNode> p1 = GetBlockNodeParent(aNode1);
nsCOMPtr<nsIDOMNode> p2 = GetBlockNodeParent(aNode2);
return (p1 == p2);
}
///////////////////////////////////////////////////////////////////////////
// GetBlockSection: return leftmost/rightmost nodes in aChild's block
//
@ -2175,117 +2152,6 @@ nsHTMLEditor::SetParagraphFormat(const nsAString& aParagraphFormat)
return InsertBasicBlock(tag);
}
// XXX: ERROR_HANDLING -- this method needs a little work to ensure all error codes are
// checked properly, all null pointers are checked, and no memory leaks occur
NS_IMETHODIMP
nsHTMLEditor::GetParentBlockTags(nsTArray<nsString> *aTagList, PRBool aGetLists)
{
nsresult res;
nsCOMPtr<nsISelection>selection;
res = GetSelection(getter_AddRefs(selection));
if (NS_FAILED(res)) return res;
if (!selection) return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
// Find out if the selection is collapsed:
PRBool isCollapsed;
res = selection->GetIsCollapsed(&isCollapsed);
if (NS_FAILED(res)) return res;
if (isCollapsed)
{
nsCOMPtr<nsIDOMNode> node, blockParent;
PRInt32 offset;
res = GetStartNodeAndOffset(selection, address_of(node), &offset);
if (!node) res = NS_ERROR_FAILURE;
if (NS_FAILED(res)) return res;
nsCOMPtr<nsIDOMElement> blockParentElem;
if (aGetLists)
{
// Get the "ol", "ul", or "dl" parent element
res = GetElementOrParentByTagName(NS_LITERAL_STRING("list"), node, getter_AddRefs(blockParentElem));
if (NS_FAILED(res)) return res;
}
else
{
PRBool isBlock (PR_FALSE);
NodeIsBlock(node, &isBlock);
if (isBlock) blockParent = node;
else blockParent = GetBlockNodeParent(node);
blockParentElem = do_QueryInterface(blockParent);
}
if (blockParentElem)
{
nsAutoString blockParentTag;
blockParentElem->GetTagName(blockParentTag);
aTagList->AppendElement(blockParentTag);
}
return res;
}
// else non-collapsed selection
nsCOMPtr<nsIEnumerator> enumerator;
res = selPriv->GetEnumerator(getter_AddRefs(enumerator));
if (NS_FAILED(res)) return res;
if (!enumerator) return NS_ERROR_NULL_POINTER;
enumerator->First();
nsCOMPtr<nsISupports> currentItem;
res = enumerator->CurrentItem(getter_AddRefs(currentItem));
if (NS_FAILED(res)) return res;
//XXX: should be while loop?
if (currentItem)
{
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
// scan the range for all the independent block content blockSections
// and get the block parent of each
nsCOMArray<nsIDOMRange> blockSections;
res = GetBlockSectionsForRange(range, blockSections);
if (NS_SUCCEEDED(res))
{
nsCOMPtr<nsIDOMRange> subRange = blockSections[0];
while (subRange)
{
nsCOMPtr<nsIDOMNode>startParent;
res = subRange->GetStartContainer(getter_AddRefs(startParent));
if (NS_SUCCEEDED(res) && startParent)
{
nsCOMPtr<nsIDOMElement> blockParent;
if (aGetLists)
{
// Get the "ol", "ul", or "dl" parent element
res = GetElementOrParentByTagName(NS_LITERAL_STRING("list"), startParent, getter_AddRefs(blockParent));
}
else
{
blockParent = do_QueryInterface(GetBlockNodeParent(startParent));
}
if (NS_SUCCEEDED(res) && blockParent)
{
nsAutoString blockParentTag;
blockParent->GetTagName(blockParentTag);
PRBool isRoot;
IsRootTag(blockParentTag, isRoot);
if ((!isRoot) && !aTagList->Contains(blockParentTag)) {
aTagList->AppendElement(blockParentTag);
}
}
}
if (NS_FAILED(res))
return res;
blockSections.RemoveObject(0);
if (blockSections.Count() == 0)
break;
subRange = blockSections[0];
}
}
}
return res;
}
NS_IMETHODIMP
nsHTMLEditor::GetParagraphState(PRBool *aMixed, nsAString &outFormat)
{
@ -2332,20 +2198,6 @@ nsHTMLEditor::GetHighlightColorState(PRBool *aMixed, nsAString &aOutColor)
return res;
}
NS_IMETHODIMP
nsHTMLEditor::GetHighlightColor(PRBool *aMixed, PRUnichar **_retval)
{
if (!aMixed || !_retval) return NS_ERROR_NULL_POINTER;
nsAutoString outColorString(NS_LITERAL_STRING("transparent"));
*aMixed = PR_FALSE;
nsresult err = NS_NOINTERFACE;
err = GetHighlightColorState(aMixed, outColorString);
*_retval = ToNewUnicode(outColorString);
return err;
}
nsresult
nsHTMLEditor::GetCSSBackgroundColorState(PRBool *aMixed, nsAString &aOutColor, PRBool aBlockLevel)
{
@ -4425,44 +4277,6 @@ nsHTMLEditor::IsRootTag(nsString &aTag, PRBool &aIsTag)
return NS_OK;
}
NS_IMETHODIMP
nsHTMLEditor::IsSubordinateBlock(nsString &aTag, PRBool &aIsTag)
{
static char p[] = "p";
static char h1[] = "h1";
static char h2[] = "h2";
static char h3[] = "h3";
static char h4[] = "h4";
static char h5[] = "h5";
static char h6[] = "h6";
static char address[] = "address";
static char pre[] = "pre";
static char li[] = "li";
static char dt[] = "dt";
static char dd[] = "dd";
if (aTag.EqualsIgnoreCase(p) ||
aTag.EqualsIgnoreCase(h1) ||
aTag.EqualsIgnoreCase(h2) ||
aTag.EqualsIgnoreCase(h3) ||
aTag.EqualsIgnoreCase(h4) ||
aTag.EqualsIgnoreCase(h5) ||
aTag.EqualsIgnoreCase(h6) ||
aTag.EqualsIgnoreCase(address) ||
aTag.EqualsIgnoreCase(pre) ||
aTag.EqualsIgnoreCase(li) ||
aTag.EqualsIgnoreCase(dt) ||
aTag.EqualsIgnoreCase(dd) )
{
aIsTag = PR_TRUE;
}
else {
aIsTag = PR_FALSE;
}
return NS_OK;
}
///////////////////////////////////////////////////////////////////////////
// GetEnclosingTable: find ancestor who is a table, if any
//
@ -4587,50 +4401,6 @@ nsHTMLEditor::CollapseAdjacentTextNodes(nsIDOMRange *aInRange)
return result;
}
NS_IMETHODIMP
nsHTMLEditor::GetNextElementByTagName(nsIDOMElement *aCurrentElement,
const nsAString *aTagName,
nsIDOMElement **aReturn)
{
nsresult res = NS_OK;
if (!aCurrentElement || !aTagName || !aReturn)
return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIAtom> tagAtom = do_GetAtom(*aTagName);
if (!tagAtom) { return NS_ERROR_NULL_POINTER; }
if (tagAtom==nsEditProperty::th)
tagAtom=nsEditProperty::td;
nsCOMPtr<nsIDOMNode> currentNode = do_QueryInterface(aCurrentElement);
if (!currentNode)
return NS_ERROR_FAILURE;
*aReturn = nsnull;
nsCOMPtr<nsIDOMNode> nextNode;
PRBool done = PR_FALSE;
do {
res = GetNextNode(currentNode, PR_TRUE, address_of(nextNode));
if (NS_FAILED(res)) return res;
if (!nextNode) break;
if (GetTag(currentNode) == tagAtom)
{
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(currentNode);
if (!element) return NS_ERROR_NULL_POINTER;
*aReturn = element;
NS_ADDREF(*aReturn);
done = PR_TRUE;
return NS_OK;
}
currentNode = nextNode;
} while (!done);
return res;
}
NS_IMETHODIMP
nsHTMLEditor::SetSelectionAtDocumentStart(nsISelection *aSelection)
{

View File

@ -172,14 +172,9 @@ public:
NS_IMETHOD LoadHTML(const nsAString &aInputString);
NS_IMETHOD GetParentBlockTags(nsTArray<nsString> *aTagList, PRBool aGetLists);
nsresult GetCSSBackgroundColorState(PRBool *aMixed, nsAString &aOutColor,
PRBool aBlockLevel);
NS_IMETHOD GetHTMLBackgroundColorState(PRBool *aMixed, nsAString &outColor);
NS_IMETHOD GetHighlightColor(PRBool *mixed, PRUnichar **_retval);
NS_IMETHOD GetNextElementByTagName(nsIDOMElement *aCurrentElement, const nsAString *aTagName, nsIDOMElement **aReturn);
/* ------------ nsIEditorStyleSheets methods -------------- */
@ -231,8 +226,6 @@ public:
PRBool* aIsSelected);
NS_IMETHOD GetFirstRow(nsIDOMElement* aTableElement, nsIDOMNode** aRowNode);
NS_IMETHOD GetNextRow(nsIDOMNode* aCurrentRowNode, nsIDOMNode** aRowNode);
NS_IMETHOD GetFirstCellInRow(nsIDOMNode* aRowNode, nsIDOMNode** aCellNode);
NS_IMETHOD GetNextCellInRow(nsIDOMNode* aCurrentCellNode, nsIDOMNode** aRowNode);
NS_IMETHOD GetLastCellInRow(nsIDOMNode* aRowNode, nsIDOMNode** aCellNode);
NS_IMETHOD SetSelectionAfterTableEdit(nsIDOMElement* aTable, PRInt32 aRow, PRInt32 aCol,
@ -265,7 +258,6 @@ public:
/* ------------ Block methods moved from nsEditor -------------- */
static nsCOMPtr<nsIDOMNode> GetBlockNodeParent(nsIDOMNode *aNode);
static PRBool HasSameBlockNodeParent(nsIDOMNode *aNode1, nsIDOMNode *aNode2);
/** Determines the bounding nodes for the block section containing aNode.
* The calculation is based on some nodes intrinsically being block elements
* acording to HTML. Style sheets are not considered in this calculation.
@ -393,14 +385,6 @@ public:
PRInt32 &aStartOffset,
PRInt32 &aEndOffset);
nsresult GetAbsoluteOffsetsForPoints(nsIDOMNode *aInStartNode,
PRInt32 aInStartOffset,
nsIDOMNode *aInEndNode,
PRInt32 aInEndOffset,
nsIDOMNode *aInCommonParentNode,
PRInt32 &aOutStartOffset,
PRInt32 &aEndOffset);
// Use this to assure that selection is set after attribute nodes when
// trying to collapse selection at begining of a block node
// e.g., when setting at beginning of a table cell
@ -426,7 +410,6 @@ public:
PRBool *aSeenBR);
// Stylesheet-related methods that aren't part of nsIEditorStyleSheets.
nsresult AddCSSStyleSheet(nsICSSStyleSheet* aSheet);
nsresult GetCSSLoader(const nsAString& aURL, nsICSSLoader** aCSSLoader);
// Returns TRUE if sheet was loaded, false if it wasn't
@ -543,8 +526,6 @@ protected:
NS_IMETHOD IsRootTag(nsString &aTag, PRBool &aIsTag);
NS_IMETHOD IsSubordinateBlock(nsString &aTag, PRBool &aIsTag);
virtual PRBool IsBlockNode(nsIDOMNode *aNode);
static nsCOMPtr<nsIDOMNode> GetEnclosingTable(nsIDOMNode *aNode);
@ -572,11 +553,6 @@ protected:
nsIDOMNode **aStyleNode,
nsAString *outValue = nsnull);
void ResetTextSelectionForRange(nsIDOMNode *aParent,
PRInt32 aStartOffset,
PRInt32 aEndOffset,
nsISelection *aSelection);
// Methods for handling plaintext quotations
NS_IMETHOD PasteAsPlaintextQuotation(PRInt32 aSelectionType);

View File

@ -391,70 +391,6 @@ nsHTMLEditor::GetNextRow(nsIDOMNode* aCurrentRowNode, nsIDOMNode **aRowNode)
return NS_EDITOR_ELEMENT_NOT_FOUND;
}
NS_IMETHODIMP
nsHTMLEditor::GetFirstCellInRow(nsIDOMNode* aRowNode, nsIDOMNode** aCellNode)
{
if (!aCellNode) return NS_ERROR_NULL_POINTER;
*aCellNode = nsnull;
if (!aRowNode) return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMNode> rowChild;
nsresult res = aRowNode->GetFirstChild(getter_AddRefs(rowChild));
if (NS_FAILED(res)) return res;
while (rowChild && !nsHTMLEditUtils::IsTableCell(rowChild))
{
// Skip over textnodes
nsCOMPtr<nsIDOMNode> nextChild;
res = rowChild->GetNextSibling(getter_AddRefs(nextChild));
if (NS_FAILED(res)) return res;
rowChild = nextChild;
};
if (rowChild)
{
*aCellNode = rowChild.get();
NS_ADDREF(*aCellNode);
return NS_OK;
}
// If here, cell was not found
return NS_EDITOR_ELEMENT_NOT_FOUND;
}
NS_IMETHODIMP
nsHTMLEditor::GetNextCellInRow(nsIDOMNode* aCurrentCellNode, nsIDOMNode** aCellNode)
{
if (!aCellNode) return NS_ERROR_NULL_POINTER;
*aCellNode = nsnull;
if (!aCurrentCellNode) return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMNode> nextCell;
nsresult res = aCurrentCellNode->GetNextSibling(getter_AddRefs(nextCell));
if (NS_FAILED(res)) return res;
while (nextCell && !nsHTMLEditUtils::IsTableCell(nextCell))
{
// Skip over textnodes
nsCOMPtr<nsIDOMNode> nextChild;
res = nextCell->GetNextSibling(getter_AddRefs(nextChild));
if (NS_FAILED(res)) return res;
nextCell = nextChild;
};
if (nextCell)
{
*aCellNode = nextCell.get();
NS_ADDREF(*aCellNode);
return NS_OK;
}
// If here, cell was not found
return NS_EDITOR_ELEMENT_NOT_FOUND;
}
NS_IMETHODIMP
nsHTMLEditor::GetLastCellInRow(nsIDOMNode* aRowNode, nsIDOMNode** aCellNode)
{

View File

@ -76,16 +76,6 @@ public:
eBlockPartial // S begins or ends in TB but extends outside of TB.
} TSDBlockSelectionStatus;
/**
* Initializes the text services document to use a particular
* DOM document.
* @param aDOMDocument is the document to use. It is AddRef'd
* by this method.
* @param aPresShell is the presentation shell to use when
* setting the selection. It is AddRef'd by this method.
*/
NS_IMETHOD InitWithDocument(nsIDOMDocument *aDOMDocument, nsIPresShell *aPresShell) = 0;
/**
* Get the DOM document for the document in use.
* @return aDocument the dom document [OUT]
@ -103,26 +93,15 @@ public:
/**
* Sets the range/extent over which the text services document
* will iterate. Note that InitWithDocument() or InitWithEditor()
* should have been called prior to calling this method. If this
* method is never called, the text services defaults to iterating
* over the entire document.
* will iterate. Note that InitWithEditor() should have been called prior to
* calling this method. If this method is never called, the text services
* defaults to iterating over the entire document.
*
* @param aDOMRange is the range to use. aDOMRange must point to a
* valid range object.
*/
NS_IMETHOD SetExtent(nsIDOMRange* aDOMRange) = 0;
/**
* Gets the range that the text services document
* is currently iterating over. If SetExtent() was never
* called, this method will return a range that spans the
* entire body of the document.
*
* @param aDOMRange will contain an AddRef'd pointer to the range.
*/
NS_IMETHOD GetExtent(nsIDOMRange** aDOMRange) = 0;
/**
* Expands the end points of the range so that it spans complete words.
* This call does not change any internal state of the text services document.
@ -137,14 +116,6 @@ public:
*/
NS_IMETHOD SetFilter(nsITextServicesFilter *aFilter) = 0;
/**
* Returns true if the document can be modified with calls
* to DeleteSelection() and InsertText().
* @param aCanEdit is true if the document can be modified,
* false if it can't.
*/
NS_IMETHOD CanEdit(PRBool *aCanEdit) = 0;
/**
* Returns the text in the current text block.
* @param aStr will contain the text.
@ -160,27 +131,6 @@ public:
NS_IMETHOD FirstBlock() = 0;
/**
* Tells the document to point to the last text block in the
* document. This method does not adjust the current cursor
* position or selection.
*/
NS_IMETHOD LastBlock() = 0;
/**
* Tells the document to point to the first text block that
* contains the current selection or caret.
* @param aSelectionStatus will contain the text block selection status
* @param aSelectionOffset will contain the offset into the
* string returned by GetCurrentTextBlock() where the selection
* begins.
* @param aLength will contain the number of characters that are
* selected in the string.
*/
NS_IMETHOD FirstSelectedBlock(TSDBlockSelectionStatus *aSelectionStatus, PRInt32 *aSelectionOffset, PRInt32 *aSelectionLength) = 0;
/**
* Tells the document to point to the last text block that
* contains the current selection or caret.
@ -259,21 +209,6 @@ public:
*/
NS_IMETHOD InsertText(const nsString *aText) = 0;
/**
* Sets the display style for the text selected by SetSelection().
* @param aStyle is the style to apply to the selected text.
*/
NS_IMETHOD SetDisplayStyle(TSDDisplayStyle aStyle) = 0;
/**
* Returns the DOM range for a given offset and length
* @param aOffset offset into string returned by GetCurrentTextBlock().
* @param aLength number characters selected.
* @return aDOMRange the DOM range that represents the offset and length
*/
NS_IMETHOD GetDOMRangeFor(PRInt32 aOffset, PRInt32 aLength, nsIDOMRange** aRange) = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsITextServicesDocument,

View File

@ -171,46 +171,6 @@ NS_IMPL_RELEASE(nsTextServicesDocument)
NS_IMPL_QUERY_INTERFACE1(nsTextServicesDocument, nsITextServicesDocument)
NS_IMETHODIMP
nsTextServicesDocument::InitWithDocument(nsIDOMDocument *aDOMDocument, nsIPresShell *aPresShell)
{
nsresult result = NS_OK;
if (!aDOMDocument || !aPresShell)
return NS_ERROR_NULL_POINTER;
NS_ASSERTION(!mSelCon, "mSelCon already initialized!");
if (mSelCon)
return NS_ERROR_FAILURE;
NS_ASSERTION(!mDOMDocument, "mDOMDocument already initialized!");
if (mDOMDocument)
return NS_ERROR_FAILURE;
LOCK_DOC(this);
mSelCon = do_QueryInterface(aPresShell);
mDOMDocument = do_QueryInterface(aDOMDocument);
result = CreateDocumentContentIterator(getter_AddRefs(mIterator));
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
mIteratorStatus = nsTextServicesDocument::eIsDone;
result = FirstBlock();
UNLOCK_DOC(this);
return result;
}
NS_IMETHODIMP
nsTextServicesDocument::InitWithEditor(nsIEditor *aEditor)
{
@ -358,27 +318,6 @@ nsTextServicesDocument::SetExtent(nsIDOMRange* aDOMRange)
return result;
}
NS_IMETHODIMP
nsTextServicesDocument::GetExtent(nsIDOMRange** aDOMRange)
{
NS_ENSURE_ARG_POINTER(aDOMRange);
*aDOMRange = nsnull;
if (mExtent)
{
// We have an extent range, so just return a
// copy of it.
return mExtent->CloneRange(aDOMRange);
}
// We don't have an extent range, so we must be
// iterating over the entire document.
return CreateDocumentContentRange(aDOMRange);
}
NS_IMETHODIMP
nsTextServicesDocument::ExpandRangeToWordBoundaries(nsIDOMRange *aRange)
{
@ -555,19 +494,6 @@ nsTextServicesDocument::SetFilter(nsITextServicesFilter *aFilter)
return NS_OK;
}
NS_IMETHODIMP
nsTextServicesDocument::CanEdit(PRBool *aCanEdit)
{
if (!aCanEdit)
return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIEditor> editor (do_QueryReferent(mEditor));
*aCanEdit = (editor) ? PR_TRUE : PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsTextServicesDocument::GetCurrentTextBlock(nsString *aStr)
{
@ -627,532 +553,6 @@ nsTextServicesDocument::FirstBlock()
return result;
}
NS_IMETHODIMP
nsTextServicesDocument::LastBlock()
{
NS_ENSURE_TRUE(mIterator, NS_ERROR_FAILURE);
LOCK_DOC(this);
// Position the iterator on the last text node
// in the tree, then walk backwards over adjacent
// text nodes until we hit a block boundary:
nsresult result = LastTextNode(mIterator, &mIteratorStatus);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
result = FirstTextNodeInCurrentBlock(mIterator);
if (NS_FAILED(result))
mIteratorStatus = nsTextServicesDocument::eIsDone;
// Keep track of prev and next blocks, just in case
// the text service blows away the current block.
if (mIteratorStatus == nsTextServicesDocument::eValid)
{
result = GetFirstTextNodeInPrevBlock(getter_AddRefs(mPrevTextBlock));
mNextTextBlock = nsnull;
}
else
{
// There's no text block in the document!
mPrevTextBlock = nsnull;
mNextTextBlock = nsnull;
}
UNLOCK_DOC(this);
return result;
}
// XXX: CODE BLOAT ALERT. FirstSelectedBlock() and LastSelectedBlock()
// are almost identical! Later, when we have time, we should try
// and combine them into one method.
NS_IMETHODIMP
nsTextServicesDocument::FirstSelectedBlock(TSDBlockSelectionStatus *aSelStatus, PRInt32 *aSelOffset, PRInt32 *aSelLength)
{
nsresult result = NS_OK;
if (!aSelStatus || !aSelOffset || !aSelLength)
return NS_ERROR_NULL_POINTER;
LOCK_DOC(this);
mIteratorStatus = nsTextServicesDocument::eIsDone;
*aSelStatus = nsITextServicesDocument::eBlockNotFound;
*aSelOffset = *aSelLength = -1;
if (!mSelCon || !mIterator)
{
UNLOCK_DOC(this);
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsISelection> selection;
PRBool isCollapsed = PR_FALSE;
result = mSelCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
result = selection->GetIsCollapsed( &isCollapsed);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
nsCOMPtr<nsIContentIterator> iter;
nsCOMPtr<nsIDOMRange> range;
nsCOMPtr<nsIDOMNode> parent;
PRInt32 i, rangeCount, offset;
if (isCollapsed)
{
// We have a caret. Check if the caret is in a text node.
// If it is, make the text node's block the current block.
// If the caret isn't in a text node, search backwards in
// the document, till we find a text node.
result = selection->GetRangeAt(0, getter_AddRefs(range));
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
if (!range)
{
UNLOCK_DOC(this);
return NS_ERROR_FAILURE;
}
result = range->GetStartContainer(getter_AddRefs(parent));
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
if (!parent)
{
UNLOCK_DOC(this);
return NS_ERROR_FAILURE;
}
result = range->GetStartOffset(&offset);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
if (IsTextNode(parent))
{
// The caret is in a text node. Find the beginning
// of the text block containing this text node and
// return.
nsCOMPtr<nsIContent> content = do_QueryInterface(parent);
if (!content)
{
UNLOCK_DOC(this);
return NS_ERROR_FAILURE;
}
result = mIterator->PositionAt(content);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
result = FirstTextNodeInCurrentBlock(mIterator);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
mIteratorStatus = nsTextServicesDocument::eValid;
result = CreateOffsetTable(&mOffsetTable, mIterator, &mIteratorStatus,
mExtent, nsnull);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
result = GetSelection(aSelStatus, aSelOffset, aSelLength);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
if (*aSelStatus == nsITextServicesDocument::eBlockContains)
result = SetSelectionInternal(*aSelOffset, *aSelLength, PR_FALSE);
}
else
{
// The caret isn't in a text node. Create an iterator
// based on a range that extends from the beginning of
// the document, to the current caret position, then
// walk backwards till you find a text node, then find
// the beginning of the block.
result = CreateDocumentContentRootToNodeOffsetRange(parent, offset, PR_TRUE, getter_AddRefs(range));
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
result = range->GetCollapsed(&isCollapsed);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
if (isCollapsed)
{
// If we get here, the range is collapsed because there is nothing before
// the caret! Just return NS_OK;
UNLOCK_DOC(this);
return NS_OK;
}
result = CreateContentIterator(range, getter_AddRefs(iter));
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
iter->Last();
nsCOMPtr<nsIContent> content;
while (!iter->IsDone())
{
content = do_QueryInterface(iter->GetCurrentNode());
if (IsTextNode(content))
break;
content = nsnull;
iter->Prev();
}
if (!content)
{
UNLOCK_DOC(this);
return NS_OK;
}
result = mIterator->PositionAt(content);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
result = FirstTextNodeInCurrentBlock(mIterator);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
mIteratorStatus = nsTextServicesDocument::eValid;
result = CreateOffsetTable(&mOffsetTable, mIterator, &mIteratorStatus,
mExtent, nsnull);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
result = GetSelection(aSelStatus, aSelOffset, aSelLength);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
}
UNLOCK_DOC(this);
return result;
}
// If we get here, we have an uncollapsed selection!
// Look through each range in the selection till you
// find the first text node. If you find one, find the
// beginning of it's text block, and make it the current
// block.
result = selection->GetRangeCount(&rangeCount);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
NS_ASSERTION(rangeCount > 0, "Unexpected range count!");
if (rangeCount <= 0)
{
UNLOCK_DOC(this);
return NS_OK;
}
// XXX: We may need to add some code here to make sure
// the ranges are sorted in document appearance order!
for (i = 0; i < rangeCount; i++)
{
// Get the i'th range from the selection.
result = selection->GetRangeAt(i, getter_AddRefs(range));
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
// Create an iterator for the range.
result = CreateContentIterator(range, getter_AddRefs(iter));
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
iter->First();
// Now walk through the range till we find a text node.
while (!iter->IsDone())
{
nsCOMPtr<nsIContent> content = do_QueryInterface(iter->GetCurrentNode());
if (IsTextNode(content))
{
// We found a text node, so position the document's
// iterator at the beginning of the block, then get
// the selection in terms of the string offset.
result = mIterator->PositionAt(content);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
result = FirstTextNodeInCurrentBlock(mIterator);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
mIteratorStatus = nsTextServicesDocument::eValid;
result = CreateOffsetTable(&mOffsetTable, mIterator, &mIteratorStatus,
mExtent, nsnull);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
result = GetSelection(aSelStatus, aSelOffset, aSelLength);
UNLOCK_DOC(this);
return result;
}
iter->Next();
}
}
// If we get here, we didn't find any text node in the selection!
// Create a range that extends from the beginning of the selection,
// to the beginning of the document, then iterate backwards through
// it till you find a text node!
result = selection->GetRangeAt(0, getter_AddRefs(range));
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
if (!range)
{
UNLOCK_DOC(this);
return NS_ERROR_FAILURE;
}
result = range->GetStartContainer(getter_AddRefs(parent));
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
if (!parent)
{
UNLOCK_DOC(this);
return NS_ERROR_FAILURE;
}
result = range->GetStartOffset(&offset);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
result = CreateDocumentContentRootToNodeOffsetRange(parent, offset, PR_TRUE, getter_AddRefs(range));
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
result = range->GetCollapsed(&isCollapsed);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
if (isCollapsed)
{
// If we get here, the range is collapsed because there is nothing before
// the current selection! Just return NS_OK;
UNLOCK_DOC(this);
return NS_OK;
}
result = CreateContentIterator(range, getter_AddRefs(iter));
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
iter->Last();
while (!iter->IsDone())
{
nsCOMPtr<nsIContent> content = do_QueryInterface(iter->GetCurrentNode());
if (IsTextNode(content))
{
// We found a text node! Adjust the document's iterator to point
// to the beginning of it's text block, then get the current selection.
result = mIterator->PositionAt(content);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
result = FirstTextNodeInCurrentBlock(mIterator);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
mIteratorStatus = nsTextServicesDocument::eValid;
result = CreateOffsetTable(&mOffsetTable, mIterator, &mIteratorStatus,
mExtent, nsnull);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
result = GetSelection(aSelStatus, aSelOffset, aSelLength);
UNLOCK_DOC(this);
return result;
}
iter->Prev();
}
// If we get here, we didn't find any block before or inside
// the selection! Just return OK.
UNLOCK_DOC(this);
return NS_OK;
}
// XXX: CODE BLOAT ALERT. FirstSelectedBlock() and LastSelectedBlock()
// are almost identical! Later, when we have time, we should try
// and combine them into one method.
NS_IMETHODIMP
nsTextServicesDocument::LastSelectedBlock(TSDBlockSelectionStatus *aSelStatus,
PRInt32 *aSelOffset,
@ -2416,75 +1816,6 @@ nsTextServicesDocument::InsertText(const nsString *aText)
return result;
}
NS_IMETHODIMP
nsTextServicesDocument::SetDisplayStyle(TSDDisplayStyle aStyle)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsTextServicesDocument::GetDOMRangeFor(PRInt32 aOffset, PRInt32 aLength, nsIDOMRange** aRange)
{
if (!mSelCon || aOffset < 0 || aLength < 0)
return NS_ERROR_FAILURE;
nsIDOMNode *sNode = 0, *eNode = 0;
PRInt32 i, sOffset = 0, eOffset = 0;
OffsetEntry *entry;
// Find the start
for (i = 0; !sNode && i < mOffsetTable.Count(); i++)
{
entry = (OffsetEntry *)mOffsetTable[i];
if (entry->mIsValid)
{
if (entry->mIsInsertedText)
{
if (entry->mStrOffset == aOffset)
{
sNode = entry->mNode;
sOffset = entry->mNodeOffset + entry->mLength;
}
}
else if (aOffset >= entry->mStrOffset && aOffset <= entry->mStrOffset + entry->mLength)
{
sNode = entry->mNode;
sOffset = entry->mNodeOffset + aOffset - entry->mStrOffset;
}
}
}
if (!sNode)
return NS_ERROR_FAILURE;
// Now find the end
PRInt32 endOffset = aOffset + aLength;
for (i = mOffsetTable.Count() - 1; !eNode && i >= 0; i--)
{
entry = (OffsetEntry *)mOffsetTable[i];
if (entry->mIsValid)
{
if (entry->mIsInsertedText)
{
if (entry->mStrOffset == eOffset)
{
eNode = entry->mNode;
eOffset = entry->mNodeOffset + entry->mLength;
}
}
else if (endOffset >= entry->mStrOffset && endOffset <= entry->mStrOffset + entry->mLength)
{
eNode = entry->mNode;
eOffset = entry->mNodeOffset + endOffset - entry->mStrOffset;
}
}
}
return CreateRange(sNode, sOffset, eNode, eOffset, aRange);
}
nsresult
nsTextServicesDocument::InsertNode(nsIDOMNode *aNode,
nsIDOMNode *aParent,

View File

@ -138,18 +138,13 @@ public:
NS_DECL_ISUPPORTS
/* nsITextServicesDocument method implementations. */
NS_IMETHOD InitWithDocument(nsIDOMDocument *aDOMDocument, nsIPresShell *aPresShell);
NS_IMETHOD InitWithEditor(nsIEditor *aEditor);
NS_IMETHOD GetDocument(nsIDOMDocument **aDoc);
NS_IMETHOD SetExtent(nsIDOMRange* aDOMRange);
NS_IMETHOD GetExtent(nsIDOMRange** aDOMRange);
NS_IMETHOD ExpandRangeToWordBoundaries(nsIDOMRange *aRange);
NS_IMETHOD SetFilter(nsITextServicesFilter *aFilter);
NS_IMETHOD CanEdit(PRBool *aCanEdit);
NS_IMETHOD GetCurrentTextBlock(nsString *aStr);
NS_IMETHOD FirstBlock();
NS_IMETHOD LastBlock();
NS_IMETHOD FirstSelectedBlock(TSDBlockSelectionStatus *aSelStatus, PRInt32 *aSelOffset, PRInt32 *aSelLength);
NS_IMETHOD LastSelectedBlock(TSDBlockSelectionStatus *aSelStatus, PRInt32 *aSelOffset, PRInt32 *aSelLength);
NS_IMETHOD PrevBlock();
NS_IMETHOD NextBlock();
@ -158,8 +153,6 @@ public:
NS_IMETHOD ScrollSelectionIntoView();
NS_IMETHOD DeleteSelection();
NS_IMETHOD InsertText(const nsString *aText);
NS_IMETHOD SetDisplayStyle(TSDDisplayStyle aStyle);
NS_IMETHOD GetDOMRangeFor(PRInt32 aOffset, PRInt32 aLength, nsIDOMRange** aRange);
/* nsIEditActionListener method implementations. */
nsresult InsertNode(nsIDOMNode * aNode,