input and textarea elements should reveal selection in setSelection when focused
authorrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 17 Jan 2018 23:19:45 +0000 (23:19 +0000)
committerrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 17 Jan 2018 23:19:45 +0000 (23:19 +0000)
https://bugs.webkit.org/show_bug.cgi?id=181715
<rdar://problem/36570546>

Reviewed by Zalan Bujtas.

Made input and textarea elements reveal selection in FrameSelection::setSelection instead of by directly
invoking FrameSelection::revealSelection in their respective updateFocusAppearance to unify code paths.

Also added options to reveal selection up to the main frame to SetSelectionOption to be used in iOS.

* editing/FrameSelection.cpp:
(WebCore::FrameSelection::FrameSelection):
(WebCore::FrameSelection::moveWithoutValidationTo): Takes SelectionRevealMode as an argument and converts
sets appropriate selection options.
(WebCore::FrameSelection::setSelection): Reconstruct SelectionRevealMode out of selection option sets.
(WebCore::FrameSelection::updateAndRevealSelection):
* editing/FrameSelection.h:
(WebCore::FrameSelection): Added RevealSelectionUpToMainFrame as a SelectionRevealMode and replaced
m_shouldRevealSelection by m_selectionRevealMode.
* html/HTMLInputElement.cpp:
(WebCore::HTMLInputElement::updateFocusAppearance): Pass SelectionRevealMode to HTMLTextFormControlElement's
select and restoreCachedSelection instead of directly invoking FrameSelection::revealSelection.
* html/HTMLTextAreaElement.cpp:
(WebCore::HTMLTextAreaElement::updateFocusAppearance): Ditto.
* html/HTMLTextFormControlElement.cpp:
(WebCore::HTMLTextFormControlElement::select):
(WebCore::HTMLTextFormControlElement::setSelectionRange):
(WebCore::HTMLTextFormControlElement::restoreCachedSelection):
* html/HTMLTextFormControlElement.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@227092 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/editing/FrameSelection.cpp
Source/WebCore/editing/FrameSelection.h
Source/WebCore/html/HTMLInputElement.cpp
Source/WebCore/html/HTMLTextAreaElement.cpp
Source/WebCore/html/HTMLTextFormControlElement.cpp
Source/WebCore/html/HTMLTextFormControlElement.h

index 071aaaf..39ddd09 100644 (file)
@@ -1,3 +1,36 @@
+2018-01-17  Ryosuke Niwa  <rniwa@webkit.org>
+
+        input and textarea elements should reveal selection in setSelection when focused
+        https://bugs.webkit.org/show_bug.cgi?id=181715
+        <rdar://problem/36570546>
+
+        Reviewed by Zalan Bujtas.
+
+        Made input and textarea elements reveal selection in FrameSelection::setSelection instead of by directly
+        invoking FrameSelection::revealSelection in their respective updateFocusAppearance to unify code paths.
+
+        Also added options to reveal selection up to the main frame to SetSelectionOption to be used in iOS.
+
+        * editing/FrameSelection.cpp:
+        (WebCore::FrameSelection::FrameSelection):
+        (WebCore::FrameSelection::moveWithoutValidationTo): Takes SelectionRevealMode as an argument and converts
+        sets appropriate selection options.
+        (WebCore::FrameSelection::setSelection): Reconstruct SelectionRevealMode out of selection option sets.
+        (WebCore::FrameSelection::updateAndRevealSelection):
+        * editing/FrameSelection.h:
+        (WebCore::FrameSelection): Added RevealSelectionUpToMainFrame as a SelectionRevealMode and replaced
+        m_shouldRevealSelection by m_selectionRevealMode.
+        * html/HTMLInputElement.cpp:
+        (WebCore::HTMLInputElement::updateFocusAppearance): Pass SelectionRevealMode to HTMLTextFormControlElement's
+        select and restoreCachedSelection instead of directly invoking FrameSelection::revealSelection.
+        * html/HTMLTextAreaElement.cpp:
+        (WebCore::HTMLTextAreaElement::updateFocusAppearance): Ditto.
+        * html/HTMLTextFormControlElement.cpp:
+        (WebCore::HTMLTextFormControlElement::select):
+        (WebCore::HTMLTextFormControlElement::setSelectionRange):
+        (WebCore::HTMLTextFormControlElement::restoreCachedSelection):
+        * html/HTMLTextFormControlElement.h:
+
 2018-01-17  Michael Catanzaro  <mcatanzaro@igalia.com>
 
         WEBKIT_FRAMEWORK should not modify file-global include directories
