From b73c71861b5c735db2c335ea238e1d54b60c7369 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Thu, 9 Mar 2017 14:44:45 -0500 Subject: [PATCH] Bug 1345237. Propagate uint32_t deeper into the editor state and text control frame code. r=mystor MozReview-Commit-ID: KeUo8My6eBJ --- dom/base/nsContentUtils.cpp | 4 +- dom/base/nsContentUtils.h | 4 +- dom/html/HTMLInputElement.cpp | 8 +- dom/html/HTMLInputElement.h | 4 +- dom/html/HTMLTextAreaElement.cpp | 8 +- dom/html/HTMLTextAreaElement.h | 4 +- dom/html/nsTextEditorState.cpp | 83 ++++++++++--------- dom/html/nsTextEditorState.h | 25 +++--- editor/libeditor/TextEditRules.cpp | 20 +++-- editor/libeditor/TextEditRules.h | 2 +- layout/forms/nsITextControlFrame.h | 4 +- layout/forms/nsTextControlFrame.cpp | 27 +++--- layout/forms/nsTextControlFrame.h | 12 +-- ...tfieldselection-setSelectionRange.html.ini | 7 -- .../selection-start-end.html | 55 +++++++++++- .../textfieldselection-setSelectionRange.html | 32 +++++++ 16 files changed, 195 insertions(+), 104 deletions(-) diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index b6065809073a..f719c4a6072c 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -7058,8 +7058,8 @@ nsContentUtils::GetAdjustedOffsetInTextControl(nsIFrame* aOffsetFrame, void nsContentUtils::GetSelectionInTextControl(Selection* aSelection, Element* aRoot, - int32_t& aOutStartOffset, - int32_t& aOutEndOffset) + uint32_t& aOutStartOffset, + uint32_t& aOutEndOffset) { MOZ_ASSERT(aSelection && aRoot); diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index e7889f9d1cbe..ee4c386dd48e 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -2417,8 +2417,8 @@ public: */ static void GetSelectionInTextControl(mozilla::dom::Selection* aSelection, Element* aRoot, - int32_t& aOutStartOffset, - int32_t& aOutEndOffset); + uint32_t& aOutStartOffset, + uint32_t& aOutEndOffset); /** * Takes a frame for anonymous content within a text control ( or diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp index 38ea926050c1..d44acd218bf6 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -6332,7 +6332,7 @@ HTMLInputElement::GetSelectionStart(ErrorResult& aRv) return Nullable(); } - int32_t selEnd, selStart; + uint32_t selEnd, selStart; GetSelectionRange(&selStart, &selEnd, aRv); return Nullable(selStart); } @@ -6358,7 +6358,7 @@ HTMLInputElement::GetSelectionEnd(ErrorResult& aRv) return Nullable(); } - int32_t selEnd, selStart; + uint32_t selEnd, selStart; GetSelectionRange(&selStart, &selEnd, aRv); return Nullable(selEnd); } @@ -6386,8 +6386,8 @@ HTMLInputElement::GetFiles(nsIDOMFileList** aFileList) } void -HTMLInputElement::GetSelectionRange(int32_t* aSelectionStart, - int32_t* aSelectionEnd, +HTMLInputElement::GetSelectionRange(uint32_t* aSelectionStart, + uint32_t* aSelectionEnd, ErrorResult& aRv) { nsTextEditorState* state = GetEditorState(); diff --git a/dom/html/HTMLInputElement.h b/dom/html/HTMLInputElement.h index 6e6f3498545a..d87be6fb3211 100644 --- a/dom/html/HTMLInputElement.h +++ b/dom/html/HTMLInputElement.h @@ -1486,8 +1486,8 @@ protected: * A helper to get the current selection range. Will throw on the ErrorResult * if we have no editor state. */ - void GetSelectionRange(int32_t* aSelectionStart, - int32_t* aSelectionEnd, + void GetSelectionRange(uint32_t* aSelectionStart, + uint32_t* aSelectionEnd, ErrorResult& aRv); nsCOMPtr mControllers; diff --git a/dom/html/HTMLTextAreaElement.cpp b/dom/html/HTMLTextAreaElement.cpp index b1b9c3a292ac..f7a813e6a622 100644 --- a/dom/html/HTMLTextAreaElement.cpp +++ b/dom/html/HTMLTextAreaElement.cpp @@ -701,7 +701,7 @@ HTMLTextAreaElement::GetTextLength(int32_t *aTextLength) Nullable HTMLTextAreaElement::GetSelectionStart(ErrorResult& aError) { - int32_t selStart, selEnd; + uint32_t selStart, selEnd; GetSelectionRange(&selStart, &selEnd, aError); return Nullable(selStart); } @@ -716,7 +716,7 @@ HTMLTextAreaElement::SetSelectionStart(const Nullable& aSelectionStart Nullable HTMLTextAreaElement::GetSelectionEnd(ErrorResult& aError) { - int32_t selStart, selEnd; + uint32_t selStart, selEnd; GetSelectionRange(&selStart, &selEnd, aError); return Nullable(selEnd); } @@ -729,8 +729,8 @@ HTMLTextAreaElement::SetSelectionEnd(const Nullable& aSelectionEnd, } void -HTMLTextAreaElement::GetSelectionRange(int32_t* aSelectionStart, - int32_t* aSelectionEnd, +HTMLTextAreaElement::GetSelectionRange(uint32_t* aSelectionStart, + uint32_t* aSelectionEnd, ErrorResult& aRv) { return mState.GetSelectionRange(aSelectionStart, aSelectionEnd, aRv); diff --git a/dom/html/HTMLTextAreaElement.h b/dom/html/HTMLTextAreaElement.h index bca401052601..6b059deb83ea 100644 --- a/dom/html/HTMLTextAreaElement.h +++ b/dom/html/HTMLTextAreaElement.h @@ -396,8 +396,8 @@ protected: * A helper to get the current selection range. Will throw on the ErrorResult * if we have no editor state. */ - void GetSelectionRange(int32_t* aSelectionStart, - int32_t* aSelectionEnd, + void GetSelectionRange(uint32_t* aSelectionStart, + uint32_t* aSelectionEnd, ErrorResult& aRv); private: static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes, diff --git a/dom/html/nsTextEditorState.cpp b/dom/html/nsTextEditorState.cpp index cdfe19c00b1b..b574cb5946ef 100644 --- a/dom/html/nsTextEditorState.cpp +++ b/dom/html/nsTextEditorState.cpp @@ -1577,8 +1577,8 @@ nsTextEditorState::SetSelectionProperties(nsTextEditorState::SelectionProperties } void -nsTextEditorState::GetSelectionRange(int32_t* aSelectionStart, - int32_t* aSelectionEnd, +nsTextEditorState::GetSelectionRange(uint32_t* aSelectionStart, + uint32_t* aSelectionEnd, ErrorResult& aRv) { MOZ_ASSERT(aSelectionStart); @@ -1640,7 +1640,7 @@ nsTextEditorState::GetSelectionDirection(ErrorResult& aRv) } void -nsTextEditorState::SetSelectionRange(int32_t aStart, int32_t aEnd, +nsTextEditorState::SetSelectionRange(uint32_t aStart, uint32_t aEnd, nsITextControlFrame::SelectionDirection aDirection, ErrorResult& aRv) { @@ -1659,10 +1659,10 @@ nsTextEditorState::SetSelectionRange(int32_t aStart, int32_t aEnd, // various mismatches between our impl and the spec. GetValue(value, false); uint32_t length = value.Length(); - if (uint32_t(aStart) > length) { + if (aStart > length) { aStart = length; } - if (uint32_t(aEnd) > length) { + if (aEnd > length) { aEnd = length; } SelectionProperties& props = GetSelectionProperties(); @@ -1703,17 +1703,15 @@ nsTextEditorState::SetSelectionRange(int32_t aStart, int32_t aEnd, } void -nsTextEditorState::SetSelectionStart(const mozilla::dom::Nullable& aStart, +nsTextEditorState::SetSelectionStart(const Nullable& aStart, ErrorResult& aRv) { - int32_t start = 0; + uint32_t start = 0; if (!aStart.IsNull()) { - // XXXbz This will do the wrong thing for input values that are out of the - // int32_t range... start = aStart.Value(); } - int32_t ignored, end; + uint32_t ignored, end; GetSelectionRange(&ignored, &end, aRv); if (aRv.Failed()) { return; @@ -1732,17 +1730,15 @@ nsTextEditorState::SetSelectionStart(const mozilla::dom::Nullable& aSt } void -nsTextEditorState::SetSelectionEnd(const mozilla::dom::Nullable& aEnd, +nsTextEditorState::SetSelectionEnd(const Nullable& aEnd, ErrorResult& aRv) { - int32_t end = 0; + uint32_t end = 0; if (!aEnd.IsNull()) { - // XXXbz This will do the wrong thing for input values that are out of the - // int32_t range... end = aEnd.Value(); } - int32_t start, ignored; + uint32_t start, ignored; GetSelectionRange(&start, &ignored, aRv); if (aRv.Failed()) { return; @@ -1805,7 +1801,7 @@ nsTextEditorState::SetSelectionDirection(const nsAString& aDirection, return; } - int32_t start, end; + uint32_t start, end; GetSelectionRange(&start, &end, aRv); if (aRv.Failed()) { return; @@ -1826,8 +1822,8 @@ DirectionStringToSelectionDirection(const Optional& aDirection) } void -nsTextEditorState::SetSelectionRange(int32_t aSelectionStart, - int32_t aSelectionEnd, +nsTextEditorState::SetSelectionRange(uint32_t aSelectionStart, + uint32_t aSelectionEnd, const Optional& aDirection, ErrorResult& aRv) { @@ -1841,21 +1837,22 @@ void nsTextEditorState::SetRangeText(const nsAString& aReplacement, ErrorResult& aRv) { - int32_t start, end; + uint32_t start, end; GetSelectionRange(&start, &end, aRv); if (aRv.Failed()) { return; } SetRangeText(aReplacement, start, end, SelectionMode::Preserve, - aRv, start, end); + aRv, Some(start), Some(end)); } void nsTextEditorState::SetRangeText(const nsAString& aReplacement, uint32_t aStart, uint32_t aEnd, SelectionMode aSelectMode, - ErrorResult& aRv, int32_t aSelectionStart, - int32_t aSelectionEnd) + ErrorResult& aRv, + const Maybe& aSelectionStart, + const Maybe& aSelectionEnd) { if (aStart > aEnd) { aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); @@ -1874,11 +1871,17 @@ nsTextEditorState::SetRangeText(const nsAString& aReplacement, uint32_t aStart, aEnd = inputValueLength; } - if (aSelectionStart == -1 && aSelectionEnd == -1) { - GetSelectionRange(&aSelectionStart, &aSelectionEnd, aRv); + uint32_t selectionStart, selectionEnd; + if (!aSelectionStart) { + MOZ_ASSERT(!aSelectionEnd); + GetSelectionRange(&selectionStart, &selectionEnd, aRv); if (aRv.Failed()) { return; } + } else { + MOZ_ASSERT(aSelectionEnd); + selectionStart = *aSelectionStart; + selectionEnd = *aSelectionEnd; } MOZ_ASSERT(aStart <= aEnd); @@ -1895,32 +1898,32 @@ nsTextEditorState::SetRangeText(const nsAString& aReplacement, uint32_t aStart, switch (aSelectMode) { case mozilla::dom::SelectionMode::Select: { - aSelectionStart = aStart; - aSelectionEnd = newEnd; + selectionStart = aStart; + selectionEnd = newEnd; } break; case mozilla::dom::SelectionMode::Start: { - aSelectionStart = aSelectionEnd = aStart; + selectionStart = selectionEnd = aStart; } break; case mozilla::dom::SelectionMode::End: { - aSelectionStart = aSelectionEnd = newEnd; + selectionStart = selectionEnd = newEnd; } break; case mozilla::dom::SelectionMode::Preserve: { - if ((uint32_t)aSelectionStart > aEnd) { - aSelectionStart += delta; - } else if ((uint32_t)aSelectionStart > aStart) { - aSelectionStart = aStart; + if (selectionStart > aEnd) { + selectionStart += delta; + } else if (selectionStart > aStart) { + selectionStart = aStart; } - if ((uint32_t)aSelectionEnd > aEnd) { - aSelectionEnd += delta; - } else if ((uint32_t)aSelectionEnd > aStart) { - aSelectionEnd = newEnd; + if (selectionEnd > aEnd) { + selectionEnd += delta; + } else if (selectionEnd > aStart) { + selectionEnd = newEnd; } } break; @@ -1928,7 +1931,7 @@ nsTextEditorState::SetRangeText(const nsAString& aReplacement, uint32_t aStart, MOZ_CRASH("Unknown mode!"); } - SetSelectionRange(aSelectionStart, aSelectionEnd, Optional(), aRv); + SetSelectionRange(selectionStart, selectionEnd, Optional(), aRv); } HTMLInputElement* @@ -2008,7 +2011,7 @@ nsTextEditorState::UnbindFromFrame(nsTextControlFrame* aFrame) // controller, and so forth. if (!IsSelectionCached()) { // Go ahead and cache it now. - int32_t start = 0, end = 0; + uint32_t start = 0, end = 0; IgnoredErrorResult rangeRv; GetSelectionRange(&start, &end, rangeRv); @@ -2575,8 +2578,8 @@ nsTextEditorState::SetValue(const nsAString& aValue, uint32_t aFlags) props.SetEnd(value.Length()); } else { // Make sure our cached selection position is not outside the new value. - props.SetStart(std::min(uint32_t(props.GetStart()), value.Length())); - props.SetEnd(std::min(uint32_t(props.GetEnd()), value.Length())); + props.SetStart(std::min(props.GetStart(), value.Length())); + props.SetEnd(std::min(props.GetEnd(), value.Length())); } } diff --git a/dom/html/nsTextEditorState.h b/dom/html/nsTextEditorState.h index 1733c4a9c5a7..e6a56e32c6f7 100644 --- a/dom/html/nsTextEditorState.h +++ b/dom/html/nsTextEditorState.h @@ -227,20 +227,20 @@ public: return mStart == 0 && mEnd == 0 && mDirection == nsITextControlFrame::eForward; } - int32_t GetStart() const + uint32_t GetStart() const { return mStart; } - void SetStart(int32_t value) + void SetStart(uint32_t value) { mIsDirty = true; mStart = value; } - int32_t GetEnd() const + uint32_t GetEnd() const { return mEnd; } - void SetEnd(int32_t value) + void SetEnd(uint32_t value) { mIsDirty = true; mEnd = value; @@ -260,7 +260,7 @@ public: return mIsDirty; } private: - int32_t mStart, mEnd; + uint32_t mStart, mEnd; bool mIsDirty = false; nsITextControlFrame::SelectionDirection mDirection; }; @@ -276,7 +276,7 @@ public: void SyncUpSelectionPropertiesBeforeDestruction(); // Get the selection range start and end points in our text. - void GetSelectionRange(int32_t* aSelectionStart, int32_t* aSelectionEnd, + void GetSelectionRange(uint32_t* aSelectionStart, uint32_t* aSelectionEnd, mozilla::ErrorResult& aRv); // Get the selection direction @@ -295,15 +295,15 @@ public: // // XXXbz This should really take uint32_t, but none of our guts (either the // frame or our cached selection state) work with uint32_t at the moment... - void SetSelectionRange(int32_t aStart, int32_t aEnd, + void SetSelectionRange(uint32_t aStart, uint32_t aEnd, nsITextControlFrame::SelectionDirection aDirection, mozilla::ErrorResult& aRv); // Set the selection range, but with an optional string for the direction. // This will convert aDirection to an nsITextControlFrame::SelectionDirection // and then call our other SetSelectionRange overload. - void SetSelectionRange(int32_t aSelectionStart, - int32_t aSelectionEnd, + void SetSelectionRange(uint32_t aSelectionStart, + uint32_t aSelectionEnd, const mozilla::dom::Optional& aDirection, mozilla::ErrorResult& aRv); @@ -338,8 +338,11 @@ public: // otherwise they're the start and end of our selection range. void SetRangeText(const nsAString& aReplacement, uint32_t aStart, uint32_t aEnd, mozilla::dom::SelectionMode aSelectMode, - mozilla::ErrorResult& aRv, int32_t aSelectionStart = -1, - int32_t aSelectionEnd = -1); + mozilla::ErrorResult& aRv, + const mozilla::Maybe& aSelectionStart = + mozilla::Nothing(), + const mozilla::Maybe& aSelectionEnd = + mozilla::Nothing()); void UpdateEditableState(bool aNotify) { if (mRootNode) { diff --git a/editor/libeditor/TextEditRules.cpp b/editor/libeditor/TextEditRules.cpp index 827f38ab908c..d5b9edd711a9 100644 --- a/editor/libeditor/TextEditRules.cpp +++ b/editor/libeditor/TextEditRules.cpp @@ -631,8 +631,8 @@ TextEditRules::WillInsertText(EditAction aAction, return NS_OK; } - int32_t start = 0; - int32_t end = 0; + uint32_t start = 0; + uint32_t end = 0; // handle password field docs if (IsPasswordEditor()) { @@ -855,7 +855,7 @@ TextEditRules::WillDeleteSelection(Selection* aSelection, NS_ENSURE_SUCCESS(rv, rv); // manage the password buffer - int32_t start, end; + uint32_t start, end; nsContentUtils::GetSelectionInTextControl(aSelection, mTextEditor->GetRoot(), start, end); @@ -872,7 +872,7 @@ TextEditRules::WillDeleteSelection(Selection* aSelection, // Collapsed selection. if (end == start) { // Deleting back. - if (nsIEditor::ePrevious == aCollapsedAction && 0 0) { mPasswordText.Cut(start-1, 1); } // Deleting forward. @@ -1277,15 +1277,15 @@ TextEditRules::TruncateInsertionIfNeeded(Selection* aSelection, return rv; } - int32_t start, end; + uint32_t start, end; nsContentUtils::GetSelectionInTextControl(aSelection, mTextEditor->GetRoot(), start, end); TextComposition* composition = mTextEditor->GetComposition(); - int32_t oldCompStrLength = composition ? composition->String().Length() : 0; + uint32_t oldCompStrLength = composition ? composition->String().Length() : 0; - const int32_t selectionLength = end - start; + const uint32_t selectionLength = end - start; const int32_t resultingDocLength = docLength - selectionLength - oldCompStrLength; if (resultingDocLength >= aMaxLength) { // This call is guaranteed to reduce the capacity of the string, so it @@ -1327,7 +1327,7 @@ TextEditRules::ResetIMETextPWBuf() } void -TextEditRules::RemoveIMETextFromPWBuf(int32_t& aStart, +TextEditRules::RemoveIMETextFromPWBuf(uint32_t& aStart, nsAString* aIMEString) { MOZ_ASSERT(aIMEString); @@ -1371,7 +1371,7 @@ TextEditRules::HideLastPWInput() NS_ENSURE_STATE(mTextEditor); RefPtr selection = mTextEditor->GetSelection(); NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER); - int32_t start, end; + uint32_t start, end; nsContentUtils::GetSelectionInTextControl(selection, mTextEditor->GetRoot(), start, end); @@ -1379,6 +1379,8 @@ TextEditRules::HideLastPWInput() NS_ENSURE_TRUE(selNode, NS_OK); selNode->GetAsText()->ReplaceData(mLastStart, mLastLength, hiddenText); + // XXXbz Selection::Collapse/Extend take int32_t, but there are tons of + // callsites... Converting all that is a battle for another day. selection->Collapse(selNode, start); if (start != end) { selection->Extend(selNode, end); diff --git a/editor/libeditor/TextEditRules.h b/editor/libeditor/TextEditRules.h index 685a11f8410a..602e703bd313 100644 --- a/editor/libeditor/TextEditRules.h +++ b/editor/libeditor/TextEditRules.h @@ -199,7 +199,7 @@ protected: /** * Remove IME composition text from password buffer. */ - void RemoveIMETextFromPWBuf(int32_t& aStart, nsAString* aIMEString); + void RemoveIMETextFromPWBuf(uint32_t& aStart, nsAString* aIMEString); nsresult CreateMozBR(nsIDOMNode* inParent, int32_t inOffset, nsIDOMNode** outBRNode = nullptr); diff --git a/layout/forms/nsITextControlFrame.h b/layout/forms/nsITextControlFrame.h index 3767f65f3128..ca7d27cba00f 100644 --- a/layout/forms/nsITextControlFrame.h +++ b/layout/forms/nsITextControlFrame.h @@ -25,8 +25,8 @@ public: NS_IMETHOD GetEditor(nsIEditor **aEditor) = 0; - NS_IMETHOD SetSelectionRange(int32_t aSelectionStart, - int32_t aSelectionEnd, + NS_IMETHOD SetSelectionRange(uint32_t aSelectionStart, + uint32_t aSelectionEnd, SelectionDirection aDirection = eNone) = 0; NS_IMETHOD GetOwnedSelectionController(nsISelectionController** aSelCon) = 0; diff --git a/layout/forms/nsTextControlFrame.cpp b/layout/forms/nsTextControlFrame.cpp index 645495d558f8..3ecf3f53c3c6 100644 --- a/layout/forms/nsTextControlFrame.cpp +++ b/layout/forms/nsTextControlFrame.cpp @@ -306,7 +306,7 @@ nsTextControlFrame::EnsureEditorInitialized() mEditorHasBeenInitialized = true; if (weakFrame.IsAlive()) { - int32_t position = 0; + uint32_t position = 0; // Set the selection to the end of the text field (bug 1287655), // but only if the contents has changed (bug 1337392). @@ -744,9 +744,9 @@ nsTextControlFrame::GetEditor(nsIEditor **aEditor) nsresult nsTextControlFrame::SetSelectionInternal(nsIDOMNode *aStartNode, - int32_t aStartOffset, + uint32_t aStartOffset, nsIDOMNode *aEndNode, - int32_t aEndOffset, + uint32_t aEndOffset, nsITextControlFrame::SelectionDirection aDirection) { // Create a new range to represent the new selection. @@ -758,6 +758,11 @@ nsTextControlFrame::SetSelectionInternal(nsIDOMNode *aStartNode, // we have access to the node. nsCOMPtr start = do_QueryInterface(aStartNode); nsCOMPtr end = do_QueryInterface(aEndNode); + // XXXbz nsRange::Set takes int32_t (and ranges generally work on int32_t), + // but we're passing uint32_t. The good news is that at this point our + // endpoints should really be within our length, so not really that big. And + // if they _are_ that big, Set() will simply error out, which is not too bad + // for a case we don't expect to happen. nsresult rv = range->Set(start, aStartOffset, end, aEndOffset); NS_ENSURE_SUCCESS(rv, rv); @@ -861,7 +866,7 @@ nsTextControlFrame::SelectAllOrCollapseToEndOfText(bool aSelect) } nsresult -nsTextControlFrame::SetSelectionEndPoints(int32_t aSelStart, int32_t aSelEnd, +nsTextControlFrame::SetSelectionEndPoints(uint32_t aSelStart, uint32_t aSelEnd, nsITextControlFrame::SelectionDirection aDirection) { NS_ASSERTION(aSelStart <= aSelEnd, "Invalid selection offsets!"); @@ -870,7 +875,7 @@ nsTextControlFrame::SetSelectionEndPoints(int32_t aSelStart, int32_t aSelEnd, return NS_ERROR_FAILURE; nsCOMPtr startNode, endNode; - int32_t startOffset, endOffset; + uint32_t startOffset, endOffset; // Calculate the selection start point. @@ -896,7 +901,7 @@ nsTextControlFrame::SetSelectionEndPoints(int32_t aSelStart, int32_t aSelEnd, } NS_IMETHODIMP -nsTextControlFrame::SetSelectionRange(int32_t aSelStart, int32_t aSelEnd, +nsTextControlFrame::SetSelectionRange(uint32_t aSelStart, uint32_t aSelEnd, nsITextControlFrame::SelectionDirection aDirection) { nsresult rv = EnsureEditorInitialized(); @@ -914,9 +919,9 @@ nsTextControlFrame::SetSelectionRange(int32_t aSelStart, int32_t aSelEnd, nsresult -nsTextControlFrame::OffsetToDOMPoint(int32_t aOffset, +nsTextControlFrame::OffsetToDOMPoint(uint32_t aOffset, nsIDOMNode** aResult, - int32_t* aPosition) + uint32_t* aPosition) { NS_ENSURE_ARG_POINTER(aResult && aPosition); @@ -948,13 +953,13 @@ nsTextControlFrame::OffsetToDOMPoint(int32_t aOffset, NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr textNode = do_QueryInterface(firstNode); - if (length == 0 || aOffset < 0) { + if (length == 0) { NS_IF_ADDREF(*aResult = rootNode); *aPosition = 0; } else if (textNode) { uint32_t textLength = 0; textNode->GetLength(&textLength); - if (length == 2 && uint32_t(aOffset) == textLength) { + if (length == 2 && aOffset == textLength) { // If we're at the end of the text node and we have a trailing BR node, // set the selection on the BR node. NS_IF_ADDREF(*aResult = rootNode); @@ -962,7 +967,7 @@ nsTextControlFrame::OffsetToDOMPoint(int32_t aOffset, } else { // Otherwise, set the selection on the textnode itself. NS_IF_ADDREF(*aResult = firstNode); - *aPosition = std::min(aOffset, int32_t(textLength)); + *aPosition = std::min(aOffset, textLength); } } else { NS_IF_ADDREF(*aResult = rootNode); diff --git a/layout/forms/nsTextControlFrame.h b/layout/forms/nsTextControlFrame.h index 8a8c1176d211..9ec8f6e76327 100644 --- a/layout/forms/nsTextControlFrame.h +++ b/layout/forms/nsTextControlFrame.h @@ -142,8 +142,8 @@ public: //==== NSITEXTCONTROLFRAME NS_IMETHOD GetEditor(nsIEditor **aEditor) override; - NS_IMETHOD SetSelectionRange(int32_t aSelectionStart, - int32_t aSelectionEnd, + NS_IMETHOD SetSelectionRange(uint32_t aSelectionStart, + uint32_t aSelectionEnd, SelectionDirection aDirection = eNone) override; NS_IMETHOD GetOwnedSelectionController(nsISelectionController** aSelCon) override; virtual nsFrameSelection* GetOwnedFrameSelection() override; @@ -265,7 +265,7 @@ protected: nsTextControlFrame* mFrame; }; - nsresult OffsetToDOMPoint(int32_t aOffset, nsIDOMNode** aResult, int32_t* aPosition); + nsresult OffsetToDOMPoint(uint32_t aOffset, nsIDOMNode** aResult, uint32_t* aPosition); /** * Update the textnode under our anonymous div to show the new @@ -308,11 +308,11 @@ protected: private: //helper methods - nsresult SetSelectionInternal(nsIDOMNode *aStartNode, int32_t aStartOffset, - nsIDOMNode *aEndNode, int32_t aEndOffset, + nsresult SetSelectionInternal(nsIDOMNode *aStartNode, uint32_t aStartOffset, + nsIDOMNode *aEndNode, uint32_t aEndOffset, SelectionDirection aDirection = eNone); nsresult SelectAllOrCollapseToEndOfText(bool aSelect); - nsresult SetSelectionEndPoints(int32_t aSelStart, int32_t aSelEnd, + nsresult SetSelectionEndPoints(uint32_t aSelStart, uint32_t aSelEnd, SelectionDirection aDirection = eNone); /** diff --git a/testing/web-platform/meta/html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange.html.ini b/testing/web-platform/meta/html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange.html.ini index 42f4b45f3766..cd131092f47e 100644 --- a/testing/web-platform/meta/html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange.html.ini +++ b/testing/web-platform/meta/html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange.html.ini @@ -23,10 +23,3 @@ [textarea direction of setSelectionRange(0,1)] expected: FAIL - - [input setSelectionRange(1,-1)] - expected: FAIL - - [input setSelectionRange(-1,1)] - expected: FAIL - diff --git a/testing/web-platform/tests/html/semantics/forms/textfieldselection/selection-start-end.html b/testing/web-platform/tests/html/semantics/forms/textfieldselection/selection-start-end.html index 06c6e5b317b7..c6b68e1d18cb 100644 --- a/testing/web-platform/tests/html/semantics/forms/textfieldselection/selection-start-end.html +++ b/testing/web-platform/tests/html/semantics/forms/textfieldselection/selection-start-end.html @@ -27,11 +27,30 @@ return el; }; + function createPrefocusedInputElement(value, append) { + var el = createInputElement(value, append); + el.focus(); + el.blur(); + return el; + } + + function createPrefocusedTextareaElement(value, append) { + var el = createTextareaElement(value, append); + el.focus(); + el.blur(); + return el; + } + function createTestElements(value) { return [ createInputElement(value, true), createInputElement(value, false), + createPrefocusedInputElement(value, true), + createPrefocusedInputElement(value, false), createTextareaElement(value, true), - createTextareaElement(value, false) ]; + createTextareaElement(value, false), + createPrefocusedTextareaElement(value, true), + createPrefocusedTextareaElement(value, false), + ]; } const testValue = "abcdefghij"; @@ -92,4 +111,38 @@ el.remove(); } }, "Setting selectionEnd to a value smaller than selectionStart should decrease selectionStart"); + + test(function() { + for (let el of createTestElements(testValue)) { + el.selectionStart = 0; + assert_equals(el.selectionStart, 0, `We just set it on ${el.id}`); + el.selectionStart = -1; + assert_equals(el.selectionStart, testValue.length, + `selectionStart setter on ${el.id} should convert -1 to 2^32-1`); + el.selectionStart = Math.pow(2, 32); + assert_equals(el.selectionStart, 0, + `selectionStart setter on ${el.id} should convert 2^32 to 0`); + el.selectionStart = Math.pow(2, 32) - 1; + assert_equals(el.selectionStart, testValue.length, + `selectionStart setter on ${el.id} should leave 2^32-1 as-is`); + el.remove(); + } + }, "selectionStart edge-case values"); + + test(function() { + for (let el of createTestElements(testValue)) { + el.selectionEnd = 0; + assert_equals(el.selectionEnd, 0, `We just set it on ${el.id}`); + el.selectionEnd = -1; + assert_equals(el.selectionEnd, testValue.length, + `selectionEnd setter on ${el.id} should convert -1 to 2^32-1`); + el.selectionEnd = Math.pow(2, 32); + assert_equals(el.selectionEnd, 0, + `selectionEnd setter on ${el.id} should convert 2^32 to 0`); + el.selectionEnd = Math.pow(2, 32) - 1; + assert_equals(el.selectionEnd, testValue.length, + `selectionEnd setter on ${el.id} should leave 2^32-1 as-is`); + el.remove(); + } + }, "selectionEnd edge-case values"); diff --git a/testing/web-platform/tests/html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange.html b/testing/web-platform/tests/html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange.html index 3c3a75433f98..537bbeccbb57 100644 --- a/testing/web-platform/tests/html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange.html +++ b/testing/web-platform/tests/html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange.html @@ -138,6 +138,22 @@ test(function() { assert_equals(input.selectionStart, 0, "element.selectionStart should be 0"); assert_equals(input.selectionEnd, 1, "element.selectionEnd should be 1"); },'input setSelectionRange(undefined,1)'); + + test(function() { + input.setSelectionRange(Math.pow(2,32) - 2, Math.pow(2,32) - 1); + assert_equals(input.selectionStart, input.value.length, + "element.selectionStart should be value.length"); + assert_equals(input.selectionEnd, input.value.length, + "element.selectionEnd should be value.length"); + }, 'input setSelectionRange(Math.pow(2,32) - 2, Math.pow(2,32) - 1)'); + + test(function() { + input.setSelectionRange(Math.pow(2,31), Math.pow(2,32) - 1); + assert_equals(input.selectionStart, input.value.length, + "element.selectionStart should be value.length"); + assert_equals(input.selectionEnd, input.value.length, + "element.selectionEnd should be value.length"); + }, 'input setSelectionRange(Math.pow(2,31), Math.pow(2,32) - 1)'); },"test of input.setSelectionRange"); async_test(function() { @@ -257,6 +273,22 @@ test(function() { assert_equals(textarea.selectionStart, 0, "element.selectionStart should be 0"); assert_equals(textarea.selectionEnd, 1, "element.selectionStart should be 1"); },'textarea setSelectionRange(undefined,1)'); + + test(function() { + textarea.setSelectionRange(Math.pow(2,32) - 2, Math.pow(2,32) - 1); + assert_equals(textarea.selectionStart, textarea.value.length, + "element.selectionStart should be value.length"); + assert_equals(textarea.selectionEnd, textarea.value.length, + "element.selectionEnd should be value.length"); + }, 'textarea setSelectionRange(Math.pow(2,32) - 2, Math.pow(2,32) - 1)'); + + test(function() { + textarea.setSelectionRange(Math.pow(2,31), Math.pow(2,32) - 1); + assert_equals(textarea.selectionStart, textarea.value.length, + "element.selectionStart should be value.length"); + assert_equals(textarea.selectionEnd, textarea.value.length, + "element.selectionEnd should be value.length"); + }, 'textarea setSelectionRange(Math.pow(2,31), Math.pow(2,32) - 1)'); },"test of textarea.setSelectionRange"); async_test(function() {