1 /*
2  * Copyright (C) 2011, 2012 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "third_party/blink/public/web/web_view.h"
32 
33 #include <limits>
34 #include <memory>
35 #include <string>
36 
37 #include "base/bind_helpers.h"
38 #include "base/stl_util.h"
39 #include "base/test/test_mock_time_task_runner.h"
40 #include "base/time/time.h"
41 #include "build/build_config.h"
42 #include "cc/trees/layer_tree_host.h"
43 #include "gin/handle.h"
44 #include "gin/object_template_builder.h"
45 #include "gin/wrappable.h"
46 #include "mojo/public/cpp/bindings/pending_receiver.h"
47 #include "mojo/public/cpp/bindings/pending_remote.h"
48 #include "mojo/public/cpp/bindings/receiver.h"
49 #include "testing/gtest/include/gtest/gtest.h"
50 #include "third_party/blink/public/common/browser_interface_broker_proxy.h"
51 #include "third_party/blink/public/common/frame/frame_owner_element_type.h"
52 #include "third_party/blink/public/common/input/web_input_event.h"
53 #include "third_party/blink/public/common/input/web_keyboard_event.h"
54 #include "third_party/blink/public/common/page/page_zoom.h"
55 #include "third_party/blink/public/mojom/input/focus_type.mojom-blink.h"
56 #include "third_party/blink/public/mojom/manifest/display_mode.mojom-shared.h"
57 #include "third_party/blink/public/platform/web_coalesced_input_event.h"
58 #include "third_party/blink/public/platform/web_drag_data.h"
59 #include "third_party/blink/public/platform/web_drag_operation.h"
60 #include "third_party/blink/public/platform/web_size.h"
61 #include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
62 #include "third_party/blink/public/public_buildflags.h"
63 #include "third_party/blink/public/web/web_autofill_client.h"
64 #include "third_party/blink/public/web/web_console_message.h"
65 #include "third_party/blink/public/web/web_device_emulation_params.h"
66 #include "third_party/blink/public/web/web_document.h"
67 #include "third_party/blink/public/web/web_element.h"
68 #include "third_party/blink/public/web/web_frame.h"
69 #include "third_party/blink/public/web/web_frame_content_dumper.h"
70 #include "third_party/blink/public/web/web_frame_widget.h"
71 #include "third_party/blink/public/web/web_hit_test_result.h"
72 #include "third_party/blink/public/web/web_input_method_controller.h"
73 #include "third_party/blink/public/web/web_local_frame.h"
74 #include "third_party/blink/public/web/web_local_frame_client.h"
75 #include "third_party/blink/public/web/web_print_params.h"
76 #include "third_party/blink/public/web/web_script_source.h"
77 #include "third_party/blink/public/web/web_settings.h"
78 #include "third_party/blink/public/web/web_tree_scope_type.h"
79 #include "third_party/blink/public/web/web_view_client.h"
80 #include "third_party/blink/public/web/web_widget.h"
81 #include "third_party/blink/public/web/web_widget_client.h"
82 #include "third_party/blink/renderer/bindings/core/v8/v8_document.h"
83 #include "third_party/blink/renderer/core/dom/document.h"
84 #include "third_party/blink/renderer/core/dom/element.h"
85 #include "third_party/blink/renderer/core/dom/node_computed_style.h"
86 #include "third_party/blink/renderer/core/editing/frame_selection.h"
87 #include "third_party/blink/renderer/core/editing/ime/input_method_controller.h"
88 #include "third_party/blink/renderer/core/editing/markers/document_marker_controller.h"
89 #include "third_party/blink/renderer/core/exported/web_settings_impl.h"
90 #include "third_party/blink/renderer/core/exported/web_view_impl.h"
91 #include "third_party/blink/renderer/core/frame/event_handler_registry.h"
92 #include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
93 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
94 #include "third_party/blink/renderer/core/frame/local_frame.h"
95 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
96 #include "third_party/blink/renderer/core/frame/settings.h"
97 #include "third_party/blink/renderer/core/frame/visual_viewport.h"
98 #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
99 #include "third_party/blink/renderer/core/fullscreen/fullscreen.h"
100 #include "third_party/blink/renderer/core/html/forms/external_date_time_chooser.h"
101 #include "third_party/blink/renderer/core/html/forms/html_input_element.h"
102 #include "third_party/blink/renderer/core/html/forms/html_text_area_element.h"
103 #include "third_party/blink/renderer/core/html/html_document.h"
104 #include "third_party/blink/renderer/core/html/html_iframe_element.h"
105 #include "third_party/blink/renderer/core/html/html_object_element.h"
106 #include "third_party/blink/renderer/core/html/html_span_element.h"
107 #include "third_party/blink/renderer/core/inspector/dev_tools_emulator.h"
108 #include "third_party/blink/renderer/core/layout/layout_theme.h"
109 #include "third_party/blink/renderer/core/layout/layout_view.h"
110 #include "third_party/blink/renderer/core/loader/document_loader.h"
111 #include "third_party/blink/renderer/core/loader/frame_load_request.h"
112 #include "third_party/blink/renderer/core/loader/interactive_detector.h"
113 #include "third_party/blink/renderer/core/page/chrome_client.h"
114 #include "third_party/blink/renderer/core/page/context_menu_controller.h"
115 #include "third_party/blink/renderer/core/page/focus_controller.h"
116 #include "third_party/blink/renderer/core/page/page.h"
117 #include "third_party/blink/renderer/core/page/page_hidden_state.h"
118 #include "third_party/blink/renderer/core/page/print_context.h"
119 #include "third_party/blink/renderer/core/page/scoped_page_pauser.h"
120 #include "third_party/blink/renderer/core/paint/paint_layer.h"
121 #include "third_party/blink/renderer/core/paint/paint_layer_painter.h"
122 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
123 #include "third_party/blink/renderer/core/scroll/scroll_types.h"
124 #include "third_party/blink/renderer/core/testing/color_scheme_helper.h"
125 #include "third_party/blink/renderer/core/testing/fake_web_plugin.h"
126 #include "third_party/blink/renderer/core/testing/mock_clipboard_host.h"
127 #include "third_party/blink/renderer/core/testing/page_test_base.h"
128 #include "third_party/blink/renderer/core/timing/dom_window_performance.h"
129 #include "third_party/blink/renderer/core/timing/event_timing.h"
130 #include "third_party/blink/renderer/core/timing/window_performance.h"
131 #include "third_party/blink/renderer/platform/cursors.h"
132 #include "third_party/blink/renderer/platform/geometry/int_rect.h"
133 #include "third_party/blink/renderer/platform/geometry/int_size.h"
134 #include "third_party/blink/renderer/platform/graphics/color.h"
135 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
136 #include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
137 #include "third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h"
138 #include "third_party/blink/renderer/platform/keyboard_codes.h"
139 #include "third_party/blink/renderer/platform/scheduler/public/thread.h"
140 #include "third_party/blink/renderer/platform/testing/histogram_tester.h"
141 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
142 #include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
143 #include "third_party/skia/include/core/SkBitmap.h"
144 #include "third_party/skia/include/core/SkCanvas.h"
145 #include "ui/base/cursor/cursor.h"
146 #include "ui/base/mojom/cursor_type.mojom-blink.h"
147 #include "ui/events/keycodes/dom/dom_key.h"
148 #include "v8/include/v8.h"
149 
150 #if defined(OS_MACOSX)
151 #include "third_party/blink/public/web/mac/web_substring_util.h"
152 #endif
153 
154 #if BUILDFLAG(ENABLE_UNHANDLED_TAP)
155 #include "third_party/blink/public/mojom/unhandled_tap_notifier/unhandled_tap_notifier.mojom-blink.h"
156 #include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
157 #endif  // BUILDFLAG(ENABLE_UNHANDLED_TAP)
158 
159 using blink::frame_test_helpers::LoadFrame;
160 using blink::url_test_helpers::ToKURL;
161 using blink::url_test_helpers::RegisterMockedURLLoad;
162 using blink::test::RunPendingTasks;
163 
164 namespace blink {
165 
166 enum HorizontalScrollbarState {
167   kNoHorizontalScrollbar,
168   kVisibleHorizontalScrollbar,
169 };
170 
171 enum VerticalScrollbarState {
172   kNoVerticalScrollbar,
173   kVisibleVerticalScrollbar,
174 };
175 
176 class TestData {
177  public:
SetWebView(WebView * web_view)178   void SetWebView(WebView* web_view) {
179     web_view_ = static_cast<WebViewImpl*>(web_view);
180   }
SetSize(const WebSize & new_size)181   void SetSize(const WebSize& new_size) { size_ = new_size; }
GetHorizontalScrollbarState() const182   HorizontalScrollbarState GetHorizontalScrollbarState() const {
183     return web_view_->HasHorizontalScrollbar() ? kVisibleHorizontalScrollbar
184                                                : kNoHorizontalScrollbar;
185   }
GetVerticalScrollbarState() const186   VerticalScrollbarState GetVerticalScrollbarState() const {
187     return web_view_->HasVerticalScrollbar() ? kVisibleVerticalScrollbar
188                                              : kNoVerticalScrollbar;
189   }
Width() const190   int Width() const { return size_.width; }
Height() const191   int Height() const { return size_.height; }
192 
193  private:
194   WebSize size_;
195   WebViewImpl* web_view_;
196 };
197 
198 class AutoResizeWebViewClient : public frame_test_helpers::TestWebViewClient {
199  public:
200   // WebViewClient methods
DidAutoResize(const WebSize & new_size)201   void DidAutoResize(const WebSize& new_size) override {
202     test_data_.SetSize(new_size);
203   }
204 
205   // Local methods
GetTestData()206   TestData& GetTestData() { return test_data_; }
207 
208  private:
209   TestData test_data_;
210 };
211 
212 class TapHandlingWebWidgetClient
213     : public frame_test_helpers::TestWebWidgetClient {
214  public:
215   // WebWidgetClient overrides.
DidHandleGestureEvent(const WebGestureEvent & event,bool event_cancelled)216   void DidHandleGestureEvent(const WebGestureEvent& event,
217                              bool event_cancelled) override {
218     if (event.GetType() == WebInputEvent::kGestureTap) {
219       tap_x_ = event.PositionInWidget().x();
220       tap_y_ = event.PositionInWidget().y();
221     } else if (event.GetType() == WebInputEvent::kGestureLongPress) {
222       longpress_x_ = event.PositionInWidget().x();
223       longpress_y_ = event.PositionInWidget().y();
224     }
225   }
226 
227   // Local methods
Reset()228   void Reset() {
229     tap_x_ = -1;
230     tap_y_ = -1;
231     longpress_x_ = -1;
232     longpress_y_ = -1;
233   }
TapX()234   int TapX() { return tap_x_; }
TapY()235   int TapY() { return tap_y_; }
LongpressX()236   int LongpressX() { return longpress_x_; }
LongpressY()237   int LongpressY() { return longpress_y_; }
238 
239  private:
240   int tap_x_;
241   int tap_y_;
242   int longpress_x_;
243   int longpress_y_;
244 };
245 
246 class WebViewTest : public testing::Test {
247  public:
WebViewTest()248   WebViewTest() : base_url_("http://www.test.com/") {}
249 
SetUp()250   void SetUp() override {
251     test_task_runner_ = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
252     // Advance clock so time is not 0.
253     test_task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(1));
254     EventTiming::SetTickClockForTesting(test_task_runner_->GetMockTickClock());
255   }
256 
TearDown()257   void TearDown() override {
258     EventTiming::SetTickClockForTesting(nullptr);
259     url_test_helpers::UnregisterAllURLsAndClearMemoryCache();
260   }
261 
262  protected:
SetViewportSize(const WebSize & size)263   void SetViewportSize(const WebSize& size) {
264     cc::LayerTreeHost* layer_tree_host = web_view_helper_.GetLayerTreeHost();
265     layer_tree_host->SetViewportRectAndScale(
266         gfx::Rect(static_cast<gfx::Size>(size)), /*device_scale_factor=*/1.f,
267         layer_tree_host->local_surface_id_allocation_from_parent());
268   }
269 
RegisterMockedHttpURLLoad(const std::string & file_name)270   std::string RegisterMockedHttpURLLoad(const std::string& file_name) {
271     // TODO(crbug.com/751425): We should use the mock functionality
272     // via |web_view_helper_|.
273     return url_test_helpers::RegisterMockedURLLoadFromBase(
274                WebString::FromUTF8(base_url_), test::CoreTestDataPath(),
275                WebString::FromUTF8(file_name))
276         .GetString()
277         .Utf8();
278   }
279 
280   void TestAutoResize(const WebSize& min_auto_resize,
281                       const WebSize& max_auto_resize,
282                       const std::string& page_width,
283                       const std::string& page_height,
284                       int expected_width,
285                       int expected_height,
286                       HorizontalScrollbarState expected_horizontal_state,
287                       VerticalScrollbarState expected_vertical_state);
288 
289   void TestTextInputType(WebTextInputType expected_type,
290                          const std::string& html_file);
291   void TestInputMode(WebTextInputMode expected_input_mode,
292                      const std::string& html_file);
293   void TestInputAction(ui::TextInputAction expected_input_action,
294                        const std::string& html_file);
295   bool TapElement(WebInputEvent::Type, Element*);
296   bool TapElementById(WebInputEvent::Type, const WebString& id);
297   IntSize PrintICBSizeFromPageSize(const FloatSize& page_size);
298 
299   ExternalDateTimeChooser* GetExternalDateTimeChooser(
300       WebViewImpl* web_view_impl);
301 
UpdateAllLifecyclePhases()302   void UpdateAllLifecyclePhases() {
303     web_view_helper_.GetWebView()->MainFrameWidget()->UpdateAllLifecyclePhases(
304         DocumentUpdateReason::kTest);
305   }
306 
GetTestInteractiveDetector(Document & document)307   InteractiveDetector* GetTestInteractiveDetector(Document& document) {
308     InteractiveDetector* detector(InteractiveDetector::From(document));
309     EXPECT_NE(nullptr, detector);
310     detector->SetTaskRunnerForTesting(test_task_runner_);
311     detector->SetTickClockForTesting(test_task_runner_->GetMockTickClock());
312     return detector;
313   }
314 
315   std::string base_url_;
316   frame_test_helpers::WebViewHelper web_view_helper_;
317   scoped_refptr<base::TestMockTimeTaskRunner> test_task_runner_;
318 };
319 
HitTestIsContentEditable(WebView * view,int x,int y)320 static bool HitTestIsContentEditable(WebView* view, int x, int y) {
321   gfx::Point hit_point(x, y);
322   WebHitTestResult hit_test_result =
323       view->MainFrameWidget()->HitTestResultAt(hit_point);
324   return hit_test_result.IsContentEditable();
325 }
326 
HitTestElementId(WebView * view,int x,int y)327 static std::string HitTestElementId(WebView* view, int x, int y) {
328   gfx::Point hit_point(x, y);
329   WebHitTestResult hit_test_result =
330       view->MainFrameWidget()->HitTestResultAt(hit_point);
331   return hit_test_result.GetNode().To<WebElement>().GetAttribute("id").Utf8();
332 }
333 
OutlineColor(Element * element)334 static Color OutlineColor(Element* element) {
335   return element->GetComputedStyle()->VisitedDependentColor(
336       GetCSSPropertyOutlineColor());
337 }
338 
TEST_F(WebViewTest,HitTestVideo)339 TEST_F(WebViewTest, HitTestVideo) {
340   // Test that hit tests on parts of a video element result in hits on the video
341   // element itself as opposed to its child elements.
342   std::string url = RegisterMockedHttpURLLoad("video_200x200.html");
343   WebView* web_view = web_view_helper_.InitializeAndLoad(url);
344   web_view->MainFrameWidget()->Resize(WebSize(200, 200));
345 
346   // Center of video.
347   EXPECT_EQ("video", HitTestElementId(web_view, 100, 100));
348 
349   // Play button.
350   EXPECT_EQ("video", HitTestElementId(web_view, 10, 195));
351 
352   // Timeline bar.
353   EXPECT_EQ("video", HitTestElementId(web_view, 100, 195));
354 }
355 
TEST_F(WebViewTest,HitTestContentEditableImageMaps)356 TEST_F(WebViewTest, HitTestContentEditableImageMaps) {
357   std::string url =
358       RegisterMockedHttpURLLoad("content-editable-image-maps.html");
359   WebView* web_view = web_view_helper_.InitializeAndLoad(url);
360   web_view->MainFrameWidget()->Resize(WebSize(500, 500));
361 
362   EXPECT_EQ("areaANotEditable", HitTestElementId(web_view, 25, 25));
363   EXPECT_FALSE(HitTestIsContentEditable(web_view, 25, 25));
364   EXPECT_EQ("imageANotEditable", HitTestElementId(web_view, 75, 25));
365   EXPECT_FALSE(HitTestIsContentEditable(web_view, 75, 25));
366 
367   EXPECT_EQ("areaBNotEditable", HitTestElementId(web_view, 25, 125));
368   EXPECT_FALSE(HitTestIsContentEditable(web_view, 25, 125));
369   EXPECT_EQ("imageBEditable", HitTestElementId(web_view, 75, 125));
370   EXPECT_TRUE(HitTestIsContentEditable(web_view, 75, 125));
371 
372   EXPECT_EQ("areaCNotEditable", HitTestElementId(web_view, 25, 225));
373   EXPECT_FALSE(HitTestIsContentEditable(web_view, 25, 225));
374   EXPECT_EQ("imageCNotEditable", HitTestElementId(web_view, 75, 225));
375   EXPECT_FALSE(HitTestIsContentEditable(web_view, 75, 225));
376 
377   EXPECT_EQ("areaDEditable", HitTestElementId(web_view, 25, 325));
378   EXPECT_TRUE(HitTestIsContentEditable(web_view, 25, 325));
379   EXPECT_EQ("imageDNotEditable", HitTestElementId(web_view, 75, 325));
380   EXPECT_FALSE(HitTestIsContentEditable(web_view, 75, 325));
381 }
382 
HitTestAbsoluteUrl(WebView * view,int x,int y)383 static std::string HitTestAbsoluteUrl(WebView* view, int x, int y) {
384   gfx::Point hit_point(x, y);
385   WebHitTestResult hit_test_result =
386       view->MainFrameWidget()->HitTestResultAt(hit_point);
387   return hit_test_result.AbsoluteImageURL().GetString().Utf8();
388 }
389 
HitTestUrlElement(WebView * view,int x,int y)390 static WebElement HitTestUrlElement(WebView* view, int x, int y) {
391   gfx::Point hit_point(x, y);
392   WebHitTestResult hit_test_result =
393       view->MainFrameWidget()->HitTestResultAt(hit_point);
394   return hit_test_result.UrlElement();
395 }
396 
TEST_F(WebViewTest,ImageMapUrls)397 TEST_F(WebViewTest, ImageMapUrls) {
398   std::string url = RegisterMockedHttpURLLoad("image-map.html");
399   WebView* web_view = web_view_helper_.InitializeAndLoad(url);
400   web_view->MainFrameWidget()->Resize(WebSize(400, 400));
401 
402   std::string image_url =
403       "data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=";
404 
405   EXPECT_EQ("area", HitTestElementId(web_view, 25, 25));
406   EXPECT_EQ("area",
407             HitTestUrlElement(web_view, 25, 25).GetAttribute("id").Utf8());
408   EXPECT_EQ(image_url, HitTestAbsoluteUrl(web_view, 25, 25));
409 
410   EXPECT_EQ("image", HitTestElementId(web_view, 75, 25));
411   EXPECT_TRUE(HitTestUrlElement(web_view, 75, 25).IsNull());
412   EXPECT_EQ(image_url, HitTestAbsoluteUrl(web_view, 75, 25));
413 }
414 
TEST_F(WebViewTest,BrokenImage)415 TEST_F(WebViewTest, BrokenImage) {
416   url_test_helpers::RegisterMockedErrorURLLoad(
417       KURL(ToKURL(base_url_), "non_existent.png"));
418   std::string url = RegisterMockedHttpURLLoad("image-broken.html");
419 
420   WebViewImpl* web_view = web_view_helper_.Initialize();
421   web_view->GetSettings()->SetLoadsImagesAutomatically(true);
422   LoadFrame(web_view->MainFrameImpl(), url);
423   web_view->MainFrameWidget()->Resize(WebSize(400, 400));
424 
425   std::string image_url = "http://www.test.com/non_existent.png";
426 
427   EXPECT_EQ("image", HitTestElementId(web_view, 25, 25));
428   EXPECT_TRUE(HitTestUrlElement(web_view, 25, 25).IsNull());
429   EXPECT_EQ(image_url, HitTestAbsoluteUrl(web_view, 25, 25));
430 }
431 
TEST_F(WebViewTest,BrokenInputImage)432 TEST_F(WebViewTest, BrokenInputImage) {
433   url_test_helpers::RegisterMockedErrorURLLoad(
434       KURL(ToKURL(base_url_), "non_existent.png"));
435   std::string url = RegisterMockedHttpURLLoad("input-image-broken.html");
436 
437   WebViewImpl* web_view = web_view_helper_.Initialize();
438   web_view->GetSettings()->SetLoadsImagesAutomatically(true);
439   LoadFrame(web_view->MainFrameImpl(), url);
440   web_view->MainFrameWidget()->Resize(WebSize(400, 400));
441 
442   std::string image_url = "http://www.test.com/non_existent.png";
443 
444   EXPECT_EQ("image", HitTestElementId(web_view, 25, 25));
445   EXPECT_TRUE(HitTestUrlElement(web_view, 25, 25).IsNull());
446   EXPECT_EQ(image_url, HitTestAbsoluteUrl(web_view, 25, 25));
447 }
448 
TEST_F(WebViewTest,SetBaseBackgroundColor)449 TEST_F(WebViewTest, SetBaseBackgroundColor) {
450   const SkColor kDarkCyan = SkColorSetARGB(0xFF, 0x22, 0x77, 0x88);
451   const SkColor kTranslucentPutty = SkColorSetARGB(0x80, 0xBF, 0xB1, 0x96);
452 
453   WebViewImpl* web_view = web_view_helper_.Initialize();
454   EXPECT_EQ(SK_ColorWHITE, web_view->BackgroundColor());
455 
456   web_view->SetBaseBackgroundColor(SK_ColorBLUE);
457   EXPECT_EQ(SK_ColorBLUE, web_view->BackgroundColor());
458 
459   WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
460   frame_test_helpers::LoadHTMLString(
461       web_view->MainFrameImpl(),
462       "<html><head><style>body "
463       "{background-color:#227788}</style></head></"
464       "html>",
465       base_url);
466   EXPECT_EQ(kDarkCyan, web_view->BackgroundColor());
467 
468   frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(),
469                                      "<html><head><style>body "
470                                      "{background-color:rgba(255,0,0,0.5)}</"
471                                      "style></head></html>",
472                                      base_url);
473   // Expected: red (50% alpha) blended atop base of SK_ColorBLUE.
474   EXPECT_EQ(0xFF80007F, web_view->BackgroundColor());
475 
476   web_view->SetBaseBackgroundColor(kTranslucentPutty);
477   // Expected: red (50% alpha) blended atop kTranslucentPutty. Note the alpha.
478   EXPECT_EQ(0xBFE93A31, web_view->BackgroundColor());
479 
480   web_view->SetBaseBackgroundColor(SK_ColorTRANSPARENT);
481   frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(),
482                                      "<html><head><style>body "
483                                      "{background-color:transparent}</style></"
484                                      "head></html>",
485                                      base_url);
486   // Expected: transparent on top of transparent will still be transparent.
487   EXPECT_EQ(SK_ColorTRANSPARENT, web_view->BackgroundColor());
488 
489   LocalFrame* frame = web_view->MainFrameImpl()->GetFrame();
490   // The shutdown() calls are a hack to prevent this test
491   // from violating invariants about frame state during navigation/detach.
492   frame->GetDocument()->Shutdown();
493 
494   // Creating a new frame view with the background color having 0 alpha.
495   frame->CreateView(IntSize(1024, 768), Color::kTransparent);
496   EXPECT_EQ(SK_ColorTRANSPARENT, frame->View()->BaseBackgroundColor());
497   frame->View()->Dispose();
498 
499   const Color transparent_red(100, 0, 0, 0);
500   frame->CreateView(IntSize(1024, 768), transparent_red);
501   EXPECT_EQ(transparent_red, frame->View()->BaseBackgroundColor());
502   frame->View()->Dispose();
503 }
504 
TEST_F(WebViewTest,SetBaseBackgroundColorBeforeMainFrame)505 TEST_F(WebViewTest, SetBaseBackgroundColorBeforeMainFrame) {
506   // Note: this test doesn't use WebViewHelper since it intentionally runs
507   // initialization code between WebView and WebLocalFrame creation.
508   frame_test_helpers::TestWebViewClient web_view_client;
509   frame_test_helpers::TestWebWidgetClient web_widget_client;
510   WebViewImpl* web_view = static_cast<WebViewImpl*>(
511       WebView::Create(&web_view_client, false,
512                       /*compositing_enabled=*/true, nullptr,
513                       mojo::ScopedInterfaceEndpointHandle()));
514 
515   EXPECT_NE(SK_ColorBLUE, web_view->BackgroundColor());
516   // WebView does not have a frame yet, but we should still be able to set the
517   // background color.
518   web_view->SetBaseBackgroundColor(SK_ColorBLUE);
519   EXPECT_EQ(SK_ColorBLUE, web_view->BackgroundColor());
520 
521   frame_test_helpers::TestWebFrameClient web_frame_client;
522   WebLocalFrame* frame = WebLocalFrame::CreateMainFrame(
523       web_view, &web_frame_client, nullptr, nullptr);
524   web_frame_client.Bind(frame);
525 
526   {
527     // Copy the steps done from WebViewHelper::InitializeWithOpener() to set up
528     // the appropriate pointers!
529     WebFrameWidget* widget = blink::WebFrameWidget::CreateForMainFrame(
530         &web_widget_client, frame,
531         CrossVariantMojoAssociatedRemote<mojom::FrameWidgetHostInterfaceBase>(),
532         CrossVariantMojoAssociatedReceiver<mojom::FrameWidgetInterfaceBase>(),
533         CrossVariantMojoAssociatedRemote<mojom::WidgetHostInterfaceBase>(),
534         CrossVariantMojoAssociatedReceiver<mojom::WidgetInterfaceBase>());
535     widget->SetCompositorHosts(web_widget_client.layer_tree_host(),
536                                web_widget_client.animation_host());
537     widget->SetCompositorVisible(true);
538     web_view->DidAttachLocalMainFrame();
539   }
540 
541   // The color should be passed to the compositor.
542   cc::LayerTreeHost* host = web_widget_client.layer_tree_host();
543   EXPECT_EQ(SK_ColorBLUE, web_view->BackgroundColor());
544   EXPECT_EQ(SK_ColorBLUE, host->background_color());
545 
546   web_view->Close();
547 }
548 
TEST_F(WebViewTest,SetBaseBackgroundColorAndBlendWithExistingContent)549 TEST_F(WebViewTest, SetBaseBackgroundColorAndBlendWithExistingContent) {
550   const SkColor kAlphaRed = SkColorSetARGB(0x80, 0xFF, 0x00, 0x00);
551   const SkColor kAlphaGreen = SkColorSetARGB(0x80, 0x00, 0xFF, 0x00);
552   const int kWidth = 100;
553   const int kHeight = 100;
554 
555   WebViewImpl* web_view = web_view_helper_.Initialize();
556 
557   // Set WebView background to green with alpha.
558   web_view->SetBaseBackgroundColor(kAlphaGreen);
559   web_view->GetSettings()->SetShouldClearDocumentBackground(false);
560   web_view->MainFrameWidget()->Resize(WebSize(kWidth, kHeight));
561   UpdateAllLifecyclePhases();
562 
563   // Set canvas background to red with alpha.
564   SkBitmap bitmap;
565   bitmap.allocN32Pixels(kWidth, kHeight);
566   SkCanvas canvas(bitmap);
567   canvas.clear(kAlphaRed);
568 
569   PaintRecordBuilder builder;
570 
571   // Paint the root of the main frame in the way that CompositedLayerMapping
572   // would.
573   LocalFrameView* view = web_view_helper_.LocalMainFrame()->GetFrameView();
574   PaintLayer* root_layer = view->GetLayoutView()->Layer();
575   CullRect paint_rect(IntRect(0, 0, kWidth, kHeight));
576   PaintLayerPaintingInfo painting_info(
577       root_layer, paint_rect, kGlobalPaintNormalPhase, PhysicalOffset());
578 
579   view->GetLayoutView()->GetDocument().Lifecycle().AdvanceTo(
580       DocumentLifecycle::kInPaint);
581   PaintLayerPainter(*root_layer)
582       .PaintLayerContents(builder.Context(), painting_info,
583                           kPaintLayerPaintingCompositingAllPhases);
584   view->GetLayoutView()->GetDocument().Lifecycle().AdvanceTo(
585       DocumentLifecycle::kPaintClean);
586   builder.EndRecording()->Playback(&canvas);
587 
588   // The result should be a blend of red and green.
589   SkColor color = bitmap.getColor(kWidth / 2, kHeight / 2);
590   EXPECT_TRUE(RedChannel(color));
591   EXPECT_TRUE(GreenChannel(color));
592 }
593 
TEST_F(WebViewTest,SetBaseBackgroundColorWithColorScheme)594 TEST_F(WebViewTest, SetBaseBackgroundColorWithColorScheme) {
595   ScopedCSSColorSchemeForTest enable_color_scheme(true);
596 
597   WebViewImpl* web_view = web_view_helper_.Initialize();
598   ColorSchemeHelper color_scheme_helper(*(web_view->GetPage()));
599   color_scheme_helper.SetPreferredColorScheme(PreferredColorScheme::kLight);
600   web_view->SetBaseBackgroundColor(SK_ColorBLUE);
601 
602   WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
603   frame_test_helpers::LoadHTMLString(
604       web_view->MainFrameImpl(),
605       "<style>:root { color-scheme: light dark }<style>", base_url);
606   UpdateAllLifecyclePhases();
607 
608   LocalFrameView* frame_view = web_view->MainFrameImpl()->GetFrame()->View();
609   EXPECT_EQ(Color(0, 0, 255), frame_view->BaseBackgroundColor());
610 
611   color_scheme_helper.SetPreferredColorScheme(PreferredColorScheme::kDark);
612   UpdateAllLifecyclePhases();
613   EXPECT_EQ(Color::kBlack, frame_view->BaseBackgroundColor());
614 
615   // Don't let dark color-scheme override a transparent background.
616   web_view->SetBaseBackgroundColor(SK_ColorTRANSPARENT);
617   EXPECT_EQ(Color::kTransparent, frame_view->BaseBackgroundColor());
618   web_view->SetBaseBackgroundColor(SK_ColorBLUE);
619   EXPECT_EQ(Color::kBlack, frame_view->BaseBackgroundColor());
620 
621   color_scheme_helper.SetPreferredColorScheme(PreferredColorScheme::kLight);
622   UpdateAllLifecyclePhases();
623   EXPECT_EQ(Color(0, 0, 255), frame_view->BaseBackgroundColor());
624 }
625 
TEST_F(WebViewTest,FocusIsInactive)626 TEST_F(WebViewTest, FocusIsInactive) {
627   RegisterMockedHttpURLLoad("visible_iframe.html");
628   WebViewImpl* web_view =
629       web_view_helper_.InitializeAndLoad(base_url_ + "visible_iframe.html");
630 
631   web_view->MainFrameWidget()->SetFocus(true);
632   web_view->SetIsActive(true);
633   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
634   EXPECT_TRUE(IsA<HTMLDocument>(frame->GetFrame()->GetDocument()));
635 
636   Document* document = frame->GetFrame()->GetDocument();
637   EXPECT_TRUE(document->hasFocus());
638   web_view->MainFrameWidget()->SetFocus(false);
639   web_view->SetIsActive(false);
640   EXPECT_FALSE(document->hasFocus());
641   web_view->MainFrameWidget()->SetFocus(true);
642   web_view->SetIsActive(true);
643   EXPECT_TRUE(document->hasFocus());
644   web_view->MainFrameWidget()->SetFocus(true);
645   web_view->SetIsActive(false);
646   EXPECT_FALSE(document->hasFocus());
647   web_view->MainFrameWidget()->SetFocus(false);
648   web_view->SetIsActive(true);
649   EXPECT_FALSE(document->hasFocus());
650   web_view->SetIsActive(false);
651   web_view->MainFrameWidget()->SetFocus(true);
652   EXPECT_TRUE(document->hasFocus());
653   web_view->SetIsActive(true);
654   web_view->MainFrameWidget()->SetFocus(false);
655   EXPECT_FALSE(document->hasFocus());
656 }
657 
TEST_F(WebViewTest,DocumentHasFocus)658 TEST_F(WebViewTest, DocumentHasFocus) {
659   WebViewImpl* web_view = web_view_helper_.Initialize();
660   web_view->MainFrameWidget()->SetFocus(true);
661 
662   WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
663   frame_test_helpers::LoadHTMLString(
664       web_view->MainFrameImpl(),
665       "<input id=input></input>"
666       "<div id=log></div>"
667       "<script>"
668       "  document.getElementById('input').addEventListener('focus', () => {"
669       "    document.getElementById('log').textContent = 'document.hasFocus(): "
670       "' + document.hasFocus();"
671       "  });"
672       "  document.getElementById('input').addEventListener('blur', () => {"
673       "    document.getElementById('log').textContent = '';"
674       "  });"
675       "  document.getElementById('input').focus();"
676       "</script>",
677       base_url);
678 
679   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
680   Document* document = frame->GetFrame()->GetDocument();
681   WebElement log_element = frame->GetDocument().GetElementById("log");
682   EXPECT_TRUE(document->hasFocus());
683   EXPECT_EQ("document.hasFocus(): true", log_element.TextContent());
684 
685   web_view->SetIsActive(false);
686   web_view->MainFrameWidget()->SetFocus(false);
687   EXPECT_FALSE(document->hasFocus());
688   EXPECT_TRUE(log_element.TextContent().IsEmpty());
689 
690   web_view->MainFrameWidget()->SetFocus(true);
691   EXPECT_TRUE(document->hasFocus());
692   EXPECT_EQ("document.hasFocus(): true", log_element.TextContent());
693 }
694 
TEST_F(WebViewTest,PlatformColorsChangedOnDeviceEmulation)695 TEST_F(WebViewTest, PlatformColorsChangedOnDeviceEmulation) {
696   WebViewImpl* web_view_impl = web_view_helper_.Initialize();
697   WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
698   frame_test_helpers::LoadHTMLString(
699       web_view_impl->MainFrameImpl(),
700       "<style>"
701       "  span { outline-color: -webkit-focus-ring-color; }"
702       "</style>"
703       "<span id='span1'></span>",
704       base_url);
705   UpdateAllLifecyclePhases();
706 
707   WebDeviceEmulationParams params;
708   params.screen_position = WebDeviceEmulationParams::kMobile;
709 
710   Document& document =
711       *web_view_impl->MainFrameImpl()->GetFrame()->GetDocument();
712 
713   Element* span1 = document.getElementById("span1");
714   ASSERT_TRUE(span1);
715 
716   // Check non-MobileLayoutTheme color.
717   Color original = LayoutTheme::GetTheme().FocusRingColor();
718   EXPECT_EQ(original, OutlineColor(span1));
719 
720   // Set the focus ring color for the mobile theme to something known.
721   Color custom_color = MakeRGB(123, 145, 167);
722   {
723     ScopedMobileLayoutThemeForTest mobile_layout_theme_enabled(true);
724     LayoutTheme::GetTheme().SetCustomFocusRingColor(custom_color);
725   }
726 
727   EXPECT_NE(custom_color, original);
728   web_view_impl->EnableDeviceEmulation(params);
729 
730   // All <span>s should have the custom outline color, and not (for example)
731   // the original color fetched from cache.
732   auto* span2 = MakeGarbageCollected<HTMLSpanElement>(document);
733   document.body()->AppendChild(span2);
734   UpdateAllLifecyclePhases();
735   EXPECT_EQ(custom_color, OutlineColor(span1));
736   EXPECT_EQ(custom_color, OutlineColor(span2));
737 
738   // Disable mobile emulation. All <span>s should once again have the
739   // original outline color.
740   web_view_impl->DisableDeviceEmulation();
741   auto* span3 = MakeGarbageCollected<HTMLSpanElement>(document);
742   document.body()->AppendChild(span3);
743   UpdateAllLifecyclePhases();
744   EXPECT_EQ(original, OutlineColor(span1));
745   EXPECT_EQ(original, OutlineColor(span2));
746   EXPECT_EQ(original, OutlineColor(span3));
747 }
748 
TEST_F(WebViewTest,ActiveState)749 TEST_F(WebViewTest, ActiveState) {
750   RegisterMockedHttpURLLoad("visible_iframe.html");
751   WebView* web_view =
752       web_view_helper_.InitializeAndLoad(base_url_ + "visible_iframe.html");
753 
754   ASSERT_TRUE(web_view);
755 
756   web_view->SetIsActive(true);
757   EXPECT_TRUE(web_view->IsActive());
758 
759   web_view->SetIsActive(false);
760   EXPECT_FALSE(web_view->IsActive());
761 
762   web_view->SetIsActive(true);
763   EXPECT_TRUE(web_view->IsActive());
764 }
765 
TEST_F(WebViewTest,HitTestResultAtWithPageScale)766 TEST_F(WebViewTest, HitTestResultAtWithPageScale) {
767   std::string url = base_url_ + "specify_size.html?" + "50px" + ":" + "50px";
768   url_test_helpers::RegisterMockedURLLoad(
769       ToKURL(url), test::CoreTestDataPath("specify_size.html"));
770   WebView* web_view = web_view_helper_.InitializeAndLoad(url);
771   web_view->MainFrameWidget()->Resize(WebSize(100, 100));
772   gfx::Point hit_point(75, 75);
773 
774   // Image is at top left quandrant, so should not hit it.
775   WebHitTestResult negative_result =
776       web_view->MainFrameWidget()->HitTestResultAt(hit_point);
777   EXPECT_FALSE(
778       negative_result.GetNode().To<WebElement>().HasHTMLTagName("img"));
779   negative_result.Reset();
780 
781   // Scale page up 2x so image should occupy the whole viewport.
782   web_view->SetPageScaleFactor(2.0f);
783   WebHitTestResult positive_result =
784       web_view->MainFrameWidget()->HitTestResultAt(hit_point);
785   EXPECT_TRUE(positive_result.GetNode().To<WebElement>().HasHTMLTagName("img"));
786   positive_result.Reset();
787 }
788 
TEST_F(WebViewTest,HitTestResultAtWithPageScaleAndPan)789 TEST_F(WebViewTest, HitTestResultAtWithPageScaleAndPan) {
790   std::string url = base_url_ + "specify_size.html?" + "50px" + ":" + "50px";
791   url_test_helpers::RegisterMockedURLLoad(
792       ToKURL(url), test::CoreTestDataPath("specify_size.html"));
793   WebViewImpl* web_view = web_view_helper_.Initialize();
794   LoadFrame(web_view->MainFrameImpl(), url);
795   web_view->MainFrameWidget()->Resize(WebSize(100, 100));
796   gfx::Point hit_point(75, 75);
797 
798   // Image is at top left quandrant, so should not hit it.
799   WebHitTestResult negative_result = web_view->HitTestResultAt(hit_point);
800   EXPECT_FALSE(
801       negative_result.GetNode().To<WebElement>().HasHTMLTagName("img"));
802   negative_result.Reset();
803 
804   // Scale page up 2x so image should occupy the whole viewport.
805   web_view->SetPageScaleFactor(2.0f);
806   WebHitTestResult positive_result = web_view->HitTestResultAt(hit_point);
807   EXPECT_TRUE(positive_result.GetNode().To<WebElement>().HasHTMLTagName("img"));
808   positive_result.Reset();
809 
810   // Pan around the zoomed in page so the image is not visible in viewport.
811   web_view->SetVisualViewportOffset(gfx::PointF(100, 100));
812   WebHitTestResult negative_result2 = web_view->HitTestResultAt(hit_point);
813   EXPECT_FALSE(
814       negative_result2.GetNode().To<WebElement>().HasHTMLTagName("img"));
815   negative_result2.Reset();
816 }
817 
TEST_F(WebViewTest,HitTestResultForTapWithTapArea)818 TEST_F(WebViewTest, HitTestResultForTapWithTapArea) {
819   std::string url = RegisterMockedHttpURLLoad("hit_test.html");
820   WebView* web_view = web_view_helper_.InitializeAndLoad(url);
821   web_view->MainFrameWidget()->Resize(WebSize(100, 100));
822   gfx::Point hit_point(55, 55);
823 
824   // Image is at top left quandrant, so should not hit it.
825   WebHitTestResult negative_result =
826       web_view->MainFrameWidget()->HitTestResultAt(hit_point);
827   EXPECT_FALSE(
828       negative_result.GetNode().To<WebElement>().HasHTMLTagName("img"));
829   negative_result.Reset();
830 
831   // The tap area is 20 by 20 square, centered at 55, 55.
832   WebSize tap_area(20, 20);
833   WebHitTestResult positive_result =
834       web_view->HitTestResultForTap(hit_point, tap_area);
835   EXPECT_TRUE(positive_result.GetNode().To<WebElement>().HasHTMLTagName("img"));
836   positive_result.Reset();
837 
838   // Move the hit point the image is just outside the tapped area now.
839   hit_point = gfx::Point(61, 61);
840   WebHitTestResult negative_result2 =
841       web_view->HitTestResultForTap(hit_point, tap_area);
842   EXPECT_FALSE(
843       negative_result2.GetNode().To<WebElement>().HasHTMLTagName("img"));
844   negative_result2.Reset();
845 }
846 
TEST_F(WebViewTest,HitTestResultForTapWithTapAreaPageScaleAndPan)847 TEST_F(WebViewTest, HitTestResultForTapWithTapAreaPageScaleAndPan) {
848   std::string url = RegisterMockedHttpURLLoad("hit_test.html");
849   WebViewImpl* web_view = web_view_helper_.Initialize();
850   LoadFrame(web_view->MainFrameImpl(), url);
851   web_view->MainFrameWidget()->Resize(WebSize(100, 100));
852   gfx::Point hit_point(55, 55);
853 
854   // Image is at top left quandrant, so should not hit it.
855   WebHitTestResult negative_result = web_view->HitTestResultAt(hit_point);
856   EXPECT_FALSE(
857       negative_result.GetNode().To<WebElement>().HasHTMLTagName("img"));
858   negative_result.Reset();
859 
860   // The tap area is 20 by 20 square, centered at 55, 55.
861   WebSize tap_area(20, 20);
862   WebHitTestResult positive_result =
863       web_view->HitTestResultForTap(hit_point, tap_area);
864   EXPECT_TRUE(positive_result.GetNode().To<WebElement>().HasHTMLTagName("img"));
865   positive_result.Reset();
866 
867   // Zoom in and pan around the page so the image is not visible in viewport.
868   web_view->SetPageScaleFactor(2.0f);
869   web_view->SetVisualViewportOffset(gfx::PointF(100, 100));
870   WebHitTestResult negative_result2 =
871       web_view->HitTestResultForTap(hit_point, tap_area);
872   EXPECT_FALSE(
873       negative_result2.GetNode().To<WebElement>().HasHTMLTagName("img"));
874   negative_result2.Reset();
875 }
876 
TestAutoResize(const WebSize & min_auto_resize,const WebSize & max_auto_resize,const std::string & page_width,const std::string & page_height,int expected_width,int expected_height,HorizontalScrollbarState expected_horizontal_state,VerticalScrollbarState expected_vertical_state)877 void WebViewTest::TestAutoResize(
878     const WebSize& min_auto_resize,
879     const WebSize& max_auto_resize,
880     const std::string& page_width,
881     const std::string& page_height,
882     int expected_width,
883     int expected_height,
884     HorizontalScrollbarState expected_horizontal_state,
885     VerticalScrollbarState expected_vertical_state) {
886   AutoResizeWebViewClient client;
887   std::string url =
888       base_url_ + "specify_size.html?" + page_width + ":" + page_height;
889   url_test_helpers::RegisterMockedURLLoad(
890       ToKURL(url), test::CoreTestDataPath("specify_size.html"));
891   WebViewImpl* web_view =
892       web_view_helper_.InitializeAndLoad(url, nullptr, &client);
893   client.GetTestData().SetWebView(web_view);
894 
895   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
896   LocalFrameView* frame_view = frame->GetFrame()->View();
897   frame_view->UpdateLayout();
898   EXPECT_FALSE(frame_view->LayoutPending());
899   EXPECT_FALSE(frame_view->NeedsLayout());
900 
901   web_view->EnableAutoResizeMode(min_auto_resize, max_auto_resize);
902   EXPECT_TRUE(frame_view->LayoutPending());
903   EXPECT_TRUE(frame_view->NeedsLayout());
904   frame_view->UpdateLayout();
905 
906   EXPECT_TRUE(frame->GetFrame()->GetDocument()->IsHTMLDocument());
907 
908   EXPECT_EQ(expected_width, client.GetTestData().Width());
909   EXPECT_EQ(expected_height, client.GetTestData().Height());
910 
911 // Android disables main frame scrollbars.
912 #if !defined(OS_ANDROID)
913   EXPECT_EQ(expected_horizontal_state,
914             client.GetTestData().GetHorizontalScrollbarState());
915   EXPECT_EQ(expected_vertical_state,
916             client.GetTestData().GetVerticalScrollbarState());
917 #endif
918 
919   // Explicitly reset to break dependency on locally scoped client.
920   web_view_helper_.Reset();
921 }
922 
TEST_F(WebViewTest,AutoResizeMinimumSize)923 TEST_F(WebViewTest, AutoResizeMinimumSize) {
924   WebSize min_auto_resize(91, 56);
925   WebSize max_auto_resize(403, 302);
926   std::string page_width = "91px";
927   std::string page_height = "56px";
928   int expected_width = 91;
929   int expected_height = 56;
930   TestAutoResize(min_auto_resize, max_auto_resize, page_width, page_height,
931                  expected_width, expected_height, kNoHorizontalScrollbar,
932                  kNoVerticalScrollbar);
933 }
934 
TEST_F(WebViewTest,AutoResizeHeightOverflowAndFixedWidth)935 TEST_F(WebViewTest, AutoResizeHeightOverflowAndFixedWidth) {
936   WebSize min_auto_resize(90, 95);
937   WebSize max_auto_resize(90, 100);
938   std::string page_width = "60px";
939   std::string page_height = "200px";
940   int expected_width = 90;
941   int expected_height = 100;
942   TestAutoResize(min_auto_resize, max_auto_resize, page_width, page_height,
943                  expected_width, expected_height, kNoHorizontalScrollbar,
944                  kVisibleVerticalScrollbar);
945 }
946 
TEST_F(WebViewTest,AutoResizeFixedHeightAndWidthOverflow)947 TEST_F(WebViewTest, AutoResizeFixedHeightAndWidthOverflow) {
948   WebSize min_auto_resize(90, 100);
949   WebSize max_auto_resize(200, 100);
950   std::string page_width = "300px";
951   std::string page_height = "80px";
952   int expected_width = 200;
953   int expected_height = 100;
954   TestAutoResize(min_auto_resize, max_auto_resize, page_width, page_height,
955                  expected_width, expected_height, kVisibleHorizontalScrollbar,
956                  kNoVerticalScrollbar);
957 }
958 
959 // Next three tests disabled for https://bugs.webkit.org/show_bug.cgi?id=92318 .
960 // It seems we can run three AutoResize tests, then the next one breaks.
TEST_F(WebViewTest,AutoResizeInBetweenSizes)961 TEST_F(WebViewTest, AutoResizeInBetweenSizes) {
962   WebSize min_auto_resize(90, 95);
963   WebSize max_auto_resize(200, 300);
964   std::string page_width = "100px";
965   std::string page_height = "200px";
966   int expected_width = 100;
967   int expected_height = 200;
968   TestAutoResize(min_auto_resize, max_auto_resize, page_width, page_height,
969                  expected_width, expected_height, kNoHorizontalScrollbar,
970                  kNoVerticalScrollbar);
971 }
972 
TEST_F(WebViewTest,AutoResizeOverflowSizes)973 TEST_F(WebViewTest, AutoResizeOverflowSizes) {
974   WebSize min_auto_resize(90, 95);
975   WebSize max_auto_resize(200, 300);
976   std::string page_width = "300px";
977   std::string page_height = "400px";
978   int expected_width = 200;
979   int expected_height = 300;
980   TestAutoResize(min_auto_resize, max_auto_resize, page_width, page_height,
981                  expected_width, expected_height, kVisibleHorizontalScrollbar,
982                  kVisibleVerticalScrollbar);
983 }
984 
TEST_F(WebViewTest,AutoResizeMaxSize)985 TEST_F(WebViewTest, AutoResizeMaxSize) {
986   WebSize min_auto_resize(90, 95);
987   WebSize max_auto_resize(200, 300);
988   std::string page_width = "200px";
989   std::string page_height = "300px";
990   int expected_width = 200;
991   int expected_height = 300;
992   TestAutoResize(min_auto_resize, max_auto_resize, page_width, page_height,
993                  expected_width, expected_height, kNoHorizontalScrollbar,
994                  kNoVerticalScrollbar);
995 }
996 
TestTextInputType(WebTextInputType expected_type,const std::string & html_file)997 void WebViewTest::TestTextInputType(WebTextInputType expected_type,
998                                     const std::string& html_file) {
999   RegisterMockedHttpURLLoad(html_file);
1000   WebViewImpl* web_view =
1001       web_view_helper_.InitializeAndLoad(base_url_ + html_file);
1002   WebInputMethodController* controller =
1003       web_view->MainFrameImpl()->GetInputMethodController();
1004   EXPECT_EQ(kWebTextInputTypeNone, controller->TextInputType());
1005   EXPECT_EQ(kWebTextInputTypeNone, controller->TextInputInfo().type);
1006   web_view->SetInitialFocus(false);
1007   EXPECT_EQ(expected_type, controller->TextInputType());
1008   EXPECT_EQ(expected_type, controller->TextInputInfo().type);
1009   web_view->FocusedElement()->blur();
1010   EXPECT_EQ(kWebTextInputTypeNone, controller->TextInputType());
1011   EXPECT_EQ(kWebTextInputTypeNone, controller->TextInputInfo().type);
1012 }
1013 
TEST_F(WebViewTest,TextInputType)1014 TEST_F(WebViewTest, TextInputType) {
1015   TestTextInputType(kWebTextInputTypeText, "input_field_default.html");
1016   TestTextInputType(kWebTextInputTypePassword, "input_field_password.html");
1017   TestTextInputType(kWebTextInputTypeEmail, "input_field_email.html");
1018   TestTextInputType(kWebTextInputTypeSearch, "input_field_search.html");
1019   TestTextInputType(kWebTextInputTypeNumber, "input_field_number.html");
1020   TestTextInputType(kWebTextInputTypeTelephone, "input_field_tel.html");
1021   TestTextInputType(kWebTextInputTypeURL, "input_field_url.html");
1022 }
1023 
TEST_F(WebViewTest,TextInputInfoUpdateStyleAndLayout)1024 TEST_F(WebViewTest, TextInputInfoUpdateStyleAndLayout) {
1025   frame_test_helpers::WebViewHelper web_view_helper;
1026   WebViewImpl* web_view_impl = web_view_helper.Initialize();
1027 
1028   WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
1029   // Here, we need to construct a document that has a special property:
1030   // Adding id="foo" to the <path> element will trigger creation of an SVG
1031   // instance tree for the use <use> element.
1032   // This is significant, because SVG instance trees are actually created lazily
1033   // during Document::updateStyleAndLayout code, thus incrementing the DOM tree
1034   // version and freaking out the EphemeralRange (invalidating it).
1035   frame_test_helpers::LoadHTMLString(
1036       web_view_impl->MainFrameImpl(),
1037       "<svg height='100%' version='1.1' viewBox='0 0 14 14' width='100%'>"
1038       "<use xmlns:xlink='http://www.w3.org/1999/xlink' xlink:href='#foo'></use>"
1039       "<path d='M 100 100 L 300 100 L 200 300 z' fill='#000'></path>"
1040       "</svg>"
1041       "<input>",
1042       base_url);
1043   web_view_impl->SetInitialFocus(false);
1044 
1045   // Add id="foo" to <path>, thus triggering the condition described above.
1046   Document* document =
1047       web_view_impl->MainFrameImpl()->GetFrame()->GetDocument();
1048   document->body()
1049       ->QuerySelector("path", ASSERT_NO_EXCEPTION)
1050       ->SetIdAttribute("foo");
1051 
1052   // This should not DCHECK.
1053   EXPECT_EQ(kWebTextInputTypeText, web_view_impl->MainFrameImpl()
1054                                        ->GetInputMethodController()
1055                                        ->TextInputInfo()
1056                                        .type);
1057 }
1058 
TestInputMode(WebTextInputMode expected_input_mode,const std::string & html_file)1059 void WebViewTest::TestInputMode(WebTextInputMode expected_input_mode,
1060                                 const std::string& html_file) {
1061   RegisterMockedHttpURLLoad(html_file);
1062   WebViewImpl* web_view_impl =
1063       web_view_helper_.InitializeAndLoad(base_url_ + html_file);
1064   web_view_impl->SetInitialFocus(false);
1065   EXPECT_EQ(expected_input_mode, web_view_impl->MainFrameImpl()
1066                                      ->GetInputMethodController()
1067                                      ->TextInputInfo()
1068                                      .input_mode);
1069 }
1070 
TEST_F(WebViewTest,InputMode)1071 TEST_F(WebViewTest, InputMode) {
1072   TestInputMode(WebTextInputMode::kWebTextInputModeDefault,
1073                 "input_mode_default.html");
1074   TestInputMode(WebTextInputMode::kWebTextInputModeDefault,
1075                 "input_mode_default_unknown.html");
1076   TestInputMode(WebTextInputMode::kWebTextInputModeNone,
1077                 "input_mode_type_none.html");
1078   TestInputMode(WebTextInputMode::kWebTextInputModeText,
1079                 "input_mode_type_text.html");
1080   TestInputMode(WebTextInputMode::kWebTextInputModeTel,
1081                 "input_mode_type_tel.html");
1082   TestInputMode(WebTextInputMode::kWebTextInputModeUrl,
1083                 "input_mode_type_url.html");
1084   TestInputMode(WebTextInputMode::kWebTextInputModeEmail,
1085                 "input_mode_type_email.html");
1086   TestInputMode(WebTextInputMode::kWebTextInputModeNumeric,
1087                 "input_mode_type_numeric.html");
1088   TestInputMode(WebTextInputMode::kWebTextInputModeDecimal,
1089                 "input_mode_type_decimal.html");
1090   TestInputMode(WebTextInputMode::kWebTextInputModeSearch,
1091                 "input_mode_type_search.html");
1092 }
1093 
TestInputAction(ui::TextInputAction expected_input_action,const std::string & html_file)1094 void WebViewTest::TestInputAction(ui::TextInputAction expected_input_action,
1095                                   const std::string& html_file) {
1096   RegisterMockedHttpURLLoad(html_file);
1097   WebViewImpl* web_view_impl =
1098       web_view_helper_.InitializeAndLoad(base_url_ + html_file);
1099   web_view_impl->SetInitialFocus(false);
1100   EXPECT_EQ(expected_input_action, web_view_impl->MainFrameImpl()
1101                                        ->GetInputMethodController()
1102                                        ->TextInputInfo()
1103                                        .action);
1104 }
1105 
TEST_F(WebViewTest,TextInputAction)1106 TEST_F(WebViewTest, TextInputAction) {
1107   TestInputAction(ui::TextInputAction::kDefault, "enter_key_hint_default.html");
1108   TestInputAction(ui::TextInputAction::kDefault,
1109                   "enter_key_hint_default_unknown.html");
1110   TestInputAction(ui::TextInputAction::kEnter, "enter_key_hint_enter.html");
1111   TestInputAction(ui::TextInputAction::kGo, "enter_key_hint_go.html");
1112   TestInputAction(ui::TextInputAction::kDone, "enter_key_hint_done.html");
1113   TestInputAction(ui::TextInputAction::kNext, "enter_key_hint_next.html");
1114   TestInputAction(ui::TextInputAction::kPrevious,
1115                   "enter_key_hint_previous.html");
1116   TestInputAction(ui::TextInputAction::kSearch, "enter_key_hint_search.html");
1117   TestInputAction(ui::TextInputAction::kSend, "enter_key_hint_send.html");
1118   TestInputAction(ui::TextInputAction::kNext, "enter_key_hint_mixed_case.html");
1119 }
1120 
TEST_F(WebViewTest,TextInputInfoWithReplacedElements)1121 TEST_F(WebViewTest, TextInputInfoWithReplacedElements) {
1122   std::string url = RegisterMockedHttpURLLoad("div_with_image.html");
1123   url_test_helpers::RegisterMockedURLLoad(
1124       ToKURL("http://www.test.com/foo.png"),
1125       test::CoreTestDataPath("white-1x1.png"));
1126   WebViewImpl* web_view_impl = web_view_helper_.InitializeAndLoad(url);
1127   web_view_impl->SetInitialFocus(false);
1128   WebTextInputInfo info = web_view_impl->MainFrameImpl()
1129                               ->GetInputMethodController()
1130                               ->TextInputInfo();
1131 
1132   EXPECT_EQ("foo\xef\xbf\xbc", info.value.Utf8());
1133 }
1134 
TEST_F(WebViewTest,SetEditableSelectionOffsetsAndTextInputInfo)1135 TEST_F(WebViewTest, SetEditableSelectionOffsetsAndTextInputInfo) {
1136   RegisterMockedHttpURLLoad("input_field_populated.html");
1137   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
1138       base_url_ + "input_field_populated.html");
1139   web_view->SetInitialFocus(false);
1140   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
1141   WebInputMethodController* active_input_method_controller =
1142       frame->GetInputMethodController();
1143   frame->SetEditableSelectionOffsets(5, 13);
1144   EXPECT_EQ("56789abc", frame->SelectionAsText());
1145   WebTextInputInfo info = active_input_method_controller->TextInputInfo();
1146   EXPECT_EQ("0123456789abcdefghijklmnopqrstuvwxyz", info.value);
1147   EXPECT_EQ(5, info.selection_start);
1148   EXPECT_EQ(13, info.selection_end);
1149   EXPECT_EQ(-1, info.composition_start);
1150   EXPECT_EQ(-1, info.composition_end);
1151 
1152   RegisterMockedHttpURLLoad("content_editable_populated.html");
1153   web_view = web_view_helper_.InitializeAndLoad(
1154       base_url_ + "content_editable_populated.html");
1155   web_view->SetInitialFocus(false);
1156   frame = web_view->MainFrameImpl();
1157   active_input_method_controller = frame->GetInputMethodController();
1158   frame->SetEditableSelectionOffsets(8, 19);
1159   EXPECT_EQ("89abcdefghi", frame->SelectionAsText());
1160   info = active_input_method_controller->TextInputInfo();
1161   EXPECT_EQ("0123456789abcdefghijklmnopqrstuvwxyz", info.value);
1162   EXPECT_EQ(8, info.selection_start);
1163   EXPECT_EQ(19, info.selection_end);
1164   EXPECT_EQ(-1, info.composition_start);
1165   EXPECT_EQ(-1, info.composition_end);
1166 }
1167 
1168 // Regression test for crbug.com/663645
TEST_F(WebViewTest,FinishComposingTextDoesNotAssert)1169 TEST_F(WebViewTest, FinishComposingTextDoesNotAssert) {
1170   RegisterMockedHttpURLLoad("input_field_default.html");
1171   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
1172       base_url_ + "input_field_default.html");
1173   web_view->SetInitialFocus(false);
1174 
1175   WebInputMethodController* active_input_method_controller =
1176       web_view->MainFrameImpl()
1177           ->FrameWidget()
1178           ->GetActiveWebInputMethodController();
1179 
1180   // The test requires non-empty composition.
1181   std::string composition_text("hello");
1182   WebVector<WebImeTextSpan> empty_ime_text_spans;
1183   active_input_method_controller->SetComposition(
1184       WebString::FromUTF8(composition_text.c_str()), empty_ime_text_spans,
1185       WebRange(), 5, 5);
1186 
1187   // Do arbitrary change to make layout dirty.
1188   Document& document = *web_view->MainFrameImpl()->GetFrame()->GetDocument();
1189   Element* br = document.CreateRawElement(html_names::kBrTag);
1190   document.body()->AppendChild(br);
1191 
1192   // Should not hit assertion when calling
1193   // WebInputMethodController::finishComposingText with non-empty composition
1194   // and dirty layout.
1195   active_input_method_controller->FinishComposingText(
1196       WebInputMethodController::kKeepSelection);
1197 }
1198 
1199 // Regression test for https://crbug.com/873999
TEST_F(WebViewTest,LongPressOutsideInputShouldNotSelectPlaceholderText)1200 TEST_F(WebViewTest, LongPressOutsideInputShouldNotSelectPlaceholderText) {
1201   RegisterMockedHttpURLLoad("input_placeholder.html");
1202   WebViewImpl* web_view =
1203       web_view_helper_.InitializeAndLoad(base_url_ + "input_placeholder.html");
1204   web_view->SetInitialFocus(false);
1205   web_view->MainFrameWidget()->Resize(WebSize(500, 300));
1206   UpdateAllLifecyclePhases();
1207   RunPendingTasks();
1208 
1209   WebString input_id = WebString::FromUTF8("input");
1210 
1211   // Focus in input.
1212   EXPECT_TRUE(TapElementById(WebInputEvent::kGestureTap, input_id));
1213 
1214   // Long press below input.
1215   WebGestureEvent event(WebInputEvent::kGestureLongPress,
1216                         WebInputEvent::kNoModifiers,
1217                         WebInputEvent::GetStaticTimeStampForTests(),
1218                         WebGestureDevice::kTouchscreen);
1219   event.SetPositionInWidget(gfx::PointF(100, 150));
1220   EXPECT_EQ(WebInputEventResult::kHandledSystem,
1221             web_view->MainFrameWidget()->HandleInputEvent(
1222                 WebCoalescedInputEvent(event)));
1223   EXPECT_TRUE(web_view->MainFrameImpl()->SelectionAsText().IsEmpty());
1224 }
1225 
TEST_F(WebViewTest,FinishComposingTextCursorPositionChange)1226 TEST_F(WebViewTest, FinishComposingTextCursorPositionChange) {
1227   RegisterMockedHttpURLLoad("input_field_populated.html");
1228   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
1229       base_url_ + "input_field_populated.html");
1230   web_view->SetInitialFocus(false);
1231 
1232   // Set up a composition that needs to be committed.
1233   std::string composition_text("hello");
1234 
1235   WebInputMethodController* active_input_method_controller =
1236       web_view->MainFrameImpl()
1237           ->FrameWidget()
1238           ->GetActiveWebInputMethodController();
1239   WebVector<WebImeTextSpan> empty_ime_text_spans;
1240   active_input_method_controller->SetComposition(
1241       WebString::FromUTF8(composition_text.c_str()), empty_ime_text_spans,
1242       WebRange(), 3, 3);
1243 
1244   WebTextInputInfo info = active_input_method_controller->TextInputInfo();
1245   EXPECT_EQ("hello", info.value.Utf8());
1246   EXPECT_EQ(3, info.selection_start);
1247   EXPECT_EQ(3, info.selection_end);
1248   EXPECT_EQ(0, info.composition_start);
1249   EXPECT_EQ(5, info.composition_end);
1250 
1251   active_input_method_controller->FinishComposingText(
1252       WebInputMethodController::kKeepSelection);
1253   info = active_input_method_controller->TextInputInfo();
1254   EXPECT_EQ(3, info.selection_start);
1255   EXPECT_EQ(3, info.selection_end);
1256   EXPECT_EQ(-1, info.composition_start);
1257   EXPECT_EQ(-1, info.composition_end);
1258 
1259   active_input_method_controller->SetComposition(
1260       WebString::FromUTF8(composition_text.c_str()), empty_ime_text_spans,
1261       WebRange(), 3, 3);
1262   info = active_input_method_controller->TextInputInfo();
1263   EXPECT_EQ("helhellolo", info.value.Utf8());
1264   EXPECT_EQ(6, info.selection_start);
1265   EXPECT_EQ(6, info.selection_end);
1266   EXPECT_EQ(3, info.composition_start);
1267   EXPECT_EQ(8, info.composition_end);
1268 
1269   active_input_method_controller->FinishComposingText(
1270       WebInputMethodController::kDoNotKeepSelection);
1271   info = active_input_method_controller->TextInputInfo();
1272   EXPECT_EQ(8, info.selection_start);
1273   EXPECT_EQ(8, info.selection_end);
1274   EXPECT_EQ(-1, info.composition_start);
1275   EXPECT_EQ(-1, info.composition_end);
1276 }
1277 
TEST_F(WebViewTest,SetCompositionForNewCaretPositions)1278 TEST_F(WebViewTest, SetCompositionForNewCaretPositions) {
1279   RegisterMockedHttpURLLoad("input_field_populated.html");
1280   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
1281       base_url_ + "input_field_populated.html");
1282   web_view->SetInitialFocus(false);
1283   WebInputMethodController* active_input_method_controller =
1284       web_view->MainFrameImpl()
1285           ->FrameWidget()
1286           ->GetActiveWebInputMethodController();
1287 
1288   WebVector<WebImeTextSpan> empty_ime_text_spans;
1289 
1290   active_input_method_controller->CommitText("hello", empty_ime_text_spans,
1291                                              WebRange(), 0);
1292   active_input_method_controller->CommitText("world", empty_ime_text_spans,
1293                                              WebRange(), -5);
1294   WebTextInputInfo info = active_input_method_controller->TextInputInfo();
1295 
1296   EXPECT_EQ("helloworld", info.value.Utf8());
1297   EXPECT_EQ(5, info.selection_start);
1298   EXPECT_EQ(5, info.selection_end);
1299   EXPECT_EQ(-1, info.composition_start);
1300   EXPECT_EQ(-1, info.composition_end);
1301 
1302   // Set up a composition that needs to be committed.
1303   std::string composition_text("ABC");
1304 
1305   // Caret is on the left of composing text.
1306   active_input_method_controller->SetComposition(
1307       WebString::FromUTF8(composition_text.c_str()), empty_ime_text_spans,
1308       WebRange(), 0, 0);
1309   info = active_input_method_controller->TextInputInfo();
1310   EXPECT_EQ("helloABCworld", info.value.Utf8());
1311   EXPECT_EQ(5, info.selection_start);
1312   EXPECT_EQ(5, info.selection_end);
1313   EXPECT_EQ(5, info.composition_start);
1314   EXPECT_EQ(8, info.composition_end);
1315 
1316   // Caret is on the right of composing text.
1317   active_input_method_controller->SetComposition(
1318       WebString::FromUTF8(composition_text.c_str()), empty_ime_text_spans,
1319       WebRange(), 3, 3);
1320   info = active_input_method_controller->TextInputInfo();
1321   EXPECT_EQ("helloABCworld", info.value.Utf8());
1322   EXPECT_EQ(8, info.selection_start);
1323   EXPECT_EQ(8, info.selection_end);
1324   EXPECT_EQ(5, info.composition_start);
1325   EXPECT_EQ(8, info.composition_end);
1326 
1327   // Caret is between composing text and left boundary.
1328   active_input_method_controller->SetComposition(
1329       WebString::FromUTF8(composition_text.c_str()), empty_ime_text_spans,
1330       WebRange(), -2, -2);
1331   info = active_input_method_controller->TextInputInfo();
1332   EXPECT_EQ("helloABCworld", info.value.Utf8());
1333   EXPECT_EQ(3, info.selection_start);
1334   EXPECT_EQ(3, info.selection_end);
1335   EXPECT_EQ(5, info.composition_start);
1336   EXPECT_EQ(8, info.composition_end);
1337 
1338   // Caret is between composing text and right boundary.
1339   active_input_method_controller->SetComposition(
1340       WebString::FromUTF8(composition_text.c_str()), empty_ime_text_spans,
1341       WebRange(), 5, 5);
1342   info = active_input_method_controller->TextInputInfo();
1343   EXPECT_EQ("helloABCworld", info.value.Utf8());
1344   EXPECT_EQ(10, info.selection_start);
1345   EXPECT_EQ(10, info.selection_end);
1346   EXPECT_EQ(5, info.composition_start);
1347   EXPECT_EQ(8, info.composition_end);
1348 
1349   // Caret is on the left boundary.
1350   active_input_method_controller->SetComposition(
1351       WebString::FromUTF8(composition_text.c_str()), empty_ime_text_spans,
1352       WebRange(), -5, -5);
1353   info = active_input_method_controller->TextInputInfo();
1354   EXPECT_EQ("helloABCworld", info.value.Utf8());
1355   EXPECT_EQ(0, info.selection_start);
1356   EXPECT_EQ(0, info.selection_end);
1357   EXPECT_EQ(5, info.composition_start);
1358   EXPECT_EQ(8, info.composition_end);
1359 
1360   // Caret is on the right boundary.
1361   active_input_method_controller->SetComposition(
1362       WebString::FromUTF8(composition_text.c_str()), empty_ime_text_spans,
1363       WebRange(), 8, 8);
1364   info = active_input_method_controller->TextInputInfo();
1365   EXPECT_EQ("helloABCworld", info.value.Utf8());
1366   EXPECT_EQ(13, info.selection_start);
1367   EXPECT_EQ(13, info.selection_end);
1368   EXPECT_EQ(5, info.composition_start);
1369   EXPECT_EQ(8, info.composition_end);
1370 
1371   // Caret exceeds the left boundary.
1372   active_input_method_controller->SetComposition(
1373       WebString::FromUTF8(composition_text.c_str()), empty_ime_text_spans,
1374       WebRange(), -100, -100);
1375   info = active_input_method_controller->TextInputInfo();
1376   EXPECT_EQ("helloABCworld", info.value.Utf8());
1377   EXPECT_EQ(0, info.selection_start);
1378   EXPECT_EQ(0, info.selection_end);
1379   EXPECT_EQ(5, info.composition_start);
1380   EXPECT_EQ(8, info.composition_end);
1381 
1382   // Caret exceeds the right boundary.
1383   active_input_method_controller->SetComposition(
1384       WebString::FromUTF8(composition_text.c_str()), empty_ime_text_spans,
1385       WebRange(), 100, 100);
1386   info = active_input_method_controller->TextInputInfo();
1387   EXPECT_EQ("helloABCworld", info.value.Utf8());
1388   EXPECT_EQ(13, info.selection_start);
1389   EXPECT_EQ(13, info.selection_end);
1390   EXPECT_EQ(5, info.composition_start);
1391   EXPECT_EQ(8, info.composition_end);
1392 }
1393 
TEST_F(WebViewTest,SetCompositionWithEmptyText)1394 TEST_F(WebViewTest, SetCompositionWithEmptyText) {
1395   RegisterMockedHttpURLLoad("input_field_populated.html");
1396   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
1397       base_url_ + "input_field_populated.html");
1398   web_view->SetInitialFocus(false);
1399   WebInputMethodController* active_input_method_controller =
1400       web_view->MainFrameImpl()
1401           ->FrameWidget()
1402           ->GetActiveWebInputMethodController();
1403 
1404   WebVector<WebImeTextSpan> empty_ime_text_spans;
1405 
1406   active_input_method_controller->CommitText("hello", empty_ime_text_spans,
1407                                              WebRange(), 0);
1408   WebTextInputInfo info = active_input_method_controller->TextInputInfo();
1409 
1410   EXPECT_EQ("hello", info.value.Utf8());
1411   EXPECT_EQ(5, info.selection_start);
1412   EXPECT_EQ(5, info.selection_end);
1413   EXPECT_EQ(-1, info.composition_start);
1414   EXPECT_EQ(-1, info.composition_end);
1415 
1416   active_input_method_controller->SetComposition(
1417       WebString::FromUTF8(""), empty_ime_text_spans, WebRange(), 0, 0);
1418   info = active_input_method_controller->TextInputInfo();
1419   EXPECT_EQ("hello", info.value.Utf8());
1420   EXPECT_EQ(5, info.selection_start);
1421   EXPECT_EQ(5, info.selection_end);
1422   EXPECT_EQ(-1, info.composition_start);
1423   EXPECT_EQ(-1, info.composition_end);
1424 
1425   active_input_method_controller->SetComposition(
1426       WebString::FromUTF8(""), empty_ime_text_spans, WebRange(), -2, -2);
1427   info = active_input_method_controller->TextInputInfo();
1428   EXPECT_EQ("hello", info.value.Utf8());
1429   EXPECT_EQ(3, info.selection_start);
1430   EXPECT_EQ(3, info.selection_end);
1431   EXPECT_EQ(-1, info.composition_start);
1432   EXPECT_EQ(-1, info.composition_end);
1433 }
1434 
TEST_F(WebViewTest,CommitTextForNewCaretPositions)1435 TEST_F(WebViewTest, CommitTextForNewCaretPositions) {
1436   RegisterMockedHttpURLLoad("input_field_populated.html");
1437   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
1438       base_url_ + "input_field_populated.html");
1439   web_view->SetInitialFocus(false);
1440   WebInputMethodController* active_input_method_controller =
1441       web_view->MainFrameImpl()
1442           ->FrameWidget()
1443           ->GetActiveWebInputMethodController();
1444 
1445   WebVector<WebImeTextSpan> empty_ime_text_spans;
1446 
1447   // Caret is on the left of composing text.
1448   active_input_method_controller->CommitText("ab", empty_ime_text_spans,
1449                                              WebRange(), -2);
1450   WebTextInputInfo info = active_input_method_controller->TextInputInfo();
1451   EXPECT_EQ("ab", info.value.Utf8());
1452   EXPECT_EQ(0, info.selection_start);
1453   EXPECT_EQ(0, info.selection_end);
1454   EXPECT_EQ(-1, info.composition_start);
1455   EXPECT_EQ(-1, info.composition_end);
1456 
1457   // Caret is on the right of composing text.
1458   active_input_method_controller->CommitText("c", empty_ime_text_spans,
1459                                              WebRange(), 1);
1460   info = active_input_method_controller->TextInputInfo();
1461   EXPECT_EQ("cab", info.value.Utf8());
1462   EXPECT_EQ(2, info.selection_start);
1463   EXPECT_EQ(2, info.selection_end);
1464   EXPECT_EQ(-1, info.composition_start);
1465   EXPECT_EQ(-1, info.composition_end);
1466 
1467   // Caret is on the left boundary.
1468   active_input_method_controller->CommitText("def", empty_ime_text_spans,
1469                                              WebRange(), -5);
1470   info = active_input_method_controller->TextInputInfo();
1471   EXPECT_EQ("cadefb", info.value.Utf8());
1472   EXPECT_EQ(0, info.selection_start);
1473   EXPECT_EQ(0, info.selection_end);
1474   EXPECT_EQ(-1, info.composition_start);
1475   EXPECT_EQ(-1, info.composition_end);
1476 
1477   // Caret is on the right boundary.
1478   active_input_method_controller->CommitText("g", empty_ime_text_spans,
1479                                              WebRange(), 6);
1480   info = active_input_method_controller->TextInputInfo();
1481   EXPECT_EQ("gcadefb", info.value.Utf8());
1482   EXPECT_EQ(7, info.selection_start);
1483   EXPECT_EQ(7, info.selection_end);
1484   EXPECT_EQ(-1, info.composition_start);
1485   EXPECT_EQ(-1, info.composition_end);
1486 
1487   // Caret exceeds the left boundary.
1488   active_input_method_controller->CommitText("hi", empty_ime_text_spans,
1489                                              WebRange(), -100);
1490   info = active_input_method_controller->TextInputInfo();
1491   EXPECT_EQ("gcadefbhi", info.value.Utf8());
1492   EXPECT_EQ(0, info.selection_start);
1493   EXPECT_EQ(0, info.selection_end);
1494   EXPECT_EQ(-1, info.composition_start);
1495   EXPECT_EQ(-1, info.composition_end);
1496 
1497   // Caret exceeds the right boundary.
1498   active_input_method_controller->CommitText("jk", empty_ime_text_spans,
1499                                              WebRange(), 100);
1500   info = active_input_method_controller->TextInputInfo();
1501   EXPECT_EQ("jkgcadefbhi", info.value.Utf8());
1502   EXPECT_EQ(11, info.selection_start);
1503   EXPECT_EQ(11, info.selection_end);
1504   EXPECT_EQ(-1, info.composition_start);
1505   EXPECT_EQ(-1, info.composition_end);
1506 }
1507 
TEST_F(WebViewTest,CommitTextWhileComposing)1508 TEST_F(WebViewTest, CommitTextWhileComposing) {
1509   RegisterMockedHttpURLLoad("input_field_populated.html");
1510   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
1511       base_url_ + "input_field_populated.html");
1512   web_view->SetInitialFocus(false);
1513   WebInputMethodController* active_input_method_controller =
1514       web_view->MainFrameImpl()
1515           ->FrameWidget()
1516           ->GetActiveWebInputMethodController();
1517 
1518   WebVector<WebImeTextSpan> empty_ime_text_spans;
1519   active_input_method_controller->SetComposition(
1520       WebString::FromUTF8("abc"), empty_ime_text_spans, WebRange(), 0, 0);
1521   WebTextInputInfo info = active_input_method_controller->TextInputInfo();
1522   EXPECT_EQ("abc", info.value.Utf8());
1523   EXPECT_EQ(0, info.selection_start);
1524   EXPECT_EQ(0, info.selection_end);
1525   EXPECT_EQ(0, info.composition_start);
1526   EXPECT_EQ(3, info.composition_end);
1527 
1528   // Deletes ongoing composition, inserts the specified text and moves the
1529   // caret.
1530   active_input_method_controller->CommitText("hello", empty_ime_text_spans,
1531                                              WebRange(), -2);
1532   info = active_input_method_controller->TextInputInfo();
1533   EXPECT_EQ("hello", info.value.Utf8());
1534   EXPECT_EQ(3, info.selection_start);
1535   EXPECT_EQ(3, info.selection_end);
1536   EXPECT_EQ(-1, info.composition_start);
1537   EXPECT_EQ(-1, info.composition_end);
1538 
1539   active_input_method_controller->SetComposition(
1540       WebString::FromUTF8("abc"), empty_ime_text_spans, WebRange(), 0, 0);
1541   info = active_input_method_controller->TextInputInfo();
1542   EXPECT_EQ("helabclo", info.value.Utf8());
1543   EXPECT_EQ(3, info.selection_start);
1544   EXPECT_EQ(3, info.selection_end);
1545   EXPECT_EQ(3, info.composition_start);
1546   EXPECT_EQ(6, info.composition_end);
1547 
1548   // Deletes ongoing composition and moves the caret.
1549   active_input_method_controller->CommitText("", empty_ime_text_spans,
1550                                              WebRange(), 2);
1551   info = active_input_method_controller->TextInputInfo();
1552   EXPECT_EQ("hello", info.value.Utf8());
1553   EXPECT_EQ(5, info.selection_start);
1554   EXPECT_EQ(5, info.selection_end);
1555   EXPECT_EQ(-1, info.composition_start);
1556   EXPECT_EQ(-1, info.composition_end);
1557 
1558   // Inserts the specified text and moves the caret.
1559   active_input_method_controller->CommitText("world", empty_ime_text_spans,
1560                                              WebRange(), -5);
1561   info = active_input_method_controller->TextInputInfo();
1562   EXPECT_EQ("helloworld", info.value.Utf8());
1563   EXPECT_EQ(5, info.selection_start);
1564   EXPECT_EQ(5, info.selection_end);
1565   EXPECT_EQ(-1, info.composition_start);
1566   EXPECT_EQ(-1, info.composition_end);
1567 
1568   // Only moves the caret.
1569   active_input_method_controller->CommitText("", empty_ime_text_spans,
1570                                              WebRange(), 5);
1571   info = active_input_method_controller->TextInputInfo();
1572   EXPECT_EQ("helloworld", info.value.Utf8());
1573   EXPECT_EQ(10, info.selection_start);
1574   EXPECT_EQ(10, info.selection_end);
1575   EXPECT_EQ(-1, info.composition_start);
1576   EXPECT_EQ(-1, info.composition_end);
1577 }
1578 
TEST_F(WebViewTest,FinishCompositionDoesNotRevealSelection)1579 TEST_F(WebViewTest, FinishCompositionDoesNotRevealSelection) {
1580   RegisterMockedHttpURLLoad("form_with_input.html");
1581   WebViewImpl* web_view =
1582       web_view_helper_.InitializeAndLoad(base_url_ + "form_with_input.html");
1583   web_view->MainFrameWidget()->Resize(WebSize(800, 600));
1584   web_view->SetInitialFocus(false);
1585   EXPECT_EQ(0, web_view->MainFrameImpl()->GetScrollOffset().width);
1586   EXPECT_EQ(0, web_view->MainFrameImpl()->GetScrollOffset().height);
1587 
1588   // Set up a composition from existing text that needs to be committed.
1589   Vector<ImeTextSpan> empty_ime_text_spans;
1590   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
1591   frame->GetFrame()->GetInputMethodController().SetCompositionFromExistingText(
1592       empty_ime_text_spans, 0, 3);
1593 
1594   // Scroll the input field out of the viewport.
1595   Element* element = static_cast<Element*>(
1596       web_view->MainFrameImpl()->GetDocument().GetElementById("btn"));
1597   element->scrollIntoView();
1598   float offset_height = web_view->MainFrameImpl()->GetScrollOffset().height;
1599   EXPECT_EQ(0, web_view->MainFrameImpl()->GetScrollOffset().width);
1600   EXPECT_LT(0, offset_height);
1601 
1602   WebTextInputInfo info = frame->GetInputMethodController()->TextInputInfo();
1603   EXPECT_EQ("hello", info.value.Utf8());
1604 
1605   // Verify that the input field is not scrolled back into the viewport.
1606   frame->FrameWidget()
1607       ->GetActiveWebInputMethodController()
1608       ->FinishComposingText(WebInputMethodController::kDoNotKeepSelection);
1609   EXPECT_EQ(0, web_view->MainFrameImpl()->GetScrollOffset().width);
1610   EXPECT_EQ(offset_height, web_view->MainFrameImpl()->GetScrollOffset().height);
1611 }
1612 
TEST_F(WebViewTest,InsertNewLinePlacementAfterFinishComposingText)1613 TEST_F(WebViewTest, InsertNewLinePlacementAfterFinishComposingText) {
1614   RegisterMockedHttpURLLoad("text_area_populated.html");
1615   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
1616       base_url_ + "text_area_populated.html");
1617   web_view->SetInitialFocus(false);
1618 
1619   WebVector<WebImeTextSpan> empty_ime_text_spans;
1620 
1621   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
1622   WebInputMethodController* active_input_method_controller =
1623       frame->GetInputMethodController();
1624   frame->SetEditableSelectionOffsets(4, 4);
1625   frame->SetCompositionFromExistingText(8, 12, empty_ime_text_spans);
1626 
1627   WebTextInputInfo info = active_input_method_controller->TextInputInfo();
1628   EXPECT_EQ("0123456789abcdefghijklmnopqrstuvwxyz", info.value.Utf8());
1629   EXPECT_EQ(4, info.selection_start);
1630   EXPECT_EQ(4, info.selection_end);
1631   EXPECT_EQ(8, info.composition_start);
1632   EXPECT_EQ(12, info.composition_end);
1633 
1634   active_input_method_controller->FinishComposingText(
1635       WebInputMethodController::kKeepSelection);
1636   info = active_input_method_controller->TextInputInfo();
1637   EXPECT_EQ(4, info.selection_start);
1638   EXPECT_EQ(4, info.selection_end);
1639   EXPECT_EQ(-1, info.composition_start);
1640   EXPECT_EQ(-1, info.composition_end);
1641 
1642   std::string composition_text("\n");
1643   active_input_method_controller->CommitText(
1644       WebString::FromUTF8(composition_text.c_str()), empty_ime_text_spans,
1645       WebRange(), 0);
1646   info = active_input_method_controller->TextInputInfo();
1647   EXPECT_EQ(5, info.selection_start);
1648   EXPECT_EQ(5, info.selection_end);
1649   EXPECT_EQ(-1, info.composition_start);
1650   EXPECT_EQ(-1, info.composition_end);
1651   EXPECT_EQ("0123\n456789abcdefghijklmnopqrstuvwxyz", info.value.Utf8());
1652 }
1653 
TEST_F(WebViewTest,ExtendSelectionAndDelete)1654 TEST_F(WebViewTest, ExtendSelectionAndDelete) {
1655   RegisterMockedHttpURLLoad("input_field_populated.html");
1656   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
1657       base_url_ + "input_field_populated.html");
1658   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
1659   web_view->SetInitialFocus(false);
1660   frame->SetEditableSelectionOffsets(10, 10);
1661   frame->ExtendSelectionAndDelete(5, 8);
1662   WebInputMethodController* active_input_method_controller =
1663       frame->GetInputMethodController();
1664   WebTextInputInfo info = active_input_method_controller->TextInputInfo();
1665   EXPECT_EQ("01234ijklmnopqrstuvwxyz", info.value.Utf8());
1666   EXPECT_EQ(5, info.selection_start);
1667   EXPECT_EQ(5, info.selection_end);
1668   frame->ExtendSelectionAndDelete(10, 0);
1669   info = active_input_method_controller->TextInputInfo();
1670   EXPECT_EQ("ijklmnopqrstuvwxyz", info.value.Utf8());
1671 }
1672 
TEST_F(WebViewTest,DeleteSurroundingText)1673 TEST_F(WebViewTest, DeleteSurroundingText) {
1674   RegisterMockedHttpURLLoad("input_field_populated.html");
1675   WebView* web_view = web_view_helper_.InitializeAndLoad(
1676       base_url_ + "input_field_populated.html");
1677   auto* frame = To<WebLocalFrameImpl>(web_view->MainFrame());
1678   WebInputMethodController* active_input_method_controller =
1679       frame->GetInputMethodController();
1680   web_view->SetInitialFocus(false);
1681 
1682   frame->SetEditableSelectionOffsets(10, 10);
1683   frame->DeleteSurroundingText(5, 8);
1684   WebTextInputInfo info = active_input_method_controller->TextInputInfo();
1685   EXPECT_EQ("01234ijklmnopqrstuvwxyz", info.value.Utf8());
1686   EXPECT_EQ(5, info.selection_start);
1687   EXPECT_EQ(5, info.selection_end);
1688 
1689   frame->SetEditableSelectionOffsets(5, 10);
1690   frame->DeleteSurroundingText(3, 5);
1691   info = active_input_method_controller->TextInputInfo();
1692   EXPECT_EQ("01ijklmstuvwxyz", info.value.Utf8());
1693   EXPECT_EQ(2, info.selection_start);
1694   EXPECT_EQ(7, info.selection_end);
1695 
1696   frame->SetEditableSelectionOffsets(5, 5);
1697   frame->DeleteSurroundingText(10, 0);
1698   info = active_input_method_controller->TextInputInfo();
1699   EXPECT_EQ("lmstuvwxyz", info.value.Utf8());
1700   EXPECT_EQ(0, info.selection_start);
1701   EXPECT_EQ(0, info.selection_end);
1702 
1703   frame->DeleteSurroundingText(0, 20);
1704   info = active_input_method_controller->TextInputInfo();
1705   EXPECT_EQ("", info.value.Utf8());
1706   EXPECT_EQ(0, info.selection_start);
1707   EXPECT_EQ(0, info.selection_end);
1708 
1709   frame->DeleteSurroundingText(10, 10);
1710   info = active_input_method_controller->TextInputInfo();
1711   EXPECT_EQ("", info.value.Utf8());
1712   EXPECT_EQ(0, info.selection_start);
1713   EXPECT_EQ(0, info.selection_end);
1714 }
1715 
TEST_F(WebViewTest,SetCompositionFromExistingText)1716 TEST_F(WebViewTest, SetCompositionFromExistingText) {
1717   RegisterMockedHttpURLLoad("input_field_populated.html");
1718   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
1719       base_url_ + "input_field_populated.html");
1720   web_view->SetInitialFocus(false);
1721   WebVector<WebImeTextSpan> ime_text_spans(static_cast<size_t>(1));
1722   ime_text_spans[0] =
1723       WebImeTextSpan(WebImeTextSpan::Type::kComposition, 0, 4,
1724                      ui::mojom::ImeTextSpanThickness::kThin,
1725                      ui::mojom::ImeTextSpanUnderlineStyle::kSolid, 0, 0);
1726   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
1727   WebInputMethodController* active_input_method_controller =
1728       frame->GetInputMethodController();
1729   frame->SetEditableSelectionOffsets(4, 10);
1730   frame->SetCompositionFromExistingText(8, 12, ime_text_spans);
1731   WebTextInputInfo info = active_input_method_controller->TextInputInfo();
1732   EXPECT_EQ(4, info.selection_start);
1733   EXPECT_EQ(10, info.selection_end);
1734   EXPECT_EQ(8, info.composition_start);
1735   EXPECT_EQ(12, info.composition_end);
1736   WebVector<WebImeTextSpan> empty_ime_text_spans;
1737   frame->SetCompositionFromExistingText(0, 0, empty_ime_text_spans);
1738   info = active_input_method_controller->TextInputInfo();
1739   EXPECT_EQ(4, info.selection_start);
1740   EXPECT_EQ(10, info.selection_end);
1741   EXPECT_EQ(-1, info.composition_start);
1742   EXPECT_EQ(-1, info.composition_end);
1743 }
1744 
TEST_F(WebViewTest,SetCompositionFromExistingTextInTextArea)1745 TEST_F(WebViewTest, SetCompositionFromExistingTextInTextArea) {
1746   RegisterMockedHttpURLLoad("text_area_populated.html");
1747   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
1748       base_url_ + "text_area_populated.html");
1749   web_view->SetInitialFocus(false);
1750   WebVector<WebImeTextSpan> ime_text_spans(static_cast<size_t>(1));
1751   ime_text_spans[0] =
1752       WebImeTextSpan(WebImeTextSpan::Type::kComposition, 0, 4,
1753                      ui::mojom::ImeTextSpanThickness::kThin,
1754                      ui::mojom::ImeTextSpanUnderlineStyle::kSolid, 0, 0);
1755   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
1756   WebInputMethodController* active_input_method_controller =
1757       frame->FrameWidget()->GetActiveWebInputMethodController();
1758   frame->SetEditableSelectionOffsets(27, 27);
1759   std::string new_line_text("\n");
1760   WebVector<WebImeTextSpan> empty_ime_text_spans;
1761   active_input_method_controller->CommitText(
1762       WebString::FromUTF8(new_line_text.c_str()), empty_ime_text_spans,
1763       WebRange(), 0);
1764   WebTextInputInfo info = active_input_method_controller->TextInputInfo();
1765   EXPECT_EQ("0123456789abcdefghijklmnopq\nrstuvwxyz", info.value.Utf8());
1766 
1767   frame->SetEditableSelectionOffsets(31, 31);
1768   frame->SetCompositionFromExistingText(30, 34, ime_text_spans);
1769   info = active_input_method_controller->TextInputInfo();
1770   EXPECT_EQ("0123456789abcdefghijklmnopq\nrstuvwxyz", info.value.Utf8());
1771   EXPECT_EQ(31, info.selection_start);
1772   EXPECT_EQ(31, info.selection_end);
1773   EXPECT_EQ(30, info.composition_start);
1774   EXPECT_EQ(34, info.composition_end);
1775 
1776   std::string composition_text("yolo");
1777   active_input_method_controller->CommitText(
1778       WebString::FromUTF8(composition_text.c_str()), empty_ime_text_spans,
1779       WebRange(), 0);
1780   info = active_input_method_controller->TextInputInfo();
1781   EXPECT_EQ("0123456789abcdefghijklmnopq\nrsyoloxyz", info.value.Utf8());
1782   EXPECT_EQ(34, info.selection_start);
1783   EXPECT_EQ(34, info.selection_end);
1784   EXPECT_EQ(-1, info.composition_start);
1785   EXPECT_EQ(-1, info.composition_end);
1786 }
1787 
TEST_F(WebViewTest,SetCompositionFromExistingTextInRichText)1788 TEST_F(WebViewTest, SetCompositionFromExistingTextInRichText) {
1789   RegisterMockedHttpURLLoad("content_editable_rich_text.html");
1790   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
1791       base_url_ + "content_editable_rich_text.html");
1792   web_view->SetInitialFocus(false);
1793   WebVector<WebImeTextSpan> ime_text_spans(static_cast<size_t>(1));
1794   ime_text_spans[0] =
1795       WebImeTextSpan(WebImeTextSpan::Type::kComposition, 0, 4,
1796                      ui::mojom::ImeTextSpanThickness::kThin,
1797                      ui::mojom::ImeTextSpanUnderlineStyle::kSolid, 0, 0);
1798   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
1799   frame->SetEditableSelectionOffsets(1, 1);
1800   WebDocument document = web_view->MainFrameImpl()->GetDocument();
1801   EXPECT_FALSE(document.GetElementById("bold").IsNull());
1802   frame->SetCompositionFromExistingText(0, 4, ime_text_spans);
1803   EXPECT_FALSE(document.GetElementById("bold").IsNull());
1804 }
1805 
TEST_F(WebViewTest,SetEditableSelectionOffsetsKeepsComposition)1806 TEST_F(WebViewTest, SetEditableSelectionOffsetsKeepsComposition) {
1807   RegisterMockedHttpURLLoad("input_field_populated.html");
1808   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
1809       base_url_ + "input_field_populated.html");
1810   web_view->SetInitialFocus(false);
1811 
1812   std::string composition_text_first("hello ");
1813   std::string composition_text_second("world");
1814   WebVector<WebImeTextSpan> empty_ime_text_spans;
1815   WebInputMethodController* active_input_method_controller =
1816       web_view->MainFrameImpl()
1817           ->FrameWidget()
1818           ->GetActiveWebInputMethodController();
1819   active_input_method_controller->CommitText(
1820       WebString::FromUTF8(composition_text_first.c_str()), empty_ime_text_spans,
1821       WebRange(), 0);
1822   active_input_method_controller->SetComposition(
1823       WebString::FromUTF8(composition_text_second.c_str()),
1824       empty_ime_text_spans, WebRange(), 5, 5);
1825 
1826   WebTextInputInfo info = active_input_method_controller->TextInputInfo();
1827   EXPECT_EQ("hello world", info.value.Utf8());
1828   EXPECT_EQ(11, info.selection_start);
1829   EXPECT_EQ(11, info.selection_end);
1830   EXPECT_EQ(6, info.composition_start);
1831   EXPECT_EQ(11, info.composition_end);
1832 
1833   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
1834   frame->SetEditableSelectionOffsets(6, 6);
1835   info = active_input_method_controller->TextInputInfo();
1836   EXPECT_EQ("hello world", info.value.Utf8());
1837   EXPECT_EQ(6, info.selection_start);
1838   EXPECT_EQ(6, info.selection_end);
1839   EXPECT_EQ(6, info.composition_start);
1840   EXPECT_EQ(11, info.composition_end);
1841 
1842   frame->SetEditableSelectionOffsets(8, 8);
1843   info = active_input_method_controller->TextInputInfo();
1844   EXPECT_EQ("hello world", info.value.Utf8());
1845   EXPECT_EQ(8, info.selection_start);
1846   EXPECT_EQ(8, info.selection_end);
1847   EXPECT_EQ(6, info.composition_start);
1848   EXPECT_EQ(11, info.composition_end);
1849 
1850   frame->SetEditableSelectionOffsets(11, 11);
1851   info = active_input_method_controller->TextInputInfo();
1852   EXPECT_EQ("hello world", info.value.Utf8());
1853   EXPECT_EQ(11, info.selection_start);
1854   EXPECT_EQ(11, info.selection_end);
1855   EXPECT_EQ(6, info.composition_start);
1856   EXPECT_EQ(11, info.composition_end);
1857 
1858   frame->SetEditableSelectionOffsets(6, 11);
1859   info = active_input_method_controller->TextInputInfo();
1860   EXPECT_EQ("hello world", info.value.Utf8());
1861   EXPECT_EQ(6, info.selection_start);
1862   EXPECT_EQ(11, info.selection_end);
1863   EXPECT_EQ(6, info.composition_start);
1864   EXPECT_EQ(11, info.composition_end);
1865 
1866   frame->SetEditableSelectionOffsets(2, 2);
1867   info = active_input_method_controller->TextInputInfo();
1868   EXPECT_EQ("hello world", info.value.Utf8());
1869   EXPECT_EQ(2, info.selection_start);
1870   EXPECT_EQ(2, info.selection_end);
1871   // Composition range should be reset by browser process or keyboard apps.
1872   EXPECT_EQ(6, info.composition_start);
1873   EXPECT_EQ(11, info.composition_end);
1874 }
1875 
TEST_F(WebViewTest,IsSelectionAnchorFirst)1876 TEST_F(WebViewTest, IsSelectionAnchorFirst) {
1877   RegisterMockedHttpURLLoad("input_field_populated.html");
1878   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
1879       base_url_ + "input_field_populated.html");
1880   WebLocalFrame* frame = web_view->MainFrameImpl();
1881 
1882   web_view->SetInitialFocus(false);
1883   frame->SetEditableSelectionOffsets(4, 10);
1884   EXPECT_TRUE(frame->IsSelectionAnchorFirst());
1885   WebRect anchor;
1886   WebRect focus;
1887   web_view->MainFrameWidget()->SelectionBounds(anchor, focus);
1888   frame->SelectRange(gfx::Point(focus.x, focus.y),
1889                      gfx::Point(anchor.x, anchor.y));
1890   EXPECT_FALSE(frame->IsSelectionAnchorFirst());
1891 }
1892 
TEST_F(WebViewTest,MoveFocusToNextFocusableElementInFormWithKeyEventListenersAndNonEditableElements)1893 TEST_F(
1894     WebViewTest,
1895     MoveFocusToNextFocusableElementInFormWithKeyEventListenersAndNonEditableElements) {
1896   const std::string test_file =
1897       "advance_focus_in_form_with_key_event_listeners.html";
1898   RegisterMockedHttpURLLoad(test_file);
1899   WebViewImpl* web_view =
1900       web_view_helper_.InitializeAndLoad(base_url_ + test_file);
1901   web_view->SetInitialFocus(false);
1902   Document* document = web_view->MainFrameImpl()->GetFrame()->GetDocument();
1903   WebInputMethodController* active_input_method_controller =
1904       web_view->MainFrameImpl()
1905           ->FrameWidget()
1906           ->GetActiveWebInputMethodController();
1907   const int default_text_input_flags = kWebTextInputFlagNone;
1908 
1909   struct FocusedElement {
1910     AtomicString element_id;
1911     int next_previous_flags;
1912   } focused_elements[] = {
1913       {"input1",
1914        default_text_input_flags | kWebTextInputFlagHaveNextFocusableElement},
1915       {"contenteditable1", kWebTextInputFlagHaveNextFocusableElement |
1916                                kWebTextInputFlagHavePreviousFocusableElement},
1917       {"input2", default_text_input_flags |
1918                      kWebTextInputFlagHaveNextFocusableElement |
1919                      kWebTextInputFlagHavePreviousFocusableElement},
1920       {"textarea1", default_text_input_flags |
1921                         kWebTextInputFlagHaveNextFocusableElement |
1922                         kWebTextInputFlagHavePreviousFocusableElement},
1923       {"input3", default_text_input_flags |
1924                      kWebTextInputFlagHaveNextFocusableElement |
1925                      kWebTextInputFlagHavePreviousFocusableElement},
1926       {"textarea2", default_text_input_flags |
1927                         kWebTextInputFlagHavePreviousFocusableElement},
1928   };
1929 
1930   // Forward Navigation in form1 with NEXT
1931   Element* input1 = document->getElementById("input1");
1932   input1->focus();
1933   Element* current_focus = nullptr;
1934   Element* next_focus = nullptr;
1935   int next_previous_flags;
1936   for (size_t i = 0; i < base::size(focused_elements); ++i) {
1937     current_focus = document->getElementById(focused_elements[i].element_id);
1938     EXPECT_EQ(current_focus, document->FocusedElement());
1939     next_previous_flags =
1940         active_input_method_controller->ComputeWebTextInputNextPreviousFlags();
1941     EXPECT_EQ(focused_elements[i].next_previous_flags, next_previous_flags);
1942     next_focus =
1943         document->GetPage()->GetFocusController().NextFocusableElementInForm(
1944             current_focus, mojom::blink::FocusType::kForward);
1945     if (next_focus) {
1946       EXPECT_EQ(next_focus->GetIdAttribute(),
1947                 focused_elements[i + 1].element_id);
1948     }
1949     web_view->MainFrameImpl()->GetFrame()->AdvanceFocusInForm(
1950         mojom::blink::FocusType::kForward);
1951   }
1952   // Now focus will stay on previous focus itself, because it has no next
1953   // element.
1954   EXPECT_EQ(current_focus, document->FocusedElement());
1955 
1956   // Backward Navigation in form1 with PREVIOUS
1957   for (size_t i = base::size(focused_elements); i-- > 0;) {
1958     current_focus = document->getElementById(focused_elements[i].element_id);
1959     EXPECT_EQ(current_focus, document->FocusedElement());
1960     next_previous_flags =
1961         active_input_method_controller->ComputeWebTextInputNextPreviousFlags();
1962     EXPECT_EQ(focused_elements[i].next_previous_flags, next_previous_flags);
1963     next_focus =
1964         document->GetPage()->GetFocusController().NextFocusableElementInForm(
1965             current_focus, mojom::blink::FocusType::kBackward);
1966     if (next_focus) {
1967       EXPECT_EQ(next_focus->GetIdAttribute(),
1968                 focused_elements[i - 1].element_id);
1969     }
1970     web_view->MainFrameImpl()->GetFrame()->AdvanceFocusInForm(
1971         mojom::blink::FocusType::kBackward);
1972   }
1973   // Now focus will stay on previous focus itself, because it has no previous
1974   // element.
1975   EXPECT_EQ(current_focus, document->FocusedElement());
1976 
1977   // Setting a non editable element as focus in form1, and ensuring editable
1978   // navigation is fine in forward and backward.
1979   Element* button1 = document->getElementById("button1");
1980   button1->focus();
1981   next_previous_flags =
1982       active_input_method_controller->ComputeWebTextInputNextPreviousFlags();
1983   EXPECT_EQ(kWebTextInputFlagHaveNextFocusableElement |
1984                 kWebTextInputFlagHavePreviousFocusableElement,
1985             next_previous_flags);
1986   next_focus =
1987       document->GetPage()->GetFocusController().NextFocusableElementInForm(
1988           button1, mojom::blink::FocusType::kForward);
1989   EXPECT_EQ(next_focus->GetIdAttribute(), "contenteditable1");
1990   web_view->MainFrameImpl()->GetFrame()->AdvanceFocusInForm(
1991       mojom::blink::FocusType::kForward);
1992   Element* content_editable1 = document->getElementById("contenteditable1");
1993   EXPECT_EQ(content_editable1, document->FocusedElement());
1994   button1->focus();
1995   next_focus =
1996       document->GetPage()->GetFocusController().NextFocusableElementInForm(
1997           button1, mojom::blink::FocusType::kBackward);
1998   EXPECT_EQ(next_focus->GetIdAttribute(), "input1");
1999   web_view->MainFrameImpl()->GetFrame()->AdvanceFocusInForm(
2000       mojom::blink::FocusType::kBackward);
2001   EXPECT_EQ(input1, document->FocusedElement());
2002 
2003   Element* anchor1 = document->getElementById("anchor1");
2004   anchor1->focus();
2005   next_previous_flags =
2006       active_input_method_controller->ComputeWebTextInputNextPreviousFlags();
2007   // No Next/Previous element for elements outside form.
2008   EXPECT_EQ(0, next_previous_flags);
2009   next_focus =
2010       document->GetPage()->GetFocusController().NextFocusableElementInForm(
2011           anchor1, mojom::blink::FocusType::kForward);
2012   EXPECT_EQ(next_focus, nullptr);
2013   web_view->MainFrameImpl()->GetFrame()->AdvanceFocusInForm(
2014       mojom::blink::FocusType::kForward);
2015   // Since anchor is not a form control element, next/previous element will
2016   // be null, hence focus will stay same as it is.
2017   EXPECT_EQ(anchor1, document->FocusedElement());
2018 
2019   next_focus =
2020       document->GetPage()->GetFocusController().NextFocusableElementInForm(
2021           anchor1, mojom::blink::FocusType::kBackward);
2022   EXPECT_EQ(next_focus, nullptr);
2023   web_view->MainFrameImpl()->GetFrame()->AdvanceFocusInForm(
2024       mojom::blink::FocusType::kBackward);
2025   EXPECT_EQ(anchor1, document->FocusedElement());
2026 
2027   // Navigation of elements which is not part of any forms.
2028   Element* text_area3 = document->getElementById("textarea3");
2029   text_area3->focus();
2030   next_previous_flags =
2031       active_input_method_controller->ComputeWebTextInputNextPreviousFlags();
2032   // No Next/Previous element for elements outside form.
2033   EXPECT_EQ(default_text_input_flags, next_previous_flags);
2034   next_focus =
2035       document->GetPage()->GetFocusController().NextFocusableElementInForm(
2036           text_area3, mojom::blink::FocusType::kForward);
2037   EXPECT_EQ(next_focus, nullptr);
2038   web_view->MainFrameImpl()->GetFrame()->AdvanceFocusInForm(
2039       mojom::blink::FocusType::kForward);
2040   // No Next/Previous element to this element because it's not part of any
2041   // form. Hence focus won't change wrt NEXT/PREVIOUS.
2042   EXPECT_EQ(text_area3, document->FocusedElement());
2043   next_focus =
2044       document->GetPage()->GetFocusController().NextFocusableElementInForm(
2045           text_area3, mojom::blink::FocusType::kBackward);
2046   EXPECT_EQ(next_focus, nullptr);
2047   web_view->MainFrameImpl()->GetFrame()->AdvanceFocusInForm(
2048       mojom::blink::FocusType::kBackward);
2049   EXPECT_EQ(text_area3, document->FocusedElement());
2050 
2051   // Navigation from an element which is part of a form but not an editable
2052   // element.
2053   Element* button2 = document->getElementById("button2");
2054   button2->focus();
2055   next_previous_flags =
2056       active_input_method_controller->ComputeWebTextInputNextPreviousFlags();
2057   // No Next element for this element, due to last element outside the form.
2058   EXPECT_EQ(kWebTextInputFlagHavePreviousFocusableElement, next_previous_flags);
2059   next_focus =
2060       document->GetPage()->GetFocusController().NextFocusableElementInForm(
2061           button2, mojom::blink::FocusType::kForward);
2062   EXPECT_EQ(next_focus, nullptr);
2063   web_view->MainFrameImpl()->GetFrame()->AdvanceFocusInForm(
2064       mojom::blink::FocusType::kForward);
2065   // No Next element to this element because it's not part of any form.
2066   // Hence focus won't change wrt NEXT.
2067   EXPECT_EQ(button2, document->FocusedElement());
2068   Element* text_area2 = document->getElementById("textarea2");
2069   next_focus =
2070       document->GetPage()->GetFocusController().NextFocusableElementInForm(
2071           button2, mojom::blink::FocusType::kBackward);
2072   EXPECT_EQ(next_focus, text_area2);
2073   web_view->MainFrameImpl()->GetFrame()->AdvanceFocusInForm(
2074       mojom::blink::FocusType::kBackward);
2075   // Since button is a form control element from form1, ensuring focus is set
2076   // at correct position.
2077   EXPECT_EQ(text_area2, document->FocusedElement());
2078 
2079   Element* content_editable2 = document->getElementById("contenteditable2");
2080   document->SetFocusedElement(
2081       content_editable2, FocusParams(SelectionBehaviorOnFocus::kNone,
2082                                      mojom::blink::FocusType::kNone, nullptr));
2083   next_previous_flags =
2084       active_input_method_controller->ComputeWebTextInputNextPreviousFlags();
2085   // No Next/Previous element for elements outside form.
2086   EXPECT_EQ(0, next_previous_flags);
2087   next_focus =
2088       document->GetPage()->GetFocusController().NextFocusableElementInForm(
2089           content_editable2, mojom::blink::FocusType::kForward);
2090   EXPECT_EQ(next_focus, nullptr);
2091   web_view->MainFrameImpl()->GetFrame()->AdvanceFocusInForm(
2092       mojom::blink::FocusType::kForward);
2093   // No Next/Previous element to this element because it's not part of any
2094   // form. Hence focus won't change wrt NEXT/PREVIOUS.
2095   EXPECT_EQ(content_editable2, document->FocusedElement());
2096   next_focus =
2097       document->GetPage()->GetFocusController().NextFocusableElementInForm(
2098           content_editable2, mojom::blink::FocusType::kBackward);
2099   EXPECT_EQ(next_focus, nullptr);
2100   web_view->MainFrameImpl()->GetFrame()->AdvanceFocusInForm(
2101       mojom::blink::FocusType::kBackward);
2102   EXPECT_EQ(content_editable2, document->FocusedElement());
2103 
2104   // Navigation of elements which is having invalid form attribute and hence
2105   // not part of any forms.
2106   Element* text_area4 = document->getElementById("textarea4");
2107   text_area4->focus();
2108   next_previous_flags =
2109       active_input_method_controller->ComputeWebTextInputNextPreviousFlags();
2110   // No Next/Previous element for elements which is having invalid form
2111   // attribute.
2112   EXPECT_EQ(default_text_input_flags, next_previous_flags);
2113   next_focus =
2114       document->GetPage()->GetFocusController().NextFocusableElementInForm(
2115           text_area4, mojom::blink::FocusType::kForward);
2116   EXPECT_EQ(next_focus, nullptr);
2117   web_view->MainFrameImpl()->GetFrame()->AdvanceFocusInForm(
2118       mojom::blink::FocusType::kForward);
2119   // No Next/Previous element to this element because it's not part of any
2120   // form. Hence focus won't change wrt NEXT/PREVIOUS.
2121   EXPECT_EQ(text_area4, document->FocusedElement());
2122   next_focus =
2123       document->GetPage()->GetFocusController().NextFocusableElementInForm(
2124           text_area4, mojom::blink::FocusType::kBackward);
2125   EXPECT_EQ(next_focus, nullptr);
2126   web_view->MainFrameImpl()->GetFrame()->AdvanceFocusInForm(
2127       mojom::blink::FocusType::kBackward);
2128   EXPECT_EQ(text_area4, document->FocusedElement());
2129 
2130   web_view_helper_.Reset();
2131 }
2132 
TEST_F(WebViewTest,MoveFocusToNextFocusableElementInFormWithNonEditableNonFormControlElements)2133 TEST_F(
2134     WebViewTest,
2135     MoveFocusToNextFocusableElementInFormWithNonEditableNonFormControlElements) {
2136   const std::string test_file =
2137       "advance_focus_in_form_with_key_event_listeners.html";
2138   RegisterMockedHttpURLLoad(test_file);
2139   WebViewImpl* web_view =
2140       web_view_helper_.InitializeAndLoad(base_url_ + test_file);
2141   web_view->SetInitialFocus(false);
2142   Document* document = web_view->MainFrameImpl()->GetFrame()->GetDocument();
2143   WebInputMethodController* active_input_method_controller =
2144       web_view->MainFrameImpl()
2145           ->FrameWidget()
2146           ->GetActiveWebInputMethodController();
2147   const int default_text_input_flags = kWebTextInputFlagNone;
2148 
2149   struct FocusedElement {
2150     const char* element_id;
2151     int next_previous_flags;
2152   } focused_elements[] = {
2153       {"textarea5",
2154        default_text_input_flags | kWebTextInputFlagHaveNextFocusableElement},
2155       {"input4", default_text_input_flags |
2156                      kWebTextInputFlagHaveNextFocusableElement |
2157                      kWebTextInputFlagHavePreviousFocusableElement},
2158       {"contenteditable3", kWebTextInputFlagHaveNextFocusableElement |
2159                                kWebTextInputFlagHavePreviousFocusableElement},
2160       {"input5", kWebTextInputFlagHavePreviousFocusableElement},
2161   };
2162 
2163   // Forward Navigation in form2 with NEXT
2164   Element* text_area5 = document->getElementById("textarea5");
2165   text_area5->focus();
2166   Element* current_focus = nullptr;
2167   Element* next_focus = nullptr;
2168   int next_previous_flags;
2169   for (size_t i = 0; i < base::size(focused_elements); ++i) {
2170     current_focus = document->getElementById(focused_elements[i].element_id);
2171     EXPECT_EQ(current_focus, document->FocusedElement());
2172     next_previous_flags =
2173         active_input_method_controller->ComputeWebTextInputNextPreviousFlags();
2174     EXPECT_EQ(focused_elements[i].next_previous_flags, next_previous_flags);
2175     next_focus =
2176         document->GetPage()->GetFocusController().NextFocusableElementInForm(
2177             current_focus, mojom::blink::FocusType::kForward);
2178     if (next_focus) {
2179       EXPECT_EQ(next_focus->GetIdAttribute(),
2180                 focused_elements[i + 1].element_id);
2181     }
2182     web_view->MainFrameImpl()->GetFrame()->AdvanceFocusInForm(
2183         mojom::blink::FocusType::kForward);
2184   }
2185   // Now focus will stay on previous focus itself, because it has no next
2186   // element.
2187   EXPECT_EQ(current_focus, document->FocusedElement());
2188 
2189   // Backward Navigation in form1 with PREVIOUS
2190   for (size_t i = base::size(focused_elements); i-- > 0;) {
2191     current_focus = document->getElementById(focused_elements[i].element_id);
2192     EXPECT_EQ(current_focus, document->FocusedElement());
2193     next_previous_flags =
2194         active_input_method_controller->ComputeWebTextInputNextPreviousFlags();
2195     EXPECT_EQ(focused_elements[i].next_previous_flags, next_previous_flags);
2196     next_focus =
2197         document->GetPage()->GetFocusController().NextFocusableElementInForm(
2198             current_focus, mojom::blink::FocusType::kBackward);
2199     if (next_focus) {
2200       EXPECT_EQ(next_focus->GetIdAttribute(),
2201                 focused_elements[i - 1].element_id);
2202     }
2203     web_view->MainFrameImpl()->GetFrame()->AdvanceFocusInForm(
2204         mojom::blink::FocusType::kBackward);
2205   }
2206   // Now focus will stay on previous focus itself, because it has no previous
2207   // element.
2208   EXPECT_EQ(current_focus, document->FocusedElement());
2209 
2210   // Setting a non editable element as focus in form1, and ensuring editable
2211   // navigation is fine in forward and backward.
2212   Element* anchor2 = document->getElementById("anchor2");
2213   anchor2->focus();
2214   next_previous_flags =
2215       active_input_method_controller->ComputeWebTextInputNextPreviousFlags();
2216   // No Next/Previous element for non-form control elements inside form.
2217   EXPECT_EQ(0, next_previous_flags);
2218   next_focus =
2219       document->GetPage()->GetFocusController().NextFocusableElementInForm(
2220           anchor2, mojom::blink::FocusType::kForward);
2221   EXPECT_EQ(next_focus, nullptr);
2222   web_view->MainFrameImpl()->GetFrame()->AdvanceFocusInForm(
2223       mojom::blink::FocusType::kForward);
2224   // Since anchor is not a form control element, next/previous element will
2225   // be null, hence focus will stay same as it is.
2226   EXPECT_EQ(anchor2, document->FocusedElement());
2227   next_focus =
2228       document->GetPage()->GetFocusController().NextFocusableElementInForm(
2229           anchor2, mojom::blink::FocusType::kBackward);
2230   EXPECT_EQ(next_focus, nullptr);
2231   web_view->MainFrameImpl()->GetFrame()->AdvanceFocusInForm(
2232       mojom::blink::FocusType::kBackward);
2233   EXPECT_EQ(anchor2, document->FocusedElement());
2234 
2235   web_view_helper_.Reset();
2236 }
2237 
TEST_F(WebViewTest,MoveFocusToNextFocusableElementInFormWithTabIndexElements)2238 TEST_F(WebViewTest, MoveFocusToNextFocusableElementInFormWithTabIndexElements) {
2239   const std::string test_file =
2240       "advance_focus_in_form_with_tabindex_elements.html";
2241   RegisterMockedHttpURLLoad(test_file);
2242   WebViewImpl* web_view =
2243       web_view_helper_.InitializeAndLoad(base_url_ + test_file);
2244   web_view->SetInitialFocus(false);
2245   Document* document = web_view->MainFrameImpl()->GetFrame()->GetDocument();
2246   WebInputMethodController* active_input_method_controller =
2247       web_view->MainFrameImpl()
2248           ->FrameWidget()
2249           ->GetActiveWebInputMethodController();
2250   const int default_text_input_flags = kWebTextInputFlagNone;
2251 
2252   struct FocusedElement {
2253     const char* element_id;
2254     int next_previous_flags;
2255   } focused_elements[] = {
2256       {"textarea6",
2257        default_text_input_flags | kWebTextInputFlagHaveNextFocusableElement},
2258       {"input5", default_text_input_flags |
2259                      kWebTextInputFlagHaveNextFocusableElement |
2260                      kWebTextInputFlagHavePreviousFocusableElement},
2261       {"contenteditable4", kWebTextInputFlagHaveNextFocusableElement |
2262                                kWebTextInputFlagHavePreviousFocusableElement},
2263       {"input6", default_text_input_flags |
2264                      kWebTextInputFlagHavePreviousFocusableElement},
2265   };
2266 
2267   // Forward Navigation in form with NEXT which has tabindex attribute
2268   // which differs visual order.
2269   Element* text_area6 = document->getElementById("textarea6");
2270   text_area6->focus();
2271   Element* current_focus = nullptr;
2272   Element* next_focus = nullptr;
2273   int next_previous_flags;
2274   for (size_t i = 0; i < base::size(focused_elements); ++i) {
2275     current_focus = document->getElementById(focused_elements[i].element_id);
2276     EXPECT_EQ(current_focus, document->FocusedElement());
2277     next_previous_flags =
2278         active_input_method_controller->ComputeWebTextInputNextPreviousFlags();
2279     EXPECT_EQ(focused_elements[i].next_previous_flags, next_previous_flags);
2280     next_focus =
2281         document->GetPage()->GetFocusController().NextFocusableElementInForm(
2282             current_focus, mojom::blink::FocusType::kForward);
2283     if (next_focus) {
2284       EXPECT_EQ(next_focus->GetIdAttribute(),
2285                 focused_elements[i + 1].element_id);
2286     }
2287     web_view->MainFrameImpl()->GetFrame()->AdvanceFocusInForm(
2288         mojom::blink::FocusType::kForward);
2289   }
2290   // No next editable element which is focusable with proper tab index, hence
2291   // staying on previous focus.
2292   EXPECT_EQ(current_focus, document->FocusedElement());
2293 
2294   // Backward Navigation in form with PREVIOUS which has tabindex attribute
2295   // which differs visual order.
2296   for (size_t i = base::size(focused_elements); i-- > 0;) {
2297     current_focus = document->getElementById(focused_elements[i].element_id);
2298     EXPECT_EQ(current_focus, document->FocusedElement());
2299     next_previous_flags =
2300         active_input_method_controller->ComputeWebTextInputNextPreviousFlags();
2301     EXPECT_EQ(focused_elements[i].next_previous_flags, next_previous_flags);
2302     next_focus =
2303         document->GetPage()->GetFocusController().NextFocusableElementInForm(
2304             current_focus, mojom::blink::FocusType::kBackward);
2305     if (next_focus) {
2306       EXPECT_EQ(next_focus->GetIdAttribute(),
2307                 focused_elements[i - 1].element_id);
2308     }
2309     web_view->MainFrameImpl()->GetFrame()->AdvanceFocusInForm(
2310         mojom::blink::FocusType::kBackward);
2311   }
2312   // Now focus will stay on previous focus itself, because it has no previous
2313   // element.
2314   EXPECT_EQ(current_focus, document->FocusedElement());
2315 
2316   // Setting an element which has invalid tabindex and ensuring it is not
2317   // modifying further navigation.
2318   Element* content_editable5 = document->getElementById("contenteditable5");
2319   content_editable5->focus();
2320   Element* input6 = document->getElementById("input6");
2321   next_focus =
2322       document->GetPage()->GetFocusController().NextFocusableElementInForm(
2323           content_editable5, mojom::blink::FocusType::kForward);
2324   EXPECT_EQ(next_focus, input6);
2325   web_view->MainFrameImpl()->GetFrame()->AdvanceFocusInForm(
2326       mojom::blink::FocusType::kForward);
2327   EXPECT_EQ(input6, document->FocusedElement());
2328   content_editable5->focus();
2329   next_focus =
2330       document->GetPage()->GetFocusController().NextFocusableElementInForm(
2331           content_editable5, mojom::blink::FocusType::kBackward);
2332   EXPECT_EQ(next_focus, text_area6);
2333   web_view->MainFrameImpl()->GetFrame()->AdvanceFocusInForm(
2334       mojom::blink::FocusType::kBackward);
2335   EXPECT_EQ(text_area6, document->FocusedElement());
2336 
2337   web_view_helper_.Reset();
2338 }
2339 
TEST_F(WebViewTest,MoveFocusToNextFocusableElementInFormWithDisabledAndReadonlyElements)2340 TEST_F(WebViewTest,
2341        MoveFocusToNextFocusableElementInFormWithDisabledAndReadonlyElements) {
2342   const std::string test_file =
2343       "advance_focus_in_form_with_disabled_and_readonly_elements.html";
2344   RegisterMockedHttpURLLoad(test_file);
2345   WebViewImpl* web_view =
2346       web_view_helper_.InitializeAndLoad(base_url_ + test_file);
2347   web_view->SetInitialFocus(false);
2348   Document* document = web_view->MainFrameImpl()->GetFrame()->GetDocument();
2349   WebInputMethodController* active_input_method_controller =
2350       web_view->MainFrameImpl()
2351           ->FrameWidget()
2352           ->GetActiveWebInputMethodController();
2353 
2354   struct FocusedElement {
2355     const char* element_id;
2356     int next_previous_flags;
2357   } focused_elements[] = {
2358       {"contenteditable6", kWebTextInputFlagHaveNextFocusableElement},
2359       {"contenteditable7", kWebTextInputFlagHavePreviousFocusableElement},
2360   };
2361   // Forward Navigation in form with NEXT which has has disabled/enabled
2362   // elements which will gets skipped during navigation.
2363   Element* content_editable6 = document->getElementById("contenteditable6");
2364   content_editable6->focus();
2365   Element* current_focus = nullptr;
2366   Element* next_focus = nullptr;
2367   int next_previous_flags;
2368   for (size_t i = 0; i < base::size(focused_elements); ++i) {
2369     current_focus = document->getElementById(focused_elements[i].element_id);
2370     EXPECT_EQ(current_focus, document->FocusedElement());
2371     next_previous_flags =
2372         active_input_method_controller->ComputeWebTextInputNextPreviousFlags();
2373     EXPECT_EQ(focused_elements[i].next_previous_flags, next_previous_flags);
2374     next_focus =
2375         document->GetPage()->GetFocusController().NextFocusableElementInForm(
2376             current_focus, mojom::blink::FocusType::kForward);
2377     if (next_focus) {
2378       EXPECT_EQ(next_focus->GetIdAttribute(),
2379                 focused_elements[i + 1].element_id);
2380     }
2381     web_view->MainFrameImpl()->GetFrame()->AdvanceFocusInForm(
2382         mojom::blink::FocusType::kForward);
2383   }
2384   // No next editable element which is focusable, hence staying on previous
2385   // focus.
2386   EXPECT_EQ(current_focus, document->FocusedElement());
2387 
2388   // Backward Navigation in form with PREVIOUS which has has
2389   // disabled/enabled elements which will gets skipped during navigation.
2390   for (size_t i = base::size(focused_elements); i-- > 0;) {
2391     current_focus = document->getElementById(focused_elements[i].element_id);
2392     EXPECT_EQ(current_focus, document->FocusedElement());
2393     next_previous_flags =
2394         active_input_method_controller->ComputeWebTextInputNextPreviousFlags();
2395     EXPECT_EQ(focused_elements[i].next_previous_flags, next_previous_flags);
2396     next_focus =
2397         document->GetPage()->GetFocusController().NextFocusableElementInForm(
2398             current_focus, mojom::blink::FocusType::kBackward);
2399     if (next_focus) {
2400       EXPECT_EQ(next_focus->GetIdAttribute(),
2401                 focused_elements[i - 1].element_id);
2402     }
2403     web_view->MainFrameImpl()->GetFrame()->AdvanceFocusInForm(
2404         mojom::blink::FocusType::kBackward);
2405   }
2406   // Now focus will stay on previous focus itself, because it has no previous
2407   // element.
2408   EXPECT_EQ(current_focus, document->FocusedElement());
2409 
2410   web_view_helper_.Reset();
2411 }
2412 
TEST_F(WebViewTest,ExitingDeviceEmulationResetsPageScale)2413 TEST_F(WebViewTest, ExitingDeviceEmulationResetsPageScale) {
2414   RegisterMockedHttpURLLoad("200-by-300.html");
2415   WebViewImpl* web_view_impl =
2416       web_view_helper_.InitializeAndLoad(base_url_ + "200-by-300.html");
2417   web_view_impl->MainFrameWidget()->Resize(WebSize(200, 300));
2418 
2419   float page_scale_expected = web_view_impl->PageScaleFactor();
2420 
2421   WebDeviceEmulationParams params;
2422   params.screen_position = WebDeviceEmulationParams::kDesktop;
2423   params.device_scale_factor = 0;
2424   params.scale = 1;
2425 
2426   web_view_impl->EnableDeviceEmulation(params);
2427 
2428   web_view_impl->SetPageScaleFactor(2);
2429 
2430   web_view_impl->DisableDeviceEmulation();
2431 
2432   EXPECT_EQ(page_scale_expected, web_view_impl->PageScaleFactor());
2433 }
2434 
TEST_F(WebViewTest,HistoryResetScrollAndScaleState)2435 TEST_F(WebViewTest, HistoryResetScrollAndScaleState) {
2436   RegisterMockedHttpURLLoad("200-by-300.html");
2437   WebViewImpl* web_view_impl =
2438       web_view_helper_.InitializeAndLoad(base_url_ + "200-by-300.html");
2439   web_view_impl->MainFrameWidget()->Resize(WebSize(100, 150));
2440   UpdateAllLifecyclePhases();
2441   EXPECT_EQ(0, web_view_impl->MainFrameImpl()->GetScrollOffset().width);
2442   EXPECT_EQ(0, web_view_impl->MainFrameImpl()->GetScrollOffset().height);
2443 
2444   // Make the page scale and scroll with the given paremeters.
2445   web_view_impl->SetPageScaleFactor(2.0f);
2446   web_view_impl->MainFrameImpl()->SetScrollOffset(WebSize(94, 111));
2447   EXPECT_EQ(2.0f, web_view_impl->PageScaleFactor());
2448   EXPECT_EQ(94, web_view_impl->MainFrameImpl()->GetScrollOffset().width);
2449   EXPECT_EQ(111, web_view_impl->MainFrameImpl()->GetScrollOffset().height);
2450   auto* main_frame_local =
2451       To<LocalFrame>(web_view_impl->GetPage()->MainFrame());
2452   main_frame_local->Loader().SaveScrollState();
2453   EXPECT_EQ(2.0f, main_frame_local->Loader()
2454                       .GetDocumentLoader()
2455                       ->GetHistoryItem()
2456                       ->GetViewState()
2457                       ->page_scale_factor_);
2458   EXPECT_EQ(94, main_frame_local->Loader()
2459                     .GetDocumentLoader()
2460                     ->GetHistoryItem()
2461                     ->GetViewState()
2462                     ->scroll_offset_.Width());
2463   EXPECT_EQ(111, main_frame_local->Loader()
2464                      .GetDocumentLoader()
2465                      ->GetHistoryItem()
2466                      ->GetViewState()
2467                      ->scroll_offset_.Height());
2468 
2469   // Confirm that resetting the page state resets the saved scroll position.
2470   web_view_impl->ResetScrollAndScaleState();
2471   EXPECT_EQ(1.0f, web_view_impl->PageScaleFactor());
2472   EXPECT_EQ(0, web_view_impl->MainFrameImpl()->GetScrollOffset().width);
2473   EXPECT_EQ(0, web_view_impl->MainFrameImpl()->GetScrollOffset().height);
2474   EXPECT_FALSE(main_frame_local->Loader()
2475                    .GetDocumentLoader()
2476                    ->GetHistoryItem()
2477                    ->GetViewState()
2478                    .has_value());
2479 }
2480 
TEST_F(WebViewTest,BackForwardRestoreScroll)2481 TEST_F(WebViewTest, BackForwardRestoreScroll) {
2482   RegisterMockedHttpURLLoad("back_forward_restore_scroll.html");
2483   WebViewImpl* web_view_impl = web_view_helper_.InitializeAndLoad(
2484       base_url_ + "back_forward_restore_scroll.html");
2485   web_view_impl->MainFrameWidget()->Resize(WebSize(640, 480));
2486   web_view_impl->MainFrameWidget()->UpdateAllLifecyclePhases(
2487       DocumentUpdateReason::kTest);
2488 
2489   // Emulate a user scroll
2490   web_view_impl->MainFrameImpl()->SetScrollOffset(WebSize(0, 900));
2491   auto* main_frame_local =
2492       To<LocalFrame>(web_view_impl->GetPage()->MainFrame());
2493   Persistent<HistoryItem> item1 =
2494       main_frame_local->Loader().GetDocumentLoader()->GetHistoryItem();
2495 
2496   // Click an anchor
2497   FrameLoadRequest request_a(
2498       main_frame_local->GetDocument(),
2499       ResourceRequest(main_frame_local->GetDocument()->CompleteURL("#a")));
2500   main_frame_local->Loader().StartNavigation(request_a);
2501   Persistent<HistoryItem> item2 =
2502       main_frame_local->Loader().GetDocumentLoader()->GetHistoryItem();
2503 
2504   // Go back, then forward, then back again.
2505   main_frame_local->Loader().GetDocumentLoader()->CommitSameDocumentNavigation(
2506       item1->Url(), WebFrameLoadType::kBackForward, item1.Get(),
2507       ClientRedirectPolicy::kNotClientRedirect, nullptr, false, nullptr);
2508   main_frame_local->Loader().GetDocumentLoader()->CommitSameDocumentNavigation(
2509       item2->Url(), WebFrameLoadType::kBackForward, item2.Get(),
2510       ClientRedirectPolicy::kNotClientRedirect, nullptr, false, nullptr);
2511   main_frame_local->Loader().GetDocumentLoader()->CommitSameDocumentNavigation(
2512       item1->Url(), WebFrameLoadType::kBackForward, item1.Get(),
2513       ClientRedirectPolicy::kNotClientRedirect, nullptr, false, nullptr);
2514   web_view_impl->MainFrameWidget()->UpdateAllLifecyclePhases(
2515       DocumentUpdateReason::kTest);
2516 
2517   // Click a different anchor
2518   FrameLoadRequest request_b(
2519       main_frame_local->GetDocument(),
2520       ResourceRequest(main_frame_local->GetDocument()->CompleteURL("#b")));
2521   main_frame_local->Loader().StartNavigation(request_b);
2522   Persistent<HistoryItem> item3 =
2523       main_frame_local->Loader().GetDocumentLoader()->GetHistoryItem();
2524   web_view_impl->MainFrameWidget()->UpdateAllLifecyclePhases(
2525       DocumentUpdateReason::kTest);
2526 
2527   // Go back, then forward. The scroll position should be properly set on the
2528   // forward navigation.
2529   main_frame_local->Loader().GetDocumentLoader()->CommitSameDocumentNavigation(
2530       item1->Url(), WebFrameLoadType::kBackForward, item1.Get(),
2531       ClientRedirectPolicy::kNotClientRedirect, nullptr, false, nullptr);
2532 
2533   main_frame_local->Loader().GetDocumentLoader()->CommitSameDocumentNavigation(
2534       item3->Url(), WebFrameLoadType::kBackForward, item3.Get(),
2535       ClientRedirectPolicy::kNotClientRedirect, nullptr, false, nullptr);
2536   // The scroll offset is only applied via invoking the anchor via the main
2537   // lifecycle, or a forced layout.
2538   // TODO(chrishtr): At the moment, WebLocalFrameImpl::GetScrollOffset() does
2539   // not force a layout. Script-exposed scroll offset-reading methods do,
2540   // however. It seems wrong not to force a layout.
2541   EXPECT_EQ(0, web_view_impl->MainFrameImpl()->GetScrollOffset().width);
2542   EXPECT_GT(web_view_impl->MainFrameImpl()->GetScrollOffset().height, 2000);
2543 }
2544 
2545 // Tests that scroll offset modified during fullscreen is preserved when
2546 // exiting fullscreen.
TEST_F(WebViewTest,FullscreenNoResetScroll)2547 TEST_F(WebViewTest, FullscreenNoResetScroll) {
2548   RegisterMockedHttpURLLoad("fullscreen_style.html");
2549   WebViewImpl* web_view_impl =
2550       web_view_helper_.InitializeAndLoad(base_url_ + "fullscreen_style.html");
2551   web_view_impl->MainFrameWidget()->Resize(WebSize(800, 600));
2552   UpdateAllLifecyclePhases();
2553 
2554   // Scroll the page down.
2555   web_view_impl->MainFrameImpl()->SetScrollOffset(WebSize(0, 2000));
2556   ASSERT_EQ(2000, web_view_impl->MainFrameImpl()->GetScrollOffset().height);
2557 
2558   // Enter fullscreen.
2559   LocalFrame* frame = web_view_impl->MainFrameImpl()->GetFrame();
2560   Element* element = frame->GetDocument()->documentElement();
2561   LocalFrame::NotifyUserActivation(frame);
2562   Fullscreen::RequestFullscreen(*element);
2563   web_view_impl->MainFrameWidget()->DidEnterFullscreen();
2564   UpdateAllLifecyclePhases();
2565 
2566   // Assert the scroll position on the document element doesn't change.
2567   ASSERT_EQ(2000, web_view_impl->MainFrameImpl()->GetScrollOffset().height);
2568 
2569   web_view_impl->MainFrameImpl()->SetScrollOffset(WebSize(0, 2100));
2570 
2571   web_view_impl->MainFrameWidget()->DidExitFullscreen();
2572   UpdateAllLifecyclePhases();
2573 
2574   EXPECT_EQ(2100, web_view_impl->MainFrameImpl()->GetScrollOffset().height);
2575 }
2576 
2577 // Tests that background color is read from the backdrop on fullscreen.
TEST_F(WebViewTest,FullscreenBackgroundColor)2578 TEST_F(WebViewTest, FullscreenBackgroundColor) {
2579   RegisterMockedHttpURLLoad("fullscreen_style.html");
2580   WebViewImpl* web_view_impl =
2581       web_view_helper_.InitializeAndLoad(base_url_ + "fullscreen_style.html");
2582   web_view_impl->MainFrameWidget()->Resize(WebSize(800, 600));
2583   UpdateAllLifecyclePhases();
2584   EXPECT_EQ(SK_ColorWHITE, web_view_impl->BackgroundColor());
2585 
2586   // Enter fullscreen.
2587   LocalFrame* frame = web_view_impl->MainFrameImpl()->GetFrame();
2588   Element* element = frame->GetDocument()->getElementById("fullscreenElement");
2589   ASSERT_TRUE(element);
2590   LocalFrame::NotifyUserActivation(frame);
2591   Fullscreen::RequestFullscreen(*element);
2592   web_view_impl->MainFrameWidget()->DidEnterFullscreen();
2593   UpdateAllLifecyclePhases();
2594 
2595   EXPECT_EQ(SK_ColorYELLOW, web_view_impl->BackgroundColor());
2596 }
2597 
2598 class PrintWebViewClient : public frame_test_helpers::TestWebViewClient {
2599  public:
PrintWebViewClient()2600   PrintWebViewClient() : print_called_(false) {}
2601 
2602   // WebViewClient methods
PrintPage(WebLocalFrame *)2603   void PrintPage(WebLocalFrame*) override { print_called_ = true; }
2604 
PrintCalled() const2605   bool PrintCalled() const { return print_called_; }
2606 
2607  private:
2608   bool print_called_;
2609 };
2610 
TEST_F(WebViewTest,PrintWithXHRInFlight)2611 TEST_F(WebViewTest, PrintWithXHRInFlight) {
2612   PrintWebViewClient client;
2613   RegisterMockedHttpURLLoad("print_with_xhr_inflight.html");
2614   WebViewImpl* web_view_impl = web_view_helper_.InitializeAndLoad(
2615       base_url_ + "print_with_xhr_inflight.html", nullptr, &client);
2616 
2617   ASSERT_TRUE(To<LocalFrame>(web_view_impl->GetPage()->MainFrame())
2618                   ->GetDocument()
2619                   ->LoadEventFinished());
2620   EXPECT_TRUE(client.PrintCalled());
2621   web_view_helper_.Reset();
2622 }
2623 
DragAndDropURL(WebViewImpl * web_view,const std::string & url)2624 static void DragAndDropURL(WebViewImpl* web_view, const std::string& url) {
2625   WebDragData drag_data;
2626   drag_data.Initialize();
2627 
2628   WebDragData::Item item;
2629   item.storage_type = WebDragData::Item::kStorageTypeString;
2630   item.string_type = "text/uri-list";
2631   item.string_data = WebString::FromUTF8(url);
2632   drag_data.AddItem(item);
2633 
2634   const gfx::PointF client_point;
2635   const gfx::PointF screen_point;
2636   WebFrameWidget* widget = web_view->MainFrameImpl()->FrameWidget();
2637   widget->DragTargetDragEnter(drag_data, client_point, screen_point,
2638                               kWebDragOperationCopy, 0);
2639   widget->DragTargetDrop(drag_data, client_point, screen_point, 0);
2640   frame_test_helpers::PumpPendingRequestsForFrameToLoad(
2641       web_view->MainFrameImpl());
2642 }
2643 
TEST_F(WebViewTest,DragDropURL)2644 TEST_F(WebViewTest, DragDropURL) {
2645   RegisterMockedHttpURLLoad("foo.html");
2646   RegisterMockedHttpURLLoad("bar.html");
2647 
2648   const std::string foo_url = base_url_ + "foo.html";
2649   const std::string bar_url = base_url_ + "bar.html";
2650 
2651   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(foo_url);
2652 
2653   ASSERT_TRUE(web_view);
2654 
2655   // Drag and drop barUrl and verify that we've navigated to it.
2656   DragAndDropURL(web_view, bar_url);
2657   EXPECT_EQ(bar_url,
2658             web_view->MainFrameImpl()->GetDocument().Url().GetString().Utf8());
2659 
2660   // Drag and drop fooUrl and verify that we've navigated back to it.
2661   DragAndDropURL(web_view, foo_url);
2662   EXPECT_EQ(foo_url,
2663             web_view->MainFrameImpl()->GetDocument().Url().GetString().Utf8());
2664 
2665   // Disable navigation on drag-and-drop.
2666   web_view->SettingsImpl()->SetNavigateOnDragDrop(false);
2667 
2668   // Attempt to drag and drop to barUrl and verify that no navigation has
2669   // occurred.
2670   DragAndDropURL(web_view, bar_url);
2671   EXPECT_EQ(foo_url,
2672             web_view->MainFrameImpl()->GetDocument().Url().GetString().Utf8());
2673 }
2674 
TapElement(WebInputEvent::Type type,Element * element)2675 bool WebViewTest::TapElement(WebInputEvent::Type type, Element* element) {
2676   if (!element || !element->GetLayoutObject())
2677     return false;
2678 
2679   DCHECK(web_view_helper_.GetWebView());
2680   element->scrollIntoViewIfNeeded();
2681 
2682   FloatPoint center(
2683       web_view_helper_.GetWebView()
2684           ->MainFrameImpl()
2685           ->GetFrameView()
2686           ->FrameToScreen(element->GetLayoutObject()->AbsoluteBoundingBoxRect())
2687           .Center());
2688 
2689   WebGestureEvent event(type, WebInputEvent::kNoModifiers,
2690                         WebInputEvent::GetStaticTimeStampForTests(),
2691                         WebGestureDevice::kTouchscreen);
2692   event.SetPositionInWidget(center);
2693 
2694   web_view_helper_.GetWebView()->MainFrameWidget()->HandleInputEvent(
2695       WebCoalescedInputEvent(event));
2696   RunPendingTasks();
2697   return true;
2698 }
2699 
TapElementById(WebInputEvent::Type type,const WebString & id)2700 bool WebViewTest::TapElementById(WebInputEvent::Type type,
2701                                  const WebString& id) {
2702   DCHECK(web_view_helper_.GetWebView());
2703   Element* element = static_cast<Element*>(
2704       web_view_helper_.LocalMainFrame()->GetDocument().GetElementById(id));
2705   return TapElement(type, element);
2706 }
2707 
PrintICBSizeFromPageSize(const FloatSize & page_size)2708 IntSize WebViewTest::PrintICBSizeFromPageSize(const FloatSize& page_size) {
2709   // The expected layout size comes from the calculation done in
2710   // ResizePageRectsKeepingRatio() which is used from PrintContext::begin() to
2711   // scale the page size.
2712   const float ratio = page_size.Height() / (float)page_size.Width();
2713   const int icb_width =
2714       floor(page_size.Width() * PrintContext::kPrintingMinimumShrinkFactor);
2715   const int icb_height = floor(icb_width * ratio);
2716   return IntSize(icb_width, icb_height);
2717 }
2718 
GetExternalDateTimeChooser(WebViewImpl * web_view_impl)2719 ExternalDateTimeChooser* WebViewTest::GetExternalDateTimeChooser(
2720     WebViewImpl* web_view_impl) {
2721   return web_view_impl->GetChromeClient()
2722       .GetExternalDateTimeChooserForTesting();
2723 }
2724 
TEST_F(WebViewTest,ClientTapHandling)2725 TEST_F(WebViewTest, ClientTapHandling) {
2726   TapHandlingWebWidgetClient client;
2727   WebView* web_view = web_view_helper_.InitializeAndLoad("about:blank", nullptr,
2728                                                          nullptr, &client);
2729   WebGestureEvent event(WebInputEvent::kGestureTap, WebInputEvent::kNoModifiers,
2730                         WebInputEvent::GetStaticTimeStampForTests(),
2731                         WebGestureDevice::kTouchscreen);
2732   event.SetPositionInWidget(gfx::PointF(3, 8));
2733   web_view->MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(event));
2734   RunPendingTasks();
2735   EXPECT_EQ(3, client.TapX());
2736   EXPECT_EQ(8, client.TapY());
2737   client.Reset();
2738   event.SetType(WebInputEvent::kGestureLongPress);
2739   event.SetPositionInWidget(gfx::PointF(25, 7));
2740   web_view->MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(event));
2741   RunPendingTasks();
2742   EXPECT_EQ(25, client.LongpressX());
2743   EXPECT_EQ(7, client.LongpressY());
2744 
2745   // Explicitly reset to break dependency on locally scoped client.
2746   web_view_helper_.Reset();
2747 }
2748 
TEST_F(WebViewTest,ClientTapHandlingNullWebViewClient)2749 TEST_F(WebViewTest, ClientTapHandlingNullWebViewClient) {
2750   // Note: this test doesn't use WebViewHelper since WebViewHelper creates an
2751   // internal WebViewClient on demand if the supplied WebViewClient is null.
2752   WebViewImpl* web_view = static_cast<WebViewImpl*>(
2753       WebView::Create(nullptr, false,
2754                       /*compositing_enabled=*/false, nullptr,
2755                       mojo::ScopedInterfaceEndpointHandle()));
2756   frame_test_helpers::TestWebFrameClient web_frame_client;
2757   frame_test_helpers::TestWebWidgetClient web_widget_client;
2758   WebLocalFrame* local_frame = WebLocalFrame::CreateMainFrame(
2759       web_view, &web_frame_client, nullptr, nullptr);
2760   web_frame_client.Bind(local_frame);
2761   blink::WebFrameWidget::CreateForMainFrame(
2762       &web_widget_client, local_frame,
2763       CrossVariantMojoAssociatedRemote<mojom::FrameWidgetHostInterfaceBase>(),
2764       CrossVariantMojoAssociatedReceiver<mojom::FrameWidgetInterfaceBase>(),
2765       CrossVariantMojoAssociatedRemote<mojom::WidgetHostInterfaceBase>(),
2766       CrossVariantMojoAssociatedReceiver<mojom::WidgetInterfaceBase>());
2767 
2768   WebGestureEvent event(WebInputEvent::kGestureTap, WebInputEvent::kNoModifiers,
2769                         WebInputEvent::GetStaticTimeStampForTests(),
2770                         WebGestureDevice::kTouchscreen);
2771   event.SetPositionInWidget(gfx::PointF(3, 8));
2772   EXPECT_EQ(WebInputEventResult::kNotHandled,
2773             web_view->MainFrameWidget()->HandleInputEvent(
2774                 WebCoalescedInputEvent(event)));
2775   web_view->Close();
2776 }
2777 
TEST_F(WebViewTest,LongPressEmptyDiv)2778 TEST_F(WebViewTest, LongPressEmptyDiv) {
2779   RegisterMockedHttpURLLoad("long_press_empty_div.html");
2780 
2781   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
2782       base_url_ + "long_press_empty_div.html");
2783   web_view->SettingsImpl()->SetAlwaysShowContextMenuOnTouch(false);
2784   web_view->MainFrameWidget()->Resize(WebSize(500, 300));
2785   UpdateAllLifecyclePhases();
2786   RunPendingTasks();
2787 
2788   WebGestureEvent event(WebInputEvent::kGestureLongPress,
2789                         WebInputEvent::kNoModifiers,
2790                         WebInputEvent::GetStaticTimeStampForTests(),
2791                         WebGestureDevice::kTouchscreen);
2792   event.SetPositionInWidget(gfx::PointF(250, 150));
2793 
2794   EXPECT_EQ(WebInputEventResult::kNotHandled,
2795             web_view->MainFrameWidget()->HandleInputEvent(
2796                 WebCoalescedInputEvent(event)));
2797 }
2798 
TEST_F(WebViewTest,LongPressEmptyDivAlwaysShow)2799 TEST_F(WebViewTest, LongPressEmptyDivAlwaysShow) {
2800   RegisterMockedHttpURLLoad("long_press_empty_div.html");
2801 
2802   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
2803       base_url_ + "long_press_empty_div.html");
2804   web_view->SettingsImpl()->SetAlwaysShowContextMenuOnTouch(true);
2805   web_view->MainFrameWidget()->Resize(WebSize(500, 300));
2806   UpdateAllLifecyclePhases();
2807   RunPendingTasks();
2808 
2809   WebGestureEvent event(WebInputEvent::kGestureLongPress,
2810                         WebInputEvent::kNoModifiers,
2811                         WebInputEvent::GetStaticTimeStampForTests(),
2812                         WebGestureDevice::kTouchscreen);
2813   event.SetPositionInWidget(gfx::PointF(250, 150));
2814 
2815   EXPECT_EQ(WebInputEventResult::kHandledSystem,
2816             web_view->MainFrameWidget()->HandleInputEvent(
2817                 WebCoalescedInputEvent(event)));
2818 }
2819 
TEST_F(WebViewTest,LongPressObject)2820 TEST_F(WebViewTest, LongPressObject) {
2821   RegisterMockedHttpURLLoad("long_press_object.html");
2822 
2823   WebViewImpl* web_view =
2824       web_view_helper_.InitializeAndLoad(base_url_ + "long_press_object.html");
2825   web_view->SettingsImpl()->SetAlwaysShowContextMenuOnTouch(true);
2826   web_view->MainFrameWidget()->Resize(WebSize(500, 300));
2827   UpdateAllLifecyclePhases();
2828   RunPendingTasks();
2829 
2830   WebGestureEvent event(WebInputEvent::kGestureLongPress,
2831                         WebInputEvent::kNoModifiers,
2832                         WebInputEvent::GetStaticTimeStampForTests(),
2833                         WebGestureDevice::kTouchscreen);
2834   event.SetPositionInWidget(gfx::PointF(10, 10));
2835 
2836   EXPECT_NE(WebInputEventResult::kHandledSystem,
2837             web_view->MainFrameWidget()->HandleInputEvent(
2838                 WebCoalescedInputEvent(event)));
2839 
2840   auto* element = To<HTMLElement>(static_cast<Node*>(
2841       web_view->MainFrameImpl()->GetDocument().GetElementById("obj")));
2842   EXPECT_FALSE(element->CanStartSelection());
2843 }
2844 
TEST_F(WebViewTest,LongPressObjectFallback)2845 TEST_F(WebViewTest, LongPressObjectFallback) {
2846   RegisterMockedHttpURLLoad("long_press_object_fallback.html");
2847 
2848   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
2849       base_url_ + "long_press_object_fallback.html");
2850   web_view->SettingsImpl()->SetAlwaysShowContextMenuOnTouch(true);
2851   web_view->MainFrameWidget()->Resize(WebSize(500, 300));
2852   UpdateAllLifecyclePhases();
2853   RunPendingTasks();
2854 
2855   WebGestureEvent event(WebInputEvent::kGestureLongPress,
2856                         WebInputEvent::kNoModifiers,
2857                         WebInputEvent::GetStaticTimeStampForTests(),
2858                         WebGestureDevice::kTouchscreen);
2859   event.SetPositionInWidget(gfx::PointF(10, 10));
2860 
2861   EXPECT_EQ(WebInputEventResult::kHandledSystem,
2862             web_view->MainFrameWidget()->HandleInputEvent(
2863                 WebCoalescedInputEvent(event)));
2864 
2865   auto* element = To<HTMLElement>(static_cast<Node*>(
2866       web_view->MainFrameImpl()->GetDocument().GetElementById("obj")));
2867   EXPECT_TRUE(element->CanStartSelection());
2868 }
2869 
TEST_F(WebViewTest,LongPressImage)2870 TEST_F(WebViewTest, LongPressImage) {
2871   RegisterMockedHttpURLLoad("long_press_image.html");
2872 
2873   WebViewImpl* web_view =
2874       web_view_helper_.InitializeAndLoad(base_url_ + "long_press_image.html");
2875   web_view->SettingsImpl()->SetAlwaysShowContextMenuOnTouch(false);
2876   web_view->MainFrameWidget()->Resize(WebSize(500, 300));
2877   UpdateAllLifecyclePhases();
2878   RunPendingTasks();
2879 
2880   WebGestureEvent event(WebInputEvent::kGestureLongPress,
2881                         WebInputEvent::kNoModifiers,
2882                         WebInputEvent::GetStaticTimeStampForTests(),
2883                         WebGestureDevice::kTouchscreen);
2884   event.SetPositionInWidget(gfx::PointF(10, 10));
2885 
2886   EXPECT_EQ(WebInputEventResult::kHandledSystem,
2887             web_view->MainFrameWidget()->HandleInputEvent(
2888                 WebCoalescedInputEvent(event)));
2889   EXPECT_TRUE(
2890       web_view->AsView()
2891           .page->GetContextMenuController()
2892           .ContextMenuNodeForFrame(web_view->MainFrameImpl()->GetFrame()));
2893 }
2894 
TEST_F(WebViewTest,LongPressVideo)2895 TEST_F(WebViewTest, LongPressVideo) {
2896   RegisterMockedHttpURLLoad("long_press_video.html");
2897 
2898   WebViewImpl* web_view =
2899       web_view_helper_.InitializeAndLoad(base_url_ + "long_press_video.html");
2900   web_view->SettingsImpl()->SetAlwaysShowContextMenuOnTouch(false);
2901   web_view->MainFrameWidget()->Resize(WebSize(500, 300));
2902   UpdateAllLifecyclePhases();
2903   RunPendingTasks();
2904 
2905   WebGestureEvent event(WebInputEvent::kGestureLongPress,
2906                         WebInputEvent::kNoModifiers,
2907                         WebInputEvent::GetStaticTimeStampForTests(),
2908                         WebGestureDevice::kTouchscreen);
2909   event.SetPositionInWidget(gfx::PointF(10, 10));
2910 
2911   EXPECT_EQ(WebInputEventResult::kHandledSystem,
2912             web_view->MainFrameWidget()->HandleInputEvent(
2913                 WebCoalescedInputEvent(event)));
2914 }
2915 
TEST_F(WebViewTest,LongPressLink)2916 TEST_F(WebViewTest, LongPressLink) {
2917   RegisterMockedHttpURLLoad("long_press_link.html");
2918 
2919   WebViewImpl* web_view =
2920       web_view_helper_.InitializeAndLoad(base_url_ + "long_press_link.html");
2921   web_view->SettingsImpl()->SetAlwaysShowContextMenuOnTouch(false);
2922   web_view->MainFrameWidget()->Resize(WebSize(500, 300));
2923   UpdateAllLifecyclePhases();
2924   RunPendingTasks();
2925 
2926   WebGestureEvent event(WebInputEvent::kGestureLongPress,
2927                         WebInputEvent::kNoModifiers,
2928                         WebInputEvent::GetStaticTimeStampForTests(),
2929                         WebGestureDevice::kTouchscreen);
2930   event.SetPositionInWidget(gfx::PointF(500, 300));
2931 
2932   EXPECT_EQ(WebInputEventResult::kHandledSystem,
2933             web_view->MainFrameWidget()->HandleInputEvent(
2934                 WebCoalescedInputEvent(event)));
2935 }
2936 
2937 // Tests that we send touchcancel when drag start by long press.
TEST_F(WebViewTest,TouchCancelOnStartDragging)2938 TEST_F(WebViewTest, TouchCancelOnStartDragging) {
2939   RegisterMockedHttpURLLoad("long_press_draggable_div.html");
2940 
2941   url_test_helpers::RegisterMockedURLLoad(
2942       ToKURL("http://www.test.com/foo.png"),
2943       test::CoreTestDataPath("white-1x1.png"));
2944   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
2945       base_url_ + "long_press_draggable_div.html");
2946 
2947   web_view->SettingsImpl()->SetTouchDragDropEnabled(true);
2948   web_view->MainFrameWidget()->Resize(WebSize(500, 300));
2949   UpdateAllLifecyclePhases();
2950   RunPendingTasks();
2951 
2952   WebPointerEvent pointer_down(
2953       WebInputEvent::kPointerDown,
2954       WebPointerProperties(1, WebPointerProperties::PointerType::kTouch), 5, 5);
2955   pointer_down.SetPositionInWidget(250, 8);
2956   web_view->MainFrameWidget()->HandleInputEvent(
2957       WebCoalescedInputEvent(pointer_down));
2958   web_view->MainFrameWidget()->DispatchBufferedTouchEvents();
2959 
2960   WebString target_id = WebString::FromUTF8("target");
2961 
2962   // Send long press to start dragging
2963   EXPECT_TRUE(TapElementById(WebInputEvent::kGestureLongPress, target_id));
2964   EXPECT_EQ("dragstart", web_view->MainFrameImpl()->GetDocument().Title());
2965 
2966   // Check pointer cancel is sent to dom.
2967   WebPointerEvent pointer_cancel(
2968       WebInputEvent::kPointerCancel,
2969       WebPointerProperties(1, WebPointerProperties::PointerType::kTouch), 5, 5);
2970   pointer_cancel.SetPositionInWidget(250, 8);
2971   EXPECT_NE(WebInputEventResult::kHandledSuppressed,
2972             web_view->MainFrameWidget()->HandleInputEvent(
2973                 WebCoalescedInputEvent(pointer_cancel)));
2974   web_view->MainFrameWidget()->DispatchBufferedTouchEvents();
2975   EXPECT_EQ("touchcancel", web_view->MainFrameImpl()->GetDocument().Title());
2976 }
2977 
TEST_F(WebViewTest,showContextMenuOnLongPressingLinks)2978 TEST_F(WebViewTest, showContextMenuOnLongPressingLinks) {
2979   RegisterMockedHttpURLLoad("long_press_links_and_images.html");
2980 
2981   url_test_helpers::RegisterMockedURLLoad(
2982       ToKURL("http://www.test.com/foo.png"),
2983       test::CoreTestDataPath("white-1x1.png"));
2984   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
2985       base_url_ + "long_press_links_and_images.html");
2986 
2987   web_view->SettingsImpl()->SetTouchDragDropEnabled(true);
2988   web_view->MainFrameWidget()->Resize(WebSize(500, 300));
2989   UpdateAllLifecyclePhases();
2990   RunPendingTasks();
2991 
2992   WebString anchor_tag_id = WebString::FromUTF8("anchorTag");
2993   WebString image_tag_id = WebString::FromUTF8("imageTag");
2994 
2995   EXPECT_TRUE(TapElementById(WebInputEvent::kGestureLongPress, anchor_tag_id));
2996   EXPECT_EQ("anchor contextmenu",
2997             web_view->MainFrameImpl()->GetDocument().Title());
2998 
2999   EXPECT_TRUE(TapElementById(WebInputEvent::kGestureLongPress, image_tag_id));
3000   EXPECT_EQ("image contextmenu",
3001             web_view->MainFrameImpl()->GetDocument().Title());
3002 }
3003 
TEST_F(WebViewTest,LongPressEmptyEditableSelection)3004 TEST_F(WebViewTest, LongPressEmptyEditableSelection) {
3005   RegisterMockedHttpURLLoad("long_press_empty_editable_selection.html");
3006 
3007   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
3008       base_url_ + "long_press_empty_editable_selection.html");
3009   web_view->SettingsImpl()->SetAlwaysShowContextMenuOnTouch(false);
3010   web_view->MainFrameWidget()->Resize(WebSize(500, 300));
3011   UpdateAllLifecyclePhases();
3012   RunPendingTasks();
3013 
3014   WebGestureEvent event(WebInputEvent::kGestureLongPress,
3015                         WebInputEvent::kNoModifiers,
3016                         WebInputEvent::GetStaticTimeStampForTests(),
3017                         WebGestureDevice::kTouchscreen);
3018   event.SetPositionInWidget(gfx::PointF(10, 10));
3019 
3020   EXPECT_EQ(WebInputEventResult::kHandledSystem,
3021             web_view->MainFrameWidget()->HandleInputEvent(
3022                 WebCoalescedInputEvent(event)));
3023 }
3024 
TEST_F(WebViewTest,LongPressEmptyNonEditableSelection)3025 TEST_F(WebViewTest, LongPressEmptyNonEditableSelection) {
3026   RegisterMockedHttpURLLoad("long_press_image.html");
3027 
3028   WebViewImpl* web_view =
3029       web_view_helper_.InitializeAndLoad(base_url_ + "long_press_image.html");
3030   web_view->MainFrameWidget()->Resize(WebSize(500, 500));
3031   UpdateAllLifecyclePhases();
3032   RunPendingTasks();
3033 
3034   WebGestureEvent event(WebInputEvent::kGestureLongPress,
3035                         WebInputEvent::kNoModifiers,
3036                         WebInputEvent::GetStaticTimeStampForTests(),
3037                         WebGestureDevice::kTouchscreen);
3038   event.SetPositionInWidget(gfx::PointF(300, 300));
3039   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
3040 
3041   EXPECT_EQ(WebInputEventResult::kHandledSystem,
3042             web_view->MainFrameWidget()->HandleInputEvent(
3043                 WebCoalescedInputEvent(event)));
3044   EXPECT_TRUE(frame->SelectionAsText().IsEmpty());
3045 }
3046 
TEST_F(WebViewTest,LongPressSelection)3047 TEST_F(WebViewTest, LongPressSelection) {
3048   RegisterMockedHttpURLLoad("longpress_selection.html");
3049 
3050   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
3051       base_url_ + "longpress_selection.html");
3052   web_view->MainFrameWidget()->Resize(WebSize(500, 300));
3053   UpdateAllLifecyclePhases();
3054   RunPendingTasks();
3055 
3056   WebString target = WebString::FromUTF8("target");
3057   WebString onselectstartfalse = WebString::FromUTF8("onselectstartfalse");
3058   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
3059 
3060   EXPECT_TRUE(
3061       TapElementById(WebInputEvent::kGestureLongPress, onselectstartfalse));
3062   EXPECT_EQ("", frame->SelectionAsText().Utf8());
3063   EXPECT_TRUE(TapElementById(WebInputEvent::kGestureLongPress, target));
3064   EXPECT_EQ("testword", frame->SelectionAsText().Utf8());
3065 }
3066 
TEST_F(WebViewTest,FinishComposingTextDoesNotDismissHandles)3067 TEST_F(WebViewTest, FinishComposingTextDoesNotDismissHandles) {
3068   RegisterMockedHttpURLLoad("longpress_selection.html");
3069 
3070   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
3071       base_url_ + "longpress_selection.html");
3072   web_view->MainFrameWidget()->Resize(WebSize(500, 300));
3073   UpdateAllLifecyclePhases();
3074   RunPendingTasks();
3075 
3076   WebString target = WebString::FromUTF8("target");
3077   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
3078   WebInputMethodController* active_input_method_controller =
3079       frame->FrameWidget()->GetActiveWebInputMethodController();
3080   EXPECT_TRUE(TapElementById(WebInputEvent::kGestureTap, target));
3081   WebVector<WebImeTextSpan> empty_ime_text_spans;
3082   frame->SetEditableSelectionOffsets(8, 8);
3083   EXPECT_TRUE(active_input_method_controller->SetComposition(
3084       "12345", empty_ime_text_spans, WebRange(), 8, 13));
3085   EXPECT_TRUE(frame->GetFrame()->GetInputMethodController().HasComposition());
3086   EXPECT_EQ("", frame->SelectionAsText().Utf8());
3087   EXPECT_FALSE(frame->GetFrame()->Selection().IsHandleVisible());
3088   EXPECT_TRUE(frame->GetFrame()->GetInputMethodController().HasComposition());
3089 
3090   EXPECT_TRUE(TapElementById(WebInputEvent::kGestureLongPress, target));
3091   EXPECT_EQ("testword12345", frame->SelectionAsText().Utf8());
3092   EXPECT_TRUE(frame->GetFrame()->Selection().IsHandleVisible());
3093   EXPECT_TRUE(frame->GetFrame()->GetInputMethodController().HasComposition());
3094 
3095   // Check that finishComposingText(KeepSelection) does not dismiss handles.
3096   active_input_method_controller->FinishComposingText(
3097       WebInputMethodController::kKeepSelection);
3098   EXPECT_TRUE(frame->GetFrame()->Selection().IsHandleVisible());
3099 }
3100 
3101 #if !defined(OS_MACOSX)
TEST_F(WebViewTest,TouchDoesntSelectEmptyTextarea)3102 TEST_F(WebViewTest, TouchDoesntSelectEmptyTextarea) {
3103   RegisterMockedHttpURLLoad("longpress_textarea.html");
3104 
3105   WebViewImpl* web_view =
3106       web_view_helper_.InitializeAndLoad(base_url_ + "longpress_textarea.html");
3107   web_view->MainFrameWidget()->Resize(WebSize(500, 300));
3108   UpdateAllLifecyclePhases();
3109   RunPendingTasks();
3110 
3111   WebString blanklinestextbox = WebString::FromUTF8("blanklinestextbox");
3112   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
3113 
3114   // Long-press on carriage returns.
3115   EXPECT_TRUE(
3116       TapElementById(WebInputEvent::kGestureLongPress, blanklinestextbox));
3117   EXPECT_TRUE(frame->SelectionAsText().IsEmpty());
3118 
3119   // Double-tap on carriage returns.
3120   WebGestureEvent event(WebInputEvent::kGestureTap, WebInputEvent::kNoModifiers,
3121                         WebInputEvent::GetStaticTimeStampForTests(),
3122                         WebGestureDevice::kTouchscreen);
3123   event.SetPositionInWidget(gfx::PointF(100, 25));
3124   event.data.tap.tap_count = 2;
3125 
3126   web_view->MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(event));
3127   EXPECT_TRUE(frame->SelectionAsText().IsEmpty());
3128 
3129   auto* text_area_element = To<HTMLTextAreaElement>(static_cast<Node*>(
3130       web_view->MainFrameImpl()->GetDocument().GetElementById(
3131           blanklinestextbox)));
3132   text_area_element->setValue("hello");
3133 
3134   // Long-press past last word of textbox.
3135   EXPECT_TRUE(
3136       TapElementById(WebInputEvent::kGestureLongPress, blanklinestextbox));
3137   EXPECT_TRUE(frame->SelectionAsText().IsEmpty());
3138 
3139   // Double-tap past last word of textbox.
3140   web_view->MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(event));
3141   EXPECT_TRUE(frame->SelectionAsText().IsEmpty());
3142 }
3143 #endif
3144 
TEST_F(WebViewTest,LongPressImageTextarea)3145 TEST_F(WebViewTest, LongPressImageTextarea) {
3146   RegisterMockedHttpURLLoad("longpress_image_contenteditable.html");
3147 
3148   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
3149       base_url_ + "longpress_image_contenteditable.html");
3150   web_view->MainFrameWidget()->Resize(WebSize(500, 300));
3151   UpdateAllLifecyclePhases();
3152   RunPendingTasks();
3153 
3154   WebString image = WebString::FromUTF8("purpleimage");
3155 
3156   EXPECT_TRUE(TapElementById(WebInputEvent::kGestureLongPress, image));
3157   WebRange range = web_view->MainFrameImpl()
3158                        ->GetInputMethodController()
3159                        ->GetSelectionOffsets();
3160   EXPECT_FALSE(range.IsNull());
3161   EXPECT_EQ(0, range.StartOffset());
3162   EXPECT_EQ(1, range.length());
3163 }
3164 
TEST_F(WebViewTest,BlinkCaretAfterLongPress)3165 TEST_F(WebViewTest, BlinkCaretAfterLongPress) {
3166   RegisterMockedHttpURLLoad("blink_caret_on_typing_after_long_press.html");
3167 
3168   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
3169       base_url_ + "blink_caret_on_typing_after_long_press.html");
3170   web_view->MainFrameWidget()->Resize(WebSize(640, 480));
3171   UpdateAllLifecyclePhases();
3172   RunPendingTasks();
3173 
3174   WebString target = WebString::FromUTF8("target");
3175   WebLocalFrameImpl* main_frame = web_view->MainFrameImpl();
3176 
3177   EXPECT_TRUE(TapElementById(WebInputEvent::kGestureLongPress, target));
3178   EXPECT_FALSE(main_frame->GetFrame()->Selection().IsCaretBlinkingSuspended());
3179 }
3180 
TEST_F(WebViewTest,BlinkCaretOnClosingContextMenu)3181 TEST_F(WebViewTest, BlinkCaretOnClosingContextMenu) {
3182   RegisterMockedHttpURLLoad("form.html");
3183   WebViewImpl* web_view =
3184       web_view_helper_.InitializeAndLoad(base_url_ + "form.html");
3185 
3186   web_view->SetInitialFocus(false);
3187   RunPendingTasks();
3188 
3189   // We suspend caret blinking when pressing with mouse right button.
3190   // Note that we do not send MouseUp event here since it will be consumed
3191   // by the context menu once it shows up.
3192   WebMouseEvent mouse_event(WebInputEvent::kMouseDown,
3193                             WebInputEvent::kNoModifiers,
3194                             WebInputEvent::GetStaticTimeStampForTests());
3195 
3196   mouse_event.button = WebMouseEvent::Button::kRight;
3197   mouse_event.SetPositionInWidget(1, 1);
3198   mouse_event.click_count = 1;
3199   web_view->MainFrameWidget()->HandleInputEvent(
3200       WebCoalescedInputEvent(mouse_event));
3201   RunPendingTasks();
3202 
3203   WebLocalFrameImpl* main_frame = web_view->MainFrameImpl();
3204   EXPECT_TRUE(main_frame->GetFrame()->Selection().IsCaretBlinkingSuspended());
3205 
3206   // Caret blinking is still suspended after showing context menu.
3207   web_view->MainFrameWidget()->ShowContextMenu(kMenuSourceMouse);
3208   EXPECT_TRUE(main_frame->GetFrame()->Selection().IsCaretBlinkingSuspended());
3209 
3210   // Caret blinking will be resumed only after context menu is closed.
3211   web_view->DidCloseContextMenu();
3212 
3213   EXPECT_FALSE(main_frame->GetFrame()->Selection().IsCaretBlinkingSuspended());
3214 }
3215 
TEST_F(WebViewTest,SelectionOnReadOnlyInput)3216 TEST_F(WebViewTest, SelectionOnReadOnlyInput) {
3217   RegisterMockedHttpURLLoad("selection_readonly.html");
3218   WebViewImpl* web_view =
3219       web_view_helper_.InitializeAndLoad(base_url_ + "selection_readonly.html");
3220   web_view->MainFrameWidget()->Resize(WebSize(640, 480));
3221   UpdateAllLifecyclePhases();
3222   RunPendingTasks();
3223 
3224   std::string test_word = "This text should be selected.";
3225 
3226   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
3227   EXPECT_EQ(test_word, frame->SelectionAsText().Utf8());
3228 
3229   WebRange range = web_view->MainFrameImpl()
3230                        ->GetInputMethodController()
3231                        ->GetSelectionOffsets();
3232   EXPECT_FALSE(range.IsNull());
3233   EXPECT_EQ(0, range.StartOffset());
3234   EXPECT_EQ(static_cast<int>(test_word.length()), range.length());
3235 }
3236 
TEST_F(WebViewTest,KeyDownScrollsHandled)3237 TEST_F(WebViewTest, KeyDownScrollsHandled) {
3238   RegisterMockedHttpURLLoad("content-width-1000.html");
3239 
3240   WebViewImpl* web_view =
3241       web_view_helper_.InitializeAndLoad(base_url_ + "content-width-1000.html");
3242   web_view->MainFrameWidget()->Resize(WebSize(100, 100));
3243   UpdateAllLifecyclePhases();
3244   RunPendingTasks();
3245 
3246   WebKeyboardEvent key_event(WebInputEvent::kRawKeyDown,
3247                              WebInputEvent::kNoModifiers,
3248                              WebInputEvent::GetStaticTimeStampForTests());
3249 
3250   // RawKeyDown pagedown should be handled.
3251   key_event.windows_key_code = VKEY_NEXT;
3252   EXPECT_EQ(WebInputEventResult::kHandledSystem,
3253             web_view->MainFrameWidget()->HandleInputEvent(
3254                 WebCoalescedInputEvent(key_event)));
3255   key_event.SetType(WebInputEvent::kKeyUp);
3256   web_view->MainFrameWidget()->HandleInputEvent(
3257       WebCoalescedInputEvent(key_event));
3258 
3259   // Coalesced KeyDown arrow-down should be handled.
3260   key_event.windows_key_code = VKEY_DOWN;
3261   key_event.SetType(WebInputEvent::kKeyDown);
3262   EXPECT_EQ(WebInputEventResult::kHandledSystem,
3263             web_view->MainFrameWidget()->HandleInputEvent(
3264                 WebCoalescedInputEvent(key_event)));
3265   key_event.SetType(WebInputEvent::kKeyUp);
3266   web_view->MainFrameWidget()->HandleInputEvent(
3267       WebCoalescedInputEvent(key_event));
3268 
3269   // Ctrl-Home should be handled...
3270   key_event.windows_key_code = VKEY_HOME;
3271   key_event.SetModifiers(WebInputEvent::kControlKey);
3272   key_event.SetType(WebInputEvent::kRawKeyDown);
3273   EXPECT_EQ(WebInputEventResult::kNotHandled,
3274             web_view->MainFrameWidget()->HandleInputEvent(
3275                 WebCoalescedInputEvent(key_event)));
3276   key_event.SetType(WebInputEvent::kKeyUp);
3277   web_view->MainFrameWidget()->HandleInputEvent(
3278       WebCoalescedInputEvent(key_event));
3279 
3280   // But Ctrl-Down should not.
3281   key_event.windows_key_code = VKEY_DOWN;
3282   key_event.SetModifiers(WebInputEvent::kControlKey);
3283   key_event.SetType(WebInputEvent::kRawKeyDown);
3284   EXPECT_EQ(WebInputEventResult::kNotHandled,
3285             web_view->MainFrameWidget()->HandleInputEvent(
3286                 WebCoalescedInputEvent(key_event)));
3287   key_event.SetType(WebInputEvent::kKeyUp);
3288   web_view->MainFrameWidget()->HandleInputEvent(
3289       WebCoalescedInputEvent(key_event));
3290 
3291   // Shift, meta, and alt should not be handled.
3292   key_event.windows_key_code = VKEY_NEXT;
3293   key_event.SetModifiers(WebInputEvent::kShiftKey);
3294   key_event.SetType(WebInputEvent::kRawKeyDown);
3295   EXPECT_EQ(WebInputEventResult::kNotHandled,
3296             web_view->MainFrameWidget()->HandleInputEvent(
3297                 WebCoalescedInputEvent(key_event)));
3298   key_event.SetType(WebInputEvent::kKeyUp);
3299   web_view->MainFrameWidget()->HandleInputEvent(
3300       WebCoalescedInputEvent(key_event));
3301 
3302   key_event.windows_key_code = VKEY_NEXT;
3303   key_event.SetModifiers(WebInputEvent::kMetaKey);
3304   key_event.SetType(WebInputEvent::kRawKeyDown);
3305   EXPECT_EQ(WebInputEventResult::kNotHandled,
3306             web_view->MainFrameWidget()->HandleInputEvent(
3307                 WebCoalescedInputEvent(key_event)));
3308   key_event.SetType(WebInputEvent::kKeyUp);
3309   web_view->MainFrameWidget()->HandleInputEvent(
3310       WebCoalescedInputEvent(key_event));
3311 
3312   key_event.windows_key_code = VKEY_NEXT;
3313   key_event.SetModifiers(WebInputEvent::kAltKey);
3314   key_event.SetType(WebInputEvent::kRawKeyDown);
3315   EXPECT_EQ(WebInputEventResult::kNotHandled,
3316             web_view->MainFrameWidget()->HandleInputEvent(
3317                 WebCoalescedInputEvent(key_event)));
3318   key_event.SetType(WebInputEvent::kKeyUp);
3319   web_view->MainFrameWidget()->HandleInputEvent(
3320       WebCoalescedInputEvent(key_event));
3321 
3322   // System-key labeled Alt-Down (as in Windows) should do nothing,
3323   // but non-system-key labeled Alt-Down (as in Mac) should be handled
3324   // as a page-down.
3325   key_event.windows_key_code = VKEY_DOWN;
3326   key_event.SetModifiers(WebInputEvent::kAltKey);
3327   key_event.is_system_key = true;
3328   key_event.SetType(WebInputEvent::kRawKeyDown);
3329   EXPECT_EQ(WebInputEventResult::kNotHandled,
3330             web_view->MainFrameWidget()->HandleInputEvent(
3331                 WebCoalescedInputEvent(key_event)));
3332   key_event.SetType(WebInputEvent::kKeyUp);
3333   web_view->MainFrameWidget()->HandleInputEvent(
3334       WebCoalescedInputEvent(key_event));
3335 
3336   key_event.windows_key_code = VKEY_DOWN;
3337   key_event.SetModifiers(WebInputEvent::kAltKey);
3338   key_event.is_system_key = false;
3339   key_event.SetType(WebInputEvent::kRawKeyDown);
3340   EXPECT_EQ(WebInputEventResult::kHandledSystem,
3341             web_view->MainFrameWidget()->HandleInputEvent(
3342                 WebCoalescedInputEvent(key_event)));
3343   key_event.SetType(WebInputEvent::kKeyUp);
3344   web_view->MainFrameWidget()->HandleInputEvent(
3345       WebCoalescedInputEvent(key_event));
3346 }
3347 
3348 class MiddleClickAutoscrollWebWidgetClient
3349     : public frame_test_helpers::TestWebWidgetClient {
3350  public:
3351   // WebWidgetClient methods
3352 
DidChangeCursor(const ui::Cursor & cursor)3353   void DidChangeCursor(const ui::Cursor& cursor) override {
3354     last_cursor_type_ = cursor.type();
3355   }
3356 
GetLastCursorType() const3357   ui::mojom::blink::CursorType GetLastCursorType() const {
3358     return last_cursor_type_;
3359   }
3360 
3361  private:
3362   ui::mojom::blink::CursorType last_cursor_type_ =
3363       ui::mojom::blink::CursorType::kPointer;
3364 };
3365 
TEST_F(WebViewTest,MiddleClickAutoscrollCursor)3366 TEST_F(WebViewTest, MiddleClickAutoscrollCursor) {
3367   MiddleClickAutoscrollWebWidgetClient client;
3368   ScopedMiddleClickAutoscrollForTest middle_click_autoscroll(true);
3369   RegisterMockedHttpURLLoad("content-width-1000.html");
3370 
3371   // We will be changing the size of the page to test each of the panning
3372   // cursor variations. For reference, content-width-1000.html is 1000px wide
3373   // and 2000px tall.
3374   // 1. 100 x 100 - The page will be scrollable in both x and y directions, so
3375   //      we expect to see the cursor with arrows in all four directions.
3376   // 2. 1010 x 100 - The page will be scrollable in the y direction, but not x,
3377   //      so we expect to see the cursor with only the vertical arrows.
3378   // 3. 100 x 2010 - The page will be scrollable in the x direction, but not y,
3379   //      so we expect to see the cursor with only the horizontal arrows.
3380   struct CursorTests {
3381     int resize_width;
3382     int resize_height;
3383     ui::mojom::blink::CursorType expected_cursor;
3384   } cursor_tests[] = {{100, 100, MiddlePanningCursor().type()},
3385                       {1010, 100, MiddlePanningVerticalCursor().type()},
3386                       {100, 2010, MiddlePanningHorizontalCursor().type()}};
3387 
3388   for (const CursorTests current_test : cursor_tests) {
3389     WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
3390         base_url_ + "content-width-1000.html", nullptr, nullptr, &client);
3391     web_view->MainFrameWidget()->Resize(
3392         WebSize(current_test.resize_width, current_test.resize_height));
3393     UpdateAllLifecyclePhases();
3394     RunPendingTasks();
3395 
3396     LocalFrame* local_frame =
3397         To<WebLocalFrameImpl>(web_view->MainFrame())->GetFrame();
3398 
3399     // Setup a mock clipboard.  On linux, middle click can paste from the
3400     // clipboard, so the input handler below will access the clipboard.
3401     PageTestBase::MockClipboardHostProvider mock_clip_host_provider(
3402         local_frame->GetBrowserInterfaceBroker());
3403 
3404     WebMouseEvent mouse_event(WebInputEvent::kMouseDown,
3405                               WebInputEvent::kNoModifiers,
3406                               WebInputEvent::GetStaticTimeStampForTests());
3407     mouse_event.button = WebMouseEvent::Button::kMiddle;
3408     mouse_event.SetPositionInWidget(1, 1);
3409     mouse_event.click_count = 1;
3410 
3411     // Start middle-click autoscroll.
3412     web_view->MainFrameWidget()->HandleInputEvent(
3413         WebCoalescedInputEvent(mouse_event));
3414     mouse_event.SetType(WebInputEvent::kMouseUp);
3415     web_view->MainFrameWidget()->HandleInputEvent(
3416         WebCoalescedInputEvent(mouse_event));
3417 
3418     EXPECT_EQ(current_test.expected_cursor, client.GetLastCursorType());
3419 
3420     // Even if a plugin tries to change the cursor type, that should be ignored
3421     // during middle-click autoscroll.
3422     web_view->GetChromeClient().SetCursorForPlugin(PointerCursor(),
3423                                                    local_frame);
3424     EXPECT_EQ(current_test.expected_cursor, client.GetLastCursorType());
3425 
3426     // End middle-click autoscroll.
3427     mouse_event.SetType(WebInputEvent::kMouseDown);
3428     web_view->MainFrameWidget()->HandleInputEvent(
3429         WebCoalescedInputEvent(mouse_event));
3430     mouse_event.SetType(WebInputEvent::kMouseUp);
3431     web_view->MainFrameWidget()->HandleInputEvent(
3432         WebCoalescedInputEvent(mouse_event));
3433 
3434     web_view->GetChromeClient().SetCursorForPlugin(IBeamCursor(), local_frame);
3435     EXPECT_EQ(IBeamCursor().type(), client.GetLastCursorType());
3436   }
3437 
3438   // Explicitly reset to break dependency on locally scoped client.
3439   web_view_helper_.Reset();
3440 }
3441 
ConfigueCompositingWebView(WebSettings * settings)3442 static void ConfigueCompositingWebView(WebSettings* settings) {
3443   settings->SetPreferCompositingToLCDTextEnabled(true);
3444 }
3445 
TEST_F(WebViewTest,ShowPressOnTransformedLink)3446 TEST_F(WebViewTest, ShowPressOnTransformedLink) {
3447   frame_test_helpers::WebViewHelper web_view_helper;
3448   WebViewImpl* web_view_impl =
3449       web_view_helper.InitializeWithSettings(&ConfigueCompositingWebView);
3450 
3451   int page_width = 640;
3452   int page_height = 480;
3453   web_view_impl->MainFrameWidget()->Resize(WebSize(page_width, page_height));
3454 
3455   WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
3456   frame_test_helpers::LoadHTMLString(
3457       web_view_impl->MainFrameImpl(),
3458       "<a href='http://www.test.com' style='position: absolute; left: 20px; "
3459       "top: 20px; width: 200px; transform:translateZ(0);'>A link to "
3460       "highlight</a>",
3461       base_url);
3462 
3463   WebGestureEvent event(WebInputEvent::kGestureShowPress,
3464                         WebInputEvent::kNoModifiers,
3465                         WebInputEvent::GetStaticTimeStampForTests(),
3466                         WebGestureDevice::kTouchscreen);
3467   event.SetPositionInWidget(gfx::PointF(20, 20));
3468 
3469   // Just make sure we don't hit any asserts.
3470   web_view_impl->MainFrameWidget()->HandleInputEvent(
3471       WebCoalescedInputEvent(event));
3472 }
3473 
3474 class MockAutofillClient : public WebAutofillClient {
3475  public:
3476   MockAutofillClient() = default;
3477 
3478   ~MockAutofillClient() override = default;
3479 
TextFieldDidChange(const WebFormControlElement &)3480   void TextFieldDidChange(const WebFormControlElement&) override {
3481     ++text_changes_;
3482   }
UserGestureObserved()3483   void UserGestureObserved() override { ++user_gesture_notifications_count_; }
3484 
ShouldSuppressKeyboard(const WebFormControlElement &)3485   bool ShouldSuppressKeyboard(const WebFormControlElement&) override {
3486     return should_suppress_keyboard_;
3487   }
3488 
SetShouldSuppressKeyboard(bool should_suppress_keyboard)3489   void SetShouldSuppressKeyboard(bool should_suppress_keyboard) {
3490     should_suppress_keyboard_ = should_suppress_keyboard;
3491   }
3492 
ClearChangeCounts()3493   void ClearChangeCounts() { text_changes_ = 0; }
3494 
TextChanges()3495   int TextChanges() { return text_changes_; }
GetUserGestureNotificationsCount()3496   int GetUserGestureNotificationsCount() {
3497     return user_gesture_notifications_count_;
3498   }
3499 
3500  private:
3501   int text_changes_ = 0;
3502   int user_gesture_notifications_count_ = 0;
3503   bool should_suppress_keyboard_ = false;
3504 };
3505 
TEST_F(WebViewTest,LosingFocusDoesNotTriggerAutofillTextChange)3506 TEST_F(WebViewTest, LosingFocusDoesNotTriggerAutofillTextChange) {
3507   RegisterMockedHttpURLLoad("input_field_populated.html");
3508   MockAutofillClient client;
3509   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
3510       base_url_ + "input_field_populated.html");
3511   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
3512   frame->SetAutofillClient(&client);
3513   web_view->SetInitialFocus(false);
3514 
3515   // Set up a composition that needs to be committed.
3516   WebVector<WebImeTextSpan> empty_ime_text_spans;
3517   frame->SetEditableSelectionOffsets(4, 10);
3518   frame->SetCompositionFromExistingText(8, 12, empty_ime_text_spans);
3519   WebTextInputInfo info = frame->GetInputMethodController()->TextInputInfo();
3520   EXPECT_EQ(4, info.selection_start);
3521   EXPECT_EQ(10, info.selection_end);
3522   EXPECT_EQ(8, info.composition_start);
3523   EXPECT_EQ(12, info.composition_end);
3524 
3525   // Clear the focus and track that the subsequent composition commit does not
3526   // trigger a text changed notification for autofill.
3527   client.ClearChangeCounts();
3528   web_view->MainFrameWidget()->SetFocus(false);
3529   EXPECT_EQ(0, client.TextChanges());
3530 
3531   frame->SetAutofillClient(nullptr);
3532 }
3533 
VerifySelectionAndComposition(WebViewImpl * web_view,int selection_start,int selection_end,int composition_start,int composition_end,const char * fail_message)3534 static void VerifySelectionAndComposition(WebViewImpl* web_view,
3535                                           int selection_start,
3536                                           int selection_end,
3537                                           int composition_start,
3538                                           int composition_end,
3539                                           const char* fail_message) {
3540   WebTextInputInfo info =
3541       web_view->MainFrameImpl()->GetInputMethodController()->TextInputInfo();
3542   EXPECT_EQ(selection_start, info.selection_start) << fail_message;
3543   EXPECT_EQ(selection_end, info.selection_end) << fail_message;
3544   EXPECT_EQ(composition_start, info.composition_start) << fail_message;
3545   EXPECT_EQ(composition_end, info.composition_end) << fail_message;
3546 }
3547 
TEST_F(WebViewTest,CompositionNotCancelledByBackspace)3548 TEST_F(WebViewTest, CompositionNotCancelledByBackspace) {
3549   RegisterMockedHttpURLLoad("composition_not_cancelled_by_backspace.html");
3550   MockAutofillClient client;
3551   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
3552       base_url_ + "composition_not_cancelled_by_backspace.html");
3553   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
3554   frame->SetAutofillClient(&client);
3555   web_view->SetInitialFocus(false);
3556 
3557   // Test both input elements.
3558   for (int i = 0; i < 2; ++i) {
3559     // Select composition and do sanity check.
3560     WebVector<WebImeTextSpan> empty_ime_text_spans;
3561     frame->SetEditableSelectionOffsets(6, 6);
3562     WebInputMethodController* active_input_method_controller =
3563         frame->FrameWidget()->GetActiveWebInputMethodController();
3564     EXPECT_TRUE(active_input_method_controller->SetComposition(
3565         "fghij", empty_ime_text_spans, WebRange(), 0, 5));
3566     frame->SetEditableSelectionOffsets(11, 11);
3567     VerifySelectionAndComposition(web_view, 11, 11, 6, 11, "initial case");
3568 
3569     // Press Backspace and verify composition didn't get cancelled. This is to
3570     // verify the fix for crbug.com/429916.
3571     WebKeyboardEvent key_event(WebInputEvent::kRawKeyDown,
3572                                WebInputEvent::kNoModifiers,
3573                                WebInputEvent::GetStaticTimeStampForTests());
3574     key_event.dom_key = ui::DomKey::BACKSPACE;
3575     key_event.windows_key_code = VKEY_BACK;
3576     web_view->MainFrameWidget()->HandleInputEvent(
3577         WebCoalescedInputEvent(key_event));
3578 
3579     frame->SetEditableSelectionOffsets(6, 6);
3580     EXPECT_TRUE(active_input_method_controller->SetComposition(
3581         "fghi", empty_ime_text_spans, WebRange(), 0, 4));
3582     frame->SetEditableSelectionOffsets(10, 10);
3583     VerifySelectionAndComposition(web_view, 10, 10, 6, 10,
3584                                   "after pressing Backspace");
3585 
3586     key_event.SetType(WebInputEvent::kKeyUp);
3587     web_view->MainFrameWidget()->HandleInputEvent(
3588         WebCoalescedInputEvent(key_event));
3589 
3590     web_view->AdvanceFocus(false);
3591   }
3592 
3593   frame->SetAutofillClient(nullptr);
3594 }
3595 
TEST_F(WebViewTest,FinishComposingTextDoesntTriggerAutofillTextChange)3596 TEST_F(WebViewTest, FinishComposingTextDoesntTriggerAutofillTextChange) {
3597   RegisterMockedHttpURLLoad("input_field_populated.html");
3598   MockAutofillClient client;
3599   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
3600       base_url_ + "input_field_populated.html");
3601   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
3602   frame->SetAutofillClient(&client);
3603   web_view->SetInitialFocus(false);
3604 
3605   WebDocument document = web_view->MainFrameImpl()->GetDocument();
3606   auto* form = To<HTMLFormControlElement>(
3607       static_cast<Element*>(document.GetElementById("sample")));
3608 
3609   WebInputMethodController* active_input_method_controller =
3610       frame->FrameWidget()->GetActiveWebInputMethodController();
3611   // Set up a composition that needs to be committed.
3612   std::string composition_text("testingtext");
3613 
3614   WebVector<WebImeTextSpan> empty_ime_text_spans;
3615   active_input_method_controller->SetComposition(
3616       WebString::FromUTF8(composition_text.c_str()), empty_ime_text_spans,
3617       WebRange(), 0, composition_text.length());
3618 
3619   WebTextInputInfo info = active_input_method_controller->TextInputInfo();
3620   EXPECT_EQ(0, info.selection_start);
3621   EXPECT_EQ((int)composition_text.length(), info.selection_end);
3622   EXPECT_EQ(0, info.composition_start);
3623   EXPECT_EQ((int)composition_text.length(), info.composition_end);
3624 
3625   form->SetAutofillState(blink::WebAutofillState::kAutofilled);
3626   client.ClearChangeCounts();
3627 
3628   active_input_method_controller->FinishComposingText(
3629       WebInputMethodController::kKeepSelection);
3630   EXPECT_EQ(0, client.TextChanges());
3631 
3632   EXPECT_TRUE(form->IsAutofilled());
3633 
3634   frame->SetAutofillClient(nullptr);
3635 }
3636 
TEST_F(WebViewTest,SetCompositionFromExistingTextDoesntTriggerAutofillTextChange)3637 TEST_F(WebViewTest,
3638        SetCompositionFromExistingTextDoesntTriggerAutofillTextChange) {
3639   RegisterMockedHttpURLLoad("input_field_populated.html");
3640   MockAutofillClient client;
3641   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
3642       base_url_ + "input_field_populated.html");
3643   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
3644   frame->SetAutofillClient(&client);
3645   web_view->SetInitialFocus(false);
3646 
3647   WebVector<WebImeTextSpan> empty_ime_text_spans;
3648 
3649   client.ClearChangeCounts();
3650   frame->SetCompositionFromExistingText(8, 12, empty_ime_text_spans);
3651 
3652   WebTextInputInfo info = frame->GetInputMethodController()->TextInputInfo();
3653   EXPECT_EQ("0123456789abcdefghijklmnopqrstuvwxyz", info.value.Utf8());
3654   EXPECT_EQ(8, info.composition_start);
3655   EXPECT_EQ(12, info.composition_end);
3656 
3657   EXPECT_EQ(0, client.TextChanges());
3658 
3659   WebDocument document = web_view->MainFrameImpl()->GetDocument();
3660   EXPECT_EQ(WebString::FromUTF8("none"),
3661             document.GetElementById("inputEvent").FirstChild().NodeValue());
3662 
3663   frame->SetAutofillClient(nullptr);
3664 }
3665 
3666 class ViewCreatingWebViewClient : public frame_test_helpers::TestWebViewClient {
3667  public:
ViewCreatingWebViewClient()3668   ViewCreatingWebViewClient() : did_focus_called_(false) {}
3669 
3670   // WebViewClient methods
CreateView(WebLocalFrame * opener,const WebURLRequest &,const WebWindowFeatures &,const WebString & name,WebNavigationPolicy,mojom::blink::WebSandboxFlags,const FeaturePolicy::FeatureState &,const SessionStorageNamespaceId &)3671   WebView* CreateView(WebLocalFrame* opener,
3672                       const WebURLRequest&,
3673                       const WebWindowFeatures&,
3674                       const WebString& name,
3675                       WebNavigationPolicy,
3676                       mojom::blink::WebSandboxFlags,
3677                       const FeaturePolicy::FeatureState&,
3678                       const SessionStorageNamespaceId&) override {
3679     return web_view_helper_.InitializeWithOpener(opener);
3680   }
3681 
3682   // WebWidgetClient methods
DidFocus(WebLocalFrame *)3683   void DidFocus(WebLocalFrame*) override { did_focus_called_ = true; }
3684 
DidFocusCalled() const3685   bool DidFocusCalled() const { return did_focus_called_; }
CreatedWebView() const3686   WebView* CreatedWebView() const { return web_view_helper_.GetWebView(); }
3687 
3688  private:
3689   frame_test_helpers::WebViewHelper web_view_helper_;
3690   bool did_focus_called_;
3691 };
3692 
TEST_F(WebViewTest,DoNotFocusCurrentFrameOnNavigateFromLocalFrame)3693 TEST_F(WebViewTest, DoNotFocusCurrentFrameOnNavigateFromLocalFrame) {
3694   ViewCreatingWebViewClient client;
3695   frame_test_helpers::WebViewHelper web_view_helper;
3696   WebViewImpl* web_view_impl = web_view_helper.Initialize(nullptr, &client);
3697 
3698   WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
3699   frame_test_helpers::LoadHTMLString(
3700       web_view_impl->MainFrameImpl(),
3701       "<html><body><iframe src=\"about:blank\"></iframe></body></html>",
3702       base_url);
3703 
3704   // Make a request from a local frame.
3705   WebURLRequest web_url_request_with_target_start(KURL("about:blank"));
3706   LocalFrame* local_frame =
3707       To<WebLocalFrameImpl>(web_view_impl->MainFrame()->FirstChild())
3708           ->GetFrame();
3709   FrameLoadRequest request_with_target_start(
3710       local_frame->GetDocument(),
3711       web_url_request_with_target_start.ToResourceRequest());
3712   local_frame->Tree().FindOrCreateFrameForNavigation(request_with_target_start,
3713                                                      "_top");
3714   EXPECT_FALSE(client.DidFocusCalled());
3715 
3716   web_view_helper.Reset();  // Remove dependency on locally scoped client.
3717 }
3718 
TEST_F(WebViewTest,FocusExistingFrameOnNavigate)3719 TEST_F(WebViewTest, FocusExistingFrameOnNavigate) {
3720   ViewCreatingWebViewClient client;
3721   frame_test_helpers::WebViewHelper web_view_helper;
3722   WebViewImpl* web_view_impl = web_view_helper.Initialize(nullptr, &client);
3723   WebLocalFrameImpl* frame = web_view_impl->MainFrameImpl();
3724   frame->SetName("_start");
3725 
3726   // Make a request that will open a new window
3727   WebURLRequest web_url_request(KURL("about:blank"));
3728   FrameLoadRequest request(nullptr, web_url_request.ToResourceRequest());
3729   To<LocalFrame>(web_view_impl->GetPage()->MainFrame())
3730       ->Tree()
3731       .FindOrCreateFrameForNavigation(request, "_blank");
3732   ASSERT_TRUE(client.CreatedWebView());
3733   EXPECT_FALSE(client.DidFocusCalled());
3734 
3735   // Make a request from the new window that will navigate the original window.
3736   // The original window should be focused.
3737   WebURLRequest web_url_request_with_target_start(KURL("about:blank"));
3738   FrameLoadRequest request_with_target_start(
3739       nullptr, web_url_request_with_target_start.ToResourceRequest());
3740   To<LocalFrame>(static_cast<WebViewImpl*>(client.CreatedWebView())
3741                      ->GetPage()
3742                      ->MainFrame())
3743       ->Tree()
3744       .FindOrCreateFrameForNavigation(request_with_target_start, "_start");
3745   EXPECT_TRUE(client.DidFocusCalled());
3746 
3747   web_view_helper.Reset();  // Remove dependency on locally scoped client.
3748 }
3749 
3750 class ViewReusingWebViewClient : public frame_test_helpers::TestWebViewClient {
3751  public:
3752   ViewReusingWebViewClient() = default;
3753 
3754   // WebViewClient methods
CreateView(WebLocalFrame *,const WebURLRequest &,const WebWindowFeatures &,const WebString & name,WebNavigationPolicy,mojom::blink::WebSandboxFlags,const FeaturePolicy::FeatureState &,const SessionStorageNamespaceId &)3755   WebView* CreateView(WebLocalFrame*,
3756                       const WebURLRequest&,
3757                       const WebWindowFeatures&,
3758                       const WebString& name,
3759                       WebNavigationPolicy,
3760                       mojom::blink::WebSandboxFlags,
3761                       const FeaturePolicy::FeatureState&,
3762                       const SessionStorageNamespaceId&) override {
3763     return web_view_;
3764   }
3765 
SetWebView(WebView * view)3766   void SetWebView(WebView* view) { web_view_ = view; }
3767 
3768  private:
3769   WebView* web_view_ = nullptr;
3770 };
3771 
TEST_F(WebViewTest,ReuseExistingWindowOnCreateViewUsesCorrectNavigationPolicy)3772 TEST_F(WebViewTest,
3773        ReuseExistingWindowOnCreateViewUsesCorrectNavigationPolicy) {
3774   ViewReusingWebViewClient view_client;
3775   frame_test_helpers::WebViewHelper web_view_helper;
3776   WebViewImpl* web_view_impl =
3777       web_view_helper.Initialize(nullptr, &view_client);
3778   view_client.SetWebView(web_view_impl);
3779   LocalFrame* frame = To<LocalFrame>(web_view_impl->GetPage()->MainFrame());
3780 
3781   // Request a new window, but the WebViewClient will decline to and instead
3782   // return the current window.
3783   WebURLRequest web_url_request(KURL("about:blank"));
3784   FrameLoadRequest request(frame->GetDocument(),
3785                            web_url_request.ToResourceRequest());
3786   FrameTree::FindResult result =
3787       frame->Tree().FindOrCreateFrameForNavigation(request, "_blank");
3788   EXPECT_EQ(frame, result.frame);
3789   EXPECT_EQ(kNavigationPolicyCurrentTab, request.GetNavigationPolicy());
3790 }
3791 
TEST_F(WebViewTest,DispatchesFocusOutFocusInOnViewToggleFocus)3792 TEST_F(WebViewTest, DispatchesFocusOutFocusInOnViewToggleFocus) {
3793   RegisterMockedHttpURLLoad("focusout_focusin_events.html");
3794   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
3795       base_url_ + "focusout_focusin_events.html");
3796 
3797   web_view->MainFrameWidget()->SetFocus(true);
3798   web_view->MainFrameWidget()->SetFocus(false);
3799   web_view->MainFrameWidget()->SetFocus(true);
3800 
3801   WebElement element =
3802       web_view->MainFrameImpl()->GetDocument().GetElementById("message");
3803   EXPECT_EQ("focusoutfocusin", element.TextContent());
3804 }
3805 
TEST_F(WebViewTest,DispatchesDomFocusOutDomFocusInOnViewToggleFocus)3806 TEST_F(WebViewTest, DispatchesDomFocusOutDomFocusInOnViewToggleFocus) {
3807   RegisterMockedHttpURLLoad("domfocusout_domfocusin_events.html");
3808   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
3809       base_url_ + "domfocusout_domfocusin_events.html");
3810 
3811   web_view->MainFrameWidget()->SetFocus(true);
3812   web_view->MainFrameWidget()->SetFocus(false);
3813   web_view->MainFrameWidget()->SetFocus(true);
3814 
3815   WebElement element =
3816       web_view->MainFrameImpl()->GetDocument().GetElementById("message");
3817   EXPECT_EQ("DOMFocusOutDOMFocusIn", element.TextContent());
3818 }
3819 
OpenDateTimeChooser(WebView * web_view,HTMLInputElement * input_element)3820 static void OpenDateTimeChooser(WebView* web_view,
3821                                 HTMLInputElement* input_element) {
3822   input_element->focus();
3823 
3824   WebKeyboardEvent key_event(WebInputEvent::kRawKeyDown,
3825                              WebInputEvent::kNoModifiers,
3826                              WebInputEvent::GetStaticTimeStampForTests());
3827   key_event.dom_key = ui::DomKey::FromCharacter(' ');
3828   key_event.windows_key_code = VKEY_SPACE;
3829   web_view->MainFrameWidget()->HandleInputEvent(
3830       WebCoalescedInputEvent(key_event));
3831 
3832   key_event.SetType(WebInputEvent::kKeyUp);
3833   web_view->MainFrameWidget()->HandleInputEvent(
3834       WebCoalescedInputEvent(key_event));
3835 }
3836 
TEST_F(WebViewTest,ChooseValueFromDateTimeChooser)3837 TEST_F(WebViewTest, ChooseValueFromDateTimeChooser) {
3838   ScopedInputMultipleFieldsUIForTest input_multiple_fields_ui(false);
3839   std::string url = RegisterMockedHttpURLLoad("date_time_chooser.html");
3840   WebViewImpl* web_view_impl =
3841       web_view_helper_.InitializeAndLoad(url, nullptr, nullptr);
3842 
3843   Document* document =
3844       web_view_impl->MainFrameImpl()->GetFrame()->GetDocument();
3845 
3846   auto* input_element = To<HTMLInputElement>(document->getElementById("date"));
3847   OpenDateTimeChooser(web_view_impl, input_element);
3848   GetExternalDateTimeChooser(web_view_impl)->ResponseHandler(true, 0);
3849   EXPECT_EQ("1970-01-01", input_element->value());
3850 
3851   OpenDateTimeChooser(web_view_impl, input_element);
3852   GetExternalDateTimeChooser(web_view_impl)
3853       ->ResponseHandler(true, std::numeric_limits<double>::quiet_NaN());
3854   EXPECT_EQ("", input_element->value());
3855 
3856   input_element =
3857       To<HTMLInputElement>(document->getElementById("datetimelocal"));
3858   OpenDateTimeChooser(web_view_impl, input_element);
3859   GetExternalDateTimeChooser(web_view_impl)->ResponseHandler(true, 0);
3860   EXPECT_EQ("1970-01-01T00:00", input_element->value());
3861 
3862   OpenDateTimeChooser(web_view_impl, input_element);
3863   GetExternalDateTimeChooser(web_view_impl)
3864       ->ResponseHandler(true, std::numeric_limits<double>::quiet_NaN());
3865   EXPECT_EQ("", input_element->value());
3866 
3867   input_element = To<HTMLInputElement>(document->getElementById("month"));
3868   OpenDateTimeChooser(web_view_impl, input_element);
3869   GetExternalDateTimeChooser(web_view_impl)->ResponseHandler(true, 0);
3870   EXPECT_EQ("1970-01", input_element->value());
3871 
3872   OpenDateTimeChooser(web_view_impl, input_element);
3873   GetExternalDateTimeChooser(web_view_impl)
3874       ->ResponseHandler(true, std::numeric_limits<double>::quiet_NaN());
3875   EXPECT_EQ("", input_element->value());
3876 
3877   input_element = To<HTMLInputElement>(document->getElementById("time"));
3878   OpenDateTimeChooser(web_view_impl, input_element);
3879   GetExternalDateTimeChooser(web_view_impl)->ResponseHandler(true, 0);
3880   EXPECT_EQ("00:00", input_element->value());
3881 
3882   OpenDateTimeChooser(web_view_impl, input_element);
3883   GetExternalDateTimeChooser(web_view_impl)
3884       ->ResponseHandler(true, std::numeric_limits<double>::quiet_NaN());
3885   EXPECT_EQ("", input_element->value());
3886 
3887   input_element = To<HTMLInputElement>(document->getElementById("week"));
3888   OpenDateTimeChooser(web_view_impl, input_element);
3889   GetExternalDateTimeChooser(web_view_impl)->ResponseHandler(true, 0);
3890   EXPECT_EQ("1970-W01", input_element->value());
3891 
3892   OpenDateTimeChooser(web_view_impl, input_element);
3893   GetExternalDateTimeChooser(web_view_impl)
3894       ->ResponseHandler(true, std::numeric_limits<double>::quiet_NaN());
3895   EXPECT_EQ("", input_element->value());
3896 
3897   // Clear the WebViewClient from the webViewHelper to avoid use-after-free in
3898   // the WebViewHelper destructor.
3899   web_view_helper_.Reset();
3900 }
3901 
TEST_F(WebViewTest,DispatchesFocusBlurOnViewToggle)3902 TEST_F(WebViewTest, DispatchesFocusBlurOnViewToggle) {
3903   RegisterMockedHttpURLLoad("focus_blur_events.html");
3904   WebViewImpl* web_view =
3905       web_view_helper_.InitializeAndLoad(base_url_ + "focus_blur_events.html");
3906 
3907   web_view->MainFrameWidget()->SetFocus(true);
3908   web_view->MainFrameWidget()->SetFocus(false);
3909   web_view->MainFrameWidget()->SetFocus(true);
3910 
3911   WebElement element =
3912       web_view->MainFrameImpl()->GetDocument().GetElementById("message");
3913   // Expect not to see duplication of events.
3914   EXPECT_EQ("blurfocus", element.TextContent());
3915 }
3916 
3917 class CreateChildCounterFrameClient
3918     : public frame_test_helpers::TestWebFrameClient {
3919  public:
CreateChildCounterFrameClient()3920   CreateChildCounterFrameClient() : count_(0) {}
3921   WebLocalFrame* CreateChildFrame(WebLocalFrame* parent,
3922                                   WebTreeScopeType,
3923                                   const WebString& name,
3924                                   const WebString& fallback_name,
3925                                   const FramePolicy&,
3926                                   const WebFrameOwnerProperties&,
3927                                   FrameOwnerElementType) override;
3928 
Count() const3929   int Count() const { return count_; }
3930 
3931  private:
3932   int count_;
3933 };
3934 
CreateChildFrame(WebLocalFrame * parent,WebTreeScopeType scope,const WebString & name,const WebString & fallback_name,const FramePolicy & frame_policy,const WebFrameOwnerProperties & frame_owner_properties,FrameOwnerElementType frame_owner_element_type)3935 WebLocalFrame* CreateChildCounterFrameClient::CreateChildFrame(
3936     WebLocalFrame* parent,
3937     WebTreeScopeType scope,
3938     const WebString& name,
3939     const WebString& fallback_name,
3940     const FramePolicy& frame_policy,
3941     const WebFrameOwnerProperties& frame_owner_properties,
3942     FrameOwnerElementType frame_owner_element_type) {
3943   ++count_;
3944   return TestWebFrameClient::CreateChildFrame(
3945       parent, scope, name, fallback_name, frame_policy, frame_owner_properties,
3946       frame_owner_element_type);
3947 }
3948 
TEST_F(WebViewTest,ChangeDisplayMode)3949 TEST_F(WebViewTest, ChangeDisplayMode) {
3950   RegisterMockedHttpURLLoad("display_mode.html");
3951   WebView* web_view =
3952       web_view_helper_.InitializeAndLoad(base_url_ + "display_mode.html");
3953 
3954   std::string content =
3955       WebFrameContentDumper::DumpWebViewAsText(web_view, 21).Utf8();
3956   EXPECT_EQ("regular-ui", content);
3957 
3958   web_view->SetDisplayMode(blink::mojom::DisplayMode::kMinimalUi);
3959   content = WebFrameContentDumper::DumpWebViewAsText(web_view, 21).Utf8();
3960   EXPECT_EQ("minimal-ui", content);
3961   web_view_helper_.Reset();
3962 }
3963 
TEST_F(WebViewTest,AddFrameInCloseUnload)3964 TEST_F(WebViewTest, AddFrameInCloseUnload) {
3965   CreateChildCounterFrameClient frame_client;
3966   RegisterMockedHttpURLLoad("add_frame_in_unload.html");
3967   web_view_helper_.InitializeAndLoad(base_url_ + "add_frame_in_unload.html",
3968                                      &frame_client);
3969   web_view_helper_.Reset();
3970   EXPECT_EQ(0, frame_client.Count());
3971 }
3972 
TEST_F(WebViewTest,AddFrameInCloseURLUnload)3973 TEST_F(WebViewTest, AddFrameInCloseURLUnload) {
3974   CreateChildCounterFrameClient frame_client;
3975   RegisterMockedHttpURLLoad("add_frame_in_unload.html");
3976   web_view_helper_.InitializeAndLoad(base_url_ + "add_frame_in_unload.html",
3977                                      &frame_client);
3978   // Dispatch unload event.
3979   web_view_helper_.LocalMainFrame()->GetFrame()->ClosePage(base::DoNothing());
3980   EXPECT_EQ(0, frame_client.Count());
3981   web_view_helper_.Reset();
3982 }
3983 
TEST_F(WebViewTest,AddFrameInNavigateUnload)3984 TEST_F(WebViewTest, AddFrameInNavigateUnload) {
3985   CreateChildCounterFrameClient frame_client;
3986   RegisterMockedHttpURLLoad("add_frame_in_unload.html");
3987   web_view_helper_.InitializeAndLoad(base_url_ + "add_frame_in_unload.html",
3988                                      &frame_client);
3989   frame_test_helpers::LoadFrame(web_view_helper_.GetWebView()->MainFrameImpl(),
3990                                 "about:blank");
3991   EXPECT_EQ(0, frame_client.Count());
3992   web_view_helper_.Reset();
3993 }
3994 
TEST_F(WebViewTest,AddFrameInChildInNavigateUnload)3995 TEST_F(WebViewTest, AddFrameInChildInNavigateUnload) {
3996   CreateChildCounterFrameClient frame_client;
3997   RegisterMockedHttpURLLoad("add_frame_in_unload_wrapper.html");
3998   RegisterMockedHttpURLLoad("add_frame_in_unload.html");
3999   web_view_helper_.InitializeAndLoad(
4000       base_url_ + "add_frame_in_unload_wrapper.html", &frame_client);
4001   frame_test_helpers::LoadFrame(web_view_helper_.GetWebView()->MainFrameImpl(),
4002                                 "about:blank");
4003   EXPECT_EQ(1, frame_client.Count());
4004   web_view_helper_.Reset();
4005 }
4006 
4007 class TouchEventHandlerWebWidgetClient
4008     : public frame_test_helpers::TestWebWidgetClient {
4009  public:
4010   // WebWidgetClient methods
SetHasTouchEventHandlers(bool state)4011   void SetHasTouchEventHandlers(bool state) override {
4012     // Only count the times the state changes.
4013     if (state != has_touch_event_handler_)
4014       has_touch_event_handler_count_[state]++;
4015     has_touch_event_handler_ = state;
4016   }
4017 
4018   // Local methods
TouchEventHandlerWebWidgetClient()4019   TouchEventHandlerWebWidgetClient()
4020       : has_touch_event_handler_count_(), has_touch_event_handler_(false) {}
4021 
GetAndResetHasTouchEventHandlerCallCount(bool state)4022   int GetAndResetHasTouchEventHandlerCallCount(bool state) {
4023     int value = has_touch_event_handler_count_[state];
4024     has_touch_event_handler_count_[state] = 0;
4025     return value;
4026   }
4027 
4028  private:
4029   int has_touch_event_handler_count_[2];
4030   bool has_touch_event_handler_;
4031 };
4032 
4033 // This test verifies that WebWidgetClient::SetHasTouchEventHandlers is called
4034 // accordingly for various calls to EventHandlerRegistry::did{Add|Remove|
4035 // RemoveAll}EventHandler(..., TouchEvent). Verifying that those calls are made
4036 // correctly is the job of web_tests/fast/events/event-handler-count.html.
TEST_F(WebViewTest,SetHasTouchEventHandlers)4037 TEST_F(WebViewTest, SetHasTouchEventHandlers) {
4038   TouchEventHandlerWebWidgetClient client;
4039   std::string url = RegisterMockedHttpURLLoad("has_touch_event_handlers.html");
4040   WebViewImpl* web_view_impl =
4041       web_view_helper_.InitializeAndLoad(url, nullptr, nullptr, &client);
4042   const EventHandlerRegistry::EventHandlerClass kTouchEvent =
4043       EventHandlerRegistry::kTouchStartOrMoveEventBlocking;
4044 
4045   // The page is initialized with at least one no-handlers call.
4046   // In practice we get two such calls because WebViewHelper::initializeAndLoad
4047   // first initializes an empty frame, and then loads a document into it, so
4048   // there are two FrameLoader::commitProvisionalLoad calls.
4049   EXPECT_EQ(0, client.GetAndResetHasTouchEventHandlerCallCount(false));
4050   EXPECT_EQ(0, client.GetAndResetHasTouchEventHandlerCallCount(true));
4051 
4052   // Adding the first document handler results in a has-handlers call.
4053   Document* document =
4054       web_view_impl->MainFrameImpl()->GetFrame()->GetDocument();
4055   EventHandlerRegistry* registry =
4056       &document->GetFrame()->GetEventHandlerRegistry();
4057   registry->DidAddEventHandler(*document, kTouchEvent);
4058   EXPECT_EQ(0, client.GetAndResetHasTouchEventHandlerCallCount(false));
4059   EXPECT_EQ(1, client.GetAndResetHasTouchEventHandlerCallCount(true));
4060 
4061   // Adding another handler has no effect.
4062   registry->DidAddEventHandler(*document, kTouchEvent);
4063   EXPECT_EQ(0, client.GetAndResetHasTouchEventHandlerCallCount(false));
4064   EXPECT_EQ(0, client.GetAndResetHasTouchEventHandlerCallCount(true));
4065 
4066   // Removing the duplicate handler has no effect.
4067   registry->DidRemoveEventHandler(*document, kTouchEvent);
4068   EXPECT_EQ(0, client.GetAndResetHasTouchEventHandlerCallCount(false));
4069   EXPECT_EQ(0, client.GetAndResetHasTouchEventHandlerCallCount(true));
4070 
4071   // Removing the final handler results in a no-handlers call.
4072   registry->DidRemoveEventHandler(*document, kTouchEvent);
4073   EXPECT_EQ(1, client.GetAndResetHasTouchEventHandlerCallCount(false));
4074   EXPECT_EQ(0, client.GetAndResetHasTouchEventHandlerCallCount(true));
4075 
4076   // Adding a handler on a div results in a has-handlers call.
4077   Element* parent_div = document->getElementById("parentdiv");
4078   DCHECK(parent_div);
4079   registry->DidAddEventHandler(*parent_div, kTouchEvent);
4080   EXPECT_EQ(0, client.GetAndResetHasTouchEventHandlerCallCount(false));
4081   EXPECT_EQ(1, client.GetAndResetHasTouchEventHandlerCallCount(true));
4082 
4083   // Adding a duplicate handler on the div, clearing all document handlers
4084   // (of which there are none) and removing the extra handler on the div
4085   // all have no effect.
4086   registry->DidAddEventHandler(*parent_div, kTouchEvent);
4087   registry->DidRemoveAllEventHandlers(*document);
4088   registry->DidRemoveEventHandler(*parent_div, kTouchEvent);
4089   EXPECT_EQ(0, client.GetAndResetHasTouchEventHandlerCallCount(false));
4090   EXPECT_EQ(0, client.GetAndResetHasTouchEventHandlerCallCount(true));
4091 
4092   // Removing the final handler on the div results in a no-handlers call.
4093   registry->DidRemoveEventHandler(*parent_div, kTouchEvent);
4094   EXPECT_EQ(1, client.GetAndResetHasTouchEventHandlerCallCount(false));
4095   EXPECT_EQ(0, client.GetAndResetHasTouchEventHandlerCallCount(true));
4096 
4097   // Adding two handlers then clearing them in a single call results in a
4098   // has-handlers then no-handlers call.
4099   registry->DidAddEventHandler(*parent_div, kTouchEvent);
4100   EXPECT_EQ(0, client.GetAndResetHasTouchEventHandlerCallCount(false));
4101   EXPECT_EQ(1, client.GetAndResetHasTouchEventHandlerCallCount(true));
4102   registry->DidAddEventHandler(*parent_div, kTouchEvent);
4103   EXPECT_EQ(0, client.GetAndResetHasTouchEventHandlerCallCount(false));
4104   EXPECT_EQ(0, client.GetAndResetHasTouchEventHandlerCallCount(true));
4105   registry->DidRemoveAllEventHandlers(*parent_div);
4106   EXPECT_EQ(1, client.GetAndResetHasTouchEventHandlerCallCount(false));
4107   EXPECT_EQ(0, client.GetAndResetHasTouchEventHandlerCallCount(true));
4108 
4109   // Adding a handler inside of a child iframe results in a has-handlers call.
4110   Element* child_frame = document->getElementById("childframe");
4111   DCHECK(child_frame);
4112   Document* child_document =
4113       To<HTMLIFrameElement>(child_frame)->contentDocument();
4114   Element* child_div = child_document->getElementById("childdiv");
4115   DCHECK(child_div);
4116   registry->DidAddEventHandler(*child_div, kTouchEvent);
4117   EXPECT_EQ(0, client.GetAndResetHasTouchEventHandlerCallCount(false));
4118   EXPECT_EQ(1, client.GetAndResetHasTouchEventHandlerCallCount(true));
4119 
4120   // Adding and clearing handlers in the parent doc or elsewhere in the child
4121   // doc has no impact.
4122   registry->DidAddEventHandler(*document, kTouchEvent);
4123   registry->DidAddEventHandler(*child_frame, kTouchEvent);
4124   registry->DidAddEventHandler(*child_document, kTouchEvent);
4125   registry->DidRemoveAllEventHandlers(*document);
4126   registry->DidRemoveAllEventHandlers(*child_frame);
4127   registry->DidRemoveAllEventHandlers(*child_document);
4128   EXPECT_EQ(0, client.GetAndResetHasTouchEventHandlerCallCount(false));
4129   EXPECT_EQ(0, client.GetAndResetHasTouchEventHandlerCallCount(true));
4130 
4131   // Removing the final handler inside the child frame results in a no-handlers
4132   // call.
4133   registry->DidRemoveAllEventHandlers(*child_div);
4134   EXPECT_EQ(1, client.GetAndResetHasTouchEventHandlerCallCount(false));
4135   EXPECT_EQ(0, client.GetAndResetHasTouchEventHandlerCallCount(true));
4136 
4137   // Adding a handler inside the child frame results in a has-handlers call.
4138   registry->DidAddEventHandler(*child_document, kTouchEvent);
4139   EXPECT_EQ(0, client.GetAndResetHasTouchEventHandlerCallCount(false));
4140   EXPECT_EQ(1, client.GetAndResetHasTouchEventHandlerCallCount(true));
4141 
4142   // Adding a handler in the parent document and removing the one in the frame
4143   // has no effect.
4144   registry->DidAddEventHandler(*child_frame, kTouchEvent);
4145   registry->DidRemoveEventHandler(*child_document, kTouchEvent);
4146   registry->DidRemoveAllEventHandlers(*child_document);
4147   registry->DidRemoveAllEventHandlers(*document);
4148   EXPECT_EQ(0, client.GetAndResetHasTouchEventHandlerCallCount(false));
4149   EXPECT_EQ(0, client.GetAndResetHasTouchEventHandlerCallCount(true));
4150 
4151   // Now removing the handler in the parent document results in a no-handlers
4152   // call.
4153   registry->DidRemoveEventHandler(*child_frame, kTouchEvent);
4154   EXPECT_EQ(1, client.GetAndResetHasTouchEventHandlerCallCount(false));
4155   EXPECT_EQ(0, client.GetAndResetHasTouchEventHandlerCallCount(true));
4156 
4157   // Free the webView before the TouchEventHandlerWebViewClient gets freed.
4158   web_view_helper_.Reset();
4159 }
4160 
4161 // This test checks that deleting nodes which have only non-JS-registered touch
4162 // handlers also removes them from the event handler registry. Note that this
4163 // is different from detaching and re-attaching the same node, which is covered
4164 // by web tests under fast/events/.
TEST_F(WebViewTest,DeleteElementWithRegisteredHandler)4165 TEST_F(WebViewTest, DeleteElementWithRegisteredHandler) {
4166   std::string url = RegisterMockedHttpURLLoad("simple_div.html");
4167   WebViewImpl* web_view_impl = web_view_helper_.InitializeAndLoad(url);
4168 
4169   Persistent<Document> document =
4170       web_view_impl->MainFrameImpl()->GetFrame()->GetDocument();
4171   Element* div = document->getElementById("div");
4172   EventHandlerRegistry& registry =
4173       document->GetFrame()->GetEventHandlerRegistry();
4174 
4175   registry.DidAddEventHandler(*div, EventHandlerRegistry::kScrollEvent);
4176   EXPECT_TRUE(registry.HasEventHandlers(EventHandlerRegistry::kScrollEvent));
4177 
4178   DummyExceptionStateForTesting exception_state;
4179   div->remove(exception_state);
4180 
4181   // For oilpan we have to force a GC to ensure the event handlers have been
4182   // removed when checking below. We do a precise GC (collectAllGarbage does not
4183   // scan the stack) to ensure the div element dies. This is also why the
4184   // Document is in a Persistent since we want that to stay around.
4185   ThreadState::Current()->CollectAllGarbageForTesting();
4186 
4187   EXPECT_FALSE(registry.HasEventHandlers(EventHandlerRegistry::kScrollEvent));
4188 }
4189 
4190 // This test verifies the text input flags are correctly exposed to script.
TEST_F(WebViewTest,TextInputFlags)4191 TEST_F(WebViewTest, TextInputFlags) {
4192   std::string url = RegisterMockedHttpURLLoad("text_input_flags.html");
4193   WebViewImpl* web_view_impl = web_view_helper_.InitializeAndLoad(url);
4194   web_view_impl->SetInitialFocus(false);
4195 
4196   WebLocalFrameImpl* frame = web_view_impl->MainFrameImpl();
4197   WebInputMethodController* active_input_method_controller =
4198       frame->GetInputMethodController();
4199   Document* document = frame->GetFrame()->GetDocument();
4200 
4201   // (A) <input>
4202   // (A.1) Verifies autocorrect/autocomplete/spellcheck flags are Off and
4203   // autocapitalize is set to none.
4204   auto* input_element = To<HTMLInputElement>(document->getElementById("input"));
4205   document->SetFocusedElement(
4206       input_element, FocusParams(SelectionBehaviorOnFocus::kNone,
4207                                  mojom::blink::FocusType::kNone, nullptr));
4208   web_view_impl->MainFrameWidget()->SetFocus(true);
4209   WebTextInputInfo info1 = active_input_method_controller->TextInputInfo();
4210   EXPECT_EQ(kWebTextInputFlagAutocompleteOff | kWebTextInputFlagAutocorrectOff |
4211                 kWebTextInputFlagSpellcheckOff |
4212                 kWebTextInputFlagAutocapitalizeNone,
4213             info1.flags);
4214 
4215   // (A.2) Verifies autocorrect/autocomplete/spellcheck flags are On and
4216   // autocapitalize is set to sentences.
4217   input_element = To<HTMLInputElement>(document->getElementById("input2"));
4218   document->SetFocusedElement(
4219       input_element, FocusParams(SelectionBehaviorOnFocus::kNone,
4220                                  mojom::blink::FocusType::kNone, nullptr));
4221   web_view_impl->MainFrameWidget()->SetFocus(true);
4222   WebTextInputInfo info2 = active_input_method_controller->TextInputInfo();
4223   EXPECT_EQ(kWebTextInputFlagAutocompleteOn | kWebTextInputFlagAutocorrectOn |
4224                 kWebTextInputFlagSpellcheckOn |
4225                 kWebTextInputFlagAutocapitalizeSentences,
4226             info2.flags);
4227 
4228   // (B) <textarea> Verifies the default text input flags are
4229   // WebTextInputFlagAutocapitalizeSentences.
4230   auto* text_area_element =
4231       To<HTMLTextAreaElement>(document->getElementById("textarea"));
4232   document->SetFocusedElement(
4233       text_area_element, FocusParams(SelectionBehaviorOnFocus::kNone,
4234                                      mojom::blink::FocusType::kNone, nullptr));
4235   web_view_impl->MainFrameWidget()->SetFocus(true);
4236   WebTextInputInfo info3 = active_input_method_controller->TextInputInfo();
4237   EXPECT_EQ(kWebTextInputFlagAutocapitalizeSentences, info3.flags);
4238 
4239   // (C) Verifies the WebTextInputInfo's don't equal.
4240   EXPECT_FALSE(info1.Equals(info2));
4241   EXPECT_FALSE(info2.Equals(info3));
4242 
4243   // Free the webView before freeing the NonUserInputTextUpdateWebViewClient.
4244   web_view_helper_.Reset();
4245 }
4246 
4247 // Check that the WebAutofillClient is correctly notified about first user
4248 // gestures after load, following various input events.
TEST_F(WebViewTest,FirstUserGestureObservedKeyEvent)4249 TEST_F(WebViewTest, FirstUserGestureObservedKeyEvent) {
4250   RegisterMockedHttpURLLoad("form.html");
4251   MockAutofillClient client;
4252   WebViewImpl* web_view =
4253       web_view_helper_.InitializeAndLoad(base_url_ + "form.html");
4254   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
4255   frame->SetAutofillClient(&client);
4256   web_view->SetInitialFocus(false);
4257 
4258   EXPECT_EQ(0, client.GetUserGestureNotificationsCount());
4259 
4260   WebKeyboardEvent key_event(WebInputEvent::kRawKeyDown,
4261                              WebInputEvent::kNoModifiers,
4262                              WebInputEvent::GetStaticTimeStampForTests());
4263   key_event.dom_key = ui::DomKey::FromCharacter(' ');
4264   key_event.windows_key_code = VKEY_SPACE;
4265   web_view->MainFrameWidget()->HandleInputEvent(
4266       WebCoalescedInputEvent(key_event));
4267   key_event.SetType(WebInputEvent::kKeyUp);
4268   web_view->MainFrameWidget()->HandleInputEvent(
4269       WebCoalescedInputEvent(key_event));
4270 
4271   EXPECT_EQ(1, client.GetUserGestureNotificationsCount());
4272   frame->SetAutofillClient(nullptr);
4273 }
4274 
TEST_F(WebViewTest,FirstUserGestureObservedMouseEvent)4275 TEST_F(WebViewTest, FirstUserGestureObservedMouseEvent) {
4276   RegisterMockedHttpURLLoad("form.html");
4277   MockAutofillClient client;
4278   WebViewImpl* web_view =
4279       web_view_helper_.InitializeAndLoad(base_url_ + "form.html");
4280   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
4281   frame->SetAutofillClient(&client);
4282   web_view->SetInitialFocus(false);
4283 
4284   EXPECT_EQ(0, client.GetUserGestureNotificationsCount());
4285 
4286   WebMouseEvent mouse_event(WebInputEvent::kMouseDown,
4287                             WebInputEvent::kNoModifiers,
4288                             WebInputEvent::GetStaticTimeStampForTests());
4289   mouse_event.button = WebMouseEvent::Button::kLeft;
4290   mouse_event.SetPositionInWidget(1, 1);
4291   mouse_event.click_count = 1;
4292   web_view->MainFrameWidget()->HandleInputEvent(
4293       WebCoalescedInputEvent(mouse_event));
4294   mouse_event.SetType(WebInputEvent::kMouseUp);
4295   web_view->MainFrameWidget()->HandleInputEvent(
4296       WebCoalescedInputEvent(mouse_event));
4297 
4298   EXPECT_EQ(1, client.GetUserGestureNotificationsCount());
4299   frame->SetAutofillClient(nullptr);
4300 }
4301 
TEST_F(WebViewTest,CompositionIsUserGesture)4302 TEST_F(WebViewTest, CompositionIsUserGesture) {
4303   RegisterMockedHttpURLLoad("input_field_populated.html");
4304   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
4305       base_url_ + "input_field_populated.html");
4306   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
4307   MockAutofillClient client;
4308   frame->SetAutofillClient(&client);
4309   web_view->SetInitialFocus(false);
4310 
4311   EXPECT_EQ(0, client.TextChanges());
4312   EXPECT_TRUE(
4313       frame->FrameWidget()->GetActiveWebInputMethodController()->SetComposition(
4314           WebString::FromUTF8(std::string("hello").c_str()),
4315           WebVector<WebImeTextSpan>(), WebRange(), 3, 3));
4316   EXPECT_TRUE(frame->HasTransientUserActivation());
4317   EXPECT_EQ(1, client.TextChanges());
4318   EXPECT_TRUE(frame->HasMarkedText());
4319 
4320   frame->SetAutofillClient(nullptr);
4321 }
4322 
4323 // Currently, SelectionAsText() is built upon TextIterator, but
4324 // WebFrameContentDumper is built upon TextDumperForTests. Their results can
4325 // be different, making the test fail.
4326 // TODO(crbug.com/781434): Build a selection serializer upon TextDumperForTests.
TEST_F(WebViewTest,DISABLED_CompareSelectAllToContentAsText)4327 TEST_F(WebViewTest, DISABLED_CompareSelectAllToContentAsText) {
4328   RegisterMockedHttpURLLoad("longpress_selection.html");
4329   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
4330       base_url_ + "longpress_selection.html");
4331 
4332   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
4333   frame->ExecuteScript(WebScriptSource(
4334       WebString::FromUTF8("document.execCommand('SelectAll', false, null)")));
4335   std::string actual = frame->SelectionAsText().Utf8();
4336 
4337   const int kMaxOutputCharacters = 1024;
4338   std::string expected =
4339       WebFrameContentDumper::DumpWebViewAsText(web_view, kMaxOutputCharacters)
4340           .Utf8();
4341   EXPECT_EQ(expected, actual);
4342 }
4343 
TEST_F(WebViewTest,AutoResizeSubtreeLayout)4344 TEST_F(WebViewTest, AutoResizeSubtreeLayout) {
4345   std::string url = RegisterMockedHttpURLLoad("subtree-layout.html");
4346   WebViewImpl* web_view = web_view_helper_.Initialize();
4347 
4348   web_view->EnableAutoResizeMode(WebSize(200, 200), WebSize(200, 200));
4349   LoadFrame(web_view->MainFrameImpl(), url);
4350 
4351   LocalFrameView* frame_view =
4352       web_view_helper_.LocalMainFrame()->GetFrameView();
4353 
4354   // Auto-resizing used to DCHECK(needsLayout()) in LayoutBlockFlow::layout.
4355   // This EXPECT is merely a dummy. The real test is that we don't trigger
4356   // asserts in debug builds.
4357   EXPECT_FALSE(frame_view->NeedsLayout());
4358 }
4359 
TEST_F(WebViewTest,PreferredSize)4360 TEST_F(WebViewTest, PreferredSize) {
4361   std::string url = base_url_ + "specify_size.html?100px:100px";
4362   url_test_helpers::RegisterMockedURLLoad(
4363       ToKURL(url), test::CoreTestDataPath("specify_size.html"));
4364   WebView* web_view = web_view_helper_.InitializeAndLoad(url);
4365 
4366   WebSize size = web_view->ContentsPreferredMinimumSize();
4367   EXPECT_EQ(100, size.width);
4368   EXPECT_EQ(100, size.height);
4369 
4370   web_view->SetZoomLevel(PageZoomFactorToZoomLevel(2.0));
4371   size = web_view->ContentsPreferredMinimumSize();
4372   EXPECT_EQ(200, size.width);
4373   EXPECT_EQ(200, size.height);
4374 
4375   // Verify that both width and height are rounded (in this case up)
4376   web_view->SetZoomLevel(PageZoomFactorToZoomLevel(0.9995));
4377   size = web_view->ContentsPreferredMinimumSize();
4378   EXPECT_EQ(100, size.width);
4379   EXPECT_EQ(100, size.height);
4380 
4381   // Verify that both width and height are rounded (in this case down)
4382   web_view->SetZoomLevel(PageZoomFactorToZoomLevel(1.0005));
4383   size = web_view->ContentsPreferredMinimumSize();
4384   EXPECT_EQ(100, size.width);
4385   EXPECT_EQ(100, size.height);
4386 
4387   url = base_url_ + "specify_size.html?1.5px:1.5px";
4388   url_test_helpers::RegisterMockedURLLoad(
4389       ToKURL(url), test::CoreTestDataPath("specify_size.html"));
4390   web_view = web_view_helper_.InitializeAndLoad(url);
4391 
4392   web_view->SetZoomLevel(PageZoomFactorToZoomLevel(1));
4393   size = web_view->ContentsPreferredMinimumSize();
4394   EXPECT_EQ(2, size.width);
4395   EXPECT_EQ(2, size.height);
4396 }
4397 
TEST_F(WebViewTest,PreferredMinimumSizeQuirksMode)4398 TEST_F(WebViewTest, PreferredMinimumSizeQuirksMode) {
4399   WebViewImpl* web_view = web_view_helper_.Initialize();
4400   web_view->MainFrameWidget()->Resize(WebSize(800, 600));
4401   frame_test_helpers::LoadHTMLString(
4402       web_view->MainFrameImpl(),
4403       R"HTML(<html>
4404         <body style="margin: 0px;">
4405           <div style="width: 99px; height: 100px; display: inline-block;"></div>
4406         </body>
4407       </html>)HTML",
4408       url_test_helpers::ToKURL("http://example.com/"));
4409 
4410   WebSize size = web_view->ContentsPreferredMinimumSize();
4411   EXPECT_EQ(99, size.width);
4412   // When in quirks mode the preferred height stretches to fill the viewport.
4413   EXPECT_EQ(600, size.height);
4414 }
4415 
TEST_F(WebViewTest,PreferredSizeWithGrid)4416 TEST_F(WebViewTest, PreferredSizeWithGrid) {
4417   WebViewImpl* web_view = web_view_helper_.Initialize();
4418   WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
4419   frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(),
4420                                      R"HTML(<!DOCTYPE html>
4421     <style>
4422       html { writing-mode: vertical-rl; }
4423       body { margin: 0px; }
4424     </style>
4425     <div style="width: 100px;">
4426       <div style="display: grid; width: 100%;">
4427         <div style="writing-mode: horizontal-tb; height: 100px;"></div>
4428       </div>
4429     </div>
4430                                    )HTML",
4431                                      base_url);
4432 
4433   WebSize size = web_view->ContentsPreferredMinimumSize();
4434   EXPECT_EQ(100, size.width);
4435   EXPECT_EQ(100, size.height);
4436 }
4437 
TEST_F(WebViewTest,PreferredSizeWithGridMinWidth)4438 TEST_F(WebViewTest, PreferredSizeWithGridMinWidth) {
4439   WebViewImpl* web_view = web_view_helper_.Initialize();
4440   WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
4441   frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(),
4442                                      R"HTML(<!DOCTYPE html>
4443     <body style="margin: 0px;">
4444       <div style="display: inline-grid; min-width: 200px;">
4445         <div>item</div>
4446       </div>
4447     </body>
4448                                    )HTML",
4449                                      base_url);
4450 
4451   WebSize size = web_view->ContentsPreferredMinimumSize();
4452   EXPECT_EQ(200, size.width);
4453 }
4454 
TEST_F(WebViewTest,PreferredSizeWithGridMinWidthFlexibleTracks)4455 TEST_F(WebViewTest, PreferredSizeWithGridMinWidthFlexibleTracks) {
4456   WebViewImpl* web_view = web_view_helper_.Initialize();
4457   WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
4458   frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(),
4459                                      R"HTML(<!DOCTYPE html>
4460     <body style="margin: 0px;">
4461       <div style="display: inline-grid; min-width: 200px; grid-template-columns: 1fr;">
4462         <div>item</div>
4463       </div>
4464     </body>
4465                                    )HTML",
4466                                      base_url);
4467 
4468   WebSize size = web_view->ContentsPreferredMinimumSize();
4469   EXPECT_EQ(200, size.width);
4470 }
4471 
4472 #if BUILDFLAG(ENABLE_UNHANDLED_TAP)
4473 
4474 // Helps set up any test that uses a mock Mojo implementation.
4475 class MojoTestHelper {
4476  public:
MojoTestHelper(const String & test_file,frame_test_helpers::WebViewHelper & web_view_helper)4477   MojoTestHelper(const String& test_file,
4478                  frame_test_helpers::WebViewHelper& web_view_helper)
4479       : web_view_helper_(web_view_helper) {
4480     web_view_ =
4481         web_view_helper.InitializeAndLoad(test_file.Utf8(), &web_frame_client_);
4482   }
4483 
~MojoTestHelper()4484   ~MojoTestHelper() {
4485     web_view_helper_.Reset();  // Remove dependency on locally scoped client.
4486   }
4487 
WebView() const4488   WebViewImpl* WebView() const { return web_view_; }
4489 
4490  private:
4491   WebViewImpl* web_view_;
4492   frame_test_helpers::WebViewHelper& web_view_helper_;
4493   frame_test_helpers::TestWebFrameClient web_frame_client_;
4494 };
4495 
4496 // Mock implementation of the UnhandledTapNotifier Mojo receiver, for testing
4497 // the ShowUnhandledTapUIIfNeeded notification.
4498 class MockUnhandledTapNotifierImpl : public mojom::blink::UnhandledTapNotifier {
4499  public:
4500   MockUnhandledTapNotifierImpl() = default;
4501   ~MockUnhandledTapNotifierImpl() override = default;
4502 
Bind(mojo::ScopedMessagePipeHandle handle)4503   void Bind(mojo::ScopedMessagePipeHandle handle) {
4504     receiver_.Bind(mojo::PendingReceiver<mojom::blink::UnhandledTapNotifier>(
4505         std::move(handle)));
4506   }
4507 
ShowUnhandledTapUIIfNeeded(mojom::blink::UnhandledTapInfoPtr unhandled_tap_info)4508   void ShowUnhandledTapUIIfNeeded(
4509       mojom::blink::UnhandledTapInfoPtr unhandled_tap_info) override {
4510     was_unhandled_tap_ = true;
4511     tapped_position_ = unhandled_tap_info->tapped_position_in_viewport;
4512     element_text_run_length_ = unhandled_tap_info->element_text_run_length;
4513     font_size_ = unhandled_tap_info->font_size_in_pixels;
4514   }
WasUnhandledTap() const4515   bool WasUnhandledTap() const { return was_unhandled_tap_; }
GetTappedXPos() const4516   int GetTappedXPos() const { return tapped_position_.x(); }
GetTappedYPos() const4517   int GetTappedYPos() const { return tapped_position_.y(); }
GetFontSize() const4518   int GetFontSize() const { return font_size_; }
GetElementTextRunLength() const4519   int GetElementTextRunLength() const { return element_text_run_length_; }
Reset()4520   void Reset() {
4521     was_unhandled_tap_ = false;
4522     tapped_position_ = IntPoint();
4523     element_text_run_length_ = 0;
4524     font_size_ = 0;
4525     receiver_.reset();
4526   }
4527 
4528  private:
4529   bool was_unhandled_tap_ = false;
4530   gfx::Point tapped_position_;
4531   int element_text_run_length_ = 0;
4532   int font_size_ = 0;
4533 
4534   mojo::Receiver<mojom::blink::UnhandledTapNotifier> receiver_{this};
4535 };
4536 
4537 // A Test Fixture for testing ShowUnhandledTapUIIfNeeded usages.
4538 class ShowUnhandledTapTest : public WebViewTest {
4539  public:
SetUp()4540   void SetUp() override {
4541     WebViewTest::SetUp();
4542     std::string test_file = "show_unhandled_tap.html";
4543     RegisterMockedHttpURLLoad("Ahem.ttf");
4544     RegisterMockedHttpURLLoad(test_file);
4545 
4546     mojo_test_helper_.reset(new MojoTestHelper(
4547         WebString::FromUTF8(base_url_ + test_file), web_view_helper_));
4548 
4549     web_view_ = mojo_test_helper_->WebView();
4550     web_view_->MainFrameWidget()->Resize(WebSize(500, 300));
4551     web_view_->MainFrameWidget()->UpdateAllLifecyclePhases(
4552         DocumentUpdateReason::kTest);
4553     RunPendingTasks();
4554 
4555     WebLocalFrameImpl* web_local_frame = web_view_->MainFrameImpl();
4556     web_local_frame->GetFrame()
4557         ->GetBrowserInterfaceBroker()
4558         .SetBinderForTesting(
4559             mojom::blink::UnhandledTapNotifier::Name_,
4560             WTF::BindRepeating(&MockUnhandledTapNotifierImpl::Bind,
4561                                WTF::Unretained(&mock_notifier_)));
4562   }
4563 
TearDown()4564   void TearDown() override {
4565     WebLocalFrameImpl* web_local_frame = web_view_->MainFrameImpl();
4566     web_local_frame->GetFrame()
4567         ->GetBrowserInterfaceBroker()
4568         .SetBinderForTesting(mojom::blink::UnhandledTapNotifier::Name_, {});
4569 
4570     WebViewTest::TearDown();
4571   }
4572 
4573  protected:
4574   // Tap on the given element by ID.
Tap(const String & element_id)4575   void Tap(const String& element_id) {
4576     mock_notifier_.Reset();
4577     EXPECT_TRUE(TapElementById(WebInputEvent::kGestureTap, element_id));
4578   }
4579 
4580   // Set up a test script for the given |operation| with the given |handler|.
SetTestScript(const String & operation,const String & handler)4581   void SetTestScript(const String& operation, const String& handler) {
4582     String test_key = operation + "-" + handler;
4583     web_view_->MainFrameImpl()->ExecuteScript(
4584         WebScriptSource(String("setTest('" + test_key + "');")));
4585   }
4586 
4587   // Test each mouse event combination with the given |handler|, and verify the
4588   // |expected| outcome.
TestEachMouseEvent(const String & handler,bool expected)4589   void TestEachMouseEvent(const String& handler, bool expected) {
4590     SetTestScript("mousedown", handler);
4591     Tap("target");
4592     EXPECT_EQ(expected, mock_notifier_.WasUnhandledTap());
4593 
4594     SetTestScript("mouseup", handler);
4595     Tap("target");
4596     EXPECT_EQ(expected, mock_notifier_.WasUnhandledTap());
4597 
4598     SetTestScript("click", handler);
4599     Tap("target");
4600     EXPECT_EQ(expected, mock_notifier_.WasUnhandledTap());
4601   }
4602 
4603   WebViewImpl* web_view_;
4604   MockUnhandledTapNotifierImpl mock_notifier_;
4605 
4606  private:
4607   std::unique_ptr<MojoTestHelper> mojo_test_helper_;
4608 };
4609 
TEST_F(ShowUnhandledTapTest,ShowUnhandledTapUIIfNeeded)4610 TEST_F(ShowUnhandledTapTest, ShowUnhandledTapUIIfNeeded) {
4611   // Scroll the bottom into view so we can distinguish window coordinates from
4612   // document coordinates.
4613   Tap("bottom");
4614   EXPECT_TRUE(mock_notifier_.WasUnhandledTap());
4615   EXPECT_EQ(64, mock_notifier_.GetTappedXPos());
4616   EXPECT_EQ(278, mock_notifier_.GetTappedYPos());
4617   EXPECT_EQ(16, mock_notifier_.GetFontSize());
4618   EXPECT_EQ(7, mock_notifier_.GetElementTextRunLength());
4619 
4620   // Test basic tap handling and notification.
4621   Tap("target");
4622   EXPECT_TRUE(mock_notifier_.WasUnhandledTap());
4623   EXPECT_EQ(144, mock_notifier_.GetTappedXPos());
4624   EXPECT_EQ(82, mock_notifier_.GetTappedYPos());
4625 
4626   // Test correct conversion of coordinates to viewport space under pinch-zoom.
4627   constexpr float scale = 1.5f;
4628   constexpr float visual_x = 6.f;
4629   constexpr float visual_y = 10.f;
4630 
4631   web_view_->SetPageScaleFactor(scale);
4632   web_view_->SetVisualViewportOffset(gfx::PointF(visual_x, visual_y));
4633 
4634   Tap("target");
4635 
4636   // Ensure position didn't change as a result of scroll into view.
4637   ASSERT_EQ(visual_x, web_view_->VisualViewportOffset().x());
4638   ASSERT_EQ(visual_y, web_view_->VisualViewportOffset().y());
4639 
4640   EXPECT_TRUE(mock_notifier_.WasUnhandledTap());
4641 
4642   constexpr float expected_x = 144 * scale - (scale * visual_x);
4643   constexpr float expected_y = 82 * scale - (scale * visual_y);
4644   EXPECT_EQ(expected_x, mock_notifier_.GetTappedXPos());
4645   EXPECT_EQ(expected_y, mock_notifier_.GetTappedYPos());
4646   EXPECT_EQ(16, mock_notifier_.GetFontSize());
4647   EXPECT_EQ(28, mock_notifier_.GetElementTextRunLength());
4648 }
4649 
TEST_F(ShowUnhandledTapTest,ShowUnhandledTapUIIfNeededWithMutateDom)4650 TEST_F(ShowUnhandledTapTest, ShowUnhandledTapUIIfNeededWithMutateDom) {
4651   // Test dom mutation.
4652   TestEachMouseEvent("mutateDom", FALSE);
4653 
4654   // Test without any DOM mutation.
4655   TestEachMouseEvent("none", TRUE);
4656 }
4657 
TEST_F(ShowUnhandledTapTest,ShowUnhandledTapUIIfNeededWithMutateStyle)4658 TEST_F(ShowUnhandledTapTest, ShowUnhandledTapUIIfNeededWithMutateStyle) {
4659   // Test style mutation.
4660   TestEachMouseEvent("mutateStyle", FALSE);
4661 
4662   // Test checkbox:indeterminate style mutation.
4663   TestEachMouseEvent("mutateIndeterminate", FALSE);
4664 
4665   // Test click div with :active style.
4666   Tap("style_active");
4667   EXPECT_FALSE(mock_notifier_.WasUnhandledTap());
4668 }
4669 
TEST_F(ShowUnhandledTapTest,ShowUnhandledTapUIIfNeededWithPreventDefault)4670 TEST_F(ShowUnhandledTapTest, ShowUnhandledTapUIIfNeededWithPreventDefault) {
4671   // Test swallowing.
4672   TestEachMouseEvent("preventDefault", FALSE);
4673 
4674   // Test without any preventDefault.
4675   TestEachMouseEvent("none", TRUE);
4676 }
4677 
TEST_F(ShowUnhandledTapTest,ShowUnhandledTapUIIfNeededWithNonTriggeringNodes)4678 TEST_F(ShowUnhandledTapTest, ShowUnhandledTapUIIfNeededWithNonTriggeringNodes) {
4679   Tap("image");
4680   EXPECT_FALSE(mock_notifier_.WasUnhandledTap());
4681 
4682   Tap("editable");
4683   EXPECT_FALSE(mock_notifier_.WasUnhandledTap());
4684 
4685   Tap("focusable");
4686   EXPECT_FALSE(mock_notifier_.WasUnhandledTap());
4687 }
4688 
TEST_F(ShowUnhandledTapTest,ShowUnhandledTapUIIfNeededWithTextSizes)4689 TEST_F(ShowUnhandledTapTest, ShowUnhandledTapUIIfNeededWithTextSizes) {
4690   Tap("large");
4691   EXPECT_TRUE(mock_notifier_.WasUnhandledTap());
4692   EXPECT_EQ(20, mock_notifier_.GetFontSize());
4693 
4694   Tap("small");
4695   EXPECT_TRUE(mock_notifier_.WasUnhandledTap());
4696   EXPECT_EQ(10, mock_notifier_.GetFontSize());
4697 }
4698 
4699 #endif  // BUILDFLAG(ENABLE_UNHANDLED_TAP)
4700 
4701 #if defined(OS_MACOSX)
TEST_F(WebViewTest,WebSubstringUtil)4702 TEST_F(WebViewTest, WebSubstringUtil) {
4703   RegisterMockedHttpURLLoad("content_editable_populated.html");
4704   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
4705       base_url_ + "content_editable_populated.html");
4706   web_view->GetSettings()->SetDefaultFontSize(12);
4707   web_view->MainFrameWidget()->Resize(WebSize(400, 400));
4708   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
4709 
4710   gfx::Point baseline_point;
4711   NSAttributedString* result = WebSubstringUtil::AttributedSubstringInRange(
4712       frame, 10, 3, &baseline_point);
4713   ASSERT_TRUE(!!result);
4714 
4715   gfx::Point point(baseline_point);
4716   result = WebSubstringUtil::AttributedWordAtPoint(frame->FrameWidget(), point,
4717                                                    baseline_point);
4718   ASSERT_TRUE(!!result);
4719 
4720   web_view->SetZoomLevel(3);
4721 
4722   result = WebSubstringUtil::AttributedSubstringInRange(frame, 5, 5,
4723                                                         &baseline_point);
4724   ASSERT_TRUE(!!result);
4725 
4726   point = baseline_point;
4727   result = WebSubstringUtil::AttributedWordAtPoint(frame->FrameWidget(), point,
4728                                                    baseline_point);
4729   ASSERT_TRUE(!!result);
4730 }
4731 
TEST_F(WebViewTest,WebSubstringUtilBaselinePoint)4732 TEST_F(WebViewTest, WebSubstringUtilBaselinePoint) {
4733   RegisterMockedHttpURLLoad("content_editable_multiline.html");
4734   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
4735       base_url_ + "content_editable_multiline.html");
4736   web_view->GetSettings()->SetDefaultFontSize(12);
4737   web_view->MainFrameWidget()->Resize(WebSize(400, 400));
4738   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
4739 
4740   gfx::Point old_point;
4741   WebSubstringUtil::AttributedSubstringInRange(frame, 3, 1, &old_point);
4742 
4743   gfx::Point new_point;
4744   WebSubstringUtil::AttributedSubstringInRange(frame, 3, 20, &new_point);
4745 
4746   EXPECT_EQ(old_point.x(), new_point.x());
4747   EXPECT_EQ(old_point.y(), new_point.y());
4748 }
4749 
TEST_F(WebViewTest,WebSubstringUtilPinchZoom)4750 TEST_F(WebViewTest, WebSubstringUtilPinchZoom) {
4751   RegisterMockedHttpURLLoad("content_editable_populated.html");
4752   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
4753       base_url_ + "content_editable_populated.html");
4754   web_view->GetSettings()->SetDefaultFontSize(12);
4755   web_view->MainFrameWidget()->Resize(WebSize(400, 400));
4756   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
4757   NSAttributedString* result = nil;
4758 
4759   gfx::Point baseline_point;
4760   result = WebSubstringUtil::AttributedSubstringInRange(frame, 10, 3,
4761                                                         &baseline_point);
4762   ASSERT_TRUE(!!result);
4763 
4764   web_view->SetPageScaleFactor(3);
4765 
4766   gfx::Point point_after_zoom;
4767   result = WebSubstringUtil::AttributedSubstringInRange(frame, 10, 3,
4768                                                         &point_after_zoom);
4769   ASSERT_TRUE(!!result);
4770 
4771   // We won't have moved by a full factor of 3 because of the translations, but
4772   // we should move by a factor of >2.
4773   EXPECT_LT(2 * baseline_point.x(), point_after_zoom.x());
4774   EXPECT_LT(2 * baseline_point.y(), point_after_zoom.y());
4775 }
4776 
TEST_F(WebViewTest,WebSubstringUtilIframe)4777 TEST_F(WebViewTest, WebSubstringUtilIframe) {
4778   RegisterMockedHttpURLLoad("single_iframe.html");
4779   RegisterMockedHttpURLLoad("visible_iframe.html");
4780   WebViewImpl* web_view =
4781       web_view_helper_.InitializeAndLoad(base_url_ + "single_iframe.html");
4782   web_view->GetSettings()->SetDefaultFontSize(12);
4783   web_view->GetSettings()->SetJavaScriptEnabled(true);
4784   web_view->MainFrameWidget()->Resize(WebSize(400, 400));
4785   WebLocalFrameImpl* main_frame = web_view->MainFrameImpl();
4786   WebLocalFrameImpl* child_frame = WebLocalFrameImpl::FromFrame(
4787       To<LocalFrame>(main_frame->GetFrame()->Tree().FirstChild()));
4788 
4789   gfx::Point baseline_point;
4790   NSAttributedString* result = WebSubstringUtil::AttributedSubstringInRange(
4791       child_frame, 11, 7, &baseline_point);
4792   ASSERT_NE(result, nullptr);
4793 
4794   gfx::Point point(baseline_point);
4795   result = WebSubstringUtil::AttributedWordAtPoint(main_frame->FrameWidget(),
4796                                                    point, baseline_point);
4797   ASSERT_NE(result, nullptr);
4798 
4799   int y_before_change = baseline_point.y();
4800 
4801   // Now move the <iframe> down by 100px.
4802   main_frame->ExecuteScript(WebScriptSource(
4803       "document.querySelector('iframe').style.marginTop = '100px';"));
4804 
4805   point = gfx::Point(point.x(), point.y() + 100);
4806   result = WebSubstringUtil::AttributedWordAtPoint(main_frame->FrameWidget(),
4807                                                    point, baseline_point);
4808   ASSERT_NE(result, nullptr);
4809 
4810   EXPECT_EQ(y_before_change, baseline_point.y() - 100);
4811 }
4812 
4813 #endif
4814 
TEST_F(WebViewTest,ShouldSuppressKeyboardForPasswordField)4815 TEST_F(WebViewTest, ShouldSuppressKeyboardForPasswordField) {
4816   RegisterMockedHttpURLLoad("input_field_password.html");
4817   // Pretend client has fill data for all fields it's queried.
4818   MockAutofillClient client;
4819   client.SetShouldSuppressKeyboard(true);
4820   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
4821       base_url_ + "input_field_password.html");
4822   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
4823   frame->SetAutofillClient(&client);
4824   // No field is focused.
4825   EXPECT_FALSE(frame->ShouldSuppressKeyboardForFocusedElement());
4826 
4827   // Focusing a field should result in treating it autofillable.
4828   web_view->SetInitialFocus(false);
4829   EXPECT_TRUE(frame->ShouldSuppressKeyboardForFocusedElement());
4830 
4831   // Pretend that |client| no longer has autofill data available.
4832   client.SetShouldSuppressKeyboard(false);
4833   EXPECT_FALSE(frame->ShouldSuppressKeyboardForFocusedElement());
4834   frame->SetAutofillClient(nullptr);
4835 }
4836 
TEST_F(WebViewTest,PasswordFieldEditingIsUserGesture)4837 TEST_F(WebViewTest, PasswordFieldEditingIsUserGesture) {
4838   RegisterMockedHttpURLLoad("input_field_password.html");
4839   MockAutofillClient client;
4840   WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
4841       base_url_ + "input_field_password.html");
4842   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
4843   frame->SetAutofillClient(&client);
4844   web_view->SetInitialFocus(false);
4845 
4846   WebVector<WebImeTextSpan> empty_ime_text_spans;
4847 
4848   EXPECT_EQ(0, client.TextChanges());
4849   EXPECT_TRUE(
4850       frame->FrameWidget()->GetActiveWebInputMethodController()->CommitText(
4851           WebString::FromUTF8(std::string("hello").c_str()),
4852           empty_ime_text_spans, WebRange(), 0));
4853   EXPECT_TRUE(frame->HasTransientUserActivation());
4854   EXPECT_EQ(1, client.TextChanges());
4855   frame->SetAutofillClient(nullptr);
4856 }
4857 
4858 // Verify that a WebView created with a ScopedPagePauser already on the
4859 // stack defers its loads.
TEST_F(WebViewTest,CreatedDuringPagePause)4860 TEST_F(WebViewTest, CreatedDuringPagePause) {
4861   {
4862     WebViewImpl* web_view = web_view_helper_.Initialize();
4863     EXPECT_FALSE(web_view->GetPage()->Paused());
4864   }
4865 
4866   {
4867     ScopedPagePauser pauser;
4868     WebViewImpl* web_view = web_view_helper_.Initialize();
4869     EXPECT_TRUE(web_view->GetPage()->Paused());
4870   }
4871 }
4872 
4873 // Make sure the SubframeBeforeUnloadUseCounter is only incremented on subframe
4874 // unloads. crbug.com/635029.
TEST_F(WebViewTest,SubframeBeforeUnloadUseCounter)4875 TEST_F(WebViewTest, SubframeBeforeUnloadUseCounter) {
4876   RegisterMockedHttpURLLoad("visible_iframe.html");
4877   RegisterMockedHttpURLLoad("single_iframe.html");
4878   WebViewImpl* web_view =
4879       web_view_helper_.InitializeAndLoad(base_url_ + "single_iframe.html");
4880 
4881   WebLocalFrame* frame = web_view_helper_.LocalMainFrame();
4882   Document* document =
4883       To<LocalFrame>(web_view_helper_.GetWebView()->GetPage()->MainFrame())
4884           ->GetDocument();
4885 
4886   // Add a beforeunload handler in the main frame. Make sure firing
4887   // beforeunload doesn't increment the subframe use counter.
4888   {
4889     frame->ExecuteScript(
4890         WebScriptSource("addEventListener('beforeunload', function() {});"));
4891     web_view->MainFrameImpl()->DispatchBeforeUnloadEvent(false);
4892     EXPECT_FALSE(
4893         document->IsUseCounted(WebFeature::kSubFrameBeforeUnloadFired));
4894   }
4895 
4896   // Add a beforeunload handler in the iframe and dispatch. Make sure we do
4897   // increment the use counter for subframe beforeunloads.
4898   {
4899     frame->ExecuteScript(WebScriptSource(
4900         "document.getElementsByTagName('iframe')[0].contentWindow."
4901         "addEventListener('beforeunload', function() {});"));
4902     To<WebLocalFrameImpl>(
4903         web_view->MainFrame()->FirstChild()->ToWebLocalFrame())
4904         ->DispatchBeforeUnloadEvent(false);
4905 
4906     Document* child_document = To<LocalFrame>(web_view_helper_.GetWebView()
4907                                                   ->GetPage()
4908                                                   ->MainFrame()
4909                                                   ->Tree()
4910                                                   .FirstChild())
4911                                    ->GetDocument();
4912     EXPECT_TRUE(
4913         child_document->IsUseCounted(WebFeature::kSubFrameBeforeUnloadFired));
4914   }
4915 }
4916 
4917 // Verify that page loads are deferred until all ScopedPageLoadDeferrers are
4918 // destroyed.
TEST_F(WebViewTest,NestedPagePauses)4919 TEST_F(WebViewTest, NestedPagePauses) {
4920   WebViewImpl* web_view = web_view_helper_.Initialize();
4921   EXPECT_FALSE(web_view->GetPage()->Paused());
4922 
4923   {
4924     ScopedPagePauser pauser;
4925     EXPECT_TRUE(web_view->GetPage()->Paused());
4926 
4927     {
4928       ScopedPagePauser pauser2;
4929       EXPECT_TRUE(web_view->GetPage()->Paused());
4930     }
4931 
4932     EXPECT_TRUE(web_view->GetPage()->Paused());
4933   }
4934 
4935   EXPECT_FALSE(web_view->GetPage()->Paused());
4936 }
4937 
TEST_F(WebViewTest,ClosingPageIsPaused)4938 TEST_F(WebViewTest, ClosingPageIsPaused) {
4939   WebViewImpl* web_view = web_view_helper_.Initialize();
4940   Page* page = web_view_helper_.GetWebView()->GetPage();
4941   EXPECT_FALSE(page->Paused());
4942 
4943   web_view->SetOpenedByDOM();
4944 
4945   auto* main_frame = To<LocalFrame>(page->MainFrame());
4946   EXPECT_FALSE(main_frame->DomWindow()->closed());
4947 
4948   ScriptState* script_state = ToScriptStateForMainWorld(main_frame);
4949   ScriptState::Scope entered_context_scope(script_state);
4950   v8::Context::BackupIncumbentScope incumbent_context_scope(
4951       script_state->GetContext());
4952 
4953   main_frame->DomWindow()->close(script_state->GetIsolate());
4954   // The window should be marked closed...
4955   EXPECT_TRUE(main_frame->DomWindow()->closed());
4956   // EXPECT_TRUE(page->isClosing());
4957   // ...but not yet detached.
4958   EXPECT_TRUE(main_frame->GetPage());
4959 
4960   {
4961     ScopedPagePauser pauser;
4962     EXPECT_TRUE(page->Paused());
4963   }
4964 }
4965 
TEST_F(WebViewTest,ForceAndResetViewport)4966 TEST_F(WebViewTest, ForceAndResetViewport) {
4967   RegisterMockedHttpURLLoad("200-by-300.html");
4968   WebViewImpl* web_view_impl =
4969       web_view_helper_.InitializeAndLoad(base_url_ + "200-by-300.html");
4970   web_view_impl->MainFrameWidget()->Resize(WebSize(100, 150));
4971   SetViewportSize(WebSize(100, 150));
4972   DevToolsEmulator* dev_tools_emulator = web_view_impl->GetDevToolsEmulator();
4973 
4974   TransformationMatrix expected_matrix;
4975   expected_matrix.MakeIdentity();
4976   EXPECT_EQ(expected_matrix, web_view_impl->GetDeviceEmulationTransform());
4977   {
4978     IntRect visible_rect(1, 2, 3, 4);
4979     dev_tools_emulator->OverrideVisibleRect(IntSize(), &visible_rect);
4980     EXPECT_EQ(IntRect(1, 2, 3, 4), visible_rect);  // Was modified.
4981   }
4982 
4983   // Override applies transform, sets visible rect, and disables
4984   // visual viewport clipping.
4985   TransformationMatrix matrix =
4986       dev_tools_emulator->ForceViewportForTesting(gfx::PointF(50, 55), 2.f);
4987   expected_matrix.MakeIdentity().Scale(2.f).Translate(-50, -55);
4988   EXPECT_EQ(expected_matrix, matrix);
4989   {
4990     IntRect visible_rect(1, 2, 3, 4);
4991     dev_tools_emulator->OverrideVisibleRect(IntSize(100, 150), &visible_rect);
4992     EXPECT_EQ(IntRect(50, 55, 50, 75), visible_rect);
4993   }
4994 
4995   // Setting new override discards previous one.
4996   matrix = dev_tools_emulator->ForceViewportForTesting(gfx::PointF(5.4f, 10.5f),
4997                                                        1.5f);
4998   expected_matrix.MakeIdentity().Scale(1.5f).Translate(-5.4f, -10.5f);
4999   EXPECT_EQ(expected_matrix, matrix);
5000   {
5001     IntRect visible_rect(1, 2, 3, 4);
5002     dev_tools_emulator->OverrideVisibleRect(IntSize(100, 150), &visible_rect);
5003     EXPECT_EQ(IntRect(5, 10, 68, 101), visible_rect);  // Was modified.
5004   }
5005 
5006   // Clearing override restores original transform, visible rect and
5007   // visual viewport clipping.
5008   matrix = dev_tools_emulator->ResetViewportForTesting();
5009   expected_matrix.MakeIdentity();
5010   EXPECT_EQ(expected_matrix, matrix);
5011   {
5012     IntRect visible_rect(1, 2, 3, 4);
5013     dev_tools_emulator->OverrideVisibleRect(IntSize(), &visible_rect);
5014     EXPECT_EQ(IntRect(1, 2, 3, 4), visible_rect);  // Not modified.
5015   }
5016 }
5017 
TEST_F(WebViewTest,ViewportOverrideIntegratesDeviceMetricsOffsetAndScale)5018 TEST_F(WebViewTest, ViewportOverrideIntegratesDeviceMetricsOffsetAndScale) {
5019   RegisterMockedHttpURLLoad("200-by-300.html");
5020   WebViewImpl* web_view_impl =
5021       web_view_helper_.InitializeAndLoad(base_url_ + "200-by-300.html");
5022   web_view_impl->MainFrameWidget()->Resize(WebSize(100, 150));
5023 
5024   TransformationMatrix expected_matrix;
5025   expected_matrix.MakeIdentity();
5026   EXPECT_EQ(expected_matrix, web_view_impl->GetDeviceEmulationTransform());
5027 
5028   WebDeviceEmulationParams emulation_params;
5029   emulation_params.scale = 2.f;
5030   web_view_impl->EnableDeviceEmulation(emulation_params);
5031   expected_matrix.MakeIdentity().Scale(2.f);
5032   EXPECT_EQ(expected_matrix, web_view_impl->GetDeviceEmulationTransform());
5033 
5034   // Device metrics offset and scale are applied before viewport override.
5035   emulation_params.viewport_offset = gfx::PointF(5, 10);
5036   emulation_params.viewport_scale = 1.5f;
5037   web_view_impl->EnableDeviceEmulation(emulation_params);
5038   expected_matrix.MakeIdentity()
5039       .Scale(1.5f)
5040       .Translate(-5, -10)
5041       .Scale(2.f);
5042   EXPECT_EQ(expected_matrix, web_view_impl->GetDeviceEmulationTransform());
5043 }
5044 
TEST_F(WebViewTest,ViewportOverrideAdaptsToScaleAndScroll)5045 TEST_F(WebViewTest, ViewportOverrideAdaptsToScaleAndScroll) {
5046   RegisterMockedHttpURLLoad("200-by-300.html");
5047   WebViewImpl* web_view_impl =
5048       web_view_helper_.InitializeAndLoad(base_url_ + "200-by-300.html");
5049   web_view_impl->MainFrameWidget()->Resize(WebSize(100, 150));
5050   SetViewportSize(WebSize(100, 150));
5051   LocalFrameView* frame_view =
5052       web_view_impl->MainFrameImpl()->GetFrame()->View();
5053   DevToolsEmulator* dev_tools_emulator = web_view_impl->GetDevToolsEmulator();
5054 
5055   TransformationMatrix expected_matrix;
5056   expected_matrix.MakeIdentity();
5057   EXPECT_EQ(expected_matrix, web_view_impl->GetDeviceEmulationTransform());
5058 
5059   // Initial transform takes current page scale and scroll position into
5060   // account.
5061   web_view_impl->SetPageScaleFactor(1.5f);
5062   frame_view->LayoutViewport()->SetScrollOffset(
5063       ScrollOffset(100, 150), mojom::blink::ScrollType::kProgrammatic,
5064       mojom::blink::ScrollBehavior::kInstant);
5065 
5066   WebDeviceEmulationParams emulation_params;
5067   emulation_params.viewport_offset = gfx::PointF(50, 55);
5068   emulation_params.viewport_scale = 2.f;
5069   web_view_impl->EnableDeviceEmulation(emulation_params);
5070   expected_matrix.MakeIdentity()
5071       .Scale(2.f)
5072       .Translate(-50, -55)
5073       .Translate(100, 150)
5074       .Scale(1. / 1.5f);
5075   EXPECT_EQ(expected_matrix, web_view_impl->GetDeviceEmulationTransform());
5076   // Scale is irrelevant for visible rect.
5077   {
5078     IntRect visible_rect(1, 2, 3, 4);
5079     dev_tools_emulator->OverrideVisibleRect(IntSize(100, 150), &visible_rect);
5080     EXPECT_EQ(IntRect(50 - 100, 55 - 150, 50, 75), visible_rect);
5081   }
5082 
5083   // Transform adapts to scroll changes.
5084   frame_view->LayoutViewport()->SetScrollOffset(
5085       ScrollOffset(50, 55), mojom::blink::ScrollType::kProgrammatic,
5086       mojom::blink::ScrollBehavior::kInstant);
5087   expected_matrix.MakeIdentity()
5088       .Scale(2.f)
5089       .Translate(-50, -55)
5090       .Translate(50, 55)
5091       .Scale(1. / 1.5f);
5092   EXPECT_EQ(expected_matrix, web_view_impl->GetDeviceEmulationTransform());
5093   // Visible rect adapts to scroll change.
5094   {
5095     IntRect visible_rect(1, 2, 3, 4);
5096     dev_tools_emulator->OverrideVisibleRect(IntSize(100, 150), &visible_rect);
5097     EXPECT_EQ(IntRect(50 - 50, 55 - 55, 50, 75), visible_rect);
5098   }
5099 
5100   // Transform adapts to page scale changes.
5101   web_view_impl->SetPageScaleFactor(2.f);
5102   expected_matrix.MakeIdentity()
5103       .Scale(2.f)
5104       .Translate(-50, -55)
5105       .Translate(50, 55)
5106       .Scale(1. / 2.f);
5107   EXPECT_EQ(expected_matrix, web_view_impl->GetDeviceEmulationTransform());
5108   // Visible rect doesn't change.
5109   {
5110     IntRect visible_rect(1, 2, 3, 4);
5111     dev_tools_emulator->OverrideVisibleRect(IntSize(100, 150), &visible_rect);
5112     EXPECT_EQ(IntRect(50 - 50, 55 - 55, 50, 75), visible_rect);
5113   }
5114 }
5115 
TEST_F(WebViewTest,ResizeForPrintingViewportUnits)5116 TEST_F(WebViewTest, ResizeForPrintingViewportUnits) {
5117   WebViewImpl* web_view = web_view_helper_.Initialize();
5118   web_view->MainFrameWidget()->Resize(WebSize(800, 600));
5119 
5120   WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
5121   frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(),
5122                                      "<style>"
5123                                      "  body { margin: 0px; }"
5124                                      "  #vw { width: 100vw; height: 100vh; }"
5125                                      "</style>"
5126                                      "<div id=vw></div>",
5127                                      base_url);
5128 
5129   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
5130   Document* document = frame->GetFrame()->GetDocument();
5131   Element* vw_element = document->getElementById("vw");
5132 
5133   EXPECT_EQ(800, vw_element->OffsetWidth());
5134 
5135   FloatSize page_size(300, 360);
5136 
5137   WebPrintParams print_params;
5138   print_params.print_content_area.width = page_size.Width();
5139   print_params.print_content_area.height = page_size.Height();
5140 
5141   IntSize expected_size = PrintICBSizeFromPageSize(page_size);
5142 
5143   frame->PrintBegin(print_params, WebNode());
5144 
5145   EXPECT_EQ(expected_size.Width(), vw_element->OffsetWidth());
5146   EXPECT_EQ(expected_size.Height(), vw_element->OffsetHeight());
5147 
5148   web_view->MainFrameWidget()->Resize(FlooredIntSize(page_size));
5149 
5150   EXPECT_EQ(expected_size.Width(), vw_element->OffsetWidth());
5151   EXPECT_EQ(expected_size.Height(), vw_element->OffsetHeight());
5152 
5153   web_view->MainFrameWidget()->Resize(WebSize(800, 600));
5154   frame->PrintEnd();
5155 
5156   EXPECT_EQ(800, vw_element->OffsetWidth());
5157 }
5158 
TEST_F(WebViewTest,WidthMediaQueryWithPageZoomAfterPrinting)5159 TEST_F(WebViewTest, WidthMediaQueryWithPageZoomAfterPrinting) {
5160   WebViewImpl* web_view = web_view_helper_.Initialize();
5161   web_view->MainFrameWidget()->Resize(WebSize(800, 600));
5162   web_view->SetZoomLevel(PageZoomFactorToZoomLevel(2.0));
5163 
5164   WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
5165   frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(),
5166                                      "<style>"
5167                                      "  @media (max-width: 600px) {"
5168                                      "    div { color: green }"
5169                                      "  }"
5170                                      "</style>"
5171                                      "<div id=d></div>",
5172                                      base_url);
5173 
5174   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
5175   Document* document = frame->GetFrame()->GetDocument();
5176   Element* div = document->getElementById("d");
5177 
5178   EXPECT_EQ(MakeRGB(0, 128, 0), div->GetComputedStyle()->VisitedDependentColor(
5179                                     GetCSSPropertyColor()));
5180 
5181   FloatSize page_size(300, 360);
5182 
5183   WebPrintParams print_params;
5184   print_params.print_content_area.width = page_size.Width();
5185   print_params.print_content_area.height = page_size.Height();
5186 
5187   frame->PrintBegin(print_params, WebNode());
5188   frame->PrintEnd();
5189 
5190   EXPECT_EQ(MakeRGB(0, 128, 0), div->GetComputedStyle()->VisitedDependentColor(
5191                                     GetCSSPropertyColor()));
5192 }
5193 
TEST_F(WebViewTest,ViewportUnitsPrintingWithPageZoom)5194 TEST_F(WebViewTest, ViewportUnitsPrintingWithPageZoom) {
5195   WebViewImpl* web_view = web_view_helper_.Initialize();
5196   web_view->MainFrameWidget()->Resize(WebSize(800, 600));
5197   web_view->SetZoomLevel(PageZoomFactorToZoomLevel(2.0));
5198 
5199   WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
5200   frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(),
5201                                      "<style>"
5202                                      "  body { margin: 0 }"
5203                                      "  #t1 { width: 100% }"
5204                                      "  #t2 { width: 100vw }"
5205                                      "</style>"
5206                                      "<div id=t1></div>"
5207                                      "<div id=t2></div>",
5208                                      base_url);
5209 
5210   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
5211   Document* document = frame->GetFrame()->GetDocument();
5212   Element* t1 = document->getElementById("t1");
5213   Element* t2 = document->getElementById("t2");
5214 
5215   EXPECT_EQ(400, t1->OffsetWidth());
5216   EXPECT_EQ(400, t2->OffsetWidth());
5217 
5218   FloatSize page_size(600, 720);
5219   int expected_width = PrintICBSizeFromPageSize(page_size).Width();
5220 
5221   WebPrintParams print_params;
5222   print_params.print_content_area.width = page_size.Width();
5223   print_params.print_content_area.height = page_size.Height();
5224 
5225   frame->PrintBegin(print_params, WebNode());
5226 
5227   EXPECT_EQ(expected_width, t1->OffsetWidth());
5228   EXPECT_EQ(expected_width, t2->OffsetWidth());
5229 
5230   frame->PrintEnd();
5231 }
5232 
TEST_F(WebViewTest,DeviceEmulationResetScrollbars)5233 TEST_F(WebViewTest, DeviceEmulationResetScrollbars) {
5234   WebViewImpl* web_view = web_view_helper_.Initialize();
5235   web_view->MainFrameWidget()->Resize(WebSize(800, 600));
5236 
5237   WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
5238   frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(),
5239                                      "<!doctype html>"
5240                                      "<meta name='viewport'"
5241                                      "    content='width=device-width'>"
5242                                      "<style>"
5243                                      "  body {margin: 0px; height:3000px;}"
5244                                      "</style>",
5245                                      base_url);
5246   UpdateAllLifecyclePhases();
5247 
5248   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
5249   auto* frame_view = frame->GetFrameView();
5250   EXPECT_FALSE(frame_view->VisualViewportSuppliesScrollbars());
5251   EXPECT_NE(nullptr, frame_view->LayoutViewport()->VerticalScrollbar());
5252 
5253   WebDeviceEmulationParams params;
5254   params.screen_position = WebDeviceEmulationParams::kMobile;
5255   params.device_scale_factor = 0;
5256   params.scale = 1;
5257 
5258   web_view->EnableDeviceEmulation(params);
5259 
5260   // The visual viewport should now proivde the scrollbars instead of the view.
5261   EXPECT_TRUE(frame_view->VisualViewportSuppliesScrollbars());
5262   EXPECT_EQ(nullptr, frame_view->LayoutViewport()->VerticalScrollbar());
5263 
5264   web_view->DisableDeviceEmulation();
5265 
5266   // The view should once again provide the scrollbars.
5267   EXPECT_FALSE(frame_view->VisualViewportSuppliesScrollbars());
5268   EXPECT_NE(nullptr, frame_view->LayoutViewport()->VerticalScrollbar());
5269 }
5270 
TEST_F(WebViewTest,SetZoomLevelWhilePluginFocused)5271 TEST_F(WebViewTest, SetZoomLevelWhilePluginFocused) {
5272   class PluginCreatingWebFrameClient
5273       : public frame_test_helpers::TestWebFrameClient {
5274    public:
5275     // WebLocalFrameClient overrides:
5276     WebPlugin* CreatePlugin(const WebPluginParams& params) override {
5277       return new FakeWebPlugin(params);
5278     }
5279   };
5280   PluginCreatingWebFrameClient frame_client;
5281   WebViewImpl* web_view = web_view_helper_.Initialize(&frame_client);
5282   WebURL base_url = url_test_helpers::ToKURL("https://example.com/");
5283   frame_test_helpers::LoadHTMLString(
5284       web_view->MainFrameImpl(),
5285       "<!DOCTYPE html><html><body>"
5286       "<object type='application/x-webkit-test-plugin'></object>"
5287       "</body></html>",
5288       base_url);
5289   // Verify the plugin is loaded.
5290   LocalFrame* main_frame = web_view->MainFrameImpl()->GetFrame();
5291   auto* plugin_element =
5292       To<HTMLObjectElement>(main_frame->GetDocument()->body()->firstChild());
5293   EXPECT_TRUE(plugin_element->OwnedPlugin());
5294   // Focus the plugin element, and then change the zoom level on the WebView.
5295   plugin_element->focus();
5296   EXPECT_FLOAT_EQ(1.0f, main_frame->PageZoomFactor());
5297   web_view->SetZoomLevel(-1.0);
5298   // Even though the plugin is focused, the entire frame's zoom factor should
5299   // still be updated.
5300   EXPECT_FLOAT_EQ(5.0f / 6.0f, main_frame->PageZoomFactor());
5301   web_view_helper_.Reset();  // Remove dependency on locally scoped client.
5302 }
5303 
5304 // Tests that a layout update that detaches a plugin doesn't crash if the
5305 // plugin tries to execute script while being destroyed.
TEST_F(WebViewTest,DetachPluginInLayout)5306 TEST_F(WebViewTest, DetachPluginInLayout) {
5307   class ScriptInDestroyPlugin : public FakeWebPlugin {
5308    public:
5309     ScriptInDestroyPlugin(WebLocalFrame* frame, const WebPluginParams& params)
5310         : FakeWebPlugin(params), frame_(frame) {}
5311 
5312     // WebPlugin overrides:
5313     void Destroy() override {
5314       frame_->ExecuteScript(WebScriptSource("console.log('done')"));
5315       // Deletes this.
5316       FakeWebPlugin::Destroy();
5317     }
5318 
5319    private:
5320     WebLocalFrame* frame_;  // Unowned
5321   };
5322 
5323   class PluginCreatingWebFrameClient
5324       : public frame_test_helpers::TestWebFrameClient {
5325    public:
5326     // WebLocalFrameClient overrides:
5327     WebPlugin* CreatePlugin(const WebPluginParams& params) override {
5328       return new ScriptInDestroyPlugin(Frame(), params);
5329     }
5330 
5331     void DidAddMessageToConsole(const WebConsoleMessage& message,
5332                                 const WebString& source_name,
5333                                 unsigned source_line,
5334                                 const WebString& stack_trace) override {
5335       message_ = message.text;
5336     }
5337 
5338     const String& Message() const { return message_; }
5339 
5340    private:
5341     String message_;
5342   };
5343 
5344   PluginCreatingWebFrameClient frame_client;
5345   WebViewImpl* web_view = web_view_helper_.Initialize(&frame_client);
5346   WebURL base_url = url_test_helpers::ToKURL("https://example.com/");
5347   frame_test_helpers::LoadHTMLString(
5348       web_view->MainFrameImpl(),
5349       "<!DOCTYPE html><html><body>"
5350       "<object type='application/x-webkit-test-plugin'></object>"
5351       "</body></html>",
5352       base_url);
5353   // Verify the plugin is loaded.
5354   LocalFrame* main_frame = web_view->MainFrameImpl()->GetFrame();
5355   auto* plugin_element =
5356       To<HTMLObjectElement>(main_frame->GetDocument()->body()->firstChild());
5357   EXPECT_TRUE(plugin_element->OwnedPlugin());
5358 
5359   plugin_element->style()->setCSSText(
5360       main_frame->GetDocument()->ToExecutionContext(), "display: none",
5361       ASSERT_NO_EXCEPTION);
5362   EXPECT_TRUE(plugin_element->OwnedPlugin());
5363   UpdateAllLifecyclePhases();
5364   EXPECT_FALSE(plugin_element->OwnedPlugin());
5365   EXPECT_EQ("done", frame_client.Message());
5366   web_view_helper_.Reset();  // Remove dependency on locally scoped client.
5367 }
5368 
5369 // Check that first input delay is correctly reported to the document.
TEST_F(WebViewTest,FirstInputDelayReported)5370 TEST_F(WebViewTest, FirstInputDelayReported) {
5371   WebViewImpl* web_view = web_view_helper_.Initialize();
5372   WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
5373   frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(),
5374                                      "<html><body></body></html>", base_url);
5375 
5376   LocalFrame* main_frame = web_view->MainFrameImpl()->GetFrame();
5377   ASSERT_NE(nullptr, main_frame);
5378 
5379   Document* document = main_frame->GetDocument();
5380   ASSERT_NE(nullptr, document);
5381 
5382   base::TimeTicks start_time = test_task_runner_->NowTicks();
5383   test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(70));
5384 
5385   InteractiveDetector* interactive_detector =
5386       GetTestInteractiveDetector(*document);
5387 
5388   EXPECT_FALSE(interactive_detector->GetFirstInputDelay().has_value());
5389 
5390   WebKeyboardEvent key_event1(WebInputEvent::kRawKeyDown,
5391                               WebInputEvent::kNoModifiers,
5392                               WebInputEvent::GetStaticTimeStampForTests());
5393   key_event1.dom_key = ui::DomKey::FromCharacter(' ');
5394   key_event1.windows_key_code = VKEY_SPACE;
5395   key_event1.SetTimeStamp(test_task_runner_->NowTicks());
5396   test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(50));
5397   web_view->MainFrameWidget()->HandleInputEvent(
5398       WebCoalescedInputEvent(key_event1));
5399 
5400   EXPECT_TRUE(interactive_detector->GetFirstInputDelay().has_value());
5401   EXPECT_NEAR(50,
5402               (*interactive_detector->GetFirstInputDelay()).InMillisecondsF(),
5403               0.01);
5404   EXPECT_EQ(70, (*interactive_detector->GetFirstInputTimestamp() - start_time)
5405                     .InMillisecondsF());
5406 
5407   // Sending a second event won't change the FirstInputDelay.
5408   WebKeyboardEvent key_event2(WebInputEvent::kRawKeyDown,
5409                               WebInputEvent::kNoModifiers,
5410                               WebInputEvent::GetStaticTimeStampForTests());
5411   key_event2.dom_key = ui::DomKey::FromCharacter(' ');
5412   key_event2.windows_key_code = VKEY_SPACE;
5413   test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(60));
5414   key_event2.SetTimeStamp(test_task_runner_->NowTicks());
5415   web_view->MainFrameWidget()->HandleInputEvent(
5416       WebCoalescedInputEvent(key_event2));
5417 
5418   EXPECT_NEAR(50,
5419               (*interactive_detector->GetFirstInputDelay()).InMillisecondsF(),
5420               0.01);
5421   EXPECT_EQ(70, (*interactive_detector->GetFirstInputTimestamp() - start_time)
5422                     .InMillisecondsF());
5423 }
5424 
5425 // Check that longest input delay is correctly reported to the document.
TEST_F(WebViewTest,LongestInputDelayReported)5426 TEST_F(WebViewTest, LongestInputDelayReported) {
5427   WebViewImpl* web_view = web_view_helper_.Initialize();
5428   WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
5429   frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(),
5430                                      "<html><body></body></html>", base_url);
5431 
5432   LocalFrame* main_frame = web_view->MainFrameImpl()->GetFrame();
5433   ASSERT_NE(nullptr, main_frame);
5434 
5435   Document* document = main_frame->GetDocument();
5436   ASSERT_NE(nullptr, document);
5437 
5438   test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(70));
5439 
5440   InteractiveDetector* interactive_detector =
5441       GetTestInteractiveDetector(*document);
5442 
5443   EXPECT_FALSE(interactive_detector->GetLongestInputDelay().has_value());
5444 
5445   WebKeyboardEvent key_event1(WebInputEvent::kRawKeyDown,
5446                               WebInputEvent::kNoModifiers,
5447                               WebInputEvent::GetStaticTimeStampForTests());
5448   key_event1.dom_key = ui::DomKey::FromCharacter(' ');
5449   key_event1.windows_key_code = VKEY_SPACE;
5450   key_event1.SetTimeStamp(test_task_runner_->NowTicks());
5451   test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(50));
5452   web_view->MainFrameWidget()->HandleInputEvent(
5453       WebCoalescedInputEvent(key_event1));
5454 
5455   base::TimeTicks longest_input_timestamp = test_task_runner_->NowTicks();
5456 
5457   WebKeyboardEvent key_event2(WebInputEvent::kRawKeyDown,
5458                               WebInputEvent::kNoModifiers,
5459                               WebInputEvent::GetStaticTimeStampForTests());
5460   key_event2.dom_key = ui::DomKey::FromCharacter(' ');
5461   key_event2.windows_key_code = VKEY_SPACE;
5462   key_event2.SetTimeStamp(longest_input_timestamp);
5463   test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(100));
5464   web_view->MainFrameWidget()->HandleInputEvent(
5465       WebCoalescedInputEvent(key_event2));
5466 
5467   WebKeyboardEvent key_event3(WebInputEvent::kRawKeyDown,
5468                               WebInputEvent::kNoModifiers,
5469                               WebInputEvent::GetStaticTimeStampForTests());
5470   key_event3.dom_key = ui::DomKey::FromCharacter(' ');
5471   key_event3.windows_key_code = VKEY_SPACE;
5472   key_event3.SetTimeStamp(test_task_runner_->NowTicks());
5473   test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(70));
5474   web_view->MainFrameWidget()->HandleInputEvent(
5475       WebCoalescedInputEvent(key_event3));
5476 
5477   EXPECT_NEAR(100,
5478               (*interactive_detector->GetLongestInputDelay()).InMillisecondsF(),
5479               0.01);
5480   EXPECT_EQ(longest_input_timestamp,
5481             interactive_detector->GetLongestInputTimestamp());
5482 }
5483 
TEST_F(WebViewTest,InputDelayReported)5484 TEST_F(WebViewTest, InputDelayReported) {
5485   test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(50));
5486 
5487   WebViewImpl* web_view = web_view_helper_.Initialize();
5488 
5489   WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
5490   frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(),
5491                                      "<html><body></body></html>", base_url,
5492                                      test_task_runner_->GetMockTickClock());
5493 
5494   LocalFrame* main_frame = web_view->MainFrameImpl()->GetFrame();
5495   ASSERT_NE(nullptr, main_frame);
5496   Document* document = main_frame->GetDocument();
5497   ASSERT_NE(nullptr, document);
5498   GetTestInteractiveDetector(*document);
5499 
5500   test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(70));
5501 
5502   HistogramTester histogram_tester;
5503   WebKeyboardEvent key_event1(WebInputEvent::kRawKeyDown,
5504                               WebInputEvent::kNoModifiers,
5505                               WebInputEvent::GetStaticTimeStampForTests());
5506   key_event1.dom_key = ui::DomKey::FromCharacter(' ');
5507   key_event1.windows_key_code = VKEY_SPACE;
5508   key_event1.SetTimeStamp(test_task_runner_->NowTicks());
5509   test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(50));
5510   web_view->MainFrameWidget()->HandleInputEvent(
5511       WebCoalescedInputEvent(key_event1));
5512 
5513   WebKeyboardEvent key_event2(WebInputEvent::kRawKeyDown,
5514                               WebInputEvent::kNoModifiers,
5515                               WebInputEvent::GetStaticTimeStampForTests());
5516   key_event2.dom_key = ui::DomKey::FromCharacter(' ');
5517   key_event2.windows_key_code = VKEY_SPACE;
5518   key_event2.SetTimeStamp(test_task_runner_->NowTicks());
5519   test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(50));
5520   web_view->MainFrameWidget()->HandleInputEvent(
5521       WebCoalescedInputEvent(key_event2));
5522 
5523   WebKeyboardEvent key_event3(WebInputEvent::kRawKeyDown,
5524                               WebInputEvent::kNoModifiers,
5525                               WebInputEvent::GetStaticTimeStampForTests());
5526   key_event3.dom_key = ui::DomKey::FromCharacter(' ');
5527   key_event3.windows_key_code = VKEY_SPACE;
5528   key_event3.SetTimeStamp(test_task_runner_->NowTicks());
5529   test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(70));
5530   web_view->MainFrameWidget()->HandleInputEvent(
5531       WebCoalescedInputEvent(key_event3));
5532 
5533   histogram_tester.ExpectTotalCount("PageLoad.InteractiveTiming.InputDelay3",
5534                                     3);
5535   histogram_tester.ExpectBucketCount("PageLoad.InteractiveTiming.InputDelay3",
5536                                      50, 2);
5537   histogram_tester.ExpectBucketCount("PageLoad.InteractiveTiming.InputDelay3",
5538                                      70, 1);
5539 
5540   histogram_tester.ExpectTotalCount(
5541       "PageLoad.InteractiveTiming.InputTimestamp3", 3);
5542   histogram_tester.ExpectBucketCount(
5543       "PageLoad.InteractiveTiming.InputTimestamp3", 70, 1);
5544   histogram_tester.ExpectBucketCount(
5545       "PageLoad.InteractiveTiming.InputTimestamp3", 120, 1);
5546   histogram_tester.ExpectBucketCount(
5547       "PageLoad.InteractiveTiming.InputTimestamp3", 170, 1);
5548 }
5549 
5550 // Tests that if the page was backgrounded while an input event was queued,
5551 // we do not count its delay to calculate longest input delay.
TEST_F(WebViewTest,LongestInputDelayPageBackgroundedDuringQueuing)5552 TEST_F(WebViewTest, LongestInputDelayPageBackgroundedDuringQueuing) {
5553   WebViewImpl* web_view = web_view_helper_.Initialize();
5554   WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
5555   frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(),
5556                                      "<html><body></body></html>", base_url);
5557 
5558   LocalFrame* main_frame = web_view->MainFrameImpl()->GetFrame();
5559   ASSERT_NE(nullptr, main_frame);
5560 
5561   Document* document = main_frame->GetDocument();
5562   ASSERT_NE(nullptr, document);
5563 
5564   test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(70));
5565 
5566   InteractiveDetector* interactive_detector =
5567       GetTestInteractiveDetector(*document);
5568 
5569   EXPECT_FALSE(interactive_detector->GetLongestInputDelay().has_value());
5570 
5571   WebKeyboardEvent key_event1(WebInputEvent::kRawKeyDown,
5572                               WebInputEvent::kNoModifiers,
5573                               WebInputEvent::GetStaticTimeStampForTests());
5574   key_event1.dom_key = ui::DomKey::FromCharacter(' ');
5575   key_event1.windows_key_code = VKEY_SPACE;
5576   base::TimeTicks key_event1_time = test_task_runner_->NowTicks();
5577   key_event1.SetTimeStamp(key_event1_time);
5578   test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(50));
5579   web_view->MainFrameWidget()->HandleInputEvent(
5580       WebCoalescedInputEvent(key_event1));
5581 
5582   WebKeyboardEvent key_event2(WebInputEvent::kRawKeyDown,
5583                               WebInputEvent::kNoModifiers,
5584                               WebInputEvent::GetStaticTimeStampForTests());
5585   key_event2.dom_key = ui::DomKey::FromCharacter(' ');
5586   key_event2.windows_key_code = VKEY_SPACE;
5587   key_event2.SetTimeStamp(test_task_runner_->NowTicks());
5588   test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(100));
5589   web_view->SetVisibilityState(PageVisibilityState::kHidden,
5590                                /*initial_state=*/false);
5591   test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(100));
5592   web_view->SetVisibilityState(PageVisibilityState::kVisible,
5593                                /*initial_state=*/false);
5594   test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(100));
5595   // Total input delay is >300ms.
5596   web_view->MainFrameWidget()->HandleInputEvent(
5597       WebCoalescedInputEvent(key_event2));
5598 
5599   EXPECT_NEAR(50,
5600               (*interactive_detector->GetLongestInputDelay()).InMillisecondsF(),
5601               0.01);
5602   EXPECT_EQ(key_event1_time, interactive_detector->GetLongestInputTimestamp());
5603 }
5604 
5605 // Tests that if the page was backgrounded at navigation start and an input
5606 // event was queued before it was foregrounded, we do not count its delay to
5607 // calculate longest input delay.
TEST_F(WebViewTest,LongestInputDelayPageBackgroundedAtNavStart)5608 TEST_F(WebViewTest, LongestInputDelayPageBackgroundedAtNavStart) {
5609   WebViewImpl* web_view = web_view_helper_.Initialize();
5610   web_view->SetVisibilityState(PageVisibilityState::kHidden,
5611                                /*initial_state=*/false);
5612   WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
5613   frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(),
5614                                      "<html><body></body></html>", base_url);
5615 
5616   LocalFrame* main_frame = web_view->MainFrameImpl()->GetFrame();
5617   ASSERT_NE(nullptr, main_frame);
5618 
5619   Document* document = main_frame->GetDocument();
5620   ASSERT_NE(nullptr, document);
5621 
5622   test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(70));
5623 
5624   InteractiveDetector* interactive_detector =
5625       GetTestInteractiveDetector(*document);
5626 
5627   WebKeyboardEvent key_event(WebInputEvent::kRawKeyDown,
5628                              WebInputEvent::kNoModifiers,
5629                              WebInputEvent::GetStaticTimeStampForTests());
5630   key_event.dom_key = ui::DomKey::FromCharacter(' ');
5631   key_event.windows_key_code = VKEY_SPACE;
5632   key_event.SetTimeStamp(test_task_runner_->NowTicks());
5633   test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(100));
5634   web_view->SetVisibilityState(PageVisibilityState::kVisible,
5635                                /*initial_state=*/false);
5636   web_view->MainFrameWidget()->HandleInputEvent(
5637       WebCoalescedInputEvent(key_event));
5638 
5639   EXPECT_FALSE(interactive_detector->GetLongestInputDelay().has_value());
5640 }
5641 
5642 // Tests page backgrounding outside of input queuing time does not affect
5643 // longest input delay.
TEST_F(WebViewTest,LongestInputDelayPageBackgroundedNotDuringQueuing)5644 TEST_F(WebViewTest, LongestInputDelayPageBackgroundedNotDuringQueuing) {
5645   WebViewImpl* web_view = web_view_helper_.Initialize();
5646   WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
5647   frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(),
5648                                      "<html><body></body></html>", base_url);
5649 
5650   LocalFrame* main_frame = web_view->MainFrameImpl()->GetFrame();
5651   ASSERT_NE(nullptr, main_frame);
5652 
5653   Document* document = main_frame->GetDocument();
5654   ASSERT_NE(nullptr, document);
5655 
5656   test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(70));
5657 
5658   InteractiveDetector* interactive_detector =
5659       GetTestInteractiveDetector(*document);
5660 
5661   EXPECT_FALSE(interactive_detector->GetLongestInputDelay().has_value());
5662 
5663   web_view->SetVisibilityState(PageVisibilityState::kHidden,
5664                                /*initial_state=*/false);
5665   test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(100));
5666   web_view->SetVisibilityState(PageVisibilityState::kVisible,
5667                                /*initial_state=*/false);
5668   test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(1));
5669 
5670   WebKeyboardEvent key_event(WebInputEvent::kRawKeyDown,
5671                              WebInputEvent::kNoModifiers,
5672                              WebInputEvent::GetStaticTimeStampForTests());
5673   key_event.dom_key = ui::DomKey::FromCharacter(' ');
5674   key_event.windows_key_code = VKEY_SPACE;
5675   base::TimeTicks key_event_time = test_task_runner_->NowTicks();
5676   key_event.SetTimeStamp(key_event_time);
5677   test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(50));
5678   web_view->MainFrameWidget()->HandleInputEvent(
5679       WebCoalescedInputEvent(key_event));
5680 
5681   EXPECT_NEAR(50,
5682               (*interactive_detector->GetLongestInputDelay()).InMillisecondsF(),
5683               0.01);
5684   EXPECT_EQ(key_event_time, interactive_detector->GetLongestInputTimestamp());
5685 }
5686 
5687 // TODO(npm): Improve this test to receive real input sequences and avoid hacks.
5688 // Check that first input delay is correctly reported to the document when the
5689 // first input is a pointer down event, and we receive a pointer up event.
TEST_F(WebViewTest,PointerDownUpFirstInputDelay)5690 TEST_F(WebViewTest, PointerDownUpFirstInputDelay) {
5691   WebViewImpl* web_view = web_view_helper_.Initialize();
5692   WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
5693   frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(),
5694                                      "<html><body></body></html>", base_url);
5695   // Add an event listener for pointerdown to ensure it is not optimized out
5696   // before reaching the EventDispatcher.
5697   WebLocalFrame* frame = web_view_helper_.LocalMainFrame();
5698   frame->ExecuteScript(
5699       WebScriptSource("addEventListener('pointerdown', function() {});"));
5700 
5701   LocalFrame* main_frame = web_view->MainFrameImpl()->GetFrame();
5702   ASSERT_NE(nullptr, main_frame);
5703 
5704   Document* document = main_frame->GetDocument();
5705   ASSERT_NE(nullptr, document);
5706 
5707   base::TimeTicks start_time = test_task_runner_->NowTicks();
5708   test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(70));
5709 
5710   InteractiveDetector* interactive_detector =
5711       GetTestInteractiveDetector(*document);
5712 
5713   WebPointerEvent pointer_down(
5714       WebInputEvent::kPointerDown,
5715       WebPointerProperties(1, WebPointerProperties::PointerType::kTouch), 5, 5);
5716   pointer_down.SetTimeStamp(test_task_runner_->NowTicks());
5717   // Set this to the left button, needed for testing to behave properly.
5718   pointer_down.SetModifiers(WebInputEvent::kLeftButtonDown);
5719   pointer_down.button = WebPointerProperties::Button::kLeft;
5720   test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(50));
5721   web_view->MainFrameWidget()->HandleInputEvent(
5722       WebCoalescedInputEvent(pointer_down));
5723 
5724   // We don't know if this pointer event will result in a scroll or not, so we
5725   // can't report its delay. We don't consider a scroll to be meaningful input.
5726   EXPECT_FALSE(interactive_detector->GetFirstInputDelay().has_value());
5727 
5728   // When we receive a pointer up, we report the delay of the pointer down.
5729   WebPointerEvent pointer_up(
5730       WebInputEvent::kPointerUp,
5731       WebPointerProperties(1, WebPointerProperties::PointerType::kTouch), 5, 5);
5732   test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(60));
5733   pointer_up.SetTimeStamp(test_task_runner_->NowTicks());
5734   web_view->MainFrameWidget()->HandleInputEvent(
5735       WebCoalescedInputEvent(pointer_up));
5736 
5737   EXPECT_NEAR(50,
5738               (*interactive_detector->GetFirstInputDelay()).InMillisecondsF(),
5739               0.01);
5740   EXPECT_EQ(70, (*interactive_detector->GetFirstInputTimestamp() - start_time)
5741                     .InMillisecondsF());
5742 }
5743 
5744 // We need a way for JS to advance the mock clock. Hook into console.log, so
5745 // that logging advances the clock by |event_handling_delay| seconds.
5746 class MockClockAdvancingWebFrameClient
5747     : public frame_test_helpers::TestWebFrameClient {
5748  public:
MockClockAdvancingWebFrameClient(scoped_refptr<base::TestMockTimeTaskRunner> task_runner,base::TimeDelta event_handling_delay)5749   MockClockAdvancingWebFrameClient(
5750       scoped_refptr<base::TestMockTimeTaskRunner> task_runner,
5751       base::TimeDelta event_handling_delay)
5752       : task_runner_(std::move(task_runner)),
5753         event_handling_delay_(event_handling_delay) {}
5754   // WebLocalFrameClient overrides:
DidAddMessageToConsole(const WebConsoleMessage & message,const WebString & source_name,unsigned source_line,const WebString & stack_trace)5755   void DidAddMessageToConsole(const WebConsoleMessage& message,
5756                               const WebString& source_name,
5757                               unsigned source_line,
5758                               const WebString& stack_trace) override {
5759     task_runner_->FastForwardBy(event_handling_delay_);
5760   }
5761 
5762  private:
5763   scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
5764   base::TimeDelta event_handling_delay_;
5765 };
5766 
5767 // Check that the input delay is correctly reported to the document.
TEST_F(WebViewTest,FirstInputDelayExcludesProcessingTime)5768 TEST_F(WebViewTest, FirstInputDelayExcludesProcessingTime) {
5769   // Page load timing logic depends on the time not being zero.
5770   test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(1));
5771   MockClockAdvancingWebFrameClient frame_client(
5772       test_task_runner_, base::TimeDelta::FromMilliseconds(6000));
5773   WebViewImpl* web_view = web_view_helper_.Initialize(&frame_client);
5774   WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
5775   frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(),
5776                                      "<html><body></body></html>", base_url,
5777                                      test_task_runner_->GetMockTickClock());
5778 
5779   LocalFrame* main_frame = web_view->MainFrameImpl()->GetFrame();
5780   ASSERT_NE(nullptr, main_frame);
5781 
5782   Document* document = main_frame->GetDocument();
5783   ASSERT_NE(nullptr, document);
5784 
5785   WebLocalFrame* frame = web_view_helper_.LocalMainFrame();
5786   // console.log will advance the mock clock.
5787   frame->ExecuteScript(
5788       WebScriptSource("document.addEventListener('keydown', "
5789                       "() => {console.log('advancing timer');})"));
5790 
5791   InteractiveDetector* interactive_detector =
5792       GetTestInteractiveDetector(*document);
5793 
5794   WebKeyboardEvent key_event(WebInputEvent::kRawKeyDown,
5795                              WebInputEvent::kNoModifiers,
5796                              WebInputEvent::GetStaticTimeStampForTests());
5797   key_event.dom_key = ui::DomKey::FromCharacter(' ');
5798   key_event.windows_key_code = VKEY_SPACE;
5799   key_event.SetTimeStamp(test_task_runner_->NowTicks());
5800 
5801   test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(5000));
5802 
5803   web_view->MainFrameWidget()->HandleInputEvent(
5804       WebCoalescedInputEvent(key_event));
5805 
5806   EXPECT_TRUE(interactive_detector->GetFirstInputDelay().has_value());
5807   base::TimeDelta first_input_delay =
5808       *interactive_detector->GetFirstInputDelay();
5809   EXPECT_EQ(5000, first_input_delay.InMillisecondsF());
5810 
5811   web_view_helper_.Reset();  // Remove dependency on locally scoped client.
5812 }
5813 
5814 // Check that the longest input delay is correctly reported to the document.
TEST_F(WebViewTest,LongestInputDelayExcludesProcessingTime)5815 TEST_F(WebViewTest, LongestInputDelayExcludesProcessingTime) {
5816   // Page load timing logic depends on the time not being zero.
5817   test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(1));
5818   MockClockAdvancingWebFrameClient frame_client(
5819       test_task_runner_, base::TimeDelta::FromMilliseconds(6000));
5820   WebViewImpl* web_view = web_view_helper_.Initialize(&frame_client);
5821   WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
5822   frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(),
5823                                      "<html><body></body></html>", base_url);
5824 
5825   LocalFrame* main_frame = web_view->MainFrameImpl()->GetFrame();
5826   ASSERT_NE(nullptr, main_frame);
5827 
5828   Document* document = main_frame->GetDocument();
5829   ASSERT_NE(nullptr, document);
5830 
5831   WebLocalFrame* frame = web_view_helper_.LocalMainFrame();
5832   // console.log will advance the mock clock.
5833   frame->ExecuteScript(
5834       WebScriptSource("document.addEventListener('keydown', "
5835                       "() => {console.log('advancing timer');})"));
5836 
5837   InteractiveDetector* interactive_detector =
5838       GetTestInteractiveDetector(*document);
5839 
5840   WebKeyboardEvent key_event(WebInputEvent::kRawKeyDown,
5841                              WebInputEvent::kNoModifiers,
5842                              WebInputEvent::GetStaticTimeStampForTests());
5843   key_event.dom_key = ui::DomKey::FromCharacter(' ');
5844   key_event.windows_key_code = VKEY_SPACE;
5845   key_event.SetTimeStamp(test_task_runner_->NowTicks());
5846 
5847   test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(5000));
5848 
5849   web_view->MainFrameWidget()->HandleInputEvent(
5850       WebCoalescedInputEvent(key_event));
5851 
5852   base::TimeDelta longest_input_delay =
5853       *interactive_detector->GetLongestInputDelay();
5854   EXPECT_EQ(5000, longest_input_delay.InMillisecondsF());
5855 
5856   web_view_helper_.Reset();  // Remove dependency on locally scoped client.
5857 }
5858 
TEST_F(WebViewTest,RootLayerAttachment)5859 TEST_F(WebViewTest, RootLayerAttachment) {
5860   WebView* web_view = web_view_helper_.InitializeAndLoad("about:blank");
5861 
5862   // Do a lifecycle update that includes compositing but not paint. Hit test
5863   // events are an example of a real case where this occurs
5864   // (see: WebViewTest::ClientTapHandling).
5865   web_view->MainFrameWidget()->UpdateLifecycle(WebLifecycleUpdate::kPrePaint,
5866                                                DocumentUpdateReason::kTest);
5867 
5868   // Layers (including the root layer) should not be attached until the paint
5869   // lifecycle phase.
5870   cc::LayerTreeHost* layer_tree_host = web_view_helper_.GetLayerTreeHost();
5871   EXPECT_FALSE(layer_tree_host->root_layer());
5872 
5873   // Do a full lifecycle update and ensure that the root layer has been added.
5874   web_view->MainFrameWidget()->UpdateLifecycle(WebLifecycleUpdate::kAll,
5875                                                DocumentUpdateReason::kTest);
5876   EXPECT_TRUE(layer_tree_host->root_layer());
5877 }
5878 
5879 // Verifies that we emit Blink.UseCounter.FeaturePolicy.PotentialAnimation for
5880 // CSS and JS animations in a document.
TEST_F(WebViewTest,PotentialViolationReportsForLayoutAnimations)5881 TEST_F(WebViewTest, PotentialViolationReportsForLayoutAnimations) {
5882   const char* kHistogramName =
5883       "Blink.UseCounter.FeaturePolicy.PotentialViolation";
5884   WebViewImpl* web_view = web_view_helper_.Initialize();
5885   // A page with non-violating animation does not generate report.
5886   WebURL base_url_no_violation =
5887       url_test_helpers::ToKURL("http://good-css.example.com/");
5888   frame_test_helpers::LoadHTMLString(
5889       web_view->MainFrameImpl(),
5890       "<html><head><style>@keyframes foo {from "
5891       "{color: blue;} to {color: red}}</style></head></html>",
5892       base_url_no_violation);
5893   HistogramTester histogram_tester;
5894   histogram_tester.ExpectTotalCount(kHistogramName, 0);
5895   // Page with 2 potential (CSS) layout-animation violations.
5896   WebURL base_url_css_violations =
5897       url_test_helpers::ToKURL("http://bad-css.example.com/");
5898   frame_test_helpers::LoadHTMLString(
5899       web_view->MainFrameImpl(),
5900       "<html><head><style>@keyframes bar {"
5901       "from{height: 100px;} to {height: 200px;}}"
5902       "@keyframes baz {from{top: 100px;} to {top: 200px;}}"
5903       "</style></head></html>",
5904       base_url_css_violations);
5905   histogram_tester.ExpectTotalCount(kHistogramName, 1);
5906   // Page with a JS layout-animations violation.
5907   WebURL base_url_js_violations =
5908       url_test_helpers::ToKURL("http://js.example.com/");
5909   frame_test_helpers::LoadHTMLString(
5910       web_view->MainFrameImpl(),
5911       "<html><body><div></div><script>document.body.firstChild.animate("
5912       "{top: '100px'});</script></body></html>",
5913       base_url_js_violations);
5914   histogram_tester.ExpectTotalCount(kHistogramName, 2);
5915 }
5916 
TEST_F(WebViewTest,ForceDarkModeInvalidatesPaint)5917 TEST_F(WebViewTest, ForceDarkModeInvalidatesPaint) {
5918   WebViewImpl* web_view = web_view_helper_.Initialize();
5919   web_view->MainFrameWidget()->Resize(WebSize(500, 500));
5920   UpdateAllLifecyclePhases();
5921 
5922   Document* document = web_view->MainFrameImpl()->GetFrame()->GetDocument();
5923   ASSERT_TRUE(document);
5924   web_view->GetSettings()->SetForceDarkModeEnabled(true);
5925   EXPECT_TRUE(document->GetLayoutView()->ShouldDoFullPaintInvalidation());
5926 }
5927 
5928 // Regression test for https://crbug.com/1012068
TEST_F(WebViewTest,LongPressImageAndThenLongTapImage)5929 TEST_F(WebViewTest, LongPressImageAndThenLongTapImage) {
5930   RegisterMockedHttpURLLoad("long_press_image.html");
5931 
5932   WebViewImpl* web_view =
5933       web_view_helper_.InitializeAndLoad(base_url_ + "long_press_image.html");
5934   web_view->SettingsImpl()->SetAlwaysShowContextMenuOnTouch(false);
5935   web_view->MainFrameWidget()->Resize(WebSize(500, 300));
5936   UpdateAllLifecyclePhases();
5937   RunPendingTasks();
5938 
5939   WebGestureEvent event(WebInputEvent::kGestureLongPress,
5940                         WebInputEvent::kNoModifiers,
5941                         WebInputEvent::GetStaticTimeStampForTests(),
5942                         WebGestureDevice::kTouchscreen);
5943   event.SetPositionInWidget(gfx::PointF(10, 10));
5944 
5945   EXPECT_EQ(WebInputEventResult::kHandledSystem,
5946             web_view->MainFrameWidget()->HandleInputEvent(
5947                 WebCoalescedInputEvent(event)));
5948   EXPECT_TRUE(
5949       web_view->AsView()
5950           .page->GetContextMenuController()
5951           .ContextMenuNodeForFrame(web_view->MainFrameImpl()->GetFrame()));
5952 
5953   WebGestureEvent tap_event(WebInputEvent::kGestureLongTap,
5954                             WebInputEvent::kNoModifiers,
5955                             WebInputEvent::GetStaticTimeStampForTests(),
5956                             WebGestureDevice::kTouchscreen);
5957   tap_event.SetPositionInWidget(gfx::PointF(10, 10));
5958 
5959   EXPECT_EQ(WebInputEventResult::kNotHandled,
5960             web_view->MainFrameWidget()->HandleInputEvent(
5961                 WebCoalescedInputEvent(tap_event)));
5962   EXPECT_TRUE(
5963       web_view->AsView()
5964           .page->GetContextMenuController()
5965           .ContextMenuNodeForFrame(web_view->MainFrameImpl()->GetFrame()));
5966 }
5967 
5968 }  // namespace blink
5969