index c711651..400edb9 100644 (file)
@@ -132,7 +132,6 @@ FrameSelection::FrameSelection(Frame* frame)
     , m_focused(frame && frame->page() && frame->page()->focusController().focusedFrame() == frame)
     , m_shouldShowBlockCursor(false)
     , m_pendingSelectionUpdate(false)
-    , m_shouldRevealSelection(false)
     , m_alwaysAlignCursorOnScrollWhenRevealingSelection(false)
 #if PLATFORM(IOS)
     , m_updateAppearanceEnabled(false)
@@ -178,13 +177,26 @@ void FrameSelection::moveTo(const Position &base, const Position &extent, EAffin
     setSelection(VisibleSelection(base, extent, affinity, selectionHasDirection), defaultSetSelectionOptions(userTriggered));
 }
 
-void FrameSelection::moveWithoutValidationTo(const Position& base, const Position& extent, bool selectionHasDirection, bool shouldSetFocus, const AXTextStateChangeIntent& intent)
+void FrameSelection::moveWithoutValidationTo(const Position& base, const Position& extent, bool selectionHasDirection, bool shouldSetFocus, SelectionRevealMode revealMode, const AXTextStateChangeIntent& intent)
 {
     VisibleSelection newSelection;
     newSelection.setWithoutValidation(base, extent);
     newSelection.setIsDirectional(selectionHasDirection);
     AXTextStateChangeIntent newIntent = intent.type == AXTextStateChangeTypeUnknown ? AXTextStateChangeIntent(AXTextStateChangeTypeSelectionMove, AXTextSelection { AXTextSelectionDirectionDiscontiguous, AXTextSelectionGranularityUnknown, false }) : intent;
-    setSelection(newSelection, defaultSetSelectionOptions() | (shouldSetFocus ? 0 : DoNotSetFocus), newIntent);
+    SetSelectionOptions options = defaultSetSelectionOptions();
+    if (!shouldSetFocus)
+        options |= DoNotSetFocus;
+    switch (revealMode) {
+    case SelectionRevealMode::DoNotReveal:
+        break;
+    case SelectionRevealMode::Reveal:
+        options |= RevealSelection;
+        break;
+    case SelectionRevealMode::RevealUpToMainFrame:
+        options |= RevealSelectionUpToMainFrame;
+        break;
+    }
+    setSelection(newSelection, options, newIntent);
 }
 
 void DragCaretController::setCaretPosition(const VisiblePosition& position)
