Use current selection when tab navigation.

This CL lets FrameSelection::RevealSelection()
 use VisibleUnits::ComputeTextRect() to compute current selection range
 instead of LayoutSelection::Bounds() of last selection range.

VisibleUnits.cpp::ComputeTextRect():
 templatize to define flat tree version.

BUG=712986

Review-Url: https://codereview.chromium.org/2894803002
Cr-Commit-Position: refs/heads/master@{#473546}
diff --git a/third_party/WebKit/LayoutTests/editing/input/scroll-with-tab-to-input-regression.html b/third_party/WebKit/LayoutTests/editing/input/scroll-with-tab-to-input-regression.html
new file mode 100644
index 0000000..97bbc20
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/editing/input/scroll-with-tab-to-input-regression.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<div style="margin-top:120%"><input id="checkbox" type="checkbox" /></div>
+<input id="input" value="foo">
+<script>
+promise_test(() =>{return new Promise((resolve) => {
+  if (window.eventSender === undefined)
+    return reject('required window.eventSender');
+  checkbox.focus();
+  setTimeout(resolve, 0);
+}).then(() => {
+  var scrollY = window.scrollY;
+  assert_greater_than(window.scrollY, 0);
+  assert_equals(document.activeElement, checkbox);
+  eventSender.keyDown('Tab');
+  assert_equals(document.activeElement, input);
+  eventSender.keyDown('Tab', ['shiftKey']);
+  assert_equals(document.activeElement, checkbox);
+  eventSender.keyDown('Tab');
+  return new Promise((resolve) => {
+    setTimeout(resolve(scrollY), 0);
+  });
+}).then((scrollY) => {
+  assert_equals(window.scrollY, scrollY, 'Screen should not scroll');
+});});
+</script>
diff --git a/third_party/WebKit/Source/core/editing/FrameSelection.cpp b/third_party/WebKit/Source/core/editing/FrameSelection.cpp
index b321e50..91eca913 100644
--- a/third_party/WebKit/Source/core/editing/FrameSelection.cpp
+++ b/third_party/WebKit/Source/core/editing/FrameSelection.cpp
@@ -949,6 +949,13 @@
   return LayoutRect(layout_selection_->SelectionBounds());
 }
 
+static IntRect AbsoluteSelectionBoundsOf(
+    const VisibleSelectionInFlatTree& selection) {
+  return ComputeTextRect(
+      EphemeralRangeInFlatTree(selection.Start(), selection.end()));
+}
+
+// TODO(editing-dev): This should be done in FlatTree world.
 void FrameSelection::RevealSelection(const ScrollAlignment& alignment,
                                      RevealExtentOption reveal_extent_option) {
   DCHECK(IsAvailable());
@@ -967,10 +974,11 @@
       rect = LayoutRect(AbsoluteCaretBounds());
       break;
     case kRangeSelection:
-      rect = LayoutRect(reveal_extent_option == kRevealExtent
-                            ? AbsoluteCaretBoundsOf(CreateVisiblePosition(
-                                  ComputeVisibleSelectionInDOMTree().Extent()))
-                            : EnclosingIntRect(UnclippedBounds()));
+      rect = LayoutRect(
+          reveal_extent_option == kRevealExtent
+              ? AbsoluteCaretBoundsOf(CreateVisiblePosition(
+                    ComputeVisibleSelectionInDOMTree().Extent()))
+              : AbsoluteSelectionBoundsOf(ComputeVisibleSelectionInFlatTree()));
       break;
   }
 
diff --git a/third_party/WebKit/Source/core/editing/FrameSelection.h b/third_party/WebKit/Source/core/editing/FrameSelection.h
index b5125f1..b8e39d7 100644
--- a/third_party/WebKit/Source/core/editing/FrameSelection.h
+++ b/third_party/WebKit/Source/core/editing/FrameSelection.h
@@ -230,6 +230,8 @@
   String SelectedTextForClipboard() const;
 
   // The bounds are clipped to the viewport as this is what callers expect.
+  // This returns last layouted selection bounds of LayoutSelection rather than
+  // SelectionEditor keeps.
   LayoutRect Bounds() const;
   LayoutRect UnclippedBounds() const;
 
diff --git a/third_party/WebKit/Source/core/editing/VisibleUnits.cpp b/third_party/WebKit/Source/core/editing/VisibleUnits.cpp
index e9a3f65..d9581df 100644
--- a/third_party/WebKit/Source/core/editing/VisibleUnits.cpp
+++ b/third_party/WebKit/Source/core/editing/VisibleUnits.cpp
@@ -4119,10 +4119,11 @@
   layout_text.AbsoluteQuadsForRange(quads, start, end);
 }
 
-template <typename RectType>
-static Vector<RectType> ComputeTextBounds(const EphemeralRange& range) {
-  const Position& start_position = range.StartPosition();
-  const Position& end_position = range.EndPosition();
+template <typename RectType, typename Strategy>
+static Vector<RectType> ComputeTextBounds(
+    const EphemeralRangeTemplate<Strategy>& range) {
+  const PositionTemplate<Strategy>& start_position = range.StartPosition();
+  const PositionTemplate<Strategy>& end_position = range.EndPosition();
   Node* const start_container = start_position.ComputeContainerNode();
   DCHECK(start_container);
   Node* const end_container = end_position.ComputeContainerNode();
@@ -4145,14 +4146,24 @@
   return result;
 }
 
-IntRect ComputeTextRect(const EphemeralRange& range) {
+template <typename Strategy>
+static IntRect ComputeTextRectTemplate(
+    const EphemeralRangeTemplate<Strategy>& range) {
   IntRect result;
-  const Vector<IntRect>& rects = ComputeTextBounds<IntRect>(range);
+  const Vector<IntRect>& rects = ComputeTextBounds<IntRect, Strategy>(range);
   for (const IntRect& rect : rects)
     result.Unite(rect);
   return result;
 }
 
+IntRect ComputeTextRect(const EphemeralRange& range) {
+  return ComputeTextRectTemplate(range);
+}
+
+IntRect ComputeTextRect(const EphemeralRangeInFlatTree& range) {
+  return ComputeTextRectTemplate(range);
+}
+
 Vector<FloatQuad> ComputeTextQuads(const EphemeralRange& range) {
   return ComputeTextBounds<FloatQuad>(range);
 }
diff --git a/third_party/WebKit/Source/core/editing/VisibleUnits.h b/third_party/WebKit/Source/core/editing/VisibleUnits.h
index 28908be..e62d4f2a 100644
--- a/third_party/WebKit/Source/core/editing/VisibleUnits.h
+++ b/third_party/WebKit/Source/core/editing/VisibleUnits.h
@@ -343,6 +343,7 @@
 CORE_EXPORT PositionInFlatTree SkipWhitespace(const PositionInFlatTree&);
 
 CORE_EXPORT IntRect ComputeTextRect(const EphemeralRange&);
+IntRect ComputeTextRect(const EphemeralRangeInFlatTree&);
 CORE_EXPORT Vector<FloatQuad> ComputeTextQuads(const EphemeralRange&);
 
 }  // namespace blink