From 872ded6605e304e2dc7d9b1074053dbd0f7987f9 Mon Sep 17 00:00:00 2001 From: "kin%netscape.com" Date: Thu, 9 Jan 2003 06:06:17 +0000 Subject: [PATCH] Fix for bug #88049: Support .selectionStart & friends for textareas Patch by petejc@optonline.net and kin@netscape.com mozilla/content/html/content/src/nsHTMLInputElement.cpp mozilla/content/html/content/src/nsHTMLTextAreaElement.cpp mozilla/dom/public/idl/html/nsIDOMNSHTMLTextAreaElement.idl mozilla/layout/html/forms/src/nsTextControlFrame.cpp mozilla/layout/html/forms/src/nsTextControlFrame.h Re-implemented selectionStart, selectionEnd, setSelectionRange() and various utility methods in nsTextControlFrame to support multi-line text widgets. r=jkeiser@netscape.com sr=sfraser@netscape.com --- .../html/content/src/nsHTMLInputElement.cpp | 38 +- .../content/src/nsHTMLTextAreaElement.cpp | 94 +-- .../idl/html/nsIDOMNSHTMLTextAreaElement.idl | 3 + layout/forms/nsTextControlFrame.cpp | 559 ++++++++++-------- layout/forms/nsTextControlFrame.h | 9 +- layout/html/forms/src/nsTextControlFrame.cpp | 559 ++++++++++-------- layout/html/forms/src/nsTextControlFrame.h | 9 +- 7 files changed, 689 insertions(+), 582 deletions(-) diff --git a/content/html/content/src/nsHTMLInputElement.cpp b/content/html/content/src/nsHTMLInputElement.cpp index 8f293296bd70..a32c6596bd0b 100644 --- a/content/html/content/src/nsHTMLInputElement.cpp +++ b/content/html/content/src/nsHTMLInputElement.cpp @@ -109,8 +109,6 @@ static NS_DEFINE_CID(kXULControllersCID, NS_XULCONTROLLERS_CID); -typedef nsITextControlFrame textControlPlace; - // // Accessors for mBitField // @@ -2079,17 +2077,18 @@ NS_IMETHODIMP nsHTMLInputElement::SetSelectionRange(PRInt32 aSelectionStart, PRInt32 aSelectionEnd) { + nsresult rv = NS_ERROR_FAILURE; nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE); if (formControlFrame) { - nsCOMPtr - textControlFrame(do_QueryInterface(formControlFrame)); + nsITextControlFrame* textControlFrame = nsnull; + CallQueryInterface(formControlFrame, &textControlFrame); if (textControlFrame) - textControlFrame->SetSelectionRange(aSelectionStart, aSelectionEnd); + rv = textControlFrame->SetSelectionRange(aSelectionStart, aSelectionEnd); } - return NS_OK; + return rv; } NS_IMETHODIMP @@ -2104,17 +2103,18 @@ nsHTMLInputElement::GetSelectionStart(PRInt32* aSelectionStart) NS_IMETHODIMP nsHTMLInputElement::SetSelectionStart(PRInt32 aSelectionStart) { + nsresult rv = NS_ERROR_FAILURE; nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE); if (formControlFrame) { - nsCOMPtr - textControlFrame(do_QueryInterface(formControlFrame)); + nsITextControlFrame* textControlFrame = nsnull; + CallQueryInterface(formControlFrame, &textControlFrame); if (textControlFrame) - textControlFrame->SetSelectionStart(aSelectionStart); + rv = textControlFrame->SetSelectionStart(aSelectionStart); } - return NS_OK; + return rv; } NS_IMETHODIMP @@ -2130,34 +2130,36 @@ nsHTMLInputElement::GetSelectionEnd(PRInt32* aSelectionEnd) NS_IMETHODIMP nsHTMLInputElement::SetSelectionEnd(PRInt32 aSelectionEnd) { + nsresult rv = NS_ERROR_FAILURE; nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE); if (formControlFrame) { - nsCOMPtr - textControlFrame(do_QueryInterface(formControlFrame)); + nsITextControlFrame* textControlFrame = nsnull; + CallQueryInterface(formControlFrame, &textControlFrame); if (textControlFrame) - textControlFrame->SetSelectionEnd(aSelectionEnd); + rv = textControlFrame->SetSelectionEnd(aSelectionEnd); } - return NS_OK; + return rv; } nsresult nsHTMLInputElement::GetSelectionRange(PRInt32* aSelectionStart, PRInt32* aSelectionEnd) { + nsresult rv = NS_ERROR_FAILURE; nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE); if (formControlFrame) { - nsCOMPtr - textControlFrame(do_QueryInterface(formControlFrame)); + nsITextControlFrame* textControlFrame = nsnull; + CallQueryInterface(formControlFrame, &textControlFrame); if (textControlFrame) - textControlFrame->GetSelectionRange(aSelectionStart, aSelectionEnd); + rv = textControlFrame->GetSelectionRange(aSelectionStart, aSelectionEnd); } - return NS_OK; + return rv; } NS_IMETHODIMP diff --git a/content/html/content/src/nsHTMLTextAreaElement.cpp b/content/html/content/src/nsHTMLTextAreaElement.cpp index 0ce5b1b1a7ec..b5c5727d2907 100644 --- a/content/html/content/src/nsHTMLTextAreaElement.cpp +++ b/content/html/content/src/nsHTMLTextAreaElement.cpp @@ -165,6 +165,7 @@ protected: nsresult SetValueInternal(const nsAString& aValue, nsITextControlFrame* aFrame); + nsresult GetSelectionRange(PRInt32* aSelectionStart, PRInt32* aSelectionEnd); }; nsresult @@ -839,64 +840,89 @@ NS_IMETHODIMP nsHTMLTextAreaElement::GetSelectionStart(PRInt32 *aSelectionStart) { NS_ENSURE_ARG_POINTER(aSelectionStart); - nsCOMPtr formControlFrame = getter_AddRefs(GetFormControlFrame(PR_TRUE)); - - nsCOMPtr - textControlFrame(do_QueryInterface(formControlFrame)); - - if (textControlFrame) { - PRInt32 selectionEnd; - return textControlFrame->GetSelectionRange(aSelectionStart, &selectionEnd); - } - - return NS_OK; + + PRInt32 selEnd; + return GetSelectionRange(aSelectionStart, &selEnd); } NS_IMETHODIMP nsHTMLTextAreaElement::SetSelectionStart(PRInt32 aSelectionStart) { - nsCOMPtr formControlFrame = getter_AddRefs(GetFormControlFrame(PR_TRUE)); + nsresult rv = NS_ERROR_FAILURE; + nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE); - nsCOMPtr - textControlFrame(do_QueryInterface(formControlFrame)); + if (formControlFrame){ + nsITextControlFrame* textControlFrame = nsnull; + CallQueryInterface(formControlFrame, &textControlFrame); - if (textControlFrame) - textControlFrame->SetSelectionStart(aSelectionStart); + if (textControlFrame) + rv = textControlFrame->SetSelectionStart(aSelectionStart); + } - return NS_OK; + return rv; } NS_IMETHODIMP nsHTMLTextAreaElement::GetSelectionEnd(PRInt32 *aSelectionEnd) { NS_ENSURE_ARG_POINTER(aSelectionEnd); - nsCOMPtr formControlFrame = getter_AddRefs(GetFormControlFrame(PR_TRUE)); - - nsCOMPtr - textControlFrame(do_QueryInterface(formControlFrame)); - - if (textControlFrame) { - PRInt32 selectionStart; - return textControlFrame->GetSelectionRange(&selectionStart, aSelectionEnd); - } - - return NS_OK; + + PRInt32 selStart; + return GetSelectionRange(&selStart, aSelectionEnd); } NS_IMETHODIMP nsHTMLTextAreaElement::SetSelectionEnd(PRInt32 aSelectionEnd) { - nsCOMPtr formControlFrame = getter_AddRefs(GetFormControlFrame(PR_TRUE)); + nsresult rv = NS_ERROR_FAILURE; + nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE); - nsCOMPtr - textControlFrame(do_QueryInterface(formControlFrame)); + if (formControlFrame) { + nsITextControlFrame* textControlFrame = nsnull; + CallQueryInterface(formControlFrame, &textControlFrame); - if (textControlFrame) - textControlFrame->SetSelectionEnd(aSelectionEnd); + if (textControlFrame) + rv = textControlFrame->SetSelectionEnd(aSelectionEnd); + } - return NS_OK; + return rv; } +nsresult +nsHTMLTextAreaElement::GetSelectionRange(PRInt32* aSelectionStart, + PRInt32* aSelectionEnd) +{ + nsresult rv = NS_ERROR_FAILURE; + nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE); + + if (formControlFrame) { + nsITextControlFrame* textControlFrame = nsnull; + CallQueryInterface(formControlFrame, &textControlFrame); + + if (textControlFrame) + rv = textControlFrame->GetSelectionRange(aSelectionStart, aSelectionEnd); + } + + return rv; +} + +NS_IMETHODIMP +nsHTMLTextAreaElement::SetSelectionRange(PRInt32 aSelectionStart, PRInt32 aSelectionEnd) +{ + nsresult rv = NS_ERROR_FAILURE; + nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE); + + if (formControlFrame) { + nsITextControlFrame* textControlFrame = nsnull; + CallQueryInterface(formControlFrame, &textControlFrame); + + if (textControlFrame) + rv = textControlFrame->SetSelectionRange(aSelectionStart, aSelectionEnd); + } + + return rv; +} + nsresult nsHTMLTextAreaElement::Reset() { diff --git a/dom/public/idl/html/nsIDOMNSHTMLTextAreaElement.idl b/dom/public/idl/html/nsIDOMNSHTMLTextAreaElement.idl index 290387687bec..57c279e7d1fa 100644 --- a/dom/public/idl/html/nsIDOMNSHTMLTextAreaElement.idl +++ b/dom/public/idl/html/nsIDOMNSHTMLTextAreaElement.idl @@ -51,4 +51,7 @@ interface nsIDOMNSHTMLTextAreaElement : nsISupports readonly attribute long textLength; attribute long selectionStart; attribute long selectionEnd; + + void setSelectionRange(in long selectionStart, + in long selectionEnd); }; diff --git a/layout/forms/nsTextControlFrame.cpp b/layout/forms/nsTextControlFrame.cpp index a628bb4a996e..5bb9f0b20253 100644 --- a/layout/forms/nsTextControlFrame.cpp +++ b/layout/forms/nsTextControlFrame.cpp @@ -1141,7 +1141,8 @@ NS_IMETHODIMP nsTextControlFrame::GetAccessible(nsIAccessible** aAccessible) } #endif -nsTextControlFrame::nsTextControlFrame(nsIPresShell* aShell):nsStackFrame(aShell) +nsTextControlFrame::nsTextControlFrame(nsIPresShell* aShell) + : nsStackFrame(aShell) { mUseEditor = PR_FALSE; mIsProcessing = PR_FALSE; @@ -2189,7 +2190,8 @@ NS_IMETHODIMP nsTextControlFrame::SetProperty(nsIPresContext* aPresContext, nsIA else if (nsHTMLAtoms::select == aName && mSelCon) { // select all the text - SelectAllContents(); + if (mEditor) + mEditor->SelectAll(); } mIsProcessing = PR_FALSE; } @@ -2238,178 +2240,77 @@ nsTextControlFrame::GetTextLength(PRInt32* aTextLength) return NS_OK; } - - -NS_IMETHODIMP -nsTextControlFrame::GetFirstTextNode(nsIDOMCharacterData* *aFirstTextNode) -{ - if (!mEditor) - return NS_ERROR_NOT_INITIALIZED; - nsCOMPtr rootElement; - mEditor->GetRootElement(getter_AddRefs(rootElement)); - *aFirstTextNode = nsnull; - - nsCOMPtr rootNode = do_QueryInterface(rootElement); - if (!rootNode) return NS_ERROR_FAILURE; - - // for a text widget, the text of the document is in a single - // text node under the body. Let's make sure that's true. - nsCOMPtr childNodesList; - rootNode->GetChildNodes(getter_AddRefs(childNodesList)); - if (!childNodesList) - { - NS_WARNING("rootNode has no text node list"); - return NS_ERROR_FAILURE; - } - - PRUint32 numChildNodes = 0; - childNodesList->GetLength(&numChildNodes); - - nsCOMPtr firstChild; - nsresult rv = rootNode->GetFirstChild(getter_AddRefs(firstChild)); - if (NS_FAILED(rv)) return rv; - if (!firstChild) return NS_ERROR_FAILURE; - - nsCOMPtr charDataNode = do_QueryInterface(firstChild, &rv); - if (NS_FAILED(rv)) return rv; - - NS_ADDREF(*aFirstTextNode = charDataNode); - return NS_OK; -} - - -nsresult -nsTextControlFrame::SelectAllContents() -{ - nsresult rv; - - if (IsSingleLineTextControl()) - { - rv = SetSelectionRange(0, eSelectToEnd); - } - else - { - // we have to select all - if (!mEditor) - return NS_ERROR_NOT_INITIALIZED; - NS_ASSERTION(mEditor, "Should have an editor here"); - rv = mEditor->SelectAll(); - } - - return rv; -} - - nsresult nsTextControlFrame::SetSelectionEndPoints(PRInt32 aSelStart, PRInt32 aSelEnd) { - NS_ASSERTION(IsSingleLineTextControl() || IsTextArea(), "Should only call this on a single line input"); - NS_ASSERTION(mEditor, "Should have an editor here"); - NS_ASSERTION(mTextSelImpl,"selection not found!"); + NS_ASSERTION(aSelStart <= aSelEnd, "Invalid selection offsets!"); - nsCOMPtr firstTextNode; - nsresult rv = GetFirstTextNode(getter_AddRefs(firstTextNode)); - if (NS_FAILED(rv) || !firstTextNode) - { - // probably an empty document. not an error - return NS_OK; + if (aSelStart > aSelEnd) + return NS_ERROR_FAILURE; + + nsCOMPtr startNode, endNode; + PRInt32 startOffset, endOffset; + + // Calculate the selection start point. + + nsresult rv = OffsetToDOMPoint(aSelStart, getter_AddRefs(startNode), &startOffset); + + NS_ENSURE_SUCCESS(rv, rv); + + if (aSelStart == aSelEnd) { + // Collapsed selection, so start and end are the same! + endNode = startNode; + endOffset = startOffset; } - - nsCOMPtr firstNode = do_QueryInterface(firstTextNode, &rv); - if (!firstNode) return rv; - - // constrain the selection to this node - PRUint32 nodeLengthU; - firstTextNode->GetLength(&nodeLengthU); - PRInt32 nodeLength = (PRInt32)nodeLengthU; - + else { + // Selection isn't collapsed so we have to calculate + // the end point too. + + rv = OffsetToDOMPoint(aSelEnd, getter_AddRefs(endNode), &endOffset); + + NS_ENSURE_SUCCESS(rv, rv); + } + + // Create a new range to represent the new selection. + // Note that we use a new range to avoid having to do + // isIncreasing checks to avoid possible errors. + + nsCOMPtr range; + + range = do_CreateInstance(kRangeCID); + NS_ENSURE_TRUE(range, NS_ERROR_FAILURE); + + rv = range->SetStart(startNode, startOffset); + NS_ENSURE_SUCCESS(rv, rv); + + rv = range->SetEnd(endNode, endOffset); + NS_ENSURE_SUCCESS(rv, rv); + + // Get the selection, clear it and add the new range to it! + nsCOMPtr selection; - mTextSelImpl->GetSelection(nsISelectionController::SELECTION_NORMAL,getter_AddRefs(selection)); - if (!selection) return NS_ERROR_FAILURE; + mTextSelImpl->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection)); + NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE); - // are we setting both start and end? - if (aSelStart != eIgnoreSelect && aSelEnd != eIgnoreSelect) - { - if (aSelStart == eSelectToEnd || aSelStart > nodeLength) - aSelStart = nodeLength; - if (aSelStart < 0) - aSelStart = 0; + rv = selection->RemoveAllRanges(); - if (aSelEnd == eSelectToEnd || aSelEnd > nodeLength) - aSelEnd = nodeLength; - if (aSelEnd < 0) - aSelEnd = 0; + NS_ENSURE_SUCCESS(rv, rv); - // remove existing ranges - selection->RemoveAllRanges(); - - nsCOMPtr selectionRange(do_CreateInstance(kRangeCID,&rv)); - if (NS_FAILED(rv)) - return rv; - - selectionRange->SetStart(firstTextNode, aSelStart); - selectionRange->SetEnd(firstTextNode, aSelEnd); - - selection->AddRange(selectionRange); - } - else // we're setting either start or end but not both - { - // does a range exist? - nsCOMPtr firstRange; - selection->GetRangeAt(0, getter_AddRefs(firstRange)); - PRBool mustAdd = PR_FALSE; - PRInt32 selStart = 0, selEnd = 0; - - if (firstRange) - { - firstRange->GetStartOffset(&selStart); - firstRange->GetEndOffset(&selEnd); - } - else - { - // no range. Make a new one. - firstRange = do_CreateInstance(kRangeCID,&rv); - if (NS_FAILED(rv)) - return rv; - mustAdd = PR_TRUE; - } - - if (aSelStart == eSelectToEnd) - selStart = nodeLength; - else if (aSelStart != eIgnoreSelect) - selStart = aSelStart; - - if (aSelEnd == eSelectToEnd) - selEnd = nodeLength; - else if (aSelEnd != eIgnoreSelect) - selEnd = aSelEnd; - - // swap them - if (selEnd < selStart) - { - PRInt32 temp = selStart; - selStart = selEnd; - selEnd = temp; - } - - firstRange->SetStart(firstTextNode, selStart); - firstRange->SetEnd(firstTextNode, selEnd); - if (mustAdd) - selection->AddRange(firstRange); - } - - return NS_OK; + return selection->AddRange(range); } NS_IMETHODIMP nsTextControlFrame::SetSelectionRange(PRInt32 aSelStart, PRInt32 aSelEnd) { - if (!IsSingleLineTextControl()) return NS_ERROR_NOT_IMPLEMENTED; - - // make sure we have an editor - if (!mEditor) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_INITIALIZED); + if (aSelStart > aSelEnd) { + // Simulate what we'd see SetSelectionStart() was called, followed + // by a SetSelectionEnd(). + + aSelStart = aSelEnd; + } + return SetSelectionEndPoints(aSelStart, aSelEnd); } @@ -2417,122 +2318,266 @@ nsTextControlFrame::SetSelectionRange(PRInt32 aSelStart, PRInt32 aSelEnd) NS_IMETHODIMP nsTextControlFrame::SetSelectionStart(PRInt32 aSelectionStart) { - if (!IsSingleLineTextControl() && !IsTextArea()) return NS_ERROR_NOT_IMPLEMENTED; + NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_INITIALIZED); - // make sure we have an editor - if (!mEditor) - return NS_ERROR_NOT_INITIALIZED; + PRInt32 selStart = 0, selEnd = 0; + + nsresult rv = GetSelectionRange(&selStart, &selEnd); + NS_ENSURE_SUCCESS(rv, rv); + + if (aSelectionStart > selEnd) { + // Collapse to the new start point. + selEnd = aSelectionStart; + } + + selStart = aSelectionStart; - return SetSelectionEndPoints(aSelectionStart, eIgnoreSelect); + return SetSelectionEndPoints(selStart, selEnd); } NS_IMETHODIMP nsTextControlFrame::SetSelectionEnd(PRInt32 aSelectionEnd) { - if (!IsSingleLineTextControl() && !IsTextArea()) return NS_ERROR_NOT_IMPLEMENTED; - - // make sure we have an editor - if (!mEditor) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_INITIALIZED); - return SetSelectionEndPoints(eIgnoreSelect, aSelectionEnd); + PRInt32 selStart = 0, selEnd = 0; + + nsresult rv = GetSelectionRange(&selStart, &selEnd); + NS_ENSURE_SUCCESS(rv, rv); + + if (aSelectionEnd < selStart) { + // Collapse to the new end point. + selStart = aSelectionEnd; + } + + selEnd = aSelectionEnd; + + return SetSelectionEndPoints(selStart, selEnd); } +nsresult +nsTextControlFrame::DOMPointToOffset(nsIDOMNode* aNode, + PRInt32 aNodeOffset, + PRInt32* aResult) +{ + NS_ENSURE_ARG_POINTER(aNode && aResult); + + *aResult = 0; + + nsCOMPtr rootElement; + mEditor->GetRootElement(getter_AddRefs(rootElement)); + nsCOMPtr rootNode(do_QueryInterface(rootElement)); + + NS_ENSURE_TRUE(rootNode, NS_ERROR_FAILURE); + + nsCOMPtr nodeList; + + nsresult rv = rootNode->GetChildNodes(getter_AddRefs(nodeList)); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(nodeList, NS_ERROR_FAILURE); + + PRUint32 length = 0; + rv = nodeList->GetLength(&length); + NS_ENSURE_SUCCESS(rv, rv); + + if (!length || aNodeOffset < 0) + return NS_OK; + + PRInt32 i, textOffset = 0; + + for (i = 0; i < length; i++) { + if (rootNode == aNode && i == aNodeOffset) { + *aResult = textOffset; + return NS_OK; + } + + nsCOMPtr item; + rv = nodeList->Item(i, getter_AddRefs(item)); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(item, NS_ERROR_FAILURE); + + nsCOMPtr domText(do_QueryInterface(item)); + + if (domText) { + PRUint32 textLength = 0; + + rv = domText->GetLength(&textLength); + NS_ENSURE_SUCCESS(rv, rv); + + if (item == aNode) { + NS_ASSERTION((aNodeOffset >= 0 && aNodeOffset <= textLength), + "Invalid aNodeOffset!"); + *aResult = textOffset + aNodeOffset; + return NS_OK; + } + + textOffset += textLength; + } + else { + // Must be a BR node, count it as a newline. + + ++textOffset; + } + } + + NS_ASSERTION((aNode == rootNode && aNodeOffset == length), + "Invalide node offset!"); + + *aResult = textOffset; + + return NS_OK; +} + +nsresult +nsTextControlFrame::OffsetToDOMPoint(PRInt32 aOffset, + nsIDOMNode** aResult, + PRInt32* aPosition) +{ + NS_ENSURE_ARG_POINTER(aResult && aPosition); + + *aResult = nsnull; + *aPosition = 0; + + nsCOMPtr rootElement; + mEditor->GetRootElement(getter_AddRefs(rootElement)); + nsCOMPtr rootNode(do_QueryInterface(rootElement)); + + NS_ENSURE_TRUE(rootNode, NS_ERROR_FAILURE); + + nsCOMPtr nodeList; + + nsresult rv = rootNode->GetChildNodes(getter_AddRefs(nodeList)); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(nodeList, NS_ERROR_FAILURE); + + PRUint32 length = 0; + + rv = nodeList->GetLength(&length); + NS_ENSURE_SUCCESS(rv, rv); + + if (!length || aOffset < 0) { + *aPosition = 0; + *aResult = rootNode; + NS_ADDREF(*aResult); + return NS_OK; + } + + PRInt32 textOffset = 0; + PRUint32 lastIndex = length - 1; + + for (PRUint32 i=0; i item; + rv = nodeList->Item(i, getter_AddRefs(item)); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(item, NS_ERROR_FAILURE); + + nsCOMPtr domText(do_QueryInterface(item)); + + if (domText) { + PRUint32 textLength = 0; + + rv = domText->GetLength(&textLength); + NS_ENSURE_SUCCESS(rv, rv); + + // Check if aOffset falls within this range. + if (aOffset >= textOffset && aOffset <= textOffset+(PRInt32)textLength) { + *aPosition = aOffset - textOffset; + *aResult = item; + NS_ADDREF(*aResult); + return NS_OK; + } + + textOffset += textLength; + + // If there aren't any more siblings after this text node, + // return the point at the end of this text node! + + if (i == lastIndex) { + *aPosition = textLength; + *aResult = item; + NS_ADDREF(*aResult); + return NS_OK; + } + } + else { + // Must be a BR node, count it as a newline. + + if (aOffset == textOffset || i == lastIndex) { + // We've found the correct position, or aOffset takes us + // beyond the last child under rootNode, just return the point + // under rootNode that is in front of this br. + + *aPosition = i; + *aResult = rootNode; + NS_ADDREF(*aResult); + return NS_OK; + } + + ++textOffset; + } + } + + NS_ASSERTION(0, "We should never get here!"); + + return NS_ERROR_FAILURE; +} NS_IMETHODIMP nsTextControlFrame::GetSelectionRange(PRInt32* aSelectionStart, PRInt32* aSelectionEnd) { - NS_ENSURE_ARG_POINTER((aSelectionStart && aSelectionEnd)); + // make sure we have an editor + NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_INITIALIZED); - // make sure we have an editor - if (!mEditor) - return NS_ERROR_NOT_INITIALIZED; + *aSelectionStart = 0; + *aSelectionEnd = 0; - *aSelectionStart = 0; - *aSelectionEnd = 0; + nsCOMPtr selection; + nsresult rv = mTextSelImpl->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection)); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE); - nsCOMPtr selection; - mTextSelImpl->GetSelection(nsISelectionController::SELECTION_NORMAL,getter_AddRefs(selection)); - if (!selection) return NS_ERROR_FAILURE; + PRInt32 numRanges = 0; + selection->GetRangeCount(&numRanges); - // we should have only zero or one range - PRInt32 numRanges = 0; - selection->GetRangeCount(&numRanges); - if (numRanges > 1) - { - NS_ASSERTION(0, "Found more than on range in GetSelectionRange"); - } - - if (numRanges != 0) - { - nsCOMPtr firstRange; - selection->GetRangeAt(0, getter_AddRefs(firstRange)); - if (!firstRange) - return NS_ERROR_FAILURE; - - if (IsSingleLineTextControl() || IsTextArea()) - { - firstRange->GetStartOffset(aSelectionStart); - firstRange->GetEndOffset(aSelectionEnd); - } - else//multiline - { - //mContent = parent. iterate over each child. - //when text nodes are reached add text length. - //if you find range-startoffset,startnode then mark aSelecitonStart - nsresult rv = NS_ERROR_FAILURE; - nsCOMPtr contentNode; - nsCOMPtr curNode; - contentNode = do_QueryInterface(mContent); - if (!contentNode || NS_FAILED(rv = contentNode->GetFirstChild(getter_AddRefs(curNode))) || !curNode) - return rv; - nsCOMPtr startParent; - nsCOMPtr endParent; - PRInt32 startOffset; - PRInt32 endOffset; - - firstRange->GetStartContainer(getter_AddRefs(startParent)); - firstRange->GetStartOffset(&startOffset); - firstRange->GetEndContainer(getter_AddRefs(endParent)); - firstRange->GetEndOffset(&endOffset); - - PRInt32 currentTextOffset = 0; - - while(curNode) - { - nsCOMPtr domText; - domText = do_QueryInterface(curNode); - if (contentNode == startParent) - { - if (domText) - *aSelectionStart = currentTextOffset + startOffset; - else - *aSelectionStart = currentTextOffset; - } - if (curNode == endParent) - { - if (domText) - *aSelectionEnd = currentTextOffset + endOffset; - else - *aSelectionEnd = currentTextOffset; - break; - } - if (domText) - { - PRUint32 length; - if (NS_SUCCEEDED(domText->GetLength(&length))) - currentTextOffset += length; - } - else - ++currentTextOffset; - } - if (!curNode) //something went very wrong... - { - *aSelectionEnd = *aSelectionStart;//couldnt find the end - } - } - } + if (numRanges < 1) return NS_OK; + + // We only operate on the first range in the selection! + + nsCOMPtr firstRange; + rv = selection->GetRangeAt(0, getter_AddRefs(firstRange)); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(firstRange, NS_ERROR_FAILURE); + + nsCOMPtr startNode, endNode; + PRInt32 startOffset = 0, endOffset = 0; + + // Get the start point of the range. + + rv = firstRange->GetStartContainer(getter_AddRefs(startNode)); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE); + + rv = firstRange->GetStartOffset(&startOffset); + NS_ENSURE_SUCCESS(rv, rv); + + // Get the end point of the range. + + rv = firstRange->GetEndContainer(getter_AddRefs(endNode)); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(endNode, NS_ERROR_FAILURE); + + rv = firstRange->GetEndOffset(&endOffset); + NS_ENSURE_SUCCESS(rv, rv); + + // Convert the start point to a selection offset. + + rv = DOMPointToOffset(startNode, startOffset, aSelectionStart); + NS_ENSURE_SUCCESS(rv, rv); + + // Convert the end point to a selection offset. + + return DOMPointToOffset(endNode, endOffset, aSelectionEnd); } @@ -3120,5 +3165,3 @@ nsTextControlFrame::HandleEvent(nsIPresContext* aPresContext, return nsStackFrame::HandleEvent(aPresContext, aEvent, aEventStatus); } - - diff --git a/layout/forms/nsTextControlFrame.h b/layout/forms/nsTextControlFrame.h index c06e09903230..974675d161fd 100644 --- a/layout/forms/nsTextControlFrame.h +++ b/layout/forms/nsTextControlFrame.h @@ -212,6 +212,8 @@ public: //for methods who access nsTextControlFrame directly void SetValueChanged(PRBool aValueChanged); /** Called when the frame is focused, to remember the value for onChange. */ nsresult InitFocusedValue(); + nsresult DOMPointToOffset(nsIDOMNode* aNode, PRInt32 aNodeOffset, PRInt32 *aResult); + nsresult OffsetToDOMPoint(PRInt32 aOffset, nsIDOMNode** aResult, PRInt32* aPosition); protected: @@ -289,13 +291,6 @@ protected: private: //helper methods - enum { - eIgnoreSelect = -2, - eSelectToEnd = -1 - }; - - NS_IMETHODIMP GetFirstTextNode(nsIDOMCharacterData* *aFirstTextNode); - nsresult SelectAllContents(); nsresult SetSelectionEndPoints(PRInt32 aSelStart, PRInt32 aSelEnd); private: diff --git a/layout/html/forms/src/nsTextControlFrame.cpp b/layout/html/forms/src/nsTextControlFrame.cpp index a628bb4a996e..5bb9f0b20253 100644 --- a/layout/html/forms/src/nsTextControlFrame.cpp +++ b/layout/html/forms/src/nsTextControlFrame.cpp @@ -1141,7 +1141,8 @@ NS_IMETHODIMP nsTextControlFrame::GetAccessible(nsIAccessible** aAccessible) } #endif -nsTextControlFrame::nsTextControlFrame(nsIPresShell* aShell):nsStackFrame(aShell) +nsTextControlFrame::nsTextControlFrame(nsIPresShell* aShell) + : nsStackFrame(aShell) { mUseEditor = PR_FALSE; mIsProcessing = PR_FALSE; @@ -2189,7 +2190,8 @@ NS_IMETHODIMP nsTextControlFrame::SetProperty(nsIPresContext* aPresContext, nsIA else if (nsHTMLAtoms::select == aName && mSelCon) { // select all the text - SelectAllContents(); + if (mEditor) + mEditor->SelectAll(); } mIsProcessing = PR_FALSE; } @@ -2238,178 +2240,77 @@ nsTextControlFrame::GetTextLength(PRInt32* aTextLength) return NS_OK; } - - -NS_IMETHODIMP -nsTextControlFrame::GetFirstTextNode(nsIDOMCharacterData* *aFirstTextNode) -{ - if (!mEditor) - return NS_ERROR_NOT_INITIALIZED; - nsCOMPtr rootElement; - mEditor->GetRootElement(getter_AddRefs(rootElement)); - *aFirstTextNode = nsnull; - - nsCOMPtr rootNode = do_QueryInterface(rootElement); - if (!rootNode) return NS_ERROR_FAILURE; - - // for a text widget, the text of the document is in a single - // text node under the body. Let's make sure that's true. - nsCOMPtr childNodesList; - rootNode->GetChildNodes(getter_AddRefs(childNodesList)); - if (!childNodesList) - { - NS_WARNING("rootNode has no text node list"); - return NS_ERROR_FAILURE; - } - - PRUint32 numChildNodes = 0; - childNodesList->GetLength(&numChildNodes); - - nsCOMPtr firstChild; - nsresult rv = rootNode->GetFirstChild(getter_AddRefs(firstChild)); - if (NS_FAILED(rv)) return rv; - if (!firstChild) return NS_ERROR_FAILURE; - - nsCOMPtr charDataNode = do_QueryInterface(firstChild, &rv); - if (NS_FAILED(rv)) return rv; - - NS_ADDREF(*aFirstTextNode = charDataNode); - return NS_OK; -} - - -nsresult -nsTextControlFrame::SelectAllContents() -{ - nsresult rv; - - if (IsSingleLineTextControl()) - { - rv = SetSelectionRange(0, eSelectToEnd); - } - else - { - // we have to select all - if (!mEditor) - return NS_ERROR_NOT_INITIALIZED; - NS_ASSERTION(mEditor, "Should have an editor here"); - rv = mEditor->SelectAll(); - } - - return rv; -} - - nsresult nsTextControlFrame::SetSelectionEndPoints(PRInt32 aSelStart, PRInt32 aSelEnd) { - NS_ASSERTION(IsSingleLineTextControl() || IsTextArea(), "Should only call this on a single line input"); - NS_ASSERTION(mEditor, "Should have an editor here"); - NS_ASSERTION(mTextSelImpl,"selection not found!"); + NS_ASSERTION(aSelStart <= aSelEnd, "Invalid selection offsets!"); - nsCOMPtr firstTextNode; - nsresult rv = GetFirstTextNode(getter_AddRefs(firstTextNode)); - if (NS_FAILED(rv) || !firstTextNode) - { - // probably an empty document. not an error - return NS_OK; + if (aSelStart > aSelEnd) + return NS_ERROR_FAILURE; + + nsCOMPtr startNode, endNode; + PRInt32 startOffset, endOffset; + + // Calculate the selection start point. + + nsresult rv = OffsetToDOMPoint(aSelStart, getter_AddRefs(startNode), &startOffset); + + NS_ENSURE_SUCCESS(rv, rv); + + if (aSelStart == aSelEnd) { + // Collapsed selection, so start and end are the same! + endNode = startNode; + endOffset = startOffset; } - - nsCOMPtr firstNode = do_QueryInterface(firstTextNode, &rv); - if (!firstNode) return rv; - - // constrain the selection to this node - PRUint32 nodeLengthU; - firstTextNode->GetLength(&nodeLengthU); - PRInt32 nodeLength = (PRInt32)nodeLengthU; - + else { + // Selection isn't collapsed so we have to calculate + // the end point too. + + rv = OffsetToDOMPoint(aSelEnd, getter_AddRefs(endNode), &endOffset); + + NS_ENSURE_SUCCESS(rv, rv); + } + + // Create a new range to represent the new selection. + // Note that we use a new range to avoid having to do + // isIncreasing checks to avoid possible errors. + + nsCOMPtr range; + + range = do_CreateInstance(kRangeCID); + NS_ENSURE_TRUE(range, NS_ERROR_FAILURE); + + rv = range->SetStart(startNode, startOffset); + NS_ENSURE_SUCCESS(rv, rv); + + rv = range->SetEnd(endNode, endOffset); + NS_ENSURE_SUCCESS(rv, rv); + + // Get the selection, clear it and add the new range to it! + nsCOMPtr selection; - mTextSelImpl->GetSelection(nsISelectionController::SELECTION_NORMAL,getter_AddRefs(selection)); - if (!selection) return NS_ERROR_FAILURE; + mTextSelImpl->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection)); + NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE); - // are we setting both start and end? - if (aSelStart != eIgnoreSelect && aSelEnd != eIgnoreSelect) - { - if (aSelStart == eSelectToEnd || aSelStart > nodeLength) - aSelStart = nodeLength; - if (aSelStart < 0) - aSelStart = 0; + rv = selection->RemoveAllRanges(); - if (aSelEnd == eSelectToEnd || aSelEnd > nodeLength) - aSelEnd = nodeLength; - if (aSelEnd < 0) - aSelEnd = 0; + NS_ENSURE_SUCCESS(rv, rv); - // remove existing ranges - selection->RemoveAllRanges(); - - nsCOMPtr selectionRange(do_CreateInstance(kRangeCID,&rv)); - if (NS_FAILED(rv)) - return rv; - - selectionRange->SetStart(firstTextNode, aSelStart); - selectionRange->SetEnd(firstTextNode, aSelEnd); - - selection->AddRange(selectionRange); - } - else // we're setting either start or end but not both - { - // does a range exist? - nsCOMPtr firstRange; - selection->GetRangeAt(0, getter_AddRefs(firstRange)); - PRBool mustAdd = PR_FALSE; - PRInt32 selStart = 0, selEnd = 0; - - if (firstRange) - { - firstRange->GetStartOffset(&selStart); - firstRange->GetEndOffset(&selEnd); - } - else - { - // no range. Make a new one. - firstRange = do_CreateInstance(kRangeCID,&rv); - if (NS_FAILED(rv)) - return rv; - mustAdd = PR_TRUE; - } - - if (aSelStart == eSelectToEnd) - selStart = nodeLength; - else if (aSelStart != eIgnoreSelect) - selStart = aSelStart; - - if (aSelEnd == eSelectToEnd) - selEnd = nodeLength; - else if (aSelEnd != eIgnoreSelect) - selEnd = aSelEnd; - - // swap them - if (selEnd < selStart) - { - PRInt32 temp = selStart; - selStart = selEnd; - selEnd = temp; - } - - firstRange->SetStart(firstTextNode, selStart); - firstRange->SetEnd(firstTextNode, selEnd); - if (mustAdd) - selection->AddRange(firstRange); - } - - return NS_OK; + return selection->AddRange(range); } NS_IMETHODIMP nsTextControlFrame::SetSelectionRange(PRInt32 aSelStart, PRInt32 aSelEnd) { - if (!IsSingleLineTextControl()) return NS_ERROR_NOT_IMPLEMENTED; - - // make sure we have an editor - if (!mEditor) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_INITIALIZED); + if (aSelStart > aSelEnd) { + // Simulate what we'd see SetSelectionStart() was called, followed + // by a SetSelectionEnd(). + + aSelStart = aSelEnd; + } + return SetSelectionEndPoints(aSelStart, aSelEnd); } @@ -2417,122 +2318,266 @@ nsTextControlFrame::SetSelectionRange(PRInt32 aSelStart, PRInt32 aSelEnd) NS_IMETHODIMP nsTextControlFrame::SetSelectionStart(PRInt32 aSelectionStart) { - if (!IsSingleLineTextControl() && !IsTextArea()) return NS_ERROR_NOT_IMPLEMENTED; + NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_INITIALIZED); - // make sure we have an editor - if (!mEditor) - return NS_ERROR_NOT_INITIALIZED; + PRInt32 selStart = 0, selEnd = 0; + + nsresult rv = GetSelectionRange(&selStart, &selEnd); + NS_ENSURE_SUCCESS(rv, rv); + + if (aSelectionStart > selEnd) { + // Collapse to the new start point. + selEnd = aSelectionStart; + } + + selStart = aSelectionStart; - return SetSelectionEndPoints(aSelectionStart, eIgnoreSelect); + return SetSelectionEndPoints(selStart, selEnd); } NS_IMETHODIMP nsTextControlFrame::SetSelectionEnd(PRInt32 aSelectionEnd) { - if (!IsSingleLineTextControl() && !IsTextArea()) return NS_ERROR_NOT_IMPLEMENTED; - - // make sure we have an editor - if (!mEditor) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_INITIALIZED); - return SetSelectionEndPoints(eIgnoreSelect, aSelectionEnd); + PRInt32 selStart = 0, selEnd = 0; + + nsresult rv = GetSelectionRange(&selStart, &selEnd); + NS_ENSURE_SUCCESS(rv, rv); + + if (aSelectionEnd < selStart) { + // Collapse to the new end point. + selStart = aSelectionEnd; + } + + selEnd = aSelectionEnd; + + return SetSelectionEndPoints(selStart, selEnd); } +nsresult +nsTextControlFrame::DOMPointToOffset(nsIDOMNode* aNode, + PRInt32 aNodeOffset, + PRInt32* aResult) +{ + NS_ENSURE_ARG_POINTER(aNode && aResult); + + *aResult = 0; + + nsCOMPtr rootElement; + mEditor->GetRootElement(getter_AddRefs(rootElement)); + nsCOMPtr rootNode(do_QueryInterface(rootElement)); + + NS_ENSURE_TRUE(rootNode, NS_ERROR_FAILURE); + + nsCOMPtr nodeList; + + nsresult rv = rootNode->GetChildNodes(getter_AddRefs(nodeList)); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(nodeList, NS_ERROR_FAILURE); + + PRUint32 length = 0; + rv = nodeList->GetLength(&length); + NS_ENSURE_SUCCESS(rv, rv); + + if (!length || aNodeOffset < 0) + return NS_OK; + + PRInt32 i, textOffset = 0; + + for (i = 0; i < length; i++) { + if (rootNode == aNode && i == aNodeOffset) { + *aResult = textOffset; + return NS_OK; + } + + nsCOMPtr item; + rv = nodeList->Item(i, getter_AddRefs(item)); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(item, NS_ERROR_FAILURE); + + nsCOMPtr domText(do_QueryInterface(item)); + + if (domText) { + PRUint32 textLength = 0; + + rv = domText->GetLength(&textLength); + NS_ENSURE_SUCCESS(rv, rv); + + if (item == aNode) { + NS_ASSERTION((aNodeOffset >= 0 && aNodeOffset <= textLength), + "Invalid aNodeOffset!"); + *aResult = textOffset + aNodeOffset; + return NS_OK; + } + + textOffset += textLength; + } + else { + // Must be a BR node, count it as a newline. + + ++textOffset; + } + } + + NS_ASSERTION((aNode == rootNode && aNodeOffset == length), + "Invalide node offset!"); + + *aResult = textOffset; + + return NS_OK; +} + +nsresult +nsTextControlFrame::OffsetToDOMPoint(PRInt32 aOffset, + nsIDOMNode** aResult, + PRInt32* aPosition) +{ + NS_ENSURE_ARG_POINTER(aResult && aPosition); + + *aResult = nsnull; + *aPosition = 0; + + nsCOMPtr rootElement; + mEditor->GetRootElement(getter_AddRefs(rootElement)); + nsCOMPtr rootNode(do_QueryInterface(rootElement)); + + NS_ENSURE_TRUE(rootNode, NS_ERROR_FAILURE); + + nsCOMPtr nodeList; + + nsresult rv = rootNode->GetChildNodes(getter_AddRefs(nodeList)); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(nodeList, NS_ERROR_FAILURE); + + PRUint32 length = 0; + + rv = nodeList->GetLength(&length); + NS_ENSURE_SUCCESS(rv, rv); + + if (!length || aOffset < 0) { + *aPosition = 0; + *aResult = rootNode; + NS_ADDREF(*aResult); + return NS_OK; + } + + PRInt32 textOffset = 0; + PRUint32 lastIndex = length - 1; + + for (PRUint32 i=0; i item; + rv = nodeList->Item(i, getter_AddRefs(item)); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(item, NS_ERROR_FAILURE); + + nsCOMPtr domText(do_QueryInterface(item)); + + if (domText) { + PRUint32 textLength = 0; + + rv = domText->GetLength(&textLength); + NS_ENSURE_SUCCESS(rv, rv); + + // Check if aOffset falls within this range. + if (aOffset >= textOffset && aOffset <= textOffset+(PRInt32)textLength) { + *aPosition = aOffset - textOffset; + *aResult = item; + NS_ADDREF(*aResult); + return NS_OK; + } + + textOffset += textLength; + + // If there aren't any more siblings after this text node, + // return the point at the end of this text node! + + if (i == lastIndex) { + *aPosition = textLength; + *aResult = item; + NS_ADDREF(*aResult); + return NS_OK; + } + } + else { + // Must be a BR node, count it as a newline. + + if (aOffset == textOffset || i == lastIndex) { + // We've found the correct position, or aOffset takes us + // beyond the last child under rootNode, just return the point + // under rootNode that is in front of this br. + + *aPosition = i; + *aResult = rootNode; + NS_ADDREF(*aResult); + return NS_OK; + } + + ++textOffset; + } + } + + NS_ASSERTION(0, "We should never get here!"); + + return NS_ERROR_FAILURE; +} NS_IMETHODIMP nsTextControlFrame::GetSelectionRange(PRInt32* aSelectionStart, PRInt32* aSelectionEnd) { - NS_ENSURE_ARG_POINTER((aSelectionStart && aSelectionEnd)); + // make sure we have an editor + NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_INITIALIZED); - // make sure we have an editor - if (!mEditor) - return NS_ERROR_NOT_INITIALIZED; + *aSelectionStart = 0; + *aSelectionEnd = 0; - *aSelectionStart = 0; - *aSelectionEnd = 0; + nsCOMPtr selection; + nsresult rv = mTextSelImpl->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection)); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE); - nsCOMPtr selection; - mTextSelImpl->GetSelection(nsISelectionController::SELECTION_NORMAL,getter_AddRefs(selection)); - if (!selection) return NS_ERROR_FAILURE; + PRInt32 numRanges = 0; + selection->GetRangeCount(&numRanges); - // we should have only zero or one range - PRInt32 numRanges = 0; - selection->GetRangeCount(&numRanges); - if (numRanges > 1) - { - NS_ASSERTION(0, "Found more than on range in GetSelectionRange"); - } - - if (numRanges != 0) - { - nsCOMPtr firstRange; - selection->GetRangeAt(0, getter_AddRefs(firstRange)); - if (!firstRange) - return NS_ERROR_FAILURE; - - if (IsSingleLineTextControl() || IsTextArea()) - { - firstRange->GetStartOffset(aSelectionStart); - firstRange->GetEndOffset(aSelectionEnd); - } - else//multiline - { - //mContent = parent. iterate over each child. - //when text nodes are reached add text length. - //if you find range-startoffset,startnode then mark aSelecitonStart - nsresult rv = NS_ERROR_FAILURE; - nsCOMPtr contentNode; - nsCOMPtr curNode; - contentNode = do_QueryInterface(mContent); - if (!contentNode || NS_FAILED(rv = contentNode->GetFirstChild(getter_AddRefs(curNode))) || !curNode) - return rv; - nsCOMPtr startParent; - nsCOMPtr endParent; - PRInt32 startOffset; - PRInt32 endOffset; - - firstRange->GetStartContainer(getter_AddRefs(startParent)); - firstRange->GetStartOffset(&startOffset); - firstRange->GetEndContainer(getter_AddRefs(endParent)); - firstRange->GetEndOffset(&endOffset); - - PRInt32 currentTextOffset = 0; - - while(curNode) - { - nsCOMPtr domText; - domText = do_QueryInterface(curNode); - if (contentNode == startParent) - { - if (domText) - *aSelectionStart = currentTextOffset + startOffset; - else - *aSelectionStart = currentTextOffset; - } - if (curNode == endParent) - { - if (domText) - *aSelectionEnd = currentTextOffset + endOffset; - else - *aSelectionEnd = currentTextOffset; - break; - } - if (domText) - { - PRUint32 length; - if (NS_SUCCEEDED(domText->GetLength(&length))) - currentTextOffset += length; - } - else - ++currentTextOffset; - } - if (!curNode) //something went very wrong... - { - *aSelectionEnd = *aSelectionStart;//couldnt find the end - } - } - } + if (numRanges < 1) return NS_OK; + + // We only operate on the first range in the selection! + + nsCOMPtr firstRange; + rv = selection->GetRangeAt(0, getter_AddRefs(firstRange)); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(firstRange, NS_ERROR_FAILURE); + + nsCOMPtr startNode, endNode; + PRInt32 startOffset = 0, endOffset = 0; + + // Get the start point of the range. + + rv = firstRange->GetStartContainer(getter_AddRefs(startNode)); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE); + + rv = firstRange->GetStartOffset(&startOffset); + NS_ENSURE_SUCCESS(rv, rv); + + // Get the end point of the range. + + rv = firstRange->GetEndContainer(getter_AddRefs(endNode)); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(endNode, NS_ERROR_FAILURE); + + rv = firstRange->GetEndOffset(&endOffset); + NS_ENSURE_SUCCESS(rv, rv); + + // Convert the start point to a selection offset. + + rv = DOMPointToOffset(startNode, startOffset, aSelectionStart); + NS_ENSURE_SUCCESS(rv, rv); + + // Convert the end point to a selection offset. + + return DOMPointToOffset(endNode, endOffset, aSelectionEnd); } @@ -3120,5 +3165,3 @@ nsTextControlFrame::HandleEvent(nsIPresContext* aPresContext, return nsStackFrame::HandleEvent(aPresContext, aEvent, aEventStatus); } - - diff --git a/layout/html/forms/src/nsTextControlFrame.h b/layout/html/forms/src/nsTextControlFrame.h index c06e09903230..974675d161fd 100644 --- a/layout/html/forms/src/nsTextControlFrame.h +++ b/layout/html/forms/src/nsTextControlFrame.h @@ -212,6 +212,8 @@ public: //for methods who access nsTextControlFrame directly void SetValueChanged(PRBool aValueChanged); /** Called when the frame is focused, to remember the value for onChange. */ nsresult InitFocusedValue(); + nsresult DOMPointToOffset(nsIDOMNode* aNode, PRInt32 aNodeOffset, PRInt32 *aResult); + nsresult OffsetToDOMPoint(PRInt32 aOffset, nsIDOMNode** aResult, PRInt32* aPosition); protected: @@ -289,13 +291,6 @@ protected: private: //helper methods - enum { - eIgnoreSelect = -2, - eSelectToEnd = -1 - }; - - NS_IMETHODIMP GetFirstTextNode(nsIDOMCharacterData* *aFirstTextNode); - nsresult SelectAllContents(); nsresult SetSelectionEndPoints(PRInt32 aSelStart, PRInt32 aSelEnd); private: