Bug 253870 - Make disabled form controls selectable. r=masayuki,MarcoZ

This rejiggers a bit the way selection focus is handled so that focusing a
disabled form control with the mouse handles selection properly, and hides the
document selection and so on.

This matches the behavior of other browsers as far as I can tell.

Given now readonly and disabled editors behave the same, we can simplify a bit
the surrounding editor code.

Differential Revision: https://phabricator.services.mozilla.com/D66464
This commit is contained in:
Emilio Cobos Álvarez
2020-03-19 13:18:16 +00:00
parent 06fecea7d2
commit b9ac81d824
32 changed files with 347 additions and 311 deletions

View File

@@ -174,10 +174,6 @@ class RestoreSelectionState : public Runnable {
mFrame->SetSelectionRange(properties.GetStart(), properties.GetEnd(),
properties.GetDirection());
}
if (!mTextControlState->mSelectionRestoreEagerInit) {
mTextControlState->HideSelectionIfBlurred();
}
mTextControlState->mSelectionRestoreEagerInit = false;
}
if (mTextControlState) {
@@ -217,7 +213,6 @@ class MOZ_RAII AutoRestoreEditorState final {
// appearing the method in profile. So, this class should check if it's
// necessary to call.
uint32_t flags = mSavedFlags;
flags &= ~(nsIEditor::eEditorDisabledMask);
flags &= ~(nsIEditor::eEditorReadonlyMask);
flags |= nsIEditor::eEditorDontEchoPassword;
if (mSavedFlags != flags) {
@@ -361,6 +356,8 @@ class TextInputSelectionController final : public nsSupportsWeakReference,
int16_t aStartOffset,
int16_t aEndOffset,
bool* aRetval) override;
void SelectionWillTakeFocus() override;
void SelectionWillLoseFocus() override;
private:
RefPtr<nsFrameSelection> mFrameSelection;
@@ -771,6 +768,22 @@ TextInputSelectionController::SelectAll() {
return frameSelection->SelectAll();
}
void TextInputSelectionController::SelectionWillTakeFocus() {
if (mFrameSelection) {
if (PresShell* shell = mFrameSelection->GetPresShell()) {
shell->FrameSelectionWillTakeFocus(*mFrameSelection);
}
}
}
void TextInputSelectionController::SelectionWillLoseFocus() {
if (mFrameSelection) {
if (PresShell* shell = mFrameSelection->GetPresShell()) {
shell->FrameSelectionWillLoseFocus(*mFrameSelection);
}
}
}
NS_IMETHODIMP
TextInputSelectionController::CheckVisibility(nsINode* node,
int16_t startOffset,
@@ -1396,7 +1409,6 @@ TextControlState::TextControlState(TextControlElement* aOwningElement)
mEditorInitialized(false),
mValueTransferInProgress(false),
mSelectionCached(true),
mSelectionRestoreEagerInit(false),
mPlaceholderVisibility(false),
mPreviewVisibility(false)
// When adding more member variable initializations here, add the same
@@ -1419,7 +1431,6 @@ TextControlState* TextControlState::Construct(
state->mEditorInitialized = false;
state->mValueTransferInProgress = false;
state->mSelectionCached = true;
state->mSelectionRestoreEagerInit = false;
state->mPlaceholderVisibility = false;
state->mPreviewVisibility = false;
// When adding more member variable initializations here, add the same
@@ -1640,7 +1651,9 @@ nsresult TextControlState::BindToFrame(nsTextControlFrame* aFrame) {
mTextListener = new TextInputListener(mTextCtrlElement);
mTextListener->SetFrame(mBoundFrame);
mSelCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
// Editor will override this as needed from InitializeSelection.
mSelCon->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN);
// Get the caret and make it a selection listener.
// FYI: It's safe to use raw pointer for calling
@@ -1884,21 +1897,13 @@ nsresult TextControlState::PrepareEditor(const nsAString* aValue) {
editorFlags = newTextEditor->Flags();
// Check if the readonly attribute is set.
if (mTextCtrlElement->HasAttr(kNameSpaceID_None, nsGkAtoms::readonly)) {
//
// TODO: Should probably call IsDisabled(), as it is cheaper.
if (mTextCtrlElement->HasAttr(kNameSpaceID_None, nsGkAtoms::readonly) ||
mTextCtrlElement->HasAttr(kNameSpaceID_None, nsGkAtoms::disabled)) {
editorFlags |= nsIEditor::eEditorReadonlyMask;
}
// Check if the disabled attribute is set.
// TODO: call IsDisabled() here!
if (mTextCtrlElement->HasAttr(kNameSpaceID_None, nsGkAtoms::disabled)) {
editorFlags |= nsIEditor::eEditorDisabledMask;
}
// Disable the selection if necessary.
if (newTextEditor->IsDisabled()) {
mSelCon->SetDisplaySelection(nsISelectionController::SELECTION_OFF);
}
SetEditorFlagsIfNecessary(*newTextEditor, editorFlags);
if (shouldInitializeEditor) {
@@ -2385,6 +2390,10 @@ void TextControlState::UnbindFromFrame(nsTextControlFrame* aFrame) {
AutoTextControlHandlingState handlingUnbindFromFrame(
*this, TextControlAction::UnbindFromFrame);
if (mSelCon) {
mSelCon->SelectionWillLoseFocus();
}
// We need to start storing the value outside of the editor if we're not
// going to use it anymore, so retrieve it for now.
nsAutoString value;
@@ -3087,13 +3096,6 @@ void TextControlState::UpdateOverlayTextVisibility(bool aNotify) {
}
}
void TextControlState::HideSelectionIfBlurred() {
MOZ_ASSERT(mSelCon, "Should have a selection controller if we have a frame!");
if (!nsContentUtils::IsFocusedContent(mTextCtrlElement)) {
mSelCon->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN);
}
}
bool TextControlState::EditorHasComposition() {
return mTextEditor && mTextEditor->IsIMEComposing();
}