mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-02 01:48:05 +00:00
Bug 1342197 part 4. Move GetSelectionRange from nsTextControlFrame to the editor state. r=ehsan
At this point, all this method does is ensure editor initialization and then ask the editor state for various information. Let's cut out the middleman. MozReview-Commit-ID: p491umScJO
This commit is contained in:
parent
e8df2552ae
commit
d2afbdd254
@ -6607,17 +6607,30 @@ HTMLInputElement::GetFiles(nsIDOMFileList** aFileList)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
NS_IMETHODIMP
|
||||
HTMLInputElement::GetSelectionRange(int32_t* aSelectionStart,
|
||||
int32_t* aSelectionEnd)
|
||||
{
|
||||
nsIFormControlFrame* formControlFrame = GetFormControlFrame(true);
|
||||
nsITextControlFrame* textControlFrame = do_QueryFrame(formControlFrame);
|
||||
if (textControlFrame) {
|
||||
return textControlFrame->GetSelectionRange(aSelectionStart, aSelectionEnd);
|
||||
// Flush frames, because our editor state will want to work with the frame.
|
||||
if (IsInComposedDoc()) {
|
||||
GetComposedDoc()->FlushPendingNotifications(FlushType::Frames);
|
||||
}
|
||||
if (!GetPrimaryFrame()) {
|
||||
// Can we return a selection range anyway here, now that it lives on our
|
||||
// state? In fact, could we make this behave more like
|
||||
// GetSelectionDirection, in the sense of working even when we have no
|
||||
// frame, by just delegating entirely to mState? And then, do we really
|
||||
// need the flush?
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
nsTextEditorState* state = GetEditorState();
|
||||
if (!state) {
|
||||
// Not a text control.
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return state->GetSelectionRange(aSelectionStart, aSelectionEnd);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -6642,28 +6655,29 @@ HTMLInputElement::GetSelectionDirection(nsAString& aDirection, ErrorResult& aRv)
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
nsIFormControlFrame* formControlFrame = GetFormControlFrame(true);
|
||||
nsITextControlFrame* textControlFrame = do_QueryFrame(formControlFrame);
|
||||
if (textControlFrame) {
|
||||
nsITextControlFrame::SelectionDirection dir;
|
||||
rv = textControlFrame->GetSelectionRange(nullptr, nullptr, &dir);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
DirectionToName(dir, aDirection);
|
||||
}
|
||||
nsTextEditorState* state = GetEditorState();
|
||||
if (!state) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
nsTextEditorState* state = GetEditorState();
|
||||
if (state && state->IsSelectionCached()) {
|
||||
DirectionToName(state->GetSelectionProperties().GetDirection(), aDirection);
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
if (formControlFrame) {
|
||||
nsITextControlFrame::SelectionDirection dir;
|
||||
rv = state->GetSelectionDirection(&dir);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
DirectionToName(dir, aDirection);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(rv);
|
||||
|
||||
if (state->IsSelectionCached()) {
|
||||
DirectionToName(state->GetSelectionProperties().GetDirection(), aDirection);
|
||||
return;
|
||||
}
|
||||
|
||||
aRv.Throw(rv);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -240,6 +240,8 @@ public:
|
||||
NS_IMETHOD_(void) InitializeKeyboardEventListeners() override;
|
||||
NS_IMETHOD_(void) OnValueChanged(bool aNotify, bool aWasInteractiveUserChange) override;
|
||||
NS_IMETHOD_(bool) HasCachedSelection() override;
|
||||
NS_IMETHOD GetSelectionRange(int32_t* aSelectionStart,
|
||||
int32_t* aSelectionEnd) override;
|
||||
|
||||
void GetDisplayFileName(nsAString& aFileName) const;
|
||||
|
||||
@ -956,8 +958,6 @@ protected:
|
||||
void SetIndeterminateInternal(bool aValue,
|
||||
bool aShouldInvalidate);
|
||||
|
||||
nsresult GetSelectionRange(int32_t* aSelectionStart, int32_t* aSelectionEnd);
|
||||
|
||||
/**
|
||||
* Called when an attribute is about to be changed
|
||||
*/
|
||||
|
@ -840,17 +840,24 @@ HTMLTextAreaElement::SetSelectionEnd(const Nullable<uint32_t>& aSelectionEnd,
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
NS_IMETHODIMP
|
||||
HTMLTextAreaElement::GetSelectionRange(int32_t* aSelectionStart,
|
||||
int32_t* aSelectionEnd)
|
||||
{
|
||||
nsIFormControlFrame* formControlFrame = GetFormControlFrame(true);
|
||||
nsITextControlFrame* textControlFrame = do_QueryFrame(formControlFrame);
|
||||
if (textControlFrame) {
|
||||
return textControlFrame->GetSelectionRange(aSelectionStart, aSelectionEnd);
|
||||
// Flush frames, because our editor state will want to work with the frame.
|
||||
if (IsInComposedDoc()) {
|
||||
GetComposedDoc()->FlushPendingNotifications(FlushType::Frames);
|
||||
}
|
||||
if (!GetPrimaryFrame()) {
|
||||
// Can we return a selection range anyway here, now that it lives on our
|
||||
// state? In fact, could we make this behave more like
|
||||
// GetSelectionDirection, in the sense of working even when we have no
|
||||
// frame, by just delegating entirely to mState? And then, do we really
|
||||
// need the flush?
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
return mState.GetSelectionRange(aSelectionStart, aSelectionEnd);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -880,22 +887,21 @@ HTMLTextAreaElement::GetSelectionDirection(nsAString& aDirection, ErrorResult& a
|
||||
{
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
nsIFormControlFrame* formControlFrame = GetFormControlFrame(true);
|
||||
nsITextControlFrame* textControlFrame = do_QueryFrame(formControlFrame);
|
||||
if (textControlFrame) {
|
||||
if (formControlFrame) {
|
||||
nsITextControlFrame::SelectionDirection dir;
|
||||
rv = textControlFrame->GetSelectionRange(nullptr, nullptr, &dir);
|
||||
rv = mState.GetSelectionDirection(&dir);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
DirectionToName(dir, aDirection);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
if (mState.IsSelectionCached()) {
|
||||
DirectionToName(mState.GetSelectionProperties().GetDirection(), aDirection);
|
||||
return;
|
||||
}
|
||||
aError.Throw(rv);
|
||||
if (mState.IsSelectionCached()) {
|
||||
DirectionToName(mState.GetSelectionProperties().GetDirection(), aDirection);
|
||||
return;
|
||||
}
|
||||
|
||||
aError.Throw(rv);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -109,6 +109,9 @@ public:
|
||||
NS_IMETHOD_(void) InitializeKeyboardEventListeners() override;
|
||||
NS_IMETHOD_(void) OnValueChanged(bool aNotify, bool aWasInteractiveUserChange) override;
|
||||
NS_IMETHOD_(bool) HasCachedSelection() override;
|
||||
NS_IMETHOD GetSelectionRange(int32_t* aSelectionStart,
|
||||
int32_t* aSelectionEnd) override;
|
||||
|
||||
|
||||
// nsIContent
|
||||
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
@ -347,8 +350,6 @@ protected:
|
||||
*/
|
||||
nsresult SetValueInternal(const nsAString& aValue, uint32_t aFlags);
|
||||
|
||||
nsresult GetSelectionRange(int32_t* aSelectionStart, int32_t* aSelectionEnd);
|
||||
|
||||
/**
|
||||
* Common method to call from the various mutation observer methods.
|
||||
* aContent is a content node that's either the one that changed or its
|
||||
|
@ -196,6 +196,12 @@ public:
|
||||
|
||||
static already_AddRefed<nsITextControlElement>
|
||||
GetTextControlElementFromEditingHost(nsIContent* aHost);
|
||||
|
||||
/**
|
||||
* Get the selection range start and end points.
|
||||
*/
|
||||
NS_IMETHOD GetSelectionRange(int32_t* aSelectionStart,
|
||||
int32_t* aSelectionEnd) = 0;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsITextControlElement,
|
||||
|
@ -1549,6 +1549,73 @@ nsTextEditorState::SetSelectionProperties(nsTextEditorState::SelectionProperties
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTextEditorState::GetSelectionRange(int32_t* aSelectionStart,
|
||||
int32_t* aSelectionEnd)
|
||||
{
|
||||
MOZ_ASSERT(mBoundFrame,
|
||||
"Caller didn't flush out frames and check for a frame?");
|
||||
MOZ_ASSERT(aSelectionStart);
|
||||
MOZ_ASSERT(aSelectionEnd);
|
||||
|
||||
// It's not clear that all the checks here are needed, but the previous
|
||||
// version of this code in nsTextControlFrame was doing them, so we keep them
|
||||
// for now.
|
||||
|
||||
nsresult rv = mBoundFrame->EnsureEditorInitialized();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsISelectionController* selCon = GetSelectionController();
|
||||
NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsISelection> selection;
|
||||
rv = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
|
||||
getter_AddRefs(selection));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
|
||||
|
||||
dom::Selection* sel = selection->AsSelection();
|
||||
mozilla::dom::Element* root = GetRootNode();
|
||||
NS_ENSURE_STATE(root);
|
||||
nsContentUtils::GetSelectionInTextControl(sel, root,
|
||||
*aSelectionStart, *aSelectionEnd);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTextEditorState::GetSelectionDirection(nsITextControlFrame::SelectionDirection* aDirection)
|
||||
{
|
||||
MOZ_ASSERT(mBoundFrame,
|
||||
"Caller didn't flush out frames and check for a frame?");
|
||||
MOZ_ASSERT(aDirection);
|
||||
|
||||
// It's not clear that all the checks here are needed, but the previous
|
||||
// version of this code in nsTextControlFrame was doing them, so we keep them
|
||||
// for now.
|
||||
|
||||
nsresult rv = mBoundFrame->EnsureEditorInitialized();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsISelectionController* selCon = GetSelectionController();
|
||||
NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsISelection> selection;
|
||||
rv = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
|
||||
getter_AddRefs(selection));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
|
||||
|
||||
dom::Selection* sel = selection->AsSelection();
|
||||
nsDirection direction = sel->GetSelectionDirection();
|
||||
if (direction == eDirNext) {
|
||||
*aDirection = nsITextControlFrame::eForward;
|
||||
} else if (direction == eDirPrevious) {
|
||||
*aDirection = nsITextControlFrame::eBackward;
|
||||
} else {
|
||||
NS_NOTREACHED("Invalid nsDirection enum value");
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
HTMLInputElement*
|
||||
nsTextEditorState::GetParentNumberControl(nsFrame* aFrame) const
|
||||
@ -1621,7 +1688,7 @@ nsTextEditorState::UnbindFromFrame(nsTextControlFrame* aFrame)
|
||||
}
|
||||
|
||||
// Save our selection state if needed.
|
||||
// Note that nsTextControlFrame::GetSelectionRange attempts to initialize the
|
||||
// Note that GetSelectionRange attempts to initialize the
|
||||
// editor before grabbing the range, and because this is not an acceptable
|
||||
// side effect for unbinding from a text control frame, we need to call
|
||||
// GetSelectionRange before calling DestroyEditor, and only if
|
||||
@ -1636,13 +1703,15 @@ nsTextEditorState::UnbindFromFrame(nsTextControlFrame* aFrame)
|
||||
// parent control, because this text editor state will be destroyed
|
||||
// together with the native anonymous text control.
|
||||
SelectionProperties props;
|
||||
mBoundFrame->GetSelectionRange(&start, &end, &direction);
|
||||
GetSelectionRange(&start, &end);
|
||||
GetSelectionDirection(&direction);
|
||||
props.SetStart(start);
|
||||
props.SetEnd(end);
|
||||
props.SetDirection(direction);
|
||||
number->SetSelectionProperties(props);
|
||||
} else {
|
||||
mBoundFrame->GetSelectionRange(&start, &end, &direction);
|
||||
GetSelectionRange(&start, &end);
|
||||
GetSelectionDirection(&direction);
|
||||
mSelectionProperties.SetStart(start);
|
||||
mSelectionProperties.SetEnd(end);
|
||||
mSelectionProperties.SetDirection(direction);
|
||||
|
@ -262,6 +262,12 @@ public:
|
||||
void WillInitEagerly() { mSelectionRestoreEagerInit = true; }
|
||||
bool HasNeverInitializedBefore() const { return !mEverInited; }
|
||||
|
||||
// Get the selection range start and end points in our text.
|
||||
nsresult GetSelectionRange(int32_t* aSelectionStart, int32_t* aSelectionEnd);
|
||||
|
||||
// Get the selection direction
|
||||
nsresult GetSelectionDirection(nsITextControlFrame::SelectionDirection* aDirection);
|
||||
|
||||
void UpdateEditableState(bool aNotify) {
|
||||
if (mRootNode) {
|
||||
mRootNode->UpdateEditableState(aNotify);
|
||||
|
@ -31,9 +31,6 @@ public:
|
||||
NS_IMETHOD SetSelectionRange(int32_t aSelectionStart,
|
||||
int32_t aSelectionEnd,
|
||||
SelectionDirection aDirection = eNone) = 0;
|
||||
NS_IMETHOD GetSelectionRange(int32_t* aSelectionStart,
|
||||
int32_t* aSelectionEnd,
|
||||
SelectionDirection* aDirection = nullptr) = 0;
|
||||
|
||||
NS_IMETHOD GetOwnedSelectionController(nsISelectionController** aSelCon) = 0;
|
||||
virtual nsFrameSelection* GetOwnedFrameSelection() = 0;
|
||||
|
@ -916,7 +916,9 @@ nsTextControlFrame::SetSelectionStart(int32_t aSelectionStart)
|
||||
|
||||
int32_t selStart = 0, selEnd = 0;
|
||||
|
||||
rv = GetSelectionRange(&selStart, &selEnd);
|
||||
nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
|
||||
MOZ_ASSERT(txtCtrl, "Content not a text control element");
|
||||
rv = txtCtrl->GetSelectionRange(&selStart, &selEnd);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aSelectionStart > selEnd) {
|
||||
@ -937,7 +939,9 @@ nsTextControlFrame::SetSelectionEnd(int32_t aSelectionEnd)
|
||||
|
||||
int32_t selStart = 0, selEnd = 0;
|
||||
|
||||
rv = GetSelectionRange(&selStart, &selEnd);
|
||||
nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
|
||||
MOZ_ASSERT(txtCtrl, "Content not a text control element");
|
||||
rv = txtCtrl->GetSelectionRange(&selStart, &selEnd);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aSelectionEnd < selStart) {
|
||||
@ -1009,58 +1013,6 @@ nsTextControlFrame::OffsetToDOMPoint(int32_t aOffset,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTextControlFrame::GetSelectionRange(int32_t* aSelectionStart,
|
||||
int32_t* aSelectionEnd,
|
||||
SelectionDirection* aDirection)
|
||||
{
|
||||
// make sure we have an editor
|
||||
nsresult rv = EnsureEditorInitialized();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aSelectionStart) {
|
||||
*aSelectionStart = 0;
|
||||
}
|
||||
if (aSelectionEnd) {
|
||||
*aSelectionEnd = 0;
|
||||
}
|
||||
if (aDirection) {
|
||||
*aDirection = eNone;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
|
||||
NS_ASSERTION(txtCtrl, "Content not a text control element");
|
||||
nsISelectionController* selCon = txtCtrl->GetSelectionController();
|
||||
NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE);
|
||||
nsCOMPtr<nsISelection> selection;
|
||||
rv = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
|
||||
|
||||
dom::Selection* sel = selection->AsSelection();
|
||||
if (aDirection) {
|
||||
nsDirection direction = sel->GetSelectionDirection();
|
||||
if (direction == eDirNext) {
|
||||
*aDirection = eForward;
|
||||
} else if (direction == eDirPrevious) {
|
||||
*aDirection = eBackward;
|
||||
} else {
|
||||
NS_NOTREACHED("Invalid nsDirection enum value");
|
||||
}
|
||||
}
|
||||
|
||||
if (!aSelectionStart || !aSelectionEnd) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mozilla::dom::Element* root = txtCtrl->GetRootEditorNode();
|
||||
NS_ENSURE_STATE(root);
|
||||
nsContentUtils::GetSelectionInTextControl(sel, root,
|
||||
*aSelectionStart, *aSelectionEnd);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/////END INTERFACE IMPLEMENTATIONS
|
||||
|
||||
////NSIFRAME
|
||||
|
@ -147,9 +147,6 @@ public:
|
||||
NS_IMETHOD SetSelectionRange(int32_t aSelectionStart,
|
||||
int32_t aSelectionEnd,
|
||||
SelectionDirection aDirection = eNone) override;
|
||||
NS_IMETHOD GetSelectionRange(int32_t* aSelectionStart,
|
||||
int32_t* aSelectionEnd,
|
||||
SelectionDirection* aDirection = nullptr) override;
|
||||
NS_IMETHOD GetOwnedSelectionController(nsISelectionController** aSelCon) override;
|
||||
virtual nsFrameSelection* GetOwnedFrameSelection() override;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user