@@ -354,7 +366,12 @@ void FrameSelection::setSelection(const VisibleSelection& selection, SetSelectio
     if (!document)
         return;
 
-    m_shouldRevealSelection = options & RevealSelection;
+    if (options & RevealSelectionUpToMainFrame)
+        m_selectionRevealMode = SelectionRevealMode::RevealUpToMainFrame;
+    else if (options & RevealSelection)
+        m_selectionRevealMode = SelectionRevealMode::Reveal;
+    else
+        m_selectionRevealMode = SelectionRevealMode::DoNotReveal;
     m_alwaysAlignCursorOnScrollWhenRevealingSelection = align == AlignCursorOnScrollAlways;
 
     m_pendingSelectionUpdate = true;
@@ -399,7 +416,7 @@ void FrameSelection::updateAndRevealSelection(const AXTextStateChangeIntent& int
 
     updateAppearance();
 
-    if (m_shouldRevealSelection) {
+    if (m_selectionRevealMode != SelectionRevealMode::DoNotReveal) {
         ScrollAlignment alignment;
 
         if (m_frame->editor().behavior().shouldCenterAlignWhenSelectionIsRevealed())
@@ -407,7 +424,7 @@ void FrameSelection::updateAndRevealSelection(const AXTextStateChangeIntent& int
         else
             alignment = m_alwaysAlignCursorOnScrollWhenRevealingSelection ? ScrollAlignment::alignTopAlways : ScrollAlignment::alignToEdgeIfNeeded;
 
-        revealSelection(SelectionRevealMode::Reveal, alignment, RevealExtent);
+        revealSelection(m_selectionRevealMode, alignment, RevealExtent);
     }
 
     notifyAccessibilityForSelectionChange(intent);
index c6ae93d..79e1717 100644 (file)
@@ -125,8 +125,9 @@ public:
         SpellCorrectionTriggered = 1 << 3,
         DoNotSetFocus = 1 << 4,
         DictationTriggered = 1 << 5,
-        RevealSelection = 1 << 6,
-        IsUserTriggered = 1 << 7,
+        IsUserTriggered = 1 << 6,
+        RevealSelection = 1 << 7,
+        RevealSelectionUpToMainFrame = 1 << 8,
     };
     typedef unsigned SetSelectionOptions; // Union of values in SetSelectionOption and EUserTriggered
     static inline SetSelectionOptions defaultSetSelectionOptions(EUserTriggered userTriggered = NotUserTriggered)
@@ -143,7 +144,7 @@ public:
     WEBCORE_EXPORT void moveTo(const VisiblePosition&, const VisiblePosition&, EUserTriggered = NotUserTriggered);
     void moveTo(const Position&, EAffinity, EUserTriggered = NotUserTriggered);
     void moveTo(const Position&, const Position&, EAffinity, EUserTriggered = NotUserTriggered);
-    void moveWithoutValidationTo(const Position&, const Position&, bool selectionHasDirection, bool shouldSetFocus, const AXTextStateChangeIntent& = AXTextStateChangeIntent());
+    void moveWithoutValidationTo(const Position&, const Position&, bool selectionHasDirection, bool shouldSetFocus, SelectionRevealMode, const AXTextStateChangeIntent& = AXTextStateChangeIntent());
 
     const VisibleSelection& selection() const { return m_selection; }
     WEBCORE_EXPORT void setSelection(const VisibleSelection&, SetSelectionOptions = defaultSetSelectionOptions(), AXTextStateChangeIntent = AXTextStateChangeIntent(), CursorAlignOnScroll = AlignCursorOnScrollIfNeeded, TextGranularity = CharacterGranularity);
@@ -344,6 +345,9 @@ private:
     Timer m_appearanceUpdateTimer;
     // The painted bounds of the caret in absolute coordinates
     IntRect m_absCaretBounds;
+
+    SelectionRevealMode m_selectionRevealMode { SelectionRevealMode::DoNotReveal };
+
     bool m_caretInsidePositionFixed : 1;
     bool m_absCaretBoundsDirty : 1;
     bool m_caretPaint : 1;
@@ -351,7 +355,6 @@ private:
     bool m_focused : 1;
     bool m_shouldShowBlockCursor : 1;
     bool m_pendingSelectionUpdate : 1;
-    bool m_shouldRevealSelection : 1;
     bool m_alwaysAlignCursorOnScrollWhenRevealingSelection : 1;
 
 #if PLATFORM(IOS)
index 4b673cc..7a7ce1d 100644 (file)
@@ -444,11 +444,9 @@ void HTMLInputElement::updateFocusAppearance(SelectionRestorationMode restoratio
 {
     if (isTextField()) {
         if (restorationMode == SelectionRestorationMode::SetDefault || !hasCachedSelection())
-            select(Element::defaultFocusTextStateChangeIntent());
+            select(revealMode, Element::defaultFocusTextStateChangeIntent());
         else
-            restoreCachedSelection();
-        if (document().frame())
-            document().frame()->selection().revealSelection(revealMode);
+            restoreCachedSelection(revealMode);
     } else
         HTMLTextFormControlElement::updateFocusAppearance(restorationMode, revealMode);
 }
index 05b4109..b8996ea 100644 (file)
@@ -260,12 +260,9 @@ void HTMLTextAreaElement::updateFocusAppearance(SelectionRestorationMode restora
         // If this is the first focus, set a caret at the beginning of the text.  
         // This matches some browsers' behavior; see bug 11746 Comment #15.
         // http://bugs.webkit.org/show_bug.cgi?id=11746#c15
-        setSelectionRange(0, 0, SelectionHasNoDirection, Element::defaultFocusTextStateChangeIntent());
+        setSelectionRange(0, 0, SelectionHasNoDirection, revealMode, Element::defaultFocusTextStateChangeIntent());
     } else
-        restoreCachedSelection(Element::defaultFocusTextStateChangeIntent());
-
-    if (document().frame())
-        document().frame()->selection().revealSelection(revealMode);
+        restoreCachedSelection(revealMode, Element::defaultFocusTextStateChangeIntent());
 }
 
 void HTMLTextAreaElement::defaultEventHandler(Event& event)
index cd90629..a67fa55 100644 (file)
@@ -184,15 +184,15 @@ void HTMLTextFormControlElement::setSelectionDirection(const String& direction)
     setSelectionRange(selectionStart(), selectionEnd(), direction);
 }
 
-void HTMLTextFormControlElement::select(const AXTextStateChangeIntent& intent)
+void HTMLTextFormControlElement::select(SelectionRevealMode revealMode, const AXTextStateChangeIntent& intent)
 {
     // FIXME: We should abstract the selection behavior into an EditingBehavior function instead
     // of hardcoding the behavior using a macro define.
 #if PLATFORM(IOS)
     // We don't want to select all the text on iOS. Instead use the standard textfield behavior of going to the end of the line.
-    setSelectionRange(std::numeric_limits<int>::max(), std::numeric_limits<int>::max(), SelectionHasForwardDirection, intent);
+    setSelectionRange(std::numeric_limits<int>::max(), std::numeric_limits<int>::max(), SelectionHasForwardDirection, revealMode, intent);
 #else
-    setSelectionRange(0, std::numeric_limits<int>::max(), SelectionHasNoDirection, intent);
+    setSelectionRange(0, std::numeric_limits<int>::max(), SelectionHasNoDirection, revealMode, intent);
 #endif
 }
 
@@ -279,10 +279,10 @@ void HTMLTextFormControlElement::setSelectionRange(int start, int end, const Str
     else if (directionString == "backward")
         direction = SelectionHasBackwardDirection;
 
-    return setSelectionRange(start, end, direction, intent);
+    return setSelectionRange(start, end, direction, SelectionRevealMode::DoNotReveal, intent);
 }
 
-void HTMLTextFormControlElement::setSelectionRange(int start, int end, TextFieldSelectionDirection direction, const AXTextStateChangeIntent& intent)
+void HTMLTextFormControlElement::setSelectionRange(int start, int end, TextFieldSelectionDirection direction, SelectionRevealMode revealMode, const AXTextStateChangeIntent& intent)
 {
     if (!isTextField())
         return;
@@ -321,7 +321,7 @@ void HTMLTextFormControlElement::setSelectionRange(int start, int end, TextField
     }
 
     if (RefPtr<Frame> frame = document().frame())
-        frame->selection().moveWithoutValidationTo(startPosition, endPosition, direction != SelectionHasNoDirection, !hasFocus, intent);
+        frame->selection().moveWithoutValidationTo(startPosition, endPosition, direction != SelectionHasNoDirection, !hasFocus, revealMode, intent);
 }
 
 int HTMLTextFormControlElement::indexForVisiblePosition(const VisiblePosition& position) const
@@ -472,9 +472,9 @@ RefPtr<Range> HTMLTextFormControlElement::selection() const
     return Range::create(document(), startNode, start, endNode, end);
 }
 
-void HTMLTextFormControlElement::restoreCachedSelection(const AXTextStateChangeIntent& intent)
+void HTMLTextFormControlElement::restoreCachedSelection(SelectionRevealMode revealMode, const AXTextStateChangeIntent& intent)
 {
-    setSelectionRange(m_cachedSelectionStart, m_cachedSelectionEnd, cachedSelectionDirection(), intent);
+    setSelectionRange(m_cachedSelectionStart, m_cachedSelectionEnd, cachedSelectionDirection(), revealMode, intent);
 }
 
 void HTMLTextFormControlElement::selectionChanged(bool shouldFireSelectEvent)
index 7354d95..f752da3 100644 (file)
@@ -69,11 +69,11 @@ public:
     WEBCORE_EXPORT void setSelectionStart(int);
     WEBCORE_EXPORT void setSelectionEnd(int);
     WEBCORE_EXPORT void setSelectionDirection(const String&);
-    WEBCORE_EXPORT void select(const AXTextStateChangeIntent& = AXTextStateChangeIntent());
+    WEBCORE_EXPORT void select(SelectionRevealMode = SelectionRevealMode::DoNotReveal, const AXTextStateChangeIntent& = AXTextStateChangeIntent());
     WEBCORE_EXPORT virtual ExceptionOr<void> setRangeText(const String& replacement);
     WEBCORE_EXPORT virtual ExceptionOr<void> setRangeText(const String& replacement, unsigned start, unsigned end, const String& selectionMode);
     void setSelectionRange(int start, int end, const String& direction, const AXTextStateChangeIntent& = AXTextStateChangeIntent());
-    WEBCORE_EXPORT void setSelectionRange(int start, int end, TextFieldSelectionDirection = SelectionHasNoDirection, const AXTextStateChangeIntent& = AXTextStateChangeIntent());
+    WEBCORE_EXPORT void setSelectionRange(int start, int end, TextFieldSelectionDirection = SelectionHasNoDirection, SelectionRevealMode = SelectionRevealMode::DoNotReveal, const AXTextStateChangeIntent& = AXTextStateChangeIntent());
     RefPtr<Range> selection() const;
     String selectedText() const;
 
@@ -116,7 +116,7 @@ protected:
         m_cachedSelectionDirection = direction;
     }
 
-    void restoreCachedSelection(const AXTextStateChangeIntent& = AXTextStateChangeIntent());
+    void restoreCachedSelection(SelectionRevealMode, const AXTextStateChangeIntent& = AXTextStateChangeIntent());
     bool hasCachedSelection() const { return m_cachedSelectionStart >= 0; }
 
     virtual void subtreeHasChanged() = 0;