1 /*
2  * Copyright (C) 2010 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_frame.h"
32 
33 #include <initializer_list>
34 #include <limits>
35 #include <memory>
36 
37 #include "base/callback_helpers.h"
38 #include "base/optional.h"
39 #include "base/stl_util.h"
40 #include "base/unguessable_token.h"
41 #include "build/build_config.h"
42 #include "build/chromeos_buildflags.h"
43 #include "cc/input/overscroll_behavior.h"
44 #include "cc/layers/picture_layer.h"
45 #include "cc/paint/paint_op_buffer.h"
46 #include "cc/trees/layer_tree_host.h"
47 #include "cc/trees/scroll_node.h"
48 #include "mojo/public/cpp/bindings/pending_remote.h"
49 #include "mojo/public/cpp/bindings/receiver.h"
50 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
51 #include "mojo/public/cpp/system/data_pipe_drainer.h"
52 #include "mojo/public/cpp/system/data_pipe_utils.h"
53 #include "skia/public/mojom/skcolor.mojom-blink.h"
54 #include "testing/gmock/include/gmock/gmock.h"
55 #include "testing/gtest/include/gtest/gtest.h"
56 #include "third_party/blink/public/common/browser_interface_broker_proxy.h"
57 #include "third_party/blink/public/common/context_menu_data/edit_flags.h"
58 #include "third_party/blink/public/common/input/web_coalesced_input_event.h"
59 #include "third_party/blink/public/common/input/web_keyboard_event.h"
60 #include "third_party/blink/public/common/loader/referrer_utils.h"
61 #include "third_party/blink/public/common/messaging/transferable_message.h"
62 #include "third_party/blink/public/common/page/launching_process_state.h"
63 #include "third_party/blink/public/common/widget/device_emulation_params.h"
64 #include "third_party/blink/public/mojom/blob/blob.mojom-blink.h"
65 #include "third_party/blink/public/mojom/blob/data_element.mojom-blink.h"
66 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
67 #include "third_party/blink/public/mojom/frame/find_in_page.mojom-blink.h"
68 #include "third_party/blink/public/mojom/frame/frame_owner_element_type.mojom-blink.h"
69 #include "third_party/blink/public/mojom/frame/viewport_intersection_state.mojom-blink.h"
70 #include "third_party/blink/public/mojom/page_state/page_state.mojom-blink.h"
71 #include "third_party/blink/public/mojom/scroll/scrollbar_mode.mojom-blink.h"
72 #include "third_party/blink/public/mojom/webpreferences/web_preferences.mojom-blink.h"
73 #include "third_party/blink/public/platform/web_cache.h"
74 #include "third_party/blink/public/platform/web_security_origin.h"
75 #include "third_party/blink/public/platform/web_url.h"
76 #include "third_party/blink/public/platform/web_url_loader_client.h"
77 #include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
78 #include "third_party/blink/public/platform/web_url_response.h"
79 #include "third_party/blink/public/web/web_console_message.h"
80 #include "third_party/blink/public/web/web_context_menu_data.h"
81 #include "third_party/blink/public/web/web_document.h"
82 #include "third_party/blink/public/web/web_document_loader.h"
83 #include "third_party/blink/public/web/web_form_element.h"
84 #include "third_party/blink/public/web/web_frame_content_dumper.h"
85 #include "third_party/blink/public/web/web_frame_widget.h"
86 #include "third_party/blink/public/web/web_history_item.h"
87 #include "third_party/blink/public/web/web_local_frame.h"
88 #include "third_party/blink/public/web/web_local_frame_client.h"
89 #include "third_party/blink/public/web/web_navigation_timings.h"
90 #include "third_party/blink/public/web/web_print_page_description.h"
91 #include "third_party/blink/public/web/web_print_params.h"
92 #include "third_party/blink/public/web/web_range.h"
93 #include "third_party/blink/public/web/web_remote_frame.h"
94 #include "third_party/blink/public/web/web_script_execution_callback.h"
95 #include "third_party/blink/public/web/web_script_source.h"
96 #include "third_party/blink/public/web/web_searchable_form_data.h"
97 #include "third_party/blink/public/web/web_security_policy.h"
98 #include "third_party/blink/public/web/web_settings.h"
99 #include "third_party/blink/public/web/web_text_check_client.h"
100 #include "third_party/blink/public/web/web_text_checking_completion.h"
101 #include "third_party/blink/public/web/web_text_checking_result.h"
102 #include "third_party/blink/public/web/web_view_client.h"
103 #include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
104 #include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value_factory.h"
105 #include "third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer.h"
106 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
107 #include "third_party/blink/renderer/bindings/core/v8/v8_node.h"
108 #include "third_party/blink/renderer/bindings/core/v8/v8_pointer_event_init.h"
109 #include "third_party/blink/renderer/core/clipboard/data_transfer.h"
110 #include "third_party/blink/renderer/core/clipboard/system_clipboard.h"
111 #include "third_party/blink/renderer/core/css/css_page_rule.h"
112 #include "third_party/blink/renderer/core/css/media_values.h"
113 #include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
114 #include "third_party/blink/renderer/core/css/resolver/viewport_style_resolver.h"
115 #include "third_party/blink/renderer/core/css/style_sheet_contents.h"
116 #include "third_party/blink/renderer/core/dom/document.h"
117 #include "third_party/blink/renderer/core/dom/node_computed_style.h"
118 #include "third_party/blink/renderer/core/dom/range.h"
119 #include "third_party/blink/renderer/core/editing/editor.h"
120 #include "third_party/blink/renderer/core/editing/ephemeral_range.h"
121 #include "third_party/blink/renderer/core/editing/finder/text_finder.h"
122 #include "third_party/blink/renderer/core/editing/frame_selection.h"
123 #include "third_party/blink/renderer/core/editing/markers/document_marker_controller.h"
124 #include "third_party/blink/renderer/core/editing/selection_template.h"
125 #include "third_party/blink/renderer/core/editing/spellcheck/idle_spell_check_controller.h"
126 #include "third_party/blink/renderer/core/editing/spellcheck/spell_checker.h"
127 #include "third_party/blink/renderer/core/events/message_event.h"
128 #include "third_party/blink/renderer/core/events/mouse_event.h"
129 #include "third_party/blink/renderer/core/exported/web_view_impl.h"
130 #include "third_party/blink/renderer/core/frame/browser_controls.h"
131 #include "third_party/blink/renderer/core/frame/event_handler_registry.h"
132 #include "third_party/blink/renderer/core/frame/find_in_page.h"
133 #include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
134 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
135 #include "third_party/blink/renderer/core/frame/local_frame.h"
136 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
137 #include "third_party/blink/renderer/core/frame/remote_frame.h"
138 #include "third_party/blink/renderer/core/frame/settings.h"
139 #include "third_party/blink/renderer/core/frame/viewport_data.h"
140 #include "third_party/blink/renderer/core/frame/visual_viewport.h"
141 #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
142 #include "third_party/blink/renderer/core/frame/web_remote_frame_impl.h"
143 #include "third_party/blink/renderer/core/frame/web_view_frame_widget.h"
144 #include "third_party/blink/renderer/core/fullscreen/fullscreen.h"
145 #include "third_party/blink/renderer/core/geometry/dom_rect.h"
146 #include "third_party/blink/renderer/core/html/forms/html_form_element.h"
147 #include "third_party/blink/renderer/core/html/forms/html_input_element.h"
148 #include "third_party/blink/renderer/core/html/html_body_element.h"
149 #include "third_party/blink/renderer/core/html/html_iframe_element.h"
150 #include "third_party/blink/renderer/core/html/image_document.h"
151 #include "third_party/blink/renderer/core/html/media/html_video_element.h"
152 #include "third_party/blink/renderer/core/input/event_handler.h"
153 #include "third_party/blink/renderer/core/inspector/dev_tools_emulator.h"
154 #include "third_party/blink/renderer/core/layout/hit_test_result.h"
155 #include "third_party/blink/renderer/core/layout/layout_view.h"
156 #include "third_party/blink/renderer/core/loader/document_loader.h"
157 #include "third_party/blink/renderer/core/loader/frame_load_request.h"
158 #include "third_party/blink/renderer/core/messaging/blink_transferable_message.h"
159 #include "third_party/blink/renderer/core/page/chrome_client.h"
160 #include "third_party/blink/renderer/core/page/drag_image.h"
161 #include "third_party/blink/renderer/core/page/page.h"
162 #include "third_party/blink/renderer/core/page/scoped_page_pauser.h"
163 #include "third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller.h"
164 #include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
165 #include "third_party/blink/renderer/core/paint/paint_layer.h"
166 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
167 #include "third_party/blink/renderer/core/scroll/scrollbar.h"
168 #include "third_party/blink/renderer/core/scroll/scrollbar_test_suite.h"
169 #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
170 #include "third_party/blink/renderer/core/testing/fake_local_frame_host.h"
171 #include "third_party/blink/renderer/core/testing/fake_remote_frame_host.h"
172 #include "third_party/blink/renderer/core/testing/fake_remote_main_frame_host.h"
173 #include "third_party/blink/renderer/core/testing/mock_clipboard_host.h"
174 #include "third_party/blink/renderer/core/testing/null_execution_context.h"
175 #include "third_party/blink/renderer/core/testing/page_test_base.h"
176 #include "third_party/blink/renderer/core/testing/scoped_fake_plugin_registry.h"
177 #include "third_party/blink/renderer/core/testing/sim/sim_request.h"
178 #include "third_party/blink/renderer/core/testing/sim/sim_test.h"
179 #include "third_party/blink/renderer/platform/bindings/microtask.h"
180 #include "third_party/blink/renderer/platform/blob/testing/fake_blob.h"
181 #include "third_party/blink/renderer/platform/exported/wrapped_resource_request.h"
182 #include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
183 #include "third_party/blink/renderer/platform/keyboard_codes.h"
184 #include "third_party/blink/renderer/platform/loader/fetch/raw_resource.h"
185 #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
186 #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h"
187 #include "third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h"
188 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
189 #include "third_party/blink/renderer/platform/scheduler/public/thread.h"
190 #include "third_party/blink/renderer/platform/testing/find_cc_layer.h"
191 #include "third_party/blink/renderer/platform/testing/histogram_tester.h"
192 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
193 #include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
194 #include "third_party/blink/renderer/platform/weborigin/kurl_hash.h"
195 #include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
196 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
197 #include "third_party/blink/renderer/platform/wtf/forward.h"
198 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
199 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
200 #include "ui/base/ime/mojom/text_input_state.mojom-blink.h"
201 #include "ui/base/mojom/ui_base_types.mojom-shared.h"
202 #include "ui/events/keycodes/dom/dom_key.h"
203 #include "ui/gfx/transform.h"
204 #include "v8/include/v8.h"
205 
206 using blink::mojom::SelectionMenuBehavior;
207 using blink::test::RunPendingTasks;
208 using blink::url_test_helpers::ToKURL;
209 using testing::_;
210 using testing::ElementsAre;
211 using testing::Mock;
212 
213 namespace blink {
214 
215 namespace {
216 
GetScrollNode(const cc::Layer * layer)217 const cc::ScrollNode* GetScrollNode(const cc::Layer* layer) {
218   return layer->layer_tree_host()
219       ->property_trees()
220       ->scroll_tree.FindNodeFromElementId(layer->element_id());
221 }
222 
GetHTMLStringForReferrerPolicy(const std::string & meta_policy,const std::string & referrer_policy)223 std::string GetHTMLStringForReferrerPolicy(const std::string& meta_policy,
224                                            const std::string& referrer_policy) {
225   std::string meta_tag =
226       meta_policy.empty()
227           ? ""
228           : base::StringPrintf("<meta name='referrer' content='%s'>",
229                                meta_policy.c_str());
230   std::string referrer_policy_attr =
231       referrer_policy.empty()
232           ? ""
233           : base::StringPrintf("referrerpolicy='%s'", referrer_policy.c_str());
234   return base::StringPrintf(
235       "<!DOCTYPE html>"
236       "%s"
237       "<a id='dl' href='download_test' download='foo' %s>Click me</a>"
238       "<script>"
239       "(function () {"
240       "  var evt = document.createEvent('MouseEvent');"
241       "  evt.initMouseEvent('click', true, true);"
242       "  document.getElementById('dl').dispatchEvent(evt);"
243       "})();"
244       "</script>",
245       meta_tag.c_str(), referrer_policy_attr.c_str());
246 }
247 }  // namespace
248 
249 const int kTouchPointPadding = 32;
250 
251 const cc::OverscrollBehavior kOverscrollBehaviorAuto =
252     cc::OverscrollBehavior(cc::OverscrollBehavior::Type::kAuto);
253 
254 const cc::OverscrollBehavior kOverscrollBehaviorContain =
255     cc::OverscrollBehavior(cc::OverscrollBehavior::Type::kContain);
256 
257 const cc::OverscrollBehavior kOverscrollBehaviorNone =
258     cc::OverscrollBehavior(cc::OverscrollBehavior::Type::kNone);
259 
260 class WebFrameTest : public testing::Test {
261  protected:
WebFrameTest()262   WebFrameTest()
263       : base_url_("http://internal.test/"),
264         not_base_url_("http://external.test/"),
265         chrome_url_("chrome://") {}
266 
~WebFrameTest()267   ~WebFrameTest() override {
268     url_test_helpers::UnregisterAllURLsAndClearMemoryCache();
269   }
270 
DisableRendererSchedulerThrottling()271   void DisableRendererSchedulerThrottling() {
272     // Make sure that the RendererScheduler is foregrounded to avoid getting
273     // throttled.
274     if (kLaunchingProcessIsBackgrounded) {
275       ThreadScheduler::Current()
276           ->GetWebMainThreadSchedulerForTest()
277           ->SetRendererBackgrounded(false);
278     }
279   }
280 
RegisterMockedHttpURLLoad(const std::string & file_name)281   void RegisterMockedHttpURLLoad(const std::string& file_name) {
282     // TODO(crbug.com/751425): We should use the mock functionality
283     // via the WebViewHelper instance in each test case.
284     RegisterMockedURLLoadFromBase(base_url_, file_name);
285   }
286 
RegisterMockedChromeURLLoad(const std::string & file_name)287   void RegisterMockedChromeURLLoad(const std::string& file_name) {
288     // TODO(crbug.com/751425): We should use the mock functionality
289     // via the WebViewHelper instance in each test case.
290     RegisterMockedURLLoadFromBase(chrome_url_, file_name);
291   }
292 
RegisterMockedURLLoadFromBase(const std::string & base_url,const std::string & file_name)293   void RegisterMockedURLLoadFromBase(const std::string& base_url,
294                                      const std::string& file_name) {
295     // TODO(crbug.com/751425): We should use the mock functionality
296     // via the WebViewHelper instance in each test case.
297     url_test_helpers::RegisterMockedURLLoadFromBase(
298         WebString::FromUTF8(base_url), test::CoreTestDataPath(),
299         WebString::FromUTF8(file_name));
300   }
301 
RegisterMockedURLLoadWithCustomResponse(const WebURL & full_url,const WebString & file_path,WebURLResponse response)302   void RegisterMockedURLLoadWithCustomResponse(const WebURL& full_url,
303                                                const WebString& file_path,
304                                                WebURLResponse response) {
305     url_test_helpers::RegisterMockedURLLoadWithCustomResponse(
306         full_url, file_path, response);
307   }
308 
RegisterMockedHttpURLLoadWithCSP(const std::string & file_name,const std::string & csp,bool report_only=false)309   void RegisterMockedHttpURLLoadWithCSP(const std::string& file_name,
310                                         const std::string& csp,
311                                         bool report_only = false) {
312     WebURLResponse response;
313     response.SetMimeType("text/html");
314     response.AddHttpHeaderField(
315         report_only ? WebString("Content-Security-Policy-Report-Only")
316                     : WebString("Content-Security-Policy"),
317         WebString::FromUTF8(csp));
318     std::string full_string = base_url_ + file_name;
319     RegisterMockedURLLoadWithCustomResponse(
320         ToKURL(full_string),
321         test::CoreTestDataPath(WebString::FromUTF8(file_name)), response);
322   }
323 
RegisterMockedHttpURLLoadWithMimeType(const std::string & file_name,const std::string & mime_type)324   void RegisterMockedHttpURLLoadWithMimeType(const std::string& file_name,
325                                              const std::string& mime_type) {
326     // TODO(crbug.com/751425): We should use the mock functionality
327     // via the WebViewHelper instance in each test case.
328     url_test_helpers::RegisterMockedURLLoadFromBase(
329         WebString::FromUTF8(base_url_), test::CoreTestDataPath(),
330         WebString::FromUTF8(file_name), WebString::FromUTF8(mime_type));
331   }
332 
ConfigureCompositingWebView(WebSettings * settings)333   static void ConfigureCompositingWebView(WebSettings* settings) {
334     settings->SetPreferCompositingToLCDTextEnabled(true);
335   }
336 
ConfigureAndroid(WebSettings * settings)337   static void ConfigureAndroid(WebSettings* settings) {
338     settings->SetViewportMetaEnabled(true);
339     settings->SetViewportEnabled(true);
340     settings->SetMainFrameResizesAreOrientationChanges(true);
341     settings->SetShrinksViewportContentToFit(true);
342     settings->SetViewportStyle(mojom::blink::ViewportStyle::kMobile);
343   }
344 
ConfigureLoadsImagesAutomatically(WebSettings * settings)345   static void ConfigureLoadsImagesAutomatically(WebSettings* settings) {
346     settings->SetLoadsImagesAutomatically(true);
347   }
348 
InitializeTextSelectionWebView(const std::string & url,frame_test_helpers::WebViewHelper * web_view_helper)349   void InitializeTextSelectionWebView(
350       const std::string& url,
351       frame_test_helpers::WebViewHelper* web_view_helper) {
352     web_view_helper->InitializeAndLoad(url);
353     web_view_helper->GetWebView()->GetSettings()->SetDefaultFontSize(12);
354     web_view_helper->Resize(gfx::Size(640, 480));
355   }
356 
NodeImageTestSetup(frame_test_helpers::WebViewHelper * web_view_helper,const std::string & testcase)357   std::unique_ptr<DragImage> NodeImageTestSetup(
358       frame_test_helpers::WebViewHelper* web_view_helper,
359       const std::string& testcase) {
360     RegisterMockedHttpURLLoad("nodeimage.html");
361     web_view_helper->InitializeAndLoad(base_url_ + "nodeimage.html");
362     web_view_helper->Resize(gfx::Size(640, 480));
363     auto* frame =
364         To<LocalFrame>(web_view_helper->GetWebView()->GetPage()->MainFrame());
365     DCHECK(frame);
366     Element* element = frame->GetDocument()->getElementById(testcase.c_str());
367     return DataTransfer::NodeImage(*frame, *element);
368   }
369 
RemoveElementById(WebLocalFrameImpl * frame,const AtomicString & id)370   void RemoveElementById(WebLocalFrameImpl* frame, const AtomicString& id) {
371     Element* element = frame->GetFrame()->GetDocument()->getElementById(id);
372     DCHECK(element);
373     element->remove();
374   }
375 
376   // Both sets the inner html and runs the document lifecycle.
InitializeWithHTML(LocalFrame & frame,const String & html_content)377   void InitializeWithHTML(LocalFrame& frame, const String& html_content) {
378     frame.GetDocument()->body()->setInnerHTML(html_content);
379     frame.GetDocument()->View()->UpdateAllLifecyclePhasesForTest();
380   }
381 
382   void SwapAndVerifyFirstChildConsistency(const char* const message,
383                                           WebFrame* parent,
384                                           WebFrame* new_child);
385   void SwapAndVerifyMiddleChildConsistency(const char* const message,
386                                            WebFrame* parent,
387                                            WebFrame* new_child);
388   void SwapAndVerifyLastChildConsistency(const char* const message,
389                                          WebFrame* parent,
390                                          WebFrame* new_child);
391   void SwapAndVerifySubframeConsistency(const char* const message,
392                                         WebFrame* parent,
393                                         WebFrame* new_child);
394 
NumMarkersInRange(const Document * document,const EphemeralRange & range,DocumentMarker::MarkerTypes marker_types)395   int NumMarkersInRange(const Document* document,
396                         const EphemeralRange& range,
397                         DocumentMarker::MarkerTypes marker_types) {
398     Node* start_container = range.StartPosition().ComputeContainerNode();
399     unsigned start_offset = static_cast<unsigned>(
400         range.StartPosition().ComputeOffsetInContainerNode());
401 
402     Node* end_container = range.EndPosition().ComputeContainerNode();
403     unsigned end_offset = static_cast<unsigned>(
404         range.EndPosition().ComputeOffsetInContainerNode());
405 
406     int node_count = 0;
407     for (Node& node : range.Nodes()) {
408       const DocumentMarkerVector& markers_in_node =
409           document->Markers().MarkersFor(To<Text>(node), marker_types);
410       node_count += std::count_if(
411           markers_in_node.begin(), markers_in_node.end(),
412           [start_offset, end_offset, &node, &start_container,
413            &end_container](const DocumentMarker* marker) {
414             if (node == start_container && marker->EndOffset() <= start_offset)
415               return false;
416             if (node == end_container && marker->StartOffset() >= end_offset)
417               return false;
418             return true;
419           });
420     }
421 
422     return node_count;
423   }
424 
UpdateAllLifecyclePhases(WebViewImpl * web_view)425   void UpdateAllLifecyclePhases(WebViewImpl* web_view) {
426     web_view->MainFrameWidget()->UpdateAllLifecyclePhases(
427         DocumentUpdateReason::kTest);
428   }
429 
GetElementAndCaretBoundsForFocusedEditableElement(frame_test_helpers::WebViewHelper & helper,IntRect & element_bounds,IntRect & caret_bounds)430   static void GetElementAndCaretBoundsForFocusedEditableElement(
431       frame_test_helpers::WebViewHelper& helper,
432       IntRect& element_bounds,
433       IntRect& caret_bounds) {
434     Element* element = helper.GetWebView()->FocusedElement();
435     gfx::Rect caret_in_viewport, unused;
436     helper.GetWebView()->MainFrameViewWidget()->CalculateSelectionBounds(
437         caret_in_viewport, unused);
438     caret_bounds =
439         helper.GetWebView()->GetPage()->GetVisualViewport().ViewportToRootFrame(
440             IntRect(caret_in_viewport));
441     element_bounds = element->GetDocument().View()->ConvertToRootFrame(
442         PixelSnappedIntRect(element->Node::BoundingBox()));
443   }
444 
445   std::string base_url_;
446   std::string not_base_url_;
447   std::string chrome_url_;
448 };
449 
TEST_F(WebFrameTest,ContentText)450 TEST_F(WebFrameTest, ContentText) {
451   RegisterMockedHttpURLLoad("iframes_test.html");
452   RegisterMockedHttpURLLoad("visible_iframe.html");
453   RegisterMockedHttpURLLoad("invisible_iframe.html");
454   RegisterMockedHttpURLLoad("zero_sized_iframe.html");
455 
456   frame_test_helpers::WebViewHelper web_view_helper;
457   web_view_helper.InitializeAndLoad(base_url_ + "iframes_test.html");
458 
459   // Now retrieve the frames text and test it only includes visible elements.
460   std::string content = WebFrameContentDumper::DumpWebViewAsText(
461                             web_view_helper.GetWebView(), 1024)
462                             .Utf8();
463   EXPECT_NE(std::string::npos, content.find(" visible paragraph"));
464   EXPECT_NE(std::string::npos, content.find(" visible iframe"));
465   EXPECT_EQ(std::string::npos, content.find(" invisible pararaph"));
466   EXPECT_EQ(std::string::npos, content.find(" invisible iframe"));
467   EXPECT_EQ(std::string::npos, content.find("iframe with zero size"));
468 }
469 
TEST_F(WebFrameTest,FrameForEnteredContext)470 TEST_F(WebFrameTest, FrameForEnteredContext) {
471   RegisterMockedHttpURLLoad("iframes_test.html");
472   RegisterMockedHttpURLLoad("visible_iframe.html");
473   RegisterMockedHttpURLLoad("invisible_iframe.html");
474   RegisterMockedHttpURLLoad("zero_sized_iframe.html");
475 
476   frame_test_helpers::WebViewHelper web_view_helper;
477   web_view_helper.InitializeAndLoad(base_url_ + "iframes_test.html");
478 
479   v8::HandleScope scope(v8::Isolate::GetCurrent());
480   EXPECT_EQ(web_view_helper.GetWebView()->MainFrame(),
481             WebLocalFrame::FrameForContext(web_view_helper.GetWebView()
482                                                ->MainFrameImpl()
483                                                ->MainWorldScriptContext()));
484   EXPECT_EQ(web_view_helper.GetWebView()->MainFrame()->FirstChild(),
485             WebLocalFrame::FrameForContext(web_view_helper.GetWebView()
486                                                ->MainFrame()
487                                                ->FirstChild()
488                                                ->ToWebLocalFrame()
489                                                ->MainWorldScriptContext()));
490 }
491 
492 class ScriptExecutionCallbackHelper : public WebScriptExecutionCallback {
493  public:
ScriptExecutionCallbackHelper(v8::Local<v8::Context> context)494   explicit ScriptExecutionCallbackHelper(v8::Local<v8::Context> context)
495       : did_complete_(false), bool_value_(false), context_(context) {}
496   ~ScriptExecutionCallbackHelper() override = default;
497 
DidComplete() const498   bool DidComplete() const { return did_complete_; }
StringValue() const499   const String& StringValue() const { return string_value_; }
BoolValue()500   bool BoolValue() { return bool_value_; }
501 
502  private:
503   // WebScriptExecutionCallback:
Completed(const WebVector<v8::Local<v8::Value>> & values)504   void Completed(const WebVector<v8::Local<v8::Value>>& values) override {
505     did_complete_ = true;
506     if (!values.empty()) {
507       if (values[0]->IsString()) {
508         string_value_ =
509             ToCoreString(values[0]->ToString(context_).ToLocalChecked());
510       } else if (values[0]->IsBoolean()) {
511         bool_value_ = values[0].As<v8::Boolean>()->Value();
512       }
513     }
514   }
515 
516   bool did_complete_;
517   String string_value_;
518   bool bool_value_;
519   v8::Local<v8::Context> context_;
520 };
521 
TEST_F(WebFrameTest,RequestExecuteScript)522 TEST_F(WebFrameTest, RequestExecuteScript) {
523   RegisterMockedHttpURLLoad("foo.html");
524 
525   frame_test_helpers::WebViewHelper web_view_helper;
526   web_view_helper.InitializeAndLoad(base_url_ + "foo.html");
527 
528   v8::HandleScope scope(v8::Isolate::GetCurrent());
529   ScriptExecutionCallbackHelper callback_helper(
530       web_view_helper.LocalMainFrame()->MainWorldScriptContext());
531   web_view_helper.GetWebView()
532       ->MainFrameImpl()
533       ->RequestExecuteScriptAndReturnValue(
534           WebScriptSource(WebString("'hello';")), false, &callback_helper);
535   RunPendingTasks();
536   EXPECT_TRUE(callback_helper.DidComplete());
537   EXPECT_EQ("hello", callback_helper.StringValue());
538 }
539 
TEST_F(WebFrameTest,SuspendedRequestExecuteScript)540 TEST_F(WebFrameTest, SuspendedRequestExecuteScript) {
541   RegisterMockedHttpURLLoad("foo.html");
542 
543   frame_test_helpers::WebViewHelper web_view_helper;
544   web_view_helper.InitializeAndLoad(base_url_ + "foo.html");
545 
546   v8::HandleScope scope(v8::Isolate::GetCurrent());
547   ScriptExecutionCallbackHelper callback_helper(
548       web_view_helper.LocalMainFrame()->MainWorldScriptContext());
549 
550   // Suspend scheduled tasks so the script doesn't run.
551   web_view_helper.GetWebView()->GetPage()->SetPaused(true);
552   web_view_helper.GetWebView()
553       ->MainFrameImpl()
554       ->RequestExecuteScriptAndReturnValue(
555           WebScriptSource(WebString("'hello';")), false, &callback_helper);
556   RunPendingTasks();
557   EXPECT_FALSE(callback_helper.DidComplete());
558 
559   web_view_helper.Reset();
560   EXPECT_TRUE(callback_helper.DidComplete());
561   EXPECT_EQ(String(), callback_helper.StringValue());
562 }
563 
TEST_F(WebFrameTest,RequestExecuteV8Function)564 TEST_F(WebFrameTest, RequestExecuteV8Function) {
565   RegisterMockedHttpURLLoad("foo.html");
566 
567   frame_test_helpers::WebViewHelper web_view_helper;
568   web_view_helper.InitializeAndLoad(base_url_ + "foo.html");
569 
570   auto callback = [](const v8::FunctionCallbackInfo<v8::Value>& info) {
571     EXPECT_EQ(2, info.Length());
572     EXPECT_TRUE(info[0]->IsUndefined());
573     info.GetReturnValue().Set(info[1]);
574   };
575 
576   v8::Isolate* isolate = v8::Isolate::GetCurrent();
577   v8::HandleScope scope(isolate);
578   v8::Local<v8::Context> context =
579       web_view_helper.LocalMainFrame()->MainWorldScriptContext();
580   ScriptExecutionCallbackHelper callback_helper(context);
581   v8::Local<v8::Function> function =
582       v8::Function::New(context, callback).ToLocalChecked();
583   v8::Local<v8::Value> args[] = {v8::Undefined(isolate),
584                                  V8String(isolate, "hello")};
585   web_view_helper.GetWebView()
586       ->MainFrame()
587       ->ToWebLocalFrame()
588       ->RequestExecuteV8Function(context, function, v8::Undefined(isolate),
589                                  base::size(args), args, &callback_helper);
590   RunPendingTasks();
591   EXPECT_TRUE(callback_helper.DidComplete());
592   EXPECT_EQ("hello", callback_helper.StringValue());
593 }
594 
TEST_F(WebFrameTest,RequestExecuteV8FunctionWhileSuspended)595 TEST_F(WebFrameTest, RequestExecuteV8FunctionWhileSuspended) {
596   DisableRendererSchedulerThrottling();
597   RegisterMockedHttpURLLoad("foo.html");
598 
599   frame_test_helpers::WebViewHelper web_view_helper;
600   web_view_helper.InitializeAndLoad(base_url_ + "foo.html");
601 
602   auto callback = [](const v8::FunctionCallbackInfo<v8::Value>& info) {
603     info.GetReturnValue().Set(V8String(info.GetIsolate(), "hello"));
604   };
605 
606   v8::HandleScope scope(v8::Isolate::GetCurrent());
607   v8::Local<v8::Context> context =
608       web_view_helper.LocalMainFrame()->MainWorldScriptContext();
609 
610   // Suspend scheduled tasks so the script doesn't run.
611   WebLocalFrameImpl* main_frame = web_view_helper.LocalMainFrame();
612   web_view_helper.GetWebView()->GetPage()->SetPaused(true);
613 
614   ScriptExecutionCallbackHelper callback_helper(context);
615   v8::Local<v8::Function> function =
616       v8::Function::New(context, callback).ToLocalChecked();
617   main_frame->RequestExecuteV8Function(context, function,
618                                        v8::Undefined(context->GetIsolate()), 0,
619                                        nullptr, &callback_helper);
620   RunPendingTasks();
621   EXPECT_FALSE(callback_helper.DidComplete());
622 
623   web_view_helper.GetWebView()->GetPage()->SetPaused(false);
624   RunPendingTasks();
625   EXPECT_TRUE(callback_helper.DidComplete());
626   EXPECT_EQ("hello", callback_helper.StringValue());
627 }
628 
TEST_F(WebFrameTest,RequestExecuteV8FunctionWhileSuspendedWithUserGesture)629 TEST_F(WebFrameTest, RequestExecuteV8FunctionWhileSuspendedWithUserGesture) {
630   DisableRendererSchedulerThrottling();
631   RegisterMockedHttpURLLoad("foo.html");
632 
633   frame_test_helpers::WebViewHelper web_view_helper;
634   web_view_helper.InitializeAndLoad(base_url_ + "foo.html");
635 
636   v8::HandleScope scope(v8::Isolate::GetCurrent());
637 
638   // Suspend scheduled tasks so the script doesn't run.
639   web_view_helper.GetWebView()->GetPage()->SetPaused(true);
640   LocalFrame::NotifyUserActivation(
641       web_view_helper.LocalMainFrame()->GetFrame(),
642       mojom::UserActivationNotificationType::kTest);
643   ScriptExecutionCallbackHelper callback_helper(
644       web_view_helper.LocalMainFrame()->MainWorldScriptContext());
645   WebScriptSource script_source("navigator.userActivation.isActive;");
646   web_view_helper.GetWebView()
647       ->MainFrameImpl()
648       ->RequestExecuteScriptAndReturnValue(script_source, false,
649                                            &callback_helper);
650   RunPendingTasks();
651   EXPECT_FALSE(callback_helper.DidComplete());
652 
653   web_view_helper.GetWebView()->GetPage()->SetPaused(false);
654   RunPendingTasks();
655   EXPECT_TRUE(callback_helper.DidComplete());
656   EXPECT_EQ(true, callback_helper.BoolValue());
657 }
658 
TEST_F(WebFrameTest,IframeScriptRemovesSelf)659 TEST_F(WebFrameTest, IframeScriptRemovesSelf) {
660   RegisterMockedHttpURLLoad("single_iframe.html");
661   RegisterMockedHttpURLLoad("visible_iframe.html");
662 
663   frame_test_helpers::WebViewHelper web_view_helper;
664   web_view_helper.InitializeAndLoad(base_url_ + "single_iframe.html");
665 
666   v8::HandleScope scope(v8::Isolate::GetCurrent());
667   ScriptExecutionCallbackHelper callback_helper(
668       web_view_helper.LocalMainFrame()->MainWorldScriptContext());
669   web_view_helper.GetWebView()
670       ->MainFrame()
671       ->FirstChild()
672       ->ToWebLocalFrame()
673       ->RequestExecuteScriptAndReturnValue(
674           WebScriptSource(WebString(
675               "var iframe = "
676               "window.top.document.getElementsByTagName('iframe')[0]; "
677               "window.top.document.body.removeChild(iframe); 'hello';")),
678           false, &callback_helper);
679   RunPendingTasks();
680   EXPECT_TRUE(callback_helper.DidComplete());
681   EXPECT_EQ(String(), callback_helper.StringValue());
682 }
683 
TEST_F(WebFrameTest,FormWithNullFrame)684 TEST_F(WebFrameTest, FormWithNullFrame) {
685   RegisterMockedHttpURLLoad("form.html");
686 
687   frame_test_helpers::WebViewHelper web_view_helper;
688   web_view_helper.InitializeAndLoad(base_url_ + "form.html");
689 
690   WebVector<WebFormElement> forms =
691       web_view_helper.LocalMainFrame()->GetDocument().Forms();
692   web_view_helper.Reset();
693 
694   EXPECT_EQ(forms.size(), 1U);
695 
696   // This test passes if this doesn't crash.
697   WebSearchableFormData searchable_data_form(forms[0]);
698 }
699 
TEST_F(WebFrameTest,ChromePageJavascript)700 TEST_F(WebFrameTest, ChromePageJavascript) {
701   RegisterMockedChromeURLLoad("history.html");
702 
703   frame_test_helpers::WebViewHelper web_view_helper;
704   web_view_helper.InitializeAndLoad(chrome_url_ + "history.html");
705 
706   // Try to run JS against the chrome-style URL.
707   frame_test_helpers::LoadFrame(web_view_helper.GetWebView()->MainFrameImpl(),
708                                 "javascript:document.body.appendChild(document."
709                                 "createTextNode('Clobbered'))");
710 
711   // Now retrieve the frame's text and ensure it was modified by running
712   // javascript.
713   std::string content = WebFrameContentDumper::DumpWebViewAsText(
714                             web_view_helper.GetWebView(), 1024)
715                             .Utf8();
716   EXPECT_NE(std::string::npos, content.find("Clobbered"));
717 }
718 
TEST_F(WebFrameTest,ChromePageNoJavascript)719 TEST_F(WebFrameTest, ChromePageNoJavascript) {
720   RegisterMockedChromeURLLoad("history.html");
721 
722   frame_test_helpers::WebViewHelper web_view_helper;
723   web_view_helper.InitializeAndLoad(chrome_url_ + "history.html");
724 
725   // Try to run JS against the chrome-style URL after prohibiting it.
726   WebSecurityPolicy::RegisterURLSchemeAsNotAllowingJavascriptURLs("chrome");
727   frame_test_helpers::LoadFrame(web_view_helper.GetWebView()->MainFrameImpl(),
728                                 "javascript:document.body.appendChild(document."
729                                 "createTextNode('Clobbered'))");
730 
731   // Now retrieve the frame's text and ensure it wasn't modified by running
732   // javascript.
733   std::string content = WebFrameContentDumper::DumpWebViewAsText(
734                             web_view_helper.GetWebView(), 1024)
735                             .Utf8();
736   EXPECT_EQ(std::string::npos, content.find("Clobbered"));
737 }
738 
TEST_F(WebFrameTest,LocationSetHostWithMissingPort)739 TEST_F(WebFrameTest, LocationSetHostWithMissingPort) {
740   std::string file_name = "print-location-href.html";
741   RegisterMockedHttpURLLoad(file_name);
742   // TODO(crbug.com/751425): We should use the mock functionality
743   // via the WebViewHelper instance in each test case.
744   RegisterMockedURLLoadFromBase("http://internal.test:0/", file_name);
745 
746   frame_test_helpers::WebViewHelper web_view_helper;
747   web_view_helper.InitializeAndLoad(base_url_ + file_name);
748 
749   // Setting host to "hostname:" should be treated as "hostname:0".
750   frame_test_helpers::LoadFrame(
751       web_view_helper.GetWebView()->MainFrameImpl(),
752       "javascript:location.host = 'internal.test:'; void 0;");
753 
754   frame_test_helpers::LoadFrame(
755       web_view_helper.GetWebView()->MainFrameImpl(),
756       "javascript:document.body.textContent = location.href; void 0;");
757 
758   std::string content = WebFrameContentDumper::DumpWebViewAsText(
759                             web_view_helper.GetWebView(), 1024)
760                             .Utf8();
761   EXPECT_EQ("http://internal.test/" + file_name, content);
762 }
763 
TEST_F(WebFrameTest,LocationSetEmptyPort)764 TEST_F(WebFrameTest, LocationSetEmptyPort) {
765   std::string file_name = "print-location-href.html";
766   RegisterMockedHttpURLLoad(file_name);
767   // TODO(crbug.com/751425): We should use the mock functionality
768   // via the WebViewHelper instance in each test case.
769   RegisterMockedURLLoadFromBase("http://internal.test:0/", file_name);
770 
771   frame_test_helpers::WebViewHelper web_view_helper;
772   web_view_helper.InitializeAndLoad(base_url_ + file_name);
773 
774   frame_test_helpers::LoadFrame(web_view_helper.GetWebView()->MainFrameImpl(),
775                                 "javascript:location.port = ''; void 0;");
776 
777   frame_test_helpers::LoadFrame(
778       web_view_helper.GetWebView()->MainFrameImpl(),
779       "javascript:document.body.textContent = location.href; void 0;");
780 
781   std::string content = WebFrameContentDumper::DumpWebViewAsText(
782                             web_view_helper.GetWebView(), 1024)
783                             .Utf8();
784   EXPECT_EQ("http://internal.test/" + file_name, content);
785 }
786 
787 class EvaluateOnLoadWebFrameClient
788     : public frame_test_helpers::TestWebFrameClient {
789  public:
EvaluateOnLoadWebFrameClient()790   EvaluateOnLoadWebFrameClient() : executing_(false), was_executed_(false) {}
791   ~EvaluateOnLoadWebFrameClient() override = default;
792 
793   // frame_test_helpers::TestWebFrameClient:
DidClearWindowObject()794   void DidClearWindowObject() override {
795     EXPECT_FALSE(executing_);
796     was_executed_ = true;
797     executing_ = true;
798     v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
799     Frame()->ExecuteScriptAndReturnValue(
800         WebScriptSource(WebString("window.someProperty = 42;")));
801     executing_ = false;
802   }
803 
804   bool executing_;
805   bool was_executed_;
806 };
807 
TEST_F(WebFrameTest,DidClearWindowObjectIsNotRecursive)808 TEST_F(WebFrameTest, DidClearWindowObjectIsNotRecursive) {
809   EvaluateOnLoadWebFrameClient web_frame_client;
810   frame_test_helpers::WebViewHelper web_view_helper;
811   web_view_helper.InitializeAndLoad("about:blank", &web_frame_client);
812   EXPECT_TRUE(web_frame_client.was_executed_);
813 }
814 
815 class CSSCallbackWebFrameClient
816     : public frame_test_helpers::TestWebFrameClient {
817  public:
CSSCallbackWebFrameClient()818   CSSCallbackWebFrameClient() : update_count_(0) {}
819   ~CSSCallbackWebFrameClient() override = default;
820 
821   // frame_test_helpers::TestWebFrameClient:
822   void DidMatchCSS(
823       const WebVector<WebString>& newly_matching_selectors,
824       const WebVector<WebString>& stopped_matching_selectors) override;
825 
MatchedSelectors()826   HashSet<String>& MatchedSelectors() {
827     auto it = matched_selectors_.find(Frame());
828     if (it != matched_selectors_.end())
829       return it->value;
830 
831     auto add_result = matched_selectors_.insert(Frame(), HashSet<String>());
832     return add_result.stored_value->value;
833   }
834 
835   HashMap<WebLocalFrame*, HashSet<String>> matched_selectors_;
836   int update_count_;
837 };
838 
DidMatchCSS(const WebVector<WebString> & newly_matching_selectors,const WebVector<WebString> & stopped_matching_selectors)839 void CSSCallbackWebFrameClient::DidMatchCSS(
840     const WebVector<WebString>& newly_matching_selectors,
841     const WebVector<WebString>& stopped_matching_selectors) {
842   ++update_count_;
843 
844   HashSet<String>& frame_selectors = MatchedSelectors();
845   for (size_t i = 0; i < newly_matching_selectors.size(); ++i) {
846     String selector = newly_matching_selectors[i];
847     EXPECT_TRUE(frame_selectors.find(selector) == frame_selectors.end())
848         << selector;
849     frame_selectors.insert(selector);
850   }
851   for (size_t i = 0; i < stopped_matching_selectors.size(); ++i) {
852     String selector = stopped_matching_selectors[i];
853     EXPECT_TRUE(frame_selectors.find(selector) != frame_selectors.end())
854         << selector;
855     frame_selectors.erase(selector);
856     EXPECT_TRUE(frame_selectors.find(selector) == frame_selectors.end())
857         << selector;
858   }
859 }
860 
861 class WebFrameCSSCallbackTest : public testing::Test {
862  protected:
WebFrameCSSCallbackTest()863   WebFrameCSSCallbackTest() {
864     frame_ = helper_.InitializeAndLoad("about:blank", &client_)
865                  ->MainFrame()
866                  ->ToWebLocalFrame();
867   }
868 
~WebFrameCSSCallbackTest()869   ~WebFrameCSSCallbackTest() override {
870     EXPECT_EQ(1U, client_.matched_selectors_.size());
871   }
872 
Doc() const873   WebDocument Doc() const { return frame_->GetDocument(); }
874 
UpdateCount() const875   int UpdateCount() const { return client_.update_count_; }
876 
MatchedSelectors()877   const HashSet<String>& MatchedSelectors() {
878     auto it = client_.matched_selectors_.find(frame_);
879     if (it != client_.matched_selectors_.end())
880       return it->value;
881 
882     auto add_result =
883         client_.matched_selectors_.insert(frame_, HashSet<String>());
884     return add_result.stored_value->value;
885   }
886 
LoadHTML(const std::string & html)887   void LoadHTML(const std::string& html) {
888     frame_test_helpers::LoadHTMLString(frame_, html, ToKURL("about:blank"));
889   }
890 
ExecuteScript(const WebString & code)891   void ExecuteScript(const WebString& code) {
892     frame_->ExecuteScript(WebScriptSource(code));
893     frame_->View()->MainFrameWidget()->UpdateAllLifecyclePhases(
894         DocumentUpdateReason::kTest);
895     RunPendingTasks();
896   }
897 
898   CSSCallbackWebFrameClient client_;
899   frame_test_helpers::WebViewHelper helper_;
900   WebLocalFrame* frame_;
901 };
902 
TEST_F(WebFrameCSSCallbackTest,AuthorStyleSheet)903 TEST_F(WebFrameCSSCallbackTest, AuthorStyleSheet) {
904   LoadHTML(
905       "<style>"
906       // This stylesheet checks that the internal property and value can't be
907       // set by a stylesheet, only WebDocument::watchCSSSelectors().
908       "div.initial_on { -internal-callback: none; }"
909       "div.initial_off { -internal-callback: -internal-presence; }"
910       "</style>"
911       "<div class=\"initial_on\"></div>"
912       "<div class=\"initial_off\"></div>");
913 
914   Vector<WebString> selectors;
915   selectors.push_back(WebString::FromUTF8("div.initial_on"));
916   frame_->GetDocument().WatchCSSSelectors(WebVector<WebString>(selectors));
917   frame_->View()->MainFrameWidget()->UpdateAllLifecyclePhases(
918       DocumentUpdateReason::kTest);
919   RunPendingTasks();
920   EXPECT_EQ(1, UpdateCount());
921   EXPECT_THAT(MatchedSelectors(), ElementsAre("div.initial_on"));
922 
923   // Check that adding a watched selector calls back for already-present nodes.
924   selectors.push_back(WebString::FromUTF8("div.initial_off"));
925   Doc().WatchCSSSelectors(WebVector<WebString>(selectors));
926   frame_->View()->MainFrameWidget()->UpdateAllLifecyclePhases(
927       DocumentUpdateReason::kTest);
928   RunPendingTasks();
929   EXPECT_EQ(2, UpdateCount());
930   EXPECT_THAT(MatchedSelectors(),
931               ElementsAre("div.initial_off", "div.initial_on"));
932 
933   // Check that we can turn off callbacks for certain selectors.
934   Doc().WatchCSSSelectors(WebVector<WebString>());
935   frame_->View()->MainFrameWidget()->UpdateAllLifecyclePhases(
936       DocumentUpdateReason::kTest);
937   RunPendingTasks();
938   EXPECT_EQ(3, UpdateCount());
939   EXPECT_THAT(MatchedSelectors(), ElementsAre());
940 }
941 
TEST_F(WebFrameCSSCallbackTest,SharedComputedStyle)942 TEST_F(WebFrameCSSCallbackTest, SharedComputedStyle) {
943   // Check that adding an element calls back when it matches an existing rule.
944   Vector<WebString> selectors;
945   selectors.push_back(WebString::FromUTF8("span"));
946   Doc().WatchCSSSelectors(WebVector<WebString>(selectors));
947 
948   ExecuteScript(
949       "i1 = document.createElement('span');"
950       "i1.id = 'first_span';"
951       "document.body.appendChild(i1)");
952   EXPECT_EQ(1, UpdateCount());
953   EXPECT_THAT(MatchedSelectors(), ElementsAre("span"));
954 
955   // Adding a second element that shares a ComputedStyle shouldn't call back.
956   // We use <span>s to avoid default style rules that can set
957   // ComputedStyle::unique().
958   ExecuteScript(
959       "i2 = document.createElement('span');"
960       "i2.id = 'second_span';"
961       "i1 = document.getElementById('first_span');"
962       "i1.parentNode.insertBefore(i2, i1.nextSibling);");
963   EXPECT_EQ(1, UpdateCount());
964   EXPECT_THAT(MatchedSelectors(), ElementsAre("span"));
965 
966   // Removing the first element shouldn't call back.
967   ExecuteScript(
968       "i1 = document.getElementById('first_span');"
969       "i1.parentNode.removeChild(i1);");
970   EXPECT_EQ(1, UpdateCount());
971   EXPECT_THAT(MatchedSelectors(), ElementsAre("span"));
972 
973   // But removing the second element *should* call back.
974   ExecuteScript(
975       "i2 = document.getElementById('second_span');"
976       "i2.parentNode.removeChild(i2);");
977   EXPECT_EQ(2, UpdateCount());
978   EXPECT_THAT(MatchedSelectors(), ElementsAre());
979 }
980 
TEST_F(WebFrameCSSCallbackTest,CatchesAttributeChange)981 TEST_F(WebFrameCSSCallbackTest, CatchesAttributeChange) {
982   LoadHTML("<span></span>");
983 
984   Vector<WebString> selectors;
985   selectors.push_back(WebString::FromUTF8("span[attr=\"value\"]"));
986   Doc().WatchCSSSelectors(WebVector<WebString>(selectors));
987   RunPendingTasks();
988 
989   EXPECT_EQ(0, UpdateCount());
990   EXPECT_THAT(MatchedSelectors(), ElementsAre());
991 
992   ExecuteScript(
993       "document.querySelector('span').setAttribute('attr', 'value');");
994   EXPECT_EQ(1, UpdateCount());
995   EXPECT_THAT(MatchedSelectors(), ElementsAre("span[attr=\"value\"]"));
996 }
997 
TEST_F(WebFrameCSSCallbackTest,DisplayNone)998 TEST_F(WebFrameCSSCallbackTest, DisplayNone) {
999   LoadHTML("<div style='display:none'><span></span></div>");
1000 
1001   Vector<WebString> selectors;
1002   selectors.push_back(WebString::FromUTF8("span"));
1003   Doc().WatchCSSSelectors(WebVector<WebString>(selectors));
1004   RunPendingTasks();
1005 
1006   EXPECT_EQ(0, UpdateCount()) << "Don't match elements in display:none trees.";
1007 
1008   ExecuteScript(
1009       "d = document.querySelector('div');"
1010       "d.style.display = 'block';");
1011   EXPECT_EQ(1, UpdateCount()) << "Match elements when they become displayed.";
1012   EXPECT_THAT(MatchedSelectors(), ElementsAre("span"));
1013 
1014   ExecuteScript(
1015       "d = document.querySelector('div');"
1016       "d.style.display = 'none';");
1017   EXPECT_EQ(2, UpdateCount())
1018       << "Unmatch elements when they become undisplayed.";
1019   EXPECT_THAT(MatchedSelectors(), ElementsAre());
1020 
1021   ExecuteScript(
1022       "s = document.querySelector('span');"
1023       "s.style.display = 'none';");
1024   EXPECT_EQ(2, UpdateCount())
1025       << "No effect from no-display'ing a span that's already undisplayed.";
1026 
1027   ExecuteScript(
1028       "d = document.querySelector('div');"
1029       "d.style.display = 'block';");
1030   EXPECT_EQ(2, UpdateCount())
1031       << "No effect from displaying a div whose span is display:none.";
1032 
1033   ExecuteScript(
1034       "s = document.querySelector('span');"
1035       "s.style.display = 'inline';");
1036   EXPECT_EQ(3, UpdateCount())
1037       << "Now the span is visible and produces a callback.";
1038   EXPECT_THAT(MatchedSelectors(), ElementsAre("span"));
1039 
1040   ExecuteScript(
1041       "s = document.querySelector('span');"
1042       "s.style.display = 'none';");
1043   EXPECT_EQ(4, UpdateCount())
1044       << "Undisplaying the span directly should produce another callback.";
1045   EXPECT_THAT(MatchedSelectors(), ElementsAre());
1046 }
1047 
TEST_F(WebFrameCSSCallbackTest,DisplayContents)1048 TEST_F(WebFrameCSSCallbackTest, DisplayContents) {
1049   LoadHTML("<div style='display:contents'><span></span></div>");
1050 
1051   Vector<WebString> selectors(1u, WebString::FromUTF8("span"));
1052   Doc().WatchCSSSelectors(WebVector<WebString>(selectors));
1053   frame_->View()->MainFrameWidget()->UpdateAllLifecyclePhases(
1054       DocumentUpdateReason::kTest);
1055   RunPendingTasks();
1056 
1057   EXPECT_EQ(1, UpdateCount()) << "Match elements in display:contents trees.";
1058   EXPECT_THAT(MatchedSelectors(), ElementsAre("span"));
1059 
1060   ExecuteScript(
1061       "s = document.querySelector('span');"
1062       "s.style.display = 'contents';");
1063   EXPECT_EQ(1, UpdateCount()) << "Match elements which are display:contents.";
1064   EXPECT_THAT(MatchedSelectors(), ElementsAre("span"));
1065 
1066   ExecuteScript(
1067       "d = document.querySelector('div');"
1068       "d.style.display = 'block';");
1069   EXPECT_EQ(1, UpdateCount())
1070       << "Still match display:contents after parent becomes display:block.";
1071   EXPECT_THAT(MatchedSelectors(), ElementsAre("span"));
1072 
1073   ExecuteScript(
1074       "d = document.querySelector('div');"
1075       "d.style.display = 'none';");
1076   EXPECT_EQ(2, UpdateCount())
1077       << "No longer matched when parent becomes display:none.";
1078   EXPECT_THAT(MatchedSelectors(), ElementsAre());
1079 }
1080 
TEST_F(WebFrameCSSCallbackTest,Reparenting)1081 TEST_F(WebFrameCSSCallbackTest, Reparenting) {
1082   LoadHTML(
1083       "<div id='d1'><span></span></div>"
1084       "<div id='d2'></div>");
1085 
1086   Vector<WebString> selectors;
1087   selectors.push_back(WebString::FromUTF8("span"));
1088   Doc().WatchCSSSelectors(WebVector<WebString>(selectors));
1089   frame_->View()->MainFrameWidget()->UpdateAllLifecyclePhases(
1090       DocumentUpdateReason::kTest);
1091   RunPendingTasks();
1092 
1093   EXPECT_EQ(1, UpdateCount());
1094   EXPECT_THAT(MatchedSelectors(), ElementsAre("span"));
1095 
1096   ExecuteScript(
1097       "s = document.querySelector('span');"
1098       "d2 = document.getElementById('d2');"
1099       "d2.appendChild(s);");
1100   EXPECT_EQ(1, UpdateCount()) << "Just moving an element that continues to "
1101                                  "match shouldn't send a spurious callback.";
1102   EXPECT_THAT(MatchedSelectors(), ElementsAre("span"));
1103 }
1104 
TEST_F(WebFrameCSSCallbackTest,MultiSelector)1105 TEST_F(WebFrameCSSCallbackTest, MultiSelector) {
1106   LoadHTML("<span></span>");
1107 
1108   // Check that selector lists match as the whole list, not as each element
1109   // independently.
1110   Vector<WebString> selectors;
1111   selectors.push_back(WebString::FromUTF8("span"));
1112   selectors.push_back(WebString::FromUTF8("span,p"));
1113   Doc().WatchCSSSelectors(WebVector<WebString>(selectors));
1114   frame_->View()->MainFrameWidget()->UpdateAllLifecyclePhases(
1115       DocumentUpdateReason::kTest);
1116   RunPendingTasks();
1117 
1118   EXPECT_EQ(1, UpdateCount());
1119   EXPECT_THAT(MatchedSelectors(), ElementsAre("span", "span, p"));
1120 }
1121 
TEST_F(WebFrameCSSCallbackTest,InvalidSelector)1122 TEST_F(WebFrameCSSCallbackTest, InvalidSelector) {
1123   LoadHTML("<p><span></span></p>");
1124 
1125   // Build a list with one valid selector and one invalid.
1126   Vector<WebString> selectors;
1127   selectors.push_back(WebString::FromUTF8("span"));
1128   selectors.push_back(WebString::FromUTF8("["));       // Invalid.
1129   selectors.push_back(WebString::FromUTF8("p span"));  // Not compound.
1130   Doc().WatchCSSSelectors(WebVector<WebString>(selectors));
1131   frame_->View()->MainFrameWidget()->UpdateAllLifecyclePhases(
1132       DocumentUpdateReason::kTest);
1133   RunPendingTasks();
1134 
1135   EXPECT_EQ(1, UpdateCount());
1136   EXPECT_THAT(MatchedSelectors(), ElementsAre("span"))
1137       << "An invalid selector shouldn't prevent other selectors from matching.";
1138 }
1139 
TEST_F(WebFrameTest,PostMessageEvent)1140 TEST_F(WebFrameTest, PostMessageEvent) {
1141   RegisterMockedHttpURLLoad("postmessage_test.html");
1142 
1143   frame_test_helpers::WebViewHelper web_view_helper;
1144   web_view_helper.InitializeAndLoad(base_url_ + "postmessage_test.html");
1145 
1146   auto* frame =
1147       To<LocalFrame>(web_view_helper.GetWebView()->GetPage()->MainFrame());
1148 
1149   scoped_refptr<SerializedScriptValue> data = SerializedScriptValue::Create();
1150   MessageEvent* message_event = MessageEvent::Create(
1151       /*ports=*/nullptr, std::move(data), "http://origin.com");
1152 
1153   // Send a message with the correct origin.
1154   scoped_refptr<SecurityOrigin> correct_origin =
1155       SecurityOrigin::Create(ToKURL(base_url_));
1156   frame->PostMessageEvent(
1157       base::nullopt, g_empty_string, correct_origin->ToString(),
1158       BlinkTransferableMessage::FromMessageEvent(message_event));
1159 
1160   // Send another message with incorrect origin.
1161   scoped_refptr<SecurityOrigin> incorrect_origin =
1162       SecurityOrigin::Create(ToKURL(chrome_url_));
1163   frame->PostMessageEvent(
1164       base::nullopt, g_empty_string, incorrect_origin->ToString(),
1165       BlinkTransferableMessage::FromMessageEvent(message_event));
1166 
1167   // Verify that only the first addition is in the body of the page.
1168   std::string content = WebFrameContentDumper::DumpWebViewAsText(
1169                             web_view_helper.GetWebView(), 1024)
1170                             .Utf8();
1171   EXPECT_NE(std::string::npos, content.find("Message 1."));
1172   EXPECT_EQ(std::string::npos, content.find("Message 2."));
1173 }
1174 
1175 namespace {
1176 
SerializeString(const StringView & message,ScriptState * script_state)1177 scoped_refptr<SerializedScriptValue> SerializeString(
1178     const StringView& message,
1179     ScriptState* script_state) {
1180   // This is inefficient, but avoids duplicating serialization logic for the
1181   // sake of this test.
1182   NonThrowableExceptionState exception_state;
1183   ScriptState::Scope scope(script_state);
1184   V8ScriptValueSerializer serializer(script_state);
1185   return serializer.Serialize(V8String(script_state->GetIsolate(), message),
1186                               exception_state);
1187 }
1188 
1189 }  // namespace
1190 
TEST_F(WebFrameTest,PostMessageThenDetach)1191 TEST_F(WebFrameTest, PostMessageThenDetach) {
1192   frame_test_helpers::WebViewHelper web_view_helper;
1193   web_view_helper.InitializeAndLoad("about:blank");
1194 
1195   auto* frame =
1196       To<LocalFrame>(web_view_helper.GetWebView()->GetPage()->MainFrame());
1197   NonThrowableExceptionState exception_state;
1198   scoped_refptr<SerializedScriptValue> message =
1199       SerializeString("message", ToScriptStateForMainWorld(frame));
1200   MessagePortArray message_ports;
1201   frame->DomWindow()->PostMessageForTesting(
1202       message, message_ports, "*", frame->DomWindow(), exception_state);
1203   web_view_helper.Reset();
1204   EXPECT_FALSE(exception_state.HadException());
1205 
1206   // Success is not crashing.
1207   RunPendingTasks();
1208 }
1209 
1210 namespace {
1211 
1212 class FixedLayoutTestWebWidgetClient
1213     : public frame_test_helpers::TestWebWidgetClient {
1214  public:
1215   FixedLayoutTestWebWidgetClient() = default;
1216   ~FixedLayoutTestWebWidgetClient() override = default;
1217 
1218   // frame_test_helpers::TestWebWidgetClient:
GetInitialScreenInfo()1219   ScreenInfo GetInitialScreenInfo() override { return screen_info_; }
1220 
1221   ScreenInfo screen_info_;
1222 };
1223 
1224 // Helper function to set autosizing multipliers on a document.
SetTextAutosizingMultiplier(Document * document,float multiplier)1225 bool SetTextAutosizingMultiplier(Document* document, float multiplier) {
1226   bool multiplier_set = false;
1227   for (LayoutObject* layout_object = document->GetLayoutView(); layout_object;
1228        layout_object = layout_object->NextInPreOrder()) {
1229     if (layout_object->Style()) {
1230       scoped_refptr<ComputedStyle> modified_style =
1231           ComputedStyle::Clone(layout_object->StyleRef());
1232       modified_style->SetTextAutosizingMultiplier(multiplier);
1233       EXPECT_EQ(multiplier, modified_style->TextAutosizingMultiplier());
1234       layout_object->SetModifiedStyleOutsideStyleRecalc(
1235           std::move(modified_style), LayoutObject::ApplyStyleChanges::kNo);
1236       multiplier_set = true;
1237     }
1238   }
1239   return multiplier_set;
1240 }
1241 
1242 // Helper function to check autosizing multipliers on a document.
CheckTextAutosizingMultiplier(Document * document,float multiplier)1243 bool CheckTextAutosizingMultiplier(Document* document, float multiplier) {
1244   bool multiplier_checked = false;
1245   for (LayoutObject* layout_object = document->GetLayoutView(); layout_object;
1246        layout_object = layout_object->NextInPreOrder()) {
1247     if (layout_object->Style() && layout_object->IsText()) {
1248       EXPECT_EQ(multiplier, layout_object->Style()->TextAutosizingMultiplier());
1249       multiplier_checked = true;
1250     }
1251   }
1252   return multiplier_checked;
1253 }
1254 
UpdateScreenInfoAndResizeView(FixedLayoutTestWebWidgetClient * client,frame_test_helpers::WebViewHelper * web_view_helper,int viewport_width,int viewport_height)1255 void UpdateScreenInfoAndResizeView(
1256     FixedLayoutTestWebWidgetClient* client,
1257     frame_test_helpers::WebViewHelper* web_view_helper,
1258     int viewport_width,
1259     int viewport_height) {
1260   client->screen_info_.rect = gfx::Rect(viewport_width, viewport_height);
1261   web_view_helper->GetWebView()->MainFrameViewWidget()->UpdateScreenInfo(
1262       client->screen_info_);
1263   web_view_helper->Resize(gfx::Size(viewport_width, viewport_height));
1264 }
1265 
1266 }  // namespace
1267 
1268 class WebFixedLayoutFrameTest : public WebFrameTest {
1269  protected:
1270   FixedLayoutTestWebWidgetClient widget_client_;
1271 };
1272 
TEST_F(WebFrameTest,ChangeInFixedLayoutResetsTextAutosizingMultipliers)1273 TEST_F(WebFrameTest, ChangeInFixedLayoutResetsTextAutosizingMultipliers) {
1274   RegisterMockedHttpURLLoad("fixed_layout.html");
1275 
1276   FixedLayoutTestWebWidgetClient client;
1277   int viewport_width = 640;
1278   int viewport_height = 480;
1279 
1280   frame_test_helpers::WebViewHelper web_view_helper;
1281   web_view_helper.InitializeAndLoad(base_url_ + "fixed_layout.html", nullptr,
1282                                     nullptr, &client, ConfigureAndroid);
1283 
1284   Document* document =
1285       To<LocalFrame>(web_view_helper.GetWebView()->GetPage()->MainFrame())
1286           ->GetDocument();
1287   document->GetSettings()->SetTextAutosizingEnabled(true);
1288   EXPECT_TRUE(document->GetSettings()->TextAutosizingEnabled());
1289   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
1290 
1291   EXPECT_TRUE(SetTextAutosizingMultiplier(document, 2));
1292 
1293   ViewportDescription description =
1294       document->GetViewportData().GetViewportDescription();
1295   // Choose a width that's not going match the viewport width of the loaded
1296   // document.
1297   description.min_width = Length::Fixed(100);
1298   description.max_width = Length::Fixed(100);
1299   web_view_helper.GetWebView()->UpdatePageDefinedViewportConstraints(
1300       description);
1301 
1302   EXPECT_TRUE(CheckTextAutosizingMultiplier(document, 1));
1303 }
1304 
TEST_F(WebFrameTest,WorkingTextAutosizingMultipliers_VirtualViewport)1305 TEST_F(WebFrameTest, WorkingTextAutosizingMultipliers_VirtualViewport) {
1306   const std::string html_file = "fixed_layout.html";
1307   RegisterMockedHttpURLLoad(html_file);
1308 
1309   FixedLayoutTestWebWidgetClient client;
1310 
1311   frame_test_helpers::WebViewHelper web_view_helper;
1312   web_view_helper.InitializeAndLoad(base_url_ + html_file, nullptr, nullptr,
1313                                     &client, ConfigureAndroid);
1314 
1315   Document* document =
1316       To<LocalFrame>(web_view_helper.GetWebView()->GetPage()->MainFrame())
1317           ->GetDocument();
1318   document->GetSettings()->SetTextAutosizingEnabled(true);
1319   EXPECT_TRUE(document->GetSettings()->TextAutosizingEnabled());
1320 
1321   web_view_helper.Resize(gfx::Size(490, 800));
1322 
1323   // Multiplier: 980 / 490 = 2.0
1324   EXPECT_TRUE(CheckTextAutosizingMultiplier(document, 2.0));
1325 }
1326 
TEST_F(WebFrameTest,VisualViewportSetSizeInvalidatesTextAutosizingMultipliers)1327 TEST_F(WebFrameTest,
1328        VisualViewportSetSizeInvalidatesTextAutosizingMultipliers) {
1329   RegisterMockedHttpURLLoad("iframe_reload.html");
1330   RegisterMockedHttpURLLoad("visible_iframe.html");
1331 
1332   FixedLayoutTestWebWidgetClient client;
1333   int viewport_width = 640;
1334   int viewport_height = 480;
1335 
1336   frame_test_helpers::WebViewHelper web_view_helper;
1337   web_view_helper.InitializeAndLoad(base_url_ + "iframe_reload.html", nullptr,
1338                                     nullptr, &client, ConfigureAndroid);
1339 
1340   auto* main_frame =
1341       To<LocalFrame>(web_view_helper.GetWebView()->GetPage()->MainFrame());
1342   Document* document = main_frame->GetDocument();
1343   LocalFrameView* frame_view = web_view_helper.LocalMainFrame()->GetFrameView();
1344   document->GetSettings()->SetTextAutosizingEnabled(true);
1345   EXPECT_TRUE(document->GetSettings()->TextAutosizingEnabled());
1346   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
1347 
1348   for (Frame* frame = main_frame; frame; frame = frame->Tree().TraverseNext()) {
1349     auto* local_frame = DynamicTo<LocalFrame>(frame);
1350     if (!local_frame)
1351       continue;
1352     EXPECT_TRUE(SetTextAutosizingMultiplier(local_frame->GetDocument(), 2));
1353     for (LayoutObject* layout_object =
1354              local_frame->GetDocument()->GetLayoutView();
1355          layout_object; layout_object = layout_object->NextInPreOrder()) {
1356       if (layout_object->IsText())
1357         EXPECT_FALSE(layout_object->NeedsLayout());
1358     }
1359   }
1360 
1361   frame_view->GetPage()->GetVisualViewport().SetSize(IntSize(200, 200));
1362 
1363   for (Frame* frame = main_frame; frame; frame = frame->Tree().TraverseNext()) {
1364     auto* local_frame = DynamicTo<LocalFrame>(frame);
1365     if (!local_frame)
1366       continue;
1367     for (LayoutObject* layout_object =
1368              local_frame->GetDocument()->GetLayoutView();
1369          !layout_object; layout_object = layout_object->NextInPreOrder()) {
1370       if (layout_object->IsText())
1371         EXPECT_TRUE(layout_object->NeedsLayout());
1372     }
1373   }
1374 }
1375 
TEST_F(WebFrameTest,ZeroHeightPositiveWidthNotIgnored)1376 TEST_F(WebFrameTest, ZeroHeightPositiveWidthNotIgnored) {
1377   FixedLayoutTestWebWidgetClient client;
1378   client.screen_info_.device_scale_factor = 1;
1379   int viewport_width = 1280;
1380   int viewport_height = 0;
1381 
1382   frame_test_helpers::WebViewHelper web_view_helper;
1383   web_view_helper.Initialize(nullptr, nullptr, &client, ConfigureAndroid);
1384   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
1385 
1386   EXPECT_EQ(viewport_width, web_view_helper.GetWebView()
1387                                 ->MainFrameImpl()
1388                                 ->GetFrameView()
1389                                 ->GetLayoutSize()
1390                                 .Width());
1391   EXPECT_EQ(viewport_height, web_view_helper.GetWebView()
1392                                  ->MainFrameImpl()
1393                                  ->GetFrameView()
1394                                  ->GetLayoutSize()
1395                                  .Height());
1396 }
1397 
TEST_F(WebFrameTest,DeviceScaleFactorUsesDefaultWithoutViewportTag)1398 TEST_F(WebFrameTest, DeviceScaleFactorUsesDefaultWithoutViewportTag) {
1399   RegisterMockedHttpURLLoad("no_viewport_tag.html");
1400 
1401   int viewport_width = 640;
1402   int viewport_height = 480;
1403 
1404   FixedLayoutTestWebWidgetClient client;
1405   client.screen_info_.device_scale_factor = 2;
1406 
1407   frame_test_helpers::WebViewHelper web_view_helper;
1408   web_view_helper.InitializeAndLoad(base_url_ + "no_viewport_tag.html", nullptr,
1409                                     nullptr, &client, ConfigureAndroid);
1410 
1411   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
1412 
1413   EXPECT_EQ(
1414       2,
1415       web_view_helper.GetWebView()->GetPage()->DeviceScaleFactorDeprecated());
1416 
1417   // Device scale factor should be independent of page scale.
1418   web_view_helper.GetWebView()->SetDefaultPageScaleLimits(1, 2);
1419   web_view_helper.GetWebView()->SetPageScaleFactor(0.5);
1420   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
1421   EXPECT_EQ(1, web_view_helper.GetWebView()->PageScaleFactor());
1422 
1423   // Force the layout to happen before leaving the test.
1424   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
1425 }
1426 
TEST_F(WebFrameTest,FixedLayoutInitializeAtMinimumScale)1427 TEST_F(WebFrameTest, FixedLayoutInitializeAtMinimumScale) {
1428   RegisterMockedHttpURLLoad("fixed_layout.html");
1429 
1430   FixedLayoutTestWebWidgetClient client;
1431   client.screen_info_.device_scale_factor = 1;
1432   int viewport_width = 640;
1433   int viewport_height = 480;
1434 
1435   // Make sure we initialize to minimum scale, even if the window size
1436   // only becomes available after the load begins.
1437   frame_test_helpers::WebViewHelper web_view_helper;
1438   web_view_helper.Initialize(nullptr, nullptr, &client, ConfigureAndroid);
1439   web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.25f, 5);
1440   frame_test_helpers::LoadFrame(web_view_helper.GetWebView()->MainFrameImpl(),
1441                                 base_url_ + "fixed_layout.html");
1442   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
1443 
1444   int default_fixed_layout_width = 980;
1445   float minimum_page_scale_factor =
1446       viewport_width / (float)default_fixed_layout_width;
1447   EXPECT_EQ(minimum_page_scale_factor,
1448             web_view_helper.GetWebView()->PageScaleFactor());
1449   EXPECT_EQ(minimum_page_scale_factor,
1450             web_view_helper.GetWebView()->MinimumPageScaleFactor());
1451 
1452   // Assume the user has pinch zoomed to page scale factor 2.
1453   float user_pinch_page_scale_factor = 2;
1454   web_view_helper.GetWebView()->SetPageScaleFactor(
1455       user_pinch_page_scale_factor);
1456   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
1457 
1458   // Make sure we don't reset to initial scale if the page continues to load.
1459   web_view_helper.GetWebView()->DidCommitLoad(false, false);
1460   web_view_helper.GetWebView()->DidChangeContentsSize();
1461   EXPECT_EQ(user_pinch_page_scale_factor,
1462             web_view_helper.GetWebView()->PageScaleFactor());
1463 
1464   // Make sure we don't reset to initial scale if the viewport size changes.
1465   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height + 100));
1466   EXPECT_EQ(user_pinch_page_scale_factor,
1467             web_view_helper.GetWebView()->PageScaleFactor());
1468 }
1469 
TEST_F(WebFrameTest,WideDocumentInitializeAtMinimumScale)1470 TEST_F(WebFrameTest, WideDocumentInitializeAtMinimumScale) {
1471   RegisterMockedHttpURLLoad("wide_document.html");
1472 
1473   FixedLayoutTestWebWidgetClient client;
1474   client.screen_info_.device_scale_factor = 1;
1475   int viewport_width = 640;
1476   int viewport_height = 480;
1477 
1478   // Make sure we initialize to minimum scale, even if the window size
1479   // only becomes available after the load begins.
1480   frame_test_helpers::WebViewHelper web_view_helper;
1481   web_view_helper.Initialize(nullptr, nullptr, &client, ConfigureAndroid);
1482   web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.25f, 5);
1483   frame_test_helpers::LoadFrame(web_view_helper.GetWebView()->MainFrameImpl(),
1484                                 base_url_ + "wide_document.html");
1485   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
1486 
1487   int wide_document_width = 1500;
1488   float minimum_page_scale_factor = viewport_width / (float)wide_document_width;
1489   EXPECT_EQ(minimum_page_scale_factor,
1490             web_view_helper.GetWebView()->PageScaleFactor());
1491   EXPECT_EQ(minimum_page_scale_factor,
1492             web_view_helper.GetWebView()->MinimumPageScaleFactor());
1493 
1494   // Assume the user has pinch zoomed to page scale factor 2.
1495   float user_pinch_page_scale_factor = 2;
1496   web_view_helper.GetWebView()->SetPageScaleFactor(
1497       user_pinch_page_scale_factor);
1498   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
1499 
1500   // Make sure we don't reset to initial scale if the page continues to load.
1501   web_view_helper.GetWebView()->DidCommitLoad(false, false);
1502   web_view_helper.GetWebView()->DidChangeContentsSize();
1503   EXPECT_EQ(user_pinch_page_scale_factor,
1504             web_view_helper.GetWebView()->PageScaleFactor());
1505 
1506   // Make sure we don't reset to initial scale if the viewport size changes.
1507   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height + 100));
1508   EXPECT_EQ(user_pinch_page_scale_factor,
1509             web_view_helper.GetWebView()->PageScaleFactor());
1510 }
1511 
TEST_F(WebFrameTest,DelayedViewportInitialScale)1512 TEST_F(WebFrameTest, DelayedViewportInitialScale) {
1513   RegisterMockedHttpURLLoad("viewport-auto-initial-scale.html");
1514 
1515   FixedLayoutTestWebWidgetClient client;
1516   client.screen_info_.device_scale_factor = 1;
1517   int viewport_width = 640;
1518   int viewport_height = 480;
1519 
1520   frame_test_helpers::WebViewHelper web_view_helper;
1521   web_view_helper.InitializeAndLoad(
1522       base_url_ + "viewport-auto-initial-scale.html", nullptr, nullptr, &client,
1523       ConfigureAndroid);
1524   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
1525 
1526   EXPECT_EQ(0.25f, web_view_helper.GetWebView()->PageScaleFactor());
1527 
1528   ViewportData& viewport =
1529       To<LocalFrame>(web_view_helper.GetWebView()->GetPage()->MainFrame())
1530           ->GetDocument()
1531           ->GetViewportData();
1532   ViewportDescription description = viewport.GetViewportDescription();
1533   description.zoom = 2;
1534   viewport.SetViewportDescription(description);
1535   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
1536   EXPECT_EQ(2, web_view_helper.GetWebView()->PageScaleFactor());
1537 }
1538 
TEST_F(WebFrameTest,setLoadWithOverviewModeToFalse)1539 TEST_F(WebFrameTest, setLoadWithOverviewModeToFalse) {
1540   RegisterMockedHttpURLLoad("viewport-auto-initial-scale.html");
1541 
1542   FixedLayoutTestWebWidgetClient client;
1543   client.screen_info_.device_scale_factor = 1;
1544   int viewport_width = 640;
1545   int viewport_height = 480;
1546 
1547   frame_test_helpers::WebViewHelper web_view_helper;
1548   web_view_helper.InitializeAndLoad(
1549       base_url_ + "viewport-auto-initial-scale.html", nullptr, nullptr, &client,
1550       ConfigureAndroid);
1551   web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
1552       true);
1553   web_view_helper.GetWebView()->GetSettings()->SetLoadWithOverviewMode(false);
1554   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
1555 
1556   // The page must be displayed at 100% zoom.
1557   EXPECT_EQ(1.0f, web_view_helper.GetWebView()->PageScaleFactor());
1558 }
1559 
TEST_F(WebFrameTest,SetLoadWithOverviewModeToFalseAndNoWideViewport)1560 TEST_F(WebFrameTest, SetLoadWithOverviewModeToFalseAndNoWideViewport) {
1561   RegisterMockedHttpURLLoad("large-div.html");
1562 
1563   FixedLayoutTestWebWidgetClient client;
1564   client.screen_info_.device_scale_factor = 1;
1565   int viewport_width = 640;
1566   int viewport_height = 480;
1567 
1568   frame_test_helpers::WebViewHelper web_view_helper;
1569   web_view_helper.InitializeAndLoad(base_url_ + "large-div.html", nullptr,
1570                                     nullptr, &client, ConfigureAndroid);
1571   web_view_helper.GetWebView()->GetSettings()->SetLoadWithOverviewMode(false);
1572   web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
1573       true);
1574   web_view_helper.GetWebView()->GetSettings()->SetUseWideViewport(false);
1575   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
1576 
1577   // The page must be displayed at 100% zoom, despite that it hosts a wide div
1578   // element.
1579   EXPECT_EQ(1.0f, web_view_helper.GetWebView()->PageScaleFactor());
1580 }
1581 
TEST_F(WebFrameTest,NoWideViewportIgnoresPageViewportWidth)1582 TEST_F(WebFrameTest, NoWideViewportIgnoresPageViewportWidth) {
1583   RegisterMockedHttpURLLoad("viewport-auto-initial-scale.html");
1584 
1585   FixedLayoutTestWebWidgetClient client;
1586   client.screen_info_.device_scale_factor = 1;
1587   int viewport_width = 640;
1588   int viewport_height = 480;
1589 
1590   frame_test_helpers::WebViewHelper web_view_helper;
1591   web_view_helper.InitializeAndLoad(
1592       base_url_ + "viewport-auto-initial-scale.html", nullptr, nullptr, &client,
1593       ConfigureAndroid);
1594   web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
1595       true);
1596   web_view_helper.GetWebView()->GetSettings()->SetUseWideViewport(false);
1597   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
1598 
1599   // The page sets viewport width to 3000, but with UseWideViewport == false is
1600   // must be ignored.
1601   EXPECT_EQ(viewport_width, web_view_helper.GetWebView()
1602                                 ->MainFrameImpl()
1603                                 ->GetFrameView()
1604                                 ->Size()
1605                                 .Width());
1606   EXPECT_EQ(viewport_height, web_view_helper.GetWebView()
1607                                  ->MainFrameImpl()
1608                                  ->GetFrameView()
1609                                  ->Size()
1610                                  .Height());
1611 }
1612 
TEST_F(WebFrameTest,NoWideViewportIgnoresPageViewportWidthButAccountsScale)1613 TEST_F(WebFrameTest, NoWideViewportIgnoresPageViewportWidthButAccountsScale) {
1614   RegisterMockedHttpURLLoad("viewport-wide-2x-initial-scale.html");
1615 
1616   FixedLayoutTestWebWidgetClient client;
1617   client.screen_info_.device_scale_factor = 1;
1618   int viewport_width = 640;
1619   int viewport_height = 480;
1620 
1621   frame_test_helpers::WebViewHelper web_view_helper;
1622   web_view_helper.InitializeAndLoad(
1623       base_url_ + "viewport-wide-2x-initial-scale.html", nullptr, nullptr,
1624       &client, ConfigureAndroid);
1625   web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
1626       true);
1627   web_view_helper.GetWebView()->GetSettings()->SetUseWideViewport(false);
1628   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
1629 
1630   // The page sets viewport width to 3000, but with UseWideViewport == false it
1631   // must be ignored while the initial scale specified by the page must be
1632   // accounted.
1633   EXPECT_EQ(viewport_width / 2, web_view_helper.GetWebView()
1634                                     ->MainFrameImpl()
1635                                     ->GetFrameView()
1636                                     ->Size()
1637                                     .Width());
1638   EXPECT_EQ(viewport_height / 2, web_view_helper.GetWebView()
1639                                      ->MainFrameImpl()
1640                                      ->GetFrameView()
1641                                      ->Size()
1642                                      .Height());
1643 }
1644 
TEST_F(WebFrameTest,WideViewportSetsTo980WithoutViewportTag)1645 TEST_F(WebFrameTest, WideViewportSetsTo980WithoutViewportTag) {
1646   RegisterMockedHttpURLLoad("no_viewport_tag.html");
1647 
1648   FixedLayoutTestWebWidgetClient client;
1649   client.screen_info_.device_scale_factor = 1;
1650   int viewport_width = 640;
1651   int viewport_height = 480;
1652 
1653   frame_test_helpers::WebViewHelper web_view_helper;
1654   web_view_helper.InitializeAndLoad(base_url_ + "no_viewport_tag.html", nullptr,
1655                                     nullptr, &client, ConfigureAndroid);
1656   web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
1657       true);
1658   web_view_helper.GetWebView()->GetSettings()->SetUseWideViewport(true);
1659   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
1660 
1661   EXPECT_EQ(980, web_view_helper.GetWebView()
1662                      ->MainFrameImpl()
1663                      ->GetFrameView()
1664                      ->LayoutViewport()
1665                      ->ContentsSize()
1666                      .Width());
1667   EXPECT_EQ(980.0 / viewport_width * viewport_height,
1668             web_view_helper.GetWebView()
1669                 ->MainFrameImpl()
1670                 ->GetFrameView()
1671                 ->LayoutViewport()
1672                 ->ContentsSize()
1673                 .Height());
1674 }
1675 
TEST_F(WebFrameTest,WideViewportSetsTo980WithXhtmlMp)1676 TEST_F(WebFrameTest, WideViewportSetsTo980WithXhtmlMp) {
1677   RegisterMockedHttpURLLoad("viewport/viewport-legacy-xhtmlmp.html");
1678 
1679   FixedLayoutTestWebWidgetClient client;
1680   client.screen_info_.device_scale_factor = 1;
1681   int viewport_width = 640;
1682   int viewport_height = 480;
1683 
1684   frame_test_helpers::WebViewHelper web_view_helper;
1685   web_view_helper.Initialize(nullptr, nullptr, &client, ConfigureAndroid);
1686   web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
1687       true);
1688   web_view_helper.GetWebView()->GetSettings()->SetUseWideViewport(true);
1689   frame_test_helpers::LoadFrame(
1690       web_view_helper.GetWebView()->MainFrameImpl(),
1691       base_url_ + "viewport/viewport-legacy-xhtmlmp.html");
1692 
1693   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
1694   EXPECT_EQ(viewport_width, web_view_helper.GetWebView()
1695                                 ->MainFrameImpl()
1696                                 ->GetFrameView()
1697                                 ->Size()
1698                                 .Width());
1699   EXPECT_EQ(viewport_height, web_view_helper.GetWebView()
1700                                  ->MainFrameImpl()
1701                                  ->GetFrameView()
1702                                  ->Size()
1703                                  .Height());
1704 }
1705 
TEST_F(WebFrameTest,NoWideViewportAndHeightInMeta)1706 TEST_F(WebFrameTest, NoWideViewportAndHeightInMeta) {
1707   RegisterMockedHttpURLLoad("viewport-height-1000.html");
1708 
1709   FixedLayoutTestWebWidgetClient client;
1710   client.screen_info_.device_scale_factor = 1;
1711   int viewport_width = 640;
1712   int viewport_height = 480;
1713 
1714   frame_test_helpers::WebViewHelper web_view_helper;
1715   web_view_helper.InitializeAndLoad(base_url_ + "viewport-height-1000.html",
1716                                     nullptr, nullptr, &client,
1717                                     ConfigureAndroid);
1718   web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
1719       true);
1720   web_view_helper.GetWebView()->GetSettings()->SetUseWideViewport(false);
1721   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
1722 
1723   EXPECT_EQ(viewport_width, web_view_helper.GetWebView()
1724                                 ->MainFrameImpl()
1725                                 ->GetFrameView()
1726                                 ->Size()
1727                                 .Width());
1728 }
1729 
TEST_F(WebFrameTest,WideViewportSetsTo980WithAutoWidth)1730 TEST_F(WebFrameTest, WideViewportSetsTo980WithAutoWidth) {
1731   RegisterMockedHttpURLLoad("viewport-2x-initial-scale.html");
1732 
1733   FixedLayoutTestWebWidgetClient client;
1734   client.screen_info_.device_scale_factor = 1;
1735   int viewport_width = 640;
1736   int viewport_height = 480;
1737 
1738   frame_test_helpers::WebViewHelper web_view_helper;
1739   web_view_helper.InitializeAndLoad(
1740       base_url_ + "viewport-2x-initial-scale.html", nullptr, nullptr, &client,
1741       ConfigureAndroid);
1742   web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
1743       true);
1744   web_view_helper.GetWebView()->GetSettings()->SetUseWideViewport(true);
1745   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
1746 
1747   EXPECT_EQ(980, web_view_helper.GetWebView()
1748                      ->MainFrameImpl()
1749                      ->GetFrameView()
1750                      ->Size()
1751                      .Width());
1752   EXPECT_EQ(980.0 / viewport_width * viewport_height,
1753             web_view_helper.GetWebView()
1754                 ->MainFrameImpl()
1755                 ->GetFrameView()
1756                 ->Size()
1757                 .Height());
1758 }
1759 
TEST_F(WebFrameTest,PageViewportInitialScaleOverridesLoadWithOverviewMode)1760 TEST_F(WebFrameTest, PageViewportInitialScaleOverridesLoadWithOverviewMode) {
1761   RegisterMockedHttpURLLoad("viewport-wide-2x-initial-scale.html");
1762 
1763   FixedLayoutTestWebWidgetClient client;
1764   client.screen_info_.device_scale_factor = 1;
1765   int viewport_width = 640;
1766   int viewport_height = 480;
1767 
1768   frame_test_helpers::WebViewHelper web_view_helper;
1769   web_view_helper.InitializeAndLoad(
1770       base_url_ + "viewport-wide-2x-initial-scale.html", nullptr, nullptr,
1771       &client, ConfigureAndroid);
1772   web_view_helper.GetWebView()->GetSettings()->SetLoadWithOverviewMode(false);
1773   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
1774 
1775   // The page must be displayed at 200% zoom, as specified in its viewport meta
1776   // tag.
1777   EXPECT_EQ(2.0f, web_view_helper.GetWebView()->PageScaleFactor());
1778 }
1779 
TEST_F(WebFrameTest,setInitialPageScaleFactorPermanently)1780 TEST_F(WebFrameTest, setInitialPageScaleFactorPermanently) {
1781   RegisterMockedHttpURLLoad("fixed_layout.html");
1782 
1783   FixedLayoutTestWebWidgetClient client;
1784   client.screen_info_.device_scale_factor = 1;
1785   float enforced_page_scale_factor = 2.0f;
1786 
1787   frame_test_helpers::WebViewHelper web_view_helper;
1788   web_view_helper.InitializeAndLoad(base_url_ + "fixed_layout.html", nullptr,
1789                                     nullptr, &client, ConfigureAndroid);
1790   web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
1791       true);
1792   web_view_helper.GetWebView()->GetSettings()->SetLoadWithOverviewMode(false);
1793   web_view_helper.GetWebView()->SetInitialPageScaleOverride(
1794       enforced_page_scale_factor);
1795   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
1796 
1797   EXPECT_EQ(enforced_page_scale_factor,
1798             web_view_helper.GetWebView()->PageScaleFactor());
1799 
1800   int viewport_width = 640;
1801   int viewport_height = 480;
1802   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
1803 
1804   EXPECT_EQ(enforced_page_scale_factor,
1805             web_view_helper.GetWebView()->PageScaleFactor());
1806 
1807   web_view_helper.GetWebView()->SetInitialPageScaleOverride(-1);
1808   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
1809   EXPECT_EQ(1.0, web_view_helper.GetWebView()->PageScaleFactor());
1810 }
1811 
TEST_F(WebFrameTest,PermanentInitialPageScaleFactorOverridesLoadWithOverviewMode)1812 TEST_F(WebFrameTest,
1813        PermanentInitialPageScaleFactorOverridesLoadWithOverviewMode) {
1814   RegisterMockedHttpURLLoad("viewport-auto-initial-scale.html");
1815 
1816   FixedLayoutTestWebWidgetClient client;
1817   client.screen_info_.device_scale_factor = 1;
1818   int viewport_width = 640;
1819   int viewport_height = 480;
1820   float enforced_page_scale_factor = 0.5f;
1821 
1822   frame_test_helpers::WebViewHelper web_view_helper;
1823   web_view_helper.InitializeAndLoad(
1824       base_url_ + "viewport-auto-initial-scale.html", nullptr, nullptr, &client,
1825       ConfigureAndroid);
1826   web_view_helper.GetWebView()->GetSettings()->SetLoadWithOverviewMode(false);
1827   web_view_helper.GetWebView()->SetInitialPageScaleOverride(
1828       enforced_page_scale_factor);
1829   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
1830 
1831   EXPECT_EQ(enforced_page_scale_factor,
1832             web_view_helper.GetWebView()->PageScaleFactor());
1833 }
1834 
TEST_F(WebFrameTest,PermanentInitialPageScaleFactorOverridesPageViewportInitialScale)1835 TEST_F(WebFrameTest,
1836        PermanentInitialPageScaleFactorOverridesPageViewportInitialScale) {
1837   RegisterMockedHttpURLLoad("viewport-wide-2x-initial-scale.html");
1838 
1839   FixedLayoutTestWebWidgetClient client;
1840   client.screen_info_.device_scale_factor = 1;
1841   int viewport_width = 640;
1842   int viewport_height = 480;
1843   float enforced_page_scale_factor = 0.5f;
1844 
1845   frame_test_helpers::WebViewHelper web_view_helper;
1846   web_view_helper.InitializeAndLoad(
1847       base_url_ + "viewport-wide-2x-initial-scale.html", nullptr, nullptr,
1848       &client, ConfigureAndroid);
1849   web_view_helper.GetWebView()->SetInitialPageScaleOverride(
1850       enforced_page_scale_factor);
1851   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
1852 
1853   EXPECT_EQ(enforced_page_scale_factor,
1854             web_view_helper.GetWebView()->PageScaleFactor());
1855 }
1856 
TEST_F(WebFrameTest,SmallPermanentInitialPageScaleFactorIsClobbered)1857 TEST_F(WebFrameTest, SmallPermanentInitialPageScaleFactorIsClobbered) {
1858   const char* pages[] = {
1859       // These pages trigger the clobbering condition. There must be a matching
1860       // item in "pageScaleFactors" array.
1861       "viewport-device-0.5x-initial-scale.html",
1862       "viewport-initial-scale-1.html",
1863       // These ones do not.
1864       "viewport-auto-initial-scale.html",
1865       "viewport-target-densitydpi-device-and-fixed-width.html"};
1866   float page_scale_factors[] = {0.5f, 1.0f};
1867   for (size_t i = 0; i < base::size(pages); ++i)
1868     RegisterMockedHttpURLLoad(pages[i]);
1869 
1870   FixedLayoutTestWebWidgetClient client;
1871   client.screen_info_.device_scale_factor = 1;
1872   int viewport_width = 400;
1873   int viewport_height = 300;
1874   float enforced_page_scale_factor = 0.75f;
1875 
1876   for (size_t i = 0; i < base::size(pages); ++i) {
1877     for (int quirk_enabled = 0; quirk_enabled <= 1; ++quirk_enabled) {
1878       frame_test_helpers::WebViewHelper web_view_helper;
1879       web_view_helper.InitializeAndLoad(base_url_ + pages[i], nullptr, nullptr,
1880                                         &client, ConfigureAndroid);
1881       web_view_helper.GetWebView()
1882           ->GetSettings()
1883           ->SetClobberUserAgentInitialScaleQuirk(quirk_enabled);
1884       web_view_helper.GetWebView()->SetInitialPageScaleOverride(
1885           enforced_page_scale_factor);
1886       web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
1887 
1888       float expected_page_scale_factor =
1889           quirk_enabled && i < base::size(page_scale_factors)
1890               ? page_scale_factors[i]
1891               : enforced_page_scale_factor;
1892       EXPECT_EQ(expected_page_scale_factor,
1893                 web_view_helper.GetWebView()->PageScaleFactor());
1894     }
1895   }
1896 }
1897 
TEST_F(WebFrameTest,PermanentInitialPageScaleFactorAffectsLayoutWidth)1898 TEST_F(WebFrameTest, PermanentInitialPageScaleFactorAffectsLayoutWidth) {
1899   FixedLayoutTestWebWidgetClient client;
1900   client.screen_info_.device_scale_factor = 1;
1901   int viewport_width = 640;
1902   int viewport_height = 480;
1903   float enforced_page_scale_factor = 0.5;
1904 
1905   frame_test_helpers::WebViewHelper web_view_helper;
1906   web_view_helper.InitializeAndLoad("about:blank", nullptr, nullptr, &client,
1907                                     ConfigureAndroid);
1908   web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
1909       true);
1910   web_view_helper.GetWebView()->GetSettings()->SetUseWideViewport(false);
1911   web_view_helper.GetWebView()->GetSettings()->SetLoadWithOverviewMode(false);
1912   web_view_helper.GetWebView()->SetInitialPageScaleOverride(
1913       enforced_page_scale_factor);
1914   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
1915 
1916   EXPECT_EQ(viewport_width / enforced_page_scale_factor,
1917             web_view_helper.GetWebView()
1918                 ->MainFrameImpl()
1919                 ->GetFrameView()
1920                 ->Size()
1921                 .Width());
1922   EXPECT_EQ(enforced_page_scale_factor,
1923             web_view_helper.GetWebView()->PageScaleFactor());
1924 }
1925 
TEST_F(WebFrameTest,DocumentElementClientHeightWorksWithWrapContentMode)1926 TEST_F(WebFrameTest, DocumentElementClientHeightWorksWithWrapContentMode) {
1927   RegisterMockedHttpURLLoad("0-by-0.html");
1928 
1929   FixedLayoutTestWebWidgetClient client;
1930   client.screen_info_.device_scale_factor = 1;
1931   int viewport_width = 640;
1932   int viewport_height = 480;
1933 
1934   frame_test_helpers::WebViewHelper web_view_helper;
1935 
1936   web_view_helper.InitializeAndLoad(base_url_ + "0-by-0.html", nullptr, nullptr,
1937                                     &client, ConfigureAndroid);
1938   web_view_helper.GetWebView()->GetSettings()->SetForceZeroLayoutHeight(true);
1939   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
1940 
1941   LocalFrame* frame = web_view_helper.LocalMainFrame()->GetFrame();
1942   Document* document = frame->GetDocument();
1943   EXPECT_EQ(viewport_height, document->documentElement()->clientHeight());
1944   EXPECT_EQ(viewport_width, document->documentElement()->clientWidth());
1945 }
1946 
TEST_F(WebFrameTest,SetForceZeroLayoutHeightWorksWithWrapContentMode)1947 TEST_F(WebFrameTest, SetForceZeroLayoutHeightWorksWithWrapContentMode) {
1948   RegisterMockedHttpURLLoad("0-by-0.html");
1949 
1950   FixedLayoutTestWebWidgetClient client;
1951   client.screen_info_.device_scale_factor = 1;
1952   int viewport_width = 640;
1953   int viewport_height = 480;
1954 
1955   frame_test_helpers::WebViewHelper web_view_helper;
1956 
1957   web_view_helper.InitializeAndLoad(base_url_ + "0-by-0.html", nullptr, nullptr,
1958                                     &client, ConfigureAndroid);
1959   web_view_helper.GetWebView()->GetSettings()->SetForceZeroLayoutHeight(true);
1960   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
1961 
1962   LocalFrameView* frame_view =
1963       web_view_helper.GetWebView()->MainFrameImpl()->GetFrameView();
1964   GraphicsLayer* scroll_container =
1965       frame_view->GetLayoutView()->Compositor()->RootGraphicsLayer();
1966 
1967   EXPECT_EQ(IntSize(), frame_view->GetLayoutSize());
1968   EXPECT_EQ(gfx::Size(), scroll_container->Size());
1969 
1970   web_view_helper.Resize(gfx::Size(viewport_width, 0));
1971   EXPECT_EQ(IntSize(viewport_width, 0), frame_view->GetLayoutSize());
1972   EXPECT_EQ(gfx::Size(viewport_width, 0), scroll_container->Size());
1973 
1974   // The flag ForceZeroLayoutHeight will cause the following resize of viewport
1975   // height to be ignored by the outer viewport (the container layer of
1976   // LayerCompositor). The height of the visualViewport, however, is not
1977   // affected.
1978   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
1979   EXPECT_FALSE(frame_view->NeedsLayout());
1980   EXPECT_EQ(IntSize(viewport_width, 0), frame_view->GetLayoutSize());
1981   EXPECT_EQ(gfx::Size(viewport_width, viewport_height),
1982             scroll_container->Size());
1983 
1984   LocalFrame* frame = web_view_helper.LocalMainFrame()->GetFrame();
1985   VisualViewport& visual_viewport = frame->GetPage()->GetVisualViewport();
1986   auto* scroll_node = visual_viewport.GetScrollTranslationNode()->ScrollNode();
1987   EXPECT_EQ(IntRect(0, 0, viewport_width, viewport_height),
1988             scroll_node->ContainerRect());
1989   EXPECT_EQ(IntSize(viewport_width, viewport_height),
1990             scroll_node->ContentsSize());
1991 }
1992 
TEST_F(WebFrameTest,SetForceZeroLayoutHeight)1993 TEST_F(WebFrameTest, SetForceZeroLayoutHeight) {
1994   RegisterMockedHttpURLLoad("200-by-300.html");
1995 
1996   FixedLayoutTestWebWidgetClient client;
1997   client.screen_info_.device_scale_factor = 1;
1998   int viewport_width = 640;
1999   int viewport_height = 480;
2000 
2001   frame_test_helpers::WebViewHelper web_view_helper;
2002 
2003   web_view_helper.InitializeAndLoad(base_url_ + "200-by-300.html", nullptr,
2004                                     nullptr, &client, ConfigureAndroid);
2005   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
2006 
2007   EXPECT_LE(viewport_height, web_view_helper.GetWebView()
2008                                  ->MainFrameImpl()
2009                                  ->GetFrameView()
2010                                  ->GetLayoutSize()
2011                                  .Height());
2012   web_view_helper.GetWebView()->GetSettings()->SetForceZeroLayoutHeight(true);
2013   EXPECT_TRUE(web_view_helper.GetWebView()
2014                   ->MainFrameImpl()
2015                   ->GetFrameView()
2016                   ->NeedsLayout());
2017 
2018   EXPECT_EQ(0, web_view_helper.GetWebView()
2019                    ->MainFrameImpl()
2020                    ->GetFrameView()
2021                    ->GetLayoutSize()
2022                    .Height());
2023 
2024   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height * 2));
2025   EXPECT_FALSE(web_view_helper.GetWebView()
2026                    ->MainFrameImpl()
2027                    ->GetFrameView()
2028                    ->NeedsLayout());
2029   EXPECT_EQ(0, web_view_helper.GetWebView()
2030                    ->MainFrameImpl()
2031                    ->GetFrameView()
2032                    ->GetLayoutSize()
2033                    .Height());
2034 
2035   web_view_helper.Resize(gfx::Size(viewport_width * 2, viewport_height));
2036   EXPECT_EQ(0, web_view_helper.GetWebView()
2037                    ->MainFrameImpl()
2038                    ->GetFrameView()
2039                    ->GetLayoutSize()
2040                    .Height());
2041 
2042   web_view_helper.GetWebView()->GetSettings()->SetForceZeroLayoutHeight(false);
2043   EXPECT_LE(viewport_height, web_view_helper.GetWebView()
2044                                  ->MainFrameImpl()
2045                                  ->GetFrameView()
2046                                  ->GetLayoutSize()
2047                                  .Height());
2048 }
2049 
TEST_F(WebFrameTest,ToggleViewportMetaOnOff)2050 TEST_F(WebFrameTest, ToggleViewportMetaOnOff) {
2051   RegisterMockedHttpURLLoad("viewport-device-width.html");
2052 
2053   FixedLayoutTestWebWidgetClient client;
2054   client.screen_info_.device_scale_factor = 1;
2055   int viewport_width = 640;
2056   int viewport_height = 480;
2057 
2058   frame_test_helpers::WebViewHelper web_view_helper;
2059   web_view_helper.InitializeAndLoad(base_url_ + "viewport-device-width.html",
2060                                     nullptr, nullptr, &client);
2061   WebSettings* settings = web_view_helper.GetWebView()->GetSettings();
2062   settings->SetViewportMetaEnabled(false);
2063   settings->SetViewportEnabled(true);
2064   settings->SetMainFrameResizesAreOrientationChanges(true);
2065   settings->SetShrinksViewportContentToFit(true);
2066   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
2067 
2068   ViewportData& viewport =
2069       To<LocalFrame>(web_view_helper.GetWebView()->GetPage()->MainFrame())
2070           ->GetDocument()
2071           ->GetViewportData();
2072   EXPECT_FALSE(viewport.GetViewportDescription().IsLegacyViewportType());
2073 
2074   settings->SetViewportMetaEnabled(true);
2075   EXPECT_TRUE(viewport.GetViewportDescription().IsLegacyViewportType());
2076 
2077   settings->SetViewportMetaEnabled(false);
2078   EXPECT_FALSE(viewport.GetViewportDescription().IsLegacyViewportType());
2079 }
2080 
TEST_F(WebFrameTest,SetForceZeroLayoutHeightWorksWithRelayoutsWhenHeightChanged)2081 TEST_F(WebFrameTest,
2082        SetForceZeroLayoutHeightWorksWithRelayoutsWhenHeightChanged) {
2083   // this unit test is an attempt to target a real world case where an app could
2084   // 1. call resize(width, 0) and setForceZeroLayoutHeight(true)
2085   // 2. load content (hoping that the viewport height would increase
2086   // as more content is added)
2087   // 3. fail to register touch events aimed at the loaded content
2088   // because the layout is only updated if either width or height is changed
2089   RegisterMockedHttpURLLoad("button.html");
2090 
2091   FixedLayoutTestWebWidgetClient client;
2092   client.screen_info_.device_scale_factor = 1;
2093   int viewport_width = 640;
2094   int viewport_height = 480;
2095 
2096   frame_test_helpers::WebViewHelper web_view_helper;
2097 
2098   web_view_helper.InitializeAndLoad(base_url_ + "button.html", nullptr, nullptr,
2099                                     &client, ConfigureAndroid);
2100   // set view height to zero so that if the height of the view is not
2101   // successfully updated during later resizes touch events will fail
2102   // (as in not hit content included in the view)
2103   web_view_helper.Resize(gfx::Size(viewport_width, 0));
2104 
2105   web_view_helper.GetWebView()->GetSettings()->SetForceZeroLayoutHeight(true);
2106   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
2107 
2108   FloatPoint hit_point = FloatPoint(30, 30);  // button size is 100x100
2109 
2110   WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
2111   Document* document = frame->GetFrame()->GetDocument();
2112   Element* element = document->getElementById("tap_button");
2113 
2114   ASSERT_NE(nullptr, element);
2115   EXPECT_EQ(String("oldValue"), element->innerText());
2116 
2117   WebGestureEvent gesture_event(WebInputEvent::Type::kGestureTap,
2118                                 WebInputEvent::kNoModifiers,
2119                                 WebInputEvent::GetStaticTimeStampForTests(),
2120                                 WebGestureDevice::kTouchscreen);
2121   gesture_event.SetFrameScale(1);
2122   gesture_event.SetPositionInWidget(hit_point);
2123   gesture_event.SetPositionInScreen(hit_point);
2124   web_view_helper.GetWebView()
2125       ->MainFrameImpl()
2126       ->GetFrame()
2127       ->GetEventHandler()
2128       .HandleGestureEvent(gesture_event);
2129   // when pressed, the button changes its own text to "updatedValue"
2130   EXPECT_EQ(String("updatedValue"), element->innerText());
2131 }
2132 
TEST_F(WebFrameTest,FrameOwnerPropertiesMargin)2133 TEST_F(WebFrameTest, FrameOwnerPropertiesMargin) {
2134   frame_test_helpers::WebViewHelper helper;
2135   helper.InitializeRemote();
2136 
2137   WebFrameOwnerProperties properties;
2138   properties.margin_width = 11;
2139   properties.margin_height = 22;
2140   WebLocalFrameImpl* local_frame = frame_test_helpers::CreateLocalChild(
2141       *helper.RemoteMainFrame(), "frameName", properties);
2142 
2143   RegisterMockedHttpURLLoad("frame_owner_properties.html");
2144   frame_test_helpers::LoadFrame(local_frame,
2145                                 base_url_ + "frame_owner_properties.html");
2146 
2147   // Check if the LocalFrame has seen the marginwidth and marginheight
2148   // properties.
2149   Document* child_document = local_frame->GetFrame()->GetDocument();
2150   EXPECT_EQ(11, child_document->FirstBodyElement()->GetIntegralAttribute(
2151                     html_names::kMarginwidthAttr));
2152   EXPECT_EQ(22, child_document->FirstBodyElement()->GetIntegralAttribute(
2153                     html_names::kMarginheightAttr));
2154 
2155   LocalFrameView* frame_view = local_frame->GetFrameView();
2156   frame_view->Resize(800, 600);
2157   frame_view->SetNeedsLayout();
2158   frame_view->UpdateAllLifecyclePhasesForTest();
2159   // Expect scrollbars to be enabled by default.
2160   EXPECT_NE(nullptr, frame_view->LayoutViewport()->HorizontalScrollbar());
2161   EXPECT_NE(nullptr, frame_view->LayoutViewport()->VerticalScrollbar());
2162 }
2163 
TEST_F(WebFrameTest,FrameOwnerPropertiesScrolling)2164 TEST_F(WebFrameTest, FrameOwnerPropertiesScrolling) {
2165   frame_test_helpers::WebViewHelper helper;
2166   helper.InitializeRemote();
2167 
2168   WebFrameOwnerProperties properties;
2169   // Turn off scrolling in the subframe.
2170   properties.scrollbar_mode = mojom::blink::ScrollbarMode::kAlwaysOff;
2171   WebLocalFrameImpl* local_frame = frame_test_helpers::CreateLocalChild(
2172       *helper.RemoteMainFrame(), "frameName", properties);
2173 
2174   RegisterMockedHttpURLLoad("frame_owner_properties.html");
2175   frame_test_helpers::LoadFrame(local_frame,
2176                                 base_url_ + "frame_owner_properties.html");
2177 
2178   Document* child_document = local_frame->GetFrame()->GetDocument();
2179   EXPECT_EQ(0, child_document->FirstBodyElement()->GetIntegralAttribute(
2180                    html_names::kMarginwidthAttr));
2181   EXPECT_EQ(0, child_document->FirstBodyElement()->GetIntegralAttribute(
2182                    html_names::kMarginheightAttr));
2183 
2184   LocalFrameView* frame_view = local_frame->GetFrameView();
2185   EXPECT_EQ(nullptr, frame_view->LayoutViewport()->HorizontalScrollbar());
2186   EXPECT_EQ(nullptr, frame_view->LayoutViewport()->VerticalScrollbar());
2187 }
2188 
TEST_F(WebFrameTest,SetForceZeroLayoutHeightWorksAcrossNavigations)2189 TEST_F(WebFrameTest, SetForceZeroLayoutHeightWorksAcrossNavigations) {
2190   RegisterMockedHttpURLLoad("200-by-300.html");
2191   RegisterMockedHttpURLLoad("large-div.html");
2192 
2193   FixedLayoutTestWebWidgetClient client;
2194   client.screen_info_.device_scale_factor = 1;
2195   int viewport_width = 640;
2196   int viewport_height = 480;
2197 
2198   frame_test_helpers::WebViewHelper web_view_helper;
2199 
2200   web_view_helper.InitializeAndLoad(base_url_ + "200-by-300.html", nullptr,
2201                                     nullptr, &client, ConfigureAndroid);
2202   web_view_helper.GetWebView()->GetSettings()->SetForceZeroLayoutHeight(true);
2203   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
2204 
2205   frame_test_helpers::LoadFrame(web_view_helper.GetWebView()->MainFrameImpl(),
2206                                 base_url_ + "large-div.html");
2207   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
2208 
2209   EXPECT_EQ(0, web_view_helper.GetWebView()
2210                    ->MainFrameImpl()
2211                    ->GetFrameView()
2212                    ->GetLayoutSize()
2213                    .Height());
2214 }
2215 
TEST_F(WebFrameTest,SetForceZeroLayoutHeightWithWideViewportQuirk)2216 TEST_F(WebFrameTest, SetForceZeroLayoutHeightWithWideViewportQuirk) {
2217   RegisterMockedHttpURLLoad("200-by-300.html");
2218 
2219   FixedLayoutTestWebWidgetClient client;
2220   client.screen_info_.device_scale_factor = 1;
2221   int viewport_width = 640;
2222   int viewport_height = 480;
2223 
2224   frame_test_helpers::WebViewHelper web_view_helper;
2225 
2226   web_view_helper.InitializeAndLoad(base_url_ + "200-by-300.html", nullptr,
2227                                     nullptr, &client, ConfigureAndroid);
2228   web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
2229       true);
2230   web_view_helper.GetWebView()->GetSettings()->SetUseWideViewport(true);
2231   web_view_helper.GetWebView()->GetSettings()->SetForceZeroLayoutHeight(true);
2232   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
2233 
2234   EXPECT_EQ(0, web_view_helper.GetWebView()
2235                    ->MainFrameImpl()
2236                    ->GetFrameView()
2237                    ->GetLayoutSize()
2238                    .Height());
2239 }
2240 
TEST_F(WebFrameTest,WideViewportQuirkClobbersHeight)2241 TEST_F(WebFrameTest, WideViewportQuirkClobbersHeight) {
2242   RegisterMockedHttpURLLoad("viewport-height-1000.html");
2243 
2244   FixedLayoutTestWebWidgetClient client;
2245   client.screen_info_.device_scale_factor = 1;
2246   int viewport_width = 600;
2247   int viewport_height = 800;
2248 
2249   frame_test_helpers::WebViewHelper web_view_helper;
2250   web_view_helper.InitializeAndLoad("about:blank", nullptr, nullptr, &client,
2251                                     ConfigureAndroid);
2252   web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
2253       true);
2254   web_view_helper.GetWebView()->GetSettings()->SetUseWideViewport(false);
2255   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
2256 
2257   frame_test_helpers::LoadFrame(web_view_helper.GetWebView()->MainFrameImpl(),
2258                                 base_url_ + "viewport-height-1000.html");
2259   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
2260 
2261   EXPECT_EQ(800, web_view_helper.GetWebView()
2262                      ->MainFrameImpl()
2263                      ->GetFrameView()
2264                      ->GetLayoutSize()
2265                      .Height());
2266   EXPECT_EQ(1, web_view_helper.GetWebView()->PageScaleFactor());
2267 }
2268 
TEST_F(WebFrameTest,OverflowHiddenDisablesScrolling)2269 TEST_F(WebFrameTest, OverflowHiddenDisablesScrolling) {
2270   RegisterMockedHttpURLLoad("body-overflow-hidden.html");
2271 
2272   FixedLayoutTestWebWidgetClient client;
2273   client.screen_info_.device_scale_factor = 1;
2274   int viewport_width = 640;
2275   int viewport_height = 480;
2276 
2277   frame_test_helpers::WebViewHelper web_view_helper;
2278   web_view_helper.Initialize(nullptr, nullptr, &client);
2279   frame_test_helpers::LoadFrame(web_view_helper.GetWebView()->MainFrameImpl(),
2280                                 base_url_ + "body-overflow-hidden.html");
2281   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
2282 
2283   LocalFrameView* view = web_view_helper.LocalMainFrame()->GetFrameView();
2284   EXPECT_FALSE(view->LayoutViewport()->UserInputScrollable(kVerticalScrollbar));
2285   EXPECT_FALSE(
2286       view->LayoutViewport()->UserInputScrollable(kHorizontalScrollbar));
2287 }
2288 
TEST_F(WebFrameTest,OverflowHiddenDisablesScrollingWithSetCanHaveScrollbars)2289 TEST_F(WebFrameTest, OverflowHiddenDisablesScrollingWithSetCanHaveScrollbars) {
2290   RegisterMockedHttpURLLoad("body-overflow-hidden-short.html");
2291 
2292   FixedLayoutTestWebWidgetClient client;
2293   client.screen_info_.device_scale_factor = 1;
2294   int viewport_width = 640;
2295   int viewport_height = 480;
2296 
2297   frame_test_helpers::WebViewHelper web_view_helper;
2298   web_view_helper.Initialize(nullptr, nullptr, &client);
2299   frame_test_helpers::LoadFrame(web_view_helper.GetWebView()->MainFrameImpl(),
2300                                 base_url_ + "body-overflow-hidden-short.html");
2301   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
2302 
2303   LocalFrameView* view = web_view_helper.LocalMainFrame()->GetFrameView();
2304   EXPECT_FALSE(view->LayoutViewport()->UserInputScrollable(kVerticalScrollbar));
2305   EXPECT_FALSE(
2306       view->LayoutViewport()->UserInputScrollable(kHorizontalScrollbar));
2307 
2308   web_view_helper.LocalMainFrame()->GetFrameView()->SetCanHaveScrollbars(true);
2309   EXPECT_FALSE(view->LayoutViewport()->UserInputScrollable(kVerticalScrollbar));
2310   EXPECT_FALSE(
2311       view->LayoutViewport()->UserInputScrollable(kHorizontalScrollbar));
2312 }
2313 
TEST_F(WebFrameTest,IgnoreOverflowHiddenQuirk)2314 TEST_F(WebFrameTest, IgnoreOverflowHiddenQuirk) {
2315   RegisterMockedHttpURLLoad("body-overflow-hidden.html");
2316 
2317   FixedLayoutTestWebWidgetClient client;
2318   client.screen_info_.device_scale_factor = 1;
2319   int viewport_width = 640;
2320   int viewport_height = 480;
2321 
2322   frame_test_helpers::WebViewHelper web_view_helper;
2323   web_view_helper.Initialize(nullptr, nullptr, &client);
2324   web_view_helper.GetWebView()
2325       ->GetSettings()
2326       ->SetIgnoreMainFrameOverflowHiddenQuirk(true);
2327   frame_test_helpers::LoadFrame(web_view_helper.GetWebView()->MainFrameImpl(),
2328                                 base_url_ + "body-overflow-hidden.html");
2329   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
2330 
2331   LocalFrameView* view = web_view_helper.LocalMainFrame()->GetFrameView();
2332   EXPECT_TRUE(view->LayoutViewport()->UserInputScrollable(kVerticalScrollbar));
2333 }
2334 
TEST_F(WebFrameTest,NonZeroValuesNoQuirk)2335 TEST_F(WebFrameTest, NonZeroValuesNoQuirk) {
2336   RegisterMockedHttpURLLoad("viewport-nonzero-values.html");
2337 
2338   FixedLayoutTestWebWidgetClient client;
2339   client.screen_info_.device_scale_factor = 1;
2340   int viewport_width = 640;
2341   int viewport_height = 480;
2342   float expected_page_scale_factor = 0.5f;
2343 
2344   frame_test_helpers::WebViewHelper web_view_helper;
2345   web_view_helper.Initialize(nullptr, nullptr, &client, ConfigureAndroid);
2346   web_view_helper.GetWebView()->GetSettings()->SetViewportMetaZeroValuesQuirk(
2347       true);
2348   web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
2349       true);
2350   frame_test_helpers::LoadFrame(web_view_helper.GetWebView()->MainFrameImpl(),
2351                                 base_url_ + "viewport-nonzero-values.html");
2352   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
2353 
2354   EXPECT_EQ(viewport_width / expected_page_scale_factor,
2355             web_view_helper.GetWebView()
2356                 ->MainFrameImpl()
2357                 ->GetFrameView()
2358                 ->GetLayoutSize()
2359                 .Width());
2360   EXPECT_EQ(expected_page_scale_factor,
2361             web_view_helper.GetWebView()->PageScaleFactor());
2362 
2363   web_view_helper.GetWebView()->GetSettings()->SetUseWideViewport(true);
2364   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
2365   EXPECT_EQ(viewport_width / expected_page_scale_factor,
2366             web_view_helper.GetWebView()
2367                 ->MainFrameImpl()
2368                 ->GetFrameView()
2369                 ->GetLayoutSize()
2370                 .Width());
2371   EXPECT_EQ(expected_page_scale_factor,
2372             web_view_helper.GetWebView()->PageScaleFactor());
2373 }
2374 
TEST_F(WebFrameTest,setPageScaleFactorDoesNotLayout)2375 TEST_F(WebFrameTest, setPageScaleFactorDoesNotLayout) {
2376   RegisterMockedHttpURLLoad("fixed_layout.html");
2377 
2378   FixedLayoutTestWebWidgetClient client;
2379   client.screen_info_.device_scale_factor = 1;
2380   // Small viewport to ensure there are always scrollbars.
2381   int viewport_width = 64;
2382   int viewport_height = 48;
2383 
2384   frame_test_helpers::WebViewHelper web_view_helper;
2385   web_view_helper.InitializeAndLoad(base_url_ + "fixed_layout.html", nullptr,
2386                                     nullptr, &client, ConfigureAndroid);
2387   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
2388 
2389   unsigned prev_layout_count =
2390       web_view_helper.LocalMainFrame()->GetFrameView()->LayoutCountForTesting();
2391   web_view_helper.GetWebView()->SetPageScaleFactor(3);
2392   EXPECT_FALSE(web_view_helper.GetWebView()
2393                    ->MainFrameImpl()
2394                    ->GetFrameView()
2395                    ->NeedsLayout());
2396   EXPECT_EQ(prev_layout_count, web_view_helper.GetWebView()
2397                                    ->MainFrameImpl()
2398                                    ->GetFrameView()
2399                                    ->LayoutCountForTesting());
2400 }
2401 
TEST_F(WebFrameTest,setPageScaleFactorWithOverlayScrollbarsDoesNotLayout)2402 TEST_F(WebFrameTest, setPageScaleFactorWithOverlayScrollbarsDoesNotLayout) {
2403   RegisterMockedHttpURLLoad("fixed_layout.html");
2404 
2405   FixedLayoutTestWebWidgetClient client;
2406   client.screen_info_.device_scale_factor = 1;
2407   int viewport_width = 640;
2408   int viewport_height = 480;
2409 
2410   frame_test_helpers::WebViewHelper web_view_helper;
2411   web_view_helper.InitializeAndLoad(base_url_ + "fixed_layout.html", nullptr,
2412                                     nullptr, &client, ConfigureAndroid);
2413   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
2414 
2415   unsigned prev_layout_count =
2416       web_view_helper.LocalMainFrame()->GetFrameView()->LayoutCountForTesting();
2417   web_view_helper.GetWebView()->SetPageScaleFactor(30);
2418   EXPECT_FALSE(web_view_helper.GetWebView()
2419                    ->MainFrameImpl()
2420                    ->GetFrameView()
2421                    ->NeedsLayout());
2422   EXPECT_EQ(prev_layout_count, web_view_helper.GetWebView()
2423                                    ->MainFrameImpl()
2424                                    ->GetFrameView()
2425                                    ->LayoutCountForTesting());
2426 }
2427 
TEST_F(WebFrameTest,pageScaleFactorWrittenToHistoryItem)2428 TEST_F(WebFrameTest, pageScaleFactorWrittenToHistoryItem) {
2429   RegisterMockedHttpURLLoad("fixed_layout.html");
2430 
2431   FixedLayoutTestWebWidgetClient client;
2432   client.screen_info_.device_scale_factor = 1;
2433   int viewport_width = 640;
2434   int viewport_height = 480;
2435 
2436   frame_test_helpers::WebViewHelper web_view_helper;
2437   web_view_helper.InitializeAndLoad(base_url_ + "fixed_layout.html", nullptr,
2438                                     nullptr, &client, ConfigureAndroid);
2439   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
2440 
2441   web_view_helper.GetWebView()->SetPageScaleFactor(3);
2442   EXPECT_EQ(3,
2443             To<LocalFrame>(web_view_helper.GetWebView()->GetPage()->MainFrame())
2444                 ->Loader()
2445                 .GetDocumentLoader()
2446                 ->GetHistoryItem()
2447                 ->GetViewState()
2448                 ->page_scale_factor_);
2449 }
2450 
TEST_F(WebFrameTest,initialScaleWrittenToHistoryItem)2451 TEST_F(WebFrameTest, initialScaleWrittenToHistoryItem) {
2452   RegisterMockedHttpURLLoad("fixed_layout.html");
2453 
2454   FixedLayoutTestWebWidgetClient client;
2455   client.screen_info_.device_scale_factor = 1;
2456   int viewport_width = 640;
2457   int viewport_height = 480;
2458 
2459   frame_test_helpers::WebViewHelper web_view_helper;
2460   web_view_helper.Initialize(nullptr, nullptr, &client, ConfigureAndroid);
2461   web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.25f, 5);
2462   frame_test_helpers::LoadFrame(web_view_helper.GetWebView()->MainFrameImpl(),
2463                                 base_url_ + "fixed_layout.html");
2464   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
2465 
2466   int default_fixed_layout_width = 980;
2467   float minimum_page_scale_factor =
2468       viewport_width / (float)default_fixed_layout_width;
2469   EXPECT_EQ(minimum_page_scale_factor,
2470             To<LocalFrame>(web_view_helper.GetWebView()->GetPage()->MainFrame())
2471                 ->Loader()
2472                 .GetDocumentLoader()
2473                 ->GetHistoryItem()
2474                 ->GetViewState()
2475                 ->page_scale_factor_);
2476 }
2477 
TEST_F(WebFrameTest,pageScaleFactorDoesntShrinkFrameView)2478 TEST_F(WebFrameTest, pageScaleFactorDoesntShrinkFrameView) {
2479   RegisterMockedHttpURLLoad("large-div.html");
2480 
2481   FixedLayoutTestWebWidgetClient client;
2482   client.screen_info_.device_scale_factor = 1;
2483   // Small viewport to ensure there are always scrollbars.
2484   int viewport_width = 64;
2485   int viewport_height = 48;
2486 
2487   frame_test_helpers::WebViewHelper web_view_helper;
2488   web_view_helper.InitializeAndLoad(base_url_ + "large-div.html", nullptr,
2489                                     nullptr, &client, ConfigureAndroid);
2490   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
2491 
2492   LocalFrameView* view = web_view_helper.LocalMainFrame()->GetFrameView();
2493   int viewport_width_minus_scrollbar = viewport_width;
2494   int viewport_height_minus_scrollbar = viewport_height;
2495 
2496   if (view->LayoutViewport()->VerticalScrollbar() &&
2497       !view->LayoutViewport()->VerticalScrollbar()->IsOverlayScrollbar())
2498     viewport_width_minus_scrollbar -= 15;
2499 
2500   if (view->LayoutViewport()->HorizontalScrollbar() &&
2501       !view->LayoutViewport()->HorizontalScrollbar()->IsOverlayScrollbar())
2502     viewport_height_minus_scrollbar -= 15;
2503 
2504   web_view_helper.GetWebView()->SetPageScaleFactor(2);
2505 
2506   IntSize unscaled_size = view->Size();
2507   EXPECT_EQ(viewport_width, unscaled_size.Width());
2508   EXPECT_EQ(viewport_height, unscaled_size.Height());
2509 
2510   IntSize unscaled_size_minus_scrollbar = view->Size();
2511   EXPECT_EQ(viewport_width_minus_scrollbar,
2512             unscaled_size_minus_scrollbar.Width());
2513   EXPECT_EQ(viewport_height_minus_scrollbar,
2514             unscaled_size_minus_scrollbar.Height());
2515 
2516   IntSize frame_view_size = view->Size();
2517   EXPECT_EQ(viewport_width_minus_scrollbar, frame_view_size.Width());
2518   EXPECT_EQ(viewport_height_minus_scrollbar, frame_view_size.Height());
2519 }
2520 
TEST_F(WebFrameTest,pageScaleFactorDoesNotApplyCssTransform)2521 TEST_F(WebFrameTest, pageScaleFactorDoesNotApplyCssTransform) {
2522   RegisterMockedHttpURLLoad("fixed_layout.html");
2523 
2524   FixedLayoutTestWebWidgetClient client;
2525   client.screen_info_.device_scale_factor = 1;
2526   int viewport_width = 640;
2527   int viewport_height = 480;
2528 
2529   frame_test_helpers::WebViewHelper web_view_helper;
2530   web_view_helper.InitializeAndLoad(base_url_ + "fixed_layout.html", nullptr,
2531                                     nullptr, &client, ConfigureAndroid);
2532   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
2533 
2534   web_view_helper.GetWebView()->SetPageScaleFactor(2);
2535 
2536   EXPECT_EQ(980,
2537             To<LocalFrame>(web_view_helper.GetWebView()->GetPage()->MainFrame())
2538                 ->ContentLayoutObject()
2539                 ->DocumentRect()
2540                 .Width());
2541   EXPECT_EQ(980, web_view_helper.GetWebView()
2542                      ->MainFrameImpl()
2543                      ->GetFrameView()
2544                      ->LayoutViewport()
2545                      ->ContentsSize()
2546                      .Width());
2547 }
2548 
TEST_F(WebFrameTest,targetDensityDpiHigh)2549 TEST_F(WebFrameTest, targetDensityDpiHigh) {
2550   RegisterMockedHttpURLLoad("viewport-target-densitydpi-high.html");
2551 
2552   FixedLayoutTestWebWidgetClient client;
2553   // high-dpi = 240
2554   float target_dpi = 240.0f;
2555   float device_scale_factors[] = {1.0f, 4.0f / 3.0f, 2.0f};
2556   int viewport_width = 640;
2557   int viewport_height = 480;
2558 
2559   for (size_t i = 0; i < base::size(device_scale_factors); ++i) {
2560     float device_scale_factor = device_scale_factors[i];
2561     float device_dpi = device_scale_factor * 160.0f;
2562     client.screen_info_.device_scale_factor = device_scale_factor;
2563 
2564     frame_test_helpers::WebViewHelper web_view_helper;
2565     web_view_helper.InitializeAndLoad(
2566         base_url_ + "viewport-target-densitydpi-high.html", nullptr, nullptr,
2567         &client, ConfigureAndroid);
2568     web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
2569         true);
2570     web_view_helper.GetWebView()
2571         ->GetSettings()
2572         ->SetSupportDeprecatedTargetDensityDPI(true);
2573     web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
2574 
2575     // We need to account for the fact that logical pixels are unconditionally
2576     // multiplied by deviceScaleFactor to produce physical pixels.
2577     float density_dpi_scale_ratio =
2578         device_scale_factor * target_dpi / device_dpi;
2579     EXPECT_NEAR(viewport_width * density_dpi_scale_ratio,
2580                 web_view_helper.GetWebView()
2581                     ->MainFrameImpl()
2582                     ->GetFrameView()
2583                     ->GetLayoutSize()
2584                     .Width(),
2585                 1.0f);
2586     EXPECT_NEAR(viewport_height * density_dpi_scale_ratio,
2587                 web_view_helper.GetWebView()
2588                     ->MainFrameImpl()
2589                     ->GetFrameView()
2590                     ->GetLayoutSize()
2591                     .Height(),
2592                 1.0f);
2593     EXPECT_NEAR(1.0f / density_dpi_scale_ratio,
2594                 web_view_helper.GetWebView()->PageScaleFactor(), 0.01f);
2595   }
2596 }
2597 
TEST_F(WebFrameTest,targetDensityDpiDevice)2598 TEST_F(WebFrameTest, targetDensityDpiDevice) {
2599   RegisterMockedHttpURLLoad("viewport-target-densitydpi-device.html");
2600 
2601   float device_scale_factors[] = {1.0f, 4.0f / 3.0f, 2.0f};
2602 
2603   FixedLayoutTestWebWidgetClient client;
2604   int viewport_width = 640;
2605   int viewport_height = 480;
2606 
2607   for (size_t i = 0; i < base::size(device_scale_factors); ++i) {
2608     client.screen_info_.device_scale_factor = device_scale_factors[i];
2609 
2610     frame_test_helpers::WebViewHelper web_view_helper;
2611     web_view_helper.InitializeAndLoad(
2612         base_url_ + "viewport-target-densitydpi-device.html", nullptr, nullptr,
2613         &client, ConfigureAndroid);
2614     web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
2615         true);
2616     web_view_helper.GetWebView()
2617         ->GetSettings()
2618         ->SetSupportDeprecatedTargetDensityDPI(true);
2619     web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
2620 
2621     EXPECT_NEAR(viewport_width * client.screen_info_.device_scale_factor,
2622                 web_view_helper.GetWebView()
2623                     ->MainFrameImpl()
2624                     ->GetFrameView()
2625                     ->GetLayoutSize()
2626                     .Width(),
2627                 1.0f);
2628     EXPECT_NEAR(viewport_height * client.screen_info_.device_scale_factor,
2629                 web_view_helper.GetWebView()
2630                     ->MainFrameImpl()
2631                     ->GetFrameView()
2632                     ->GetLayoutSize()
2633                     .Height(),
2634                 1.0f);
2635     EXPECT_NEAR(1.0f / client.screen_info_.device_scale_factor,
2636                 web_view_helper.GetWebView()->PageScaleFactor(), 0.01f);
2637   }
2638 }
2639 
TEST_F(WebFrameTest,targetDensityDpiDeviceAndFixedWidth)2640 TEST_F(WebFrameTest, targetDensityDpiDeviceAndFixedWidth) {
2641   RegisterMockedHttpURLLoad(
2642       "viewport-target-densitydpi-device-and-fixed-width.html");
2643 
2644   float device_scale_factors[] = {1.0f, 4.0f / 3.0f, 2.0f};
2645 
2646   FixedLayoutTestWebWidgetClient client;
2647   int viewport_width = 640;
2648   int viewport_height = 480;
2649 
2650   for (size_t i = 0; i < base::size(device_scale_factors); ++i) {
2651     client.screen_info_.device_scale_factor = device_scale_factors[i];
2652 
2653     frame_test_helpers::WebViewHelper web_view_helper;
2654     web_view_helper.InitializeAndLoad(
2655         base_url_ + "viewport-target-densitydpi-device-and-fixed-width.html",
2656         nullptr, nullptr, &client, ConfigureAndroid);
2657     web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
2658         true);
2659     web_view_helper.GetWebView()
2660         ->GetSettings()
2661         ->SetSupportDeprecatedTargetDensityDPI(true);
2662     web_view_helper.GetWebView()->GetSettings()->SetUseWideViewport(true);
2663     web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
2664 
2665     EXPECT_NEAR(viewport_width,
2666                 web_view_helper.GetWebView()
2667                     ->MainFrameImpl()
2668                     ->GetFrameView()
2669                     ->GetLayoutSize()
2670                     .Width(),
2671                 1.0f);
2672     EXPECT_NEAR(viewport_height,
2673                 web_view_helper.GetWebView()
2674                     ->MainFrameImpl()
2675                     ->GetFrameView()
2676                     ->GetLayoutSize()
2677                     .Height(),
2678                 1.0f);
2679     EXPECT_NEAR(1.0f, web_view_helper.GetWebView()->PageScaleFactor(), 0.01f);
2680   }
2681 }
2682 
TEST_F(WebFrameTest,NoWideViewportAndScaleLessThanOne)2683 TEST_F(WebFrameTest, NoWideViewportAndScaleLessThanOne) {
2684   RegisterMockedHttpURLLoad("viewport-initial-scale-less-than-1.html");
2685 
2686   FixedLayoutTestWebWidgetClient client;
2687   client.screen_info_.device_scale_factor = 1.33f;
2688   int viewport_width = 640;
2689   int viewport_height = 480;
2690 
2691   frame_test_helpers::WebViewHelper web_view_helper;
2692   web_view_helper.InitializeAndLoad(
2693       base_url_ + "viewport-initial-scale-less-than-1.html", nullptr, nullptr,
2694       &client, ConfigureAndroid);
2695   web_view_helper.GetWebView()
2696       ->GetSettings()
2697       ->SetSupportDeprecatedTargetDensityDPI(true);
2698   web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
2699       true);
2700   web_view_helper.GetWebView()->GetSettings()->SetUseWideViewport(false);
2701   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
2702 
2703   EXPECT_NEAR(viewport_width * client.screen_info_.device_scale_factor,
2704               web_view_helper.GetWebView()
2705                   ->MainFrameImpl()
2706                   ->GetFrameView()
2707                   ->GetLayoutSize()
2708                   .Width(),
2709               1.0f);
2710   EXPECT_NEAR(viewport_height * client.screen_info_.device_scale_factor,
2711               web_view_helper.GetWebView()
2712                   ->MainFrameImpl()
2713                   ->GetFrameView()
2714                   ->GetLayoutSize()
2715                   .Height(),
2716               1.0f);
2717   EXPECT_NEAR(1.0f / client.screen_info_.device_scale_factor,
2718               web_view_helper.GetWebView()->PageScaleFactor(), 0.01f);
2719 }
2720 
TEST_F(WebFrameTest,NoWideViewportAndScaleLessThanOneWithDeviceWidth)2721 TEST_F(WebFrameTest, NoWideViewportAndScaleLessThanOneWithDeviceWidth) {
2722   RegisterMockedHttpURLLoad(
2723       "viewport-initial-scale-less-than-1-device-width.html");
2724 
2725   FixedLayoutTestWebWidgetClient client;
2726   client.screen_info_.device_scale_factor = 1.33f;
2727   int viewport_width = 640;
2728   int viewport_height = 480;
2729 
2730   frame_test_helpers::WebViewHelper web_view_helper;
2731   web_view_helper.InitializeAndLoad(
2732       base_url_ + "viewport-initial-scale-less-than-1-device-width.html",
2733       nullptr, nullptr, &client, ConfigureAndroid);
2734   web_view_helper.GetWebView()
2735       ->GetSettings()
2736       ->SetSupportDeprecatedTargetDensityDPI(true);
2737   web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
2738       true);
2739   web_view_helper.GetWebView()->GetSettings()->SetUseWideViewport(false);
2740   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
2741 
2742   const float kPageZoom = 0.25f;
2743   EXPECT_NEAR(
2744       viewport_width * client.screen_info_.device_scale_factor / kPageZoom,
2745       web_view_helper.GetWebView()
2746           ->MainFrameImpl()
2747           ->GetFrameView()
2748           ->GetLayoutSize()
2749           .Width(),
2750       1.0f);
2751   EXPECT_NEAR(
2752       viewport_height * client.screen_info_.device_scale_factor / kPageZoom,
2753       web_view_helper.GetWebView()
2754           ->MainFrameImpl()
2755           ->GetFrameView()
2756           ->GetLayoutSize()
2757           .Height(),
2758       1.0f);
2759   EXPECT_NEAR(1.0f / client.screen_info_.device_scale_factor,
2760               web_view_helper.GetWebView()->PageScaleFactor(), 0.01f);
2761 }
2762 
TEST_F(WebFrameTest,NoWideViewportAndNoViewportWithInitialPageScaleOverride)2763 TEST_F(WebFrameTest, NoWideViewportAndNoViewportWithInitialPageScaleOverride) {
2764   RegisterMockedHttpURLLoad("large-div.html");
2765 
2766   FixedLayoutTestWebWidgetClient client;
2767   int viewport_width = 640;
2768   int viewport_height = 480;
2769   float enforced_page_scale_factor = 5.0f;
2770 
2771   frame_test_helpers::WebViewHelper web_view_helper;
2772   web_view_helper.InitializeAndLoad(base_url_ + "large-div.html", nullptr,
2773                                     nullptr, &client, ConfigureAndroid);
2774   web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.25f, 5);
2775   web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
2776       true);
2777   web_view_helper.GetWebView()->GetSettings()->SetUseWideViewport(false);
2778   web_view_helper.GetWebView()->SetInitialPageScaleOverride(
2779       enforced_page_scale_factor);
2780   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
2781 
2782   EXPECT_NEAR(viewport_width / enforced_page_scale_factor,
2783               web_view_helper.GetWebView()
2784                   ->MainFrameImpl()
2785                   ->GetFrameView()
2786                   ->GetLayoutSize()
2787                   .Width(),
2788               1.0f);
2789   EXPECT_NEAR(viewport_height / enforced_page_scale_factor,
2790               web_view_helper.GetWebView()
2791                   ->MainFrameImpl()
2792                   ->GetFrameView()
2793                   ->GetLayoutSize()
2794                   .Height(),
2795               1.0f);
2796   EXPECT_NEAR(enforced_page_scale_factor,
2797               web_view_helper.GetWebView()->PageScaleFactor(), 0.01f);
2798 }
2799 
TEST_F(WebFrameTest,NoUserScalableQuirkIgnoresViewportScale)2800 TEST_F(WebFrameTest, NoUserScalableQuirkIgnoresViewportScale) {
2801   RegisterMockedHttpURLLoad("viewport-initial-scale-and-user-scalable-no.html");
2802 
2803   FixedLayoutTestWebWidgetClient client;
2804   int viewport_width = 640;
2805   int viewport_height = 480;
2806 
2807   frame_test_helpers::WebViewHelper web_view_helper;
2808   web_view_helper.InitializeAndLoad(
2809       base_url_ + "viewport-initial-scale-and-user-scalable-no.html", nullptr,
2810       nullptr, &client, ConfigureAndroid);
2811   web_view_helper.GetWebView()
2812       ->GetSettings()
2813       ->SetViewportMetaNonUserScalableQuirk(true);
2814   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
2815 
2816   EXPECT_NEAR(viewport_width,
2817               web_view_helper.GetWebView()
2818                   ->MainFrameImpl()
2819                   ->GetFrameView()
2820                   ->GetLayoutSize()
2821                   .Width(),
2822               1.0f);
2823   EXPECT_NEAR(viewport_height,
2824               web_view_helper.GetWebView()
2825                   ->MainFrameImpl()
2826                   ->GetFrameView()
2827                   ->GetLayoutSize()
2828                   .Height(),
2829               1.0f);
2830   EXPECT_NEAR(1.0f, web_view_helper.GetWebView()->PageScaleFactor(), 0.01f);
2831 }
2832 
TEST_F(WebFrameTest,NoUserScalableQuirkIgnoresViewportScaleForNonWideViewport)2833 TEST_F(WebFrameTest,
2834        NoUserScalableQuirkIgnoresViewportScaleForNonWideViewport) {
2835   RegisterMockedHttpURLLoad("viewport-initial-scale-and-user-scalable-no.html");
2836 
2837   FixedLayoutTestWebWidgetClient client;
2838   client.screen_info_.device_scale_factor = 1.33f;
2839   int viewport_width = 640;
2840   int viewport_height = 480;
2841 
2842   frame_test_helpers::WebViewHelper web_view_helper;
2843   web_view_helper.InitializeAndLoad(
2844       base_url_ + "viewport-initial-scale-and-user-scalable-no.html", nullptr,
2845       nullptr, &client, ConfigureAndroid);
2846   web_view_helper.GetWebView()
2847       ->GetSettings()
2848       ->SetSupportDeprecatedTargetDensityDPI(true);
2849   web_view_helper.GetWebView()
2850       ->GetSettings()
2851       ->SetViewportMetaNonUserScalableQuirk(true);
2852   web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
2853       true);
2854   web_view_helper.GetWebView()->GetSettings()->SetUseWideViewport(false);
2855   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
2856 
2857   EXPECT_NEAR(viewport_width * client.screen_info_.device_scale_factor,
2858               web_view_helper.GetWebView()
2859                   ->MainFrameImpl()
2860                   ->GetFrameView()
2861                   ->GetLayoutSize()
2862                   .Width(),
2863               1.0f);
2864   EXPECT_NEAR(viewport_height * client.screen_info_.device_scale_factor,
2865               web_view_helper.GetWebView()
2866                   ->MainFrameImpl()
2867                   ->GetFrameView()
2868                   ->GetLayoutSize()
2869                   .Height(),
2870               1.0f);
2871   EXPECT_NEAR(1.0f / client.screen_info_.device_scale_factor,
2872               web_view_helper.GetWebView()->PageScaleFactor(), 0.01f);
2873 }
2874 
TEST_F(WebFrameTest,NoUserScalableQuirkIgnoresViewportScaleForWideViewport)2875 TEST_F(WebFrameTest, NoUserScalableQuirkIgnoresViewportScaleForWideViewport) {
2876   RegisterMockedHttpURLLoad("viewport-2x-initial-scale-non-user-scalable.html");
2877 
2878   FixedLayoutTestWebWidgetClient client;
2879   int viewport_width = 640;
2880   int viewport_height = 480;
2881 
2882   frame_test_helpers::WebViewHelper web_view_helper;
2883   web_view_helper.InitializeAndLoad(
2884       base_url_ + "viewport-2x-initial-scale-non-user-scalable.html", nullptr,
2885       nullptr, &client, ConfigureAndroid);
2886   web_view_helper.GetWebView()
2887       ->GetSettings()
2888       ->SetViewportMetaNonUserScalableQuirk(true);
2889   web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
2890       true);
2891   web_view_helper.GetWebView()->GetSettings()->SetUseWideViewport(true);
2892   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
2893 
2894   EXPECT_NEAR(viewport_width,
2895               web_view_helper.GetWebView()
2896                   ->MainFrameImpl()
2897                   ->GetFrameView()
2898                   ->GetLayoutSize()
2899                   .Width(),
2900               1.0f);
2901   EXPECT_NEAR(viewport_height,
2902               web_view_helper.GetWebView()
2903                   ->MainFrameImpl()
2904                   ->GetFrameView()
2905                   ->GetLayoutSize()
2906                   .Height(),
2907               1.0f);
2908   EXPECT_NEAR(1.0f, web_view_helper.GetWebView()->PageScaleFactor(), 0.01f);
2909 }
2910 
TEST_F(WebFrameTest,DesktopPageCanBeZoomedInWhenWideViewportIsTurnedOff)2911 TEST_F(WebFrameTest, DesktopPageCanBeZoomedInWhenWideViewportIsTurnedOff) {
2912   RegisterMockedHttpURLLoad("no_viewport_tag.html");
2913 
2914   FixedLayoutTestWebWidgetClient client;
2915   int viewport_width = 640;
2916   int viewport_height = 480;
2917 
2918   frame_test_helpers::WebViewHelper web_view_helper;
2919   web_view_helper.InitializeAndLoad(base_url_ + "no_viewport_tag.html", nullptr,
2920                                     nullptr, &client, ConfigureAndroid);
2921   web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.25f, 5);
2922   web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
2923       true);
2924   web_view_helper.GetWebView()->GetSettings()->SetUseWideViewport(false);
2925   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
2926 
2927   EXPECT_NEAR(1.0f, web_view_helper.GetWebView()->PageScaleFactor(), 0.01f);
2928   EXPECT_NEAR(1.0f, web_view_helper.GetWebView()->MinimumPageScaleFactor(),
2929               0.01f);
2930   EXPECT_NEAR(5.0f, web_view_helper.GetWebView()->MaximumPageScaleFactor(),
2931               0.01f);
2932 }
2933 
2934 class WebFrameResizeTest : public WebFrameTest {
2935  protected:
ComputeRelativeOffset(const IntPoint & absolute_offset,const LayoutRect & rect)2936   static FloatSize ComputeRelativeOffset(const IntPoint& absolute_offset,
2937                                          const LayoutRect& rect) {
2938     FloatSize relative_offset =
2939         FloatPoint(absolute_offset) - FloatPoint(rect.Location());
2940     relative_offset.Scale(1.f / rect.Width(), 1.f / rect.Height());
2941     return relative_offset;
2942   }
2943 
TestResizeYieldsCorrectScrollAndScale(const char * url,const float initial_page_scale_factor,const WebSize scroll_offset,const WebSize viewport_size,const bool should_scale_relative_to_viewport_width)2944   void TestResizeYieldsCorrectScrollAndScale(
2945       const char* url,
2946       const float initial_page_scale_factor,
2947       const WebSize scroll_offset,
2948       const WebSize viewport_size,
2949       const bool should_scale_relative_to_viewport_width) {
2950     RegisterMockedHttpURLLoad(url);
2951 
2952     const float aspect_ratio =
2953         static_cast<float>(viewport_size.width) / viewport_size.height;
2954 
2955     frame_test_helpers::WebViewHelper web_view_helper;
2956     web_view_helper.InitializeAndLoad(base_url_ + url, nullptr, nullptr,
2957                                       nullptr, ConfigureAndroid);
2958     web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.25f, 5);
2959 
2960     // Origin scrollOffsets preserved under resize.
2961     {
2962       web_view_helper.Resize(
2963           gfx::Size(viewport_size.width, viewport_size.height));
2964       web_view_helper.GetWebView()->SetPageScaleFactor(
2965           initial_page_scale_factor);
2966       ASSERT_EQ(gfx::Size(viewport_size),
2967                 web_view_helper.GetWebView()->MainFrameWidget()->Size());
2968       ASSERT_EQ(initial_page_scale_factor,
2969                 web_view_helper.GetWebView()->PageScaleFactor());
2970       web_view_helper.Resize(
2971           gfx::Size(viewport_size.height, viewport_size.width));
2972       float expected_page_scale_factor =
2973           initial_page_scale_factor *
2974           (should_scale_relative_to_viewport_width ? 1 / aspect_ratio : 1);
2975       EXPECT_NEAR(expected_page_scale_factor,
2976                   web_view_helper.GetWebView()->PageScaleFactor(), 0.05f);
2977       EXPECT_EQ(WebSize(), web_view_helper.LocalMainFrame()->GetScrollOffset());
2978     }
2979 
2980     // Resizing just the height should not affect pageScaleFactor or
2981     // scrollOffset.
2982     {
2983       web_view_helper.Resize(
2984           gfx::Size(viewport_size.width, viewport_size.height));
2985       web_view_helper.GetWebView()->SetPageScaleFactor(
2986           initial_page_scale_factor);
2987       web_view_helper.LocalMainFrame()->SetScrollOffset(scroll_offset);
2988       UpdateAllLifecyclePhases(web_view_helper.GetWebView());
2989       const WebSize expected_scroll_offset =
2990           web_view_helper.LocalMainFrame()->GetScrollOffset();
2991       web_view_helper.Resize(
2992           gfx::Size(viewport_size.width, viewport_size.height * 0.8f));
2993       EXPECT_EQ(initial_page_scale_factor,
2994                 web_view_helper.GetWebView()->PageScaleFactor());
2995       EXPECT_EQ(expected_scroll_offset,
2996                 web_view_helper.LocalMainFrame()->GetScrollOffset());
2997       web_view_helper.Resize(
2998           gfx::Size(viewport_size.width, viewport_size.height * 0.8f));
2999       EXPECT_EQ(initial_page_scale_factor,
3000                 web_view_helper.GetWebView()->PageScaleFactor());
3001       EXPECT_EQ(expected_scroll_offset,
3002                 web_view_helper.LocalMainFrame()->GetScrollOffset());
3003     }
3004   }
3005 };
3006 
TEST_F(WebFrameResizeTest,ResizeYieldsCorrectScrollAndScaleForWidthEqualsDeviceWidth)3007 TEST_F(WebFrameResizeTest,
3008        ResizeYieldsCorrectScrollAndScaleForWidthEqualsDeviceWidth) {
3009   // With width=device-width, pageScaleFactor is preserved across resizes as
3010   // long as the content adjusts according to the device-width.
3011   const char* url = "resize_scroll_mobile.html";
3012   const float kInitialPageScaleFactor = 1;
3013   const WebSize scroll_offset(0, 50);
3014   const WebSize viewport_size(120, 160);
3015   const bool kShouldScaleRelativeToViewportWidth = true;
3016 
3017   TestResizeYieldsCorrectScrollAndScale(url, kInitialPageScaleFactor,
3018                                         scroll_offset, viewport_size,
3019                                         kShouldScaleRelativeToViewportWidth);
3020 }
3021 
TEST_F(WebFrameResizeTest,ResizeYieldsCorrectScrollAndScaleForMinimumScale)3022 TEST_F(WebFrameResizeTest, ResizeYieldsCorrectScrollAndScaleForMinimumScale) {
3023   // This tests a scenario where minimum-scale is set to 1.0, but some element
3024   // on the page is slightly larger than the portrait width, so our "natural"
3025   // minimum-scale would be lower. In that case, we should stick to 1.0 scale
3026   // on rotation and not do anything strange.
3027   const char* url = "resize_scroll_minimum_scale.html";
3028   const float kInitialPageScaleFactor = 1;
3029   const WebSize scroll_offset(0, 0);
3030   const WebSize viewport_size(240, 320);
3031   const bool kShouldScaleRelativeToViewportWidth = false;
3032 
3033   TestResizeYieldsCorrectScrollAndScale(url, kInitialPageScaleFactor,
3034                                         scroll_offset, viewport_size,
3035                                         kShouldScaleRelativeToViewportWidth);
3036 }
3037 
TEST_F(WebFrameResizeTest,ResizeYieldsCorrectScrollAndScaleForFixedWidth)3038 TEST_F(WebFrameResizeTest, ResizeYieldsCorrectScrollAndScaleForFixedWidth) {
3039   // With a fixed width, pageScaleFactor scales by the relative change in
3040   // viewport width.
3041   const char* url = "resize_scroll_fixed_width.html";
3042   const float kInitialPageScaleFactor = 2;
3043   const WebSize scroll_offset(0, 200);
3044   const WebSize viewport_size(240, 320);
3045   const bool kShouldScaleRelativeToViewportWidth = true;
3046 
3047   TestResizeYieldsCorrectScrollAndScale(url, kInitialPageScaleFactor,
3048                                         scroll_offset, viewport_size,
3049                                         kShouldScaleRelativeToViewportWidth);
3050 }
3051 
TEST_F(WebFrameResizeTest,ResizeYieldsCorrectScrollAndScaleForFixedLayout)3052 TEST_F(WebFrameResizeTest, ResizeYieldsCorrectScrollAndScaleForFixedLayout) {
3053   // With a fixed layout, pageScaleFactor scales by the relative change in
3054   // viewport width.
3055   const char* url = "resize_scroll_fixed_layout.html";
3056   const float kInitialPageScaleFactor = 2;
3057   const WebSize scroll_offset(200, 400);
3058   const WebSize viewport_size(320, 240);
3059   const bool kShouldScaleRelativeToViewportWidth = true;
3060 
3061   TestResizeYieldsCorrectScrollAndScale(url, kInitialPageScaleFactor,
3062                                         scroll_offset, viewport_size,
3063                                         kShouldScaleRelativeToViewportWidth);
3064 }
3065 
TEST_F(WebFrameTest,pageScaleFactorUpdatesScrollbars)3066 TEST_F(WebFrameTest, pageScaleFactorUpdatesScrollbars) {
3067   RegisterMockedHttpURLLoad("fixed_layout.html");
3068 
3069   FixedLayoutTestWebWidgetClient client;
3070   client.screen_info_.device_scale_factor = 1;
3071   int viewport_width = 640;
3072   int viewport_height = 480;
3073 
3074   frame_test_helpers::WebViewHelper web_view_helper;
3075   web_view_helper.InitializeAndLoad(base_url_ + "fixed_layout.html", nullptr,
3076                                     nullptr, &client, ConfigureAndroid);
3077   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
3078 
3079   LocalFrameView* view = web_view_helper.LocalMainFrame()->GetFrameView();
3080   ScrollableArea* scrollable_area = view->LayoutViewport();
3081   EXPECT_EQ(scrollable_area->ScrollSize(kHorizontalScrollbar),
3082             scrollable_area->ContentsSize().Width() - view->Width());
3083   EXPECT_EQ(scrollable_area->ScrollSize(kVerticalScrollbar),
3084             scrollable_area->ContentsSize().Height() - view->Height());
3085 
3086   web_view_helper.GetWebView()->SetPageScaleFactor(10);
3087 
3088   EXPECT_EQ(scrollable_area->ScrollSize(kHorizontalScrollbar),
3089             scrollable_area->ContentsSize().Width() - view->Width());
3090   EXPECT_EQ(scrollable_area->ScrollSize(kVerticalScrollbar),
3091             scrollable_area->ContentsSize().Height() - view->Height());
3092 }
3093 
TEST_F(WebFrameTest,CanOverrideScaleLimits)3094 TEST_F(WebFrameTest, CanOverrideScaleLimits) {
3095   RegisterMockedHttpURLLoad("no_scale_for_you.html");
3096 
3097   FixedLayoutTestWebWidgetClient client;
3098   client.screen_info_.device_scale_factor = 1;
3099   int viewport_width = 640;
3100   int viewport_height = 480;
3101 
3102   frame_test_helpers::WebViewHelper web_view_helper;
3103   web_view_helper.InitializeAndLoad(base_url_ + "no_scale_for_you.html",
3104                                     nullptr, nullptr, &client,
3105                                     ConfigureAndroid);
3106   web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.25f, 5);
3107   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
3108 
3109   EXPECT_EQ(2.0f, web_view_helper.GetWebView()->MinimumPageScaleFactor());
3110   EXPECT_EQ(2.0f, web_view_helper.GetWebView()->MaximumPageScaleFactor());
3111 
3112   web_view_helper.GetWebView()->SetIgnoreViewportTagScaleLimits(true);
3113   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
3114 
3115   EXPECT_EQ(1.0f, web_view_helper.GetWebView()->MinimumPageScaleFactor());
3116   EXPECT_EQ(5.0f, web_view_helper.GetWebView()->MaximumPageScaleFactor());
3117 
3118   web_view_helper.GetWebView()->SetIgnoreViewportTagScaleLimits(false);
3119   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
3120 
3121   EXPECT_EQ(2.0f, web_view_helper.GetWebView()->MinimumPageScaleFactor());
3122   EXPECT_EQ(2.0f, web_view_helper.GetWebView()->MaximumPageScaleFactor());
3123 }
3124 
3125 // Android doesn't have scrollbars on the main LocalFrameView
3126 #if defined(OS_ANDROID)
TEST_F(WebFrameTest,DISABLED_updateOverlayScrollbarLayers)3127 TEST_F(WebFrameTest, DISABLED_updateOverlayScrollbarLayers)
3128 #else
3129 TEST_F(WebFrameTest, updateOverlayScrollbarLayers)
3130 #endif
3131 {
3132   RegisterMockedHttpURLLoad("large-div.html");
3133 
3134   int view_width = 500;
3135   int view_height = 500;
3136 
3137   FixedLayoutTestWebWidgetClient client;
3138   frame_test_helpers::WebViewHelper web_view_helper;
3139   web_view_helper.Initialize(nullptr, nullptr, &client,
3140                              &ConfigureCompositingWebView);
3141 
3142   web_view_helper.Resize(gfx::Size(view_width, view_height));
3143   frame_test_helpers::LoadFrame(web_view_helper.GetWebView()->MainFrameImpl(),
3144                                 base_url_ + "large-div.html");
3145 
3146   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
3147   LocalFrameView* view = web_view_helper.LocalMainFrame()->GetFrameView();
3148   EXPECT_TRUE(view->LayoutViewport()->LayerForHorizontalScrollbar());
3149   EXPECT_TRUE(view->LayoutViewport()->LayerForVerticalScrollbar());
3150 
3151   web_view_helper.Resize(gfx::Size(view_width * 10, view_height * 10));
3152   EXPECT_FALSE(view->LayoutViewport()->LayerForHorizontalScrollbar());
3153   EXPECT_FALSE(view->LayoutViewport()->LayerForVerticalScrollbar());
3154 }
3155 
SetScaleAndScrollAndLayout(WebViewImpl * web_view,const gfx::Point & scroll,float scale)3156 void SetScaleAndScrollAndLayout(WebViewImpl* web_view,
3157                                 const gfx::Point& scroll,
3158                                 float scale) {
3159   web_view->SetPageScaleFactor(scale);
3160   web_view->MainFrameImpl()->SetScrollOffset(WebSize(scroll.x(), scroll.y()));
3161   web_view->MainFrameWidget()->UpdateAllLifecyclePhases(
3162       DocumentUpdateReason::kTest);
3163 }
3164 
SimulatePageScale(WebViewImpl * web_view_impl,float & scale)3165 void SimulatePageScale(WebViewImpl* web_view_impl, float& scale) {
3166   float scale_delta =
3167       web_view_impl->FakePageScaleAnimationPageScaleForTesting() /
3168       web_view_impl->PageScaleFactor();
3169   web_view_impl->MainFrameWidget()->ApplyViewportChangesForTesting(
3170       {gfx::ScrollOffset(), gfx::Vector2dF(), scale_delta, false, 0, 0,
3171        cc::BrowserControlsState::kBoth});
3172   scale = web_view_impl->PageScaleFactor();
3173 }
3174 
ComputeBlockBoundHelper(WebViewImpl * web_view_impl,const gfx::Point & point,bool ignore_clipping)3175 WebRect ComputeBlockBoundHelper(WebViewImpl* web_view_impl,
3176                                 const gfx::Point& point,
3177                                 bool ignore_clipping) {
3178   DCHECK(web_view_impl->MainFrameImpl());
3179   WebFrameWidgetBase* widget =
3180       web_view_impl->MainFrameImpl()->FrameWidgetImpl();
3181   DCHECK(widget);
3182   return widget->ComputeBlockBound(point, ignore_clipping);
3183 }
3184 
SimulateDoubleTap(WebViewImpl * web_view_impl,gfx::Point & point,float & scale)3185 void SimulateDoubleTap(WebViewImpl* web_view_impl,
3186                        gfx::Point& point,
3187                        float& scale) {
3188   web_view_impl->AnimateDoubleTapZoom(
3189       IntPoint(point), ComputeBlockBoundHelper(web_view_impl, point, false));
3190   EXPECT_TRUE(web_view_impl->FakeDoubleTapAnimationPendingForTesting());
3191   SimulatePageScale(web_view_impl, scale);
3192 }
3193 
TEST_F(WebFrameTest,DivAutoZoomParamsTest)3194 TEST_F(WebFrameTest, DivAutoZoomParamsTest) {
3195   RegisterMockedHttpURLLoad("get_scale_for_auto_zoom_into_div_test.html");
3196 
3197   const float kDeviceScaleFactor = 2.0f;
3198   int viewport_width = 640 / kDeviceScaleFactor;
3199   int viewport_height = 1280 / kDeviceScaleFactor;
3200   float double_tap_zoom_already_legible_ratio = 1.2f;
3201   frame_test_helpers::WebViewHelper web_view_helper;
3202   web_view_helper.InitializeAndLoad(
3203       base_url_ + "get_scale_for_auto_zoom_into_div_test.html", nullptr,
3204       nullptr, nullptr, ConfigureAndroid);
3205   web_view_helper.GetWebView()->SetDeviceScaleFactor(kDeviceScaleFactor);
3206   web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.01f, 4);
3207   web_view_helper.GetWebView()->SetPageScaleFactor(0.5f);
3208   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
3209 
3210   WebRect wide_div(200, 100, 400, 150);
3211   WebRect tall_div(200, 300, 400, 800);
3212   gfx::Point double_tap_point_wide(wide_div.x + 50, wide_div.y + 50);
3213   gfx::Point double_tap_point_tall(tall_div.x + 50, tall_div.y + 50);
3214   float scale;
3215   IntPoint scroll;
3216 
3217   float double_tap_zoom_already_legible_scale =
3218       web_view_helper.GetWebView()->MinimumPageScaleFactor() *
3219       double_tap_zoom_already_legible_ratio;
3220 
3221   // Test double-tap zooming into wide div.
3222   WebRect wide_block_bound = ComputeBlockBoundHelper(
3223       web_view_helper.GetWebView(), double_tap_point_wide, false);
3224   web_view_helper.GetWebView()->ComputeScaleAndScrollForBlockRect(
3225       double_tap_point_wide, wide_block_bound, kTouchPointPadding,
3226       double_tap_zoom_already_legible_scale, scale, scroll);
3227   // The div should horizontally fill the screen (modulo margins), and
3228   // vertically centered (modulo integer rounding).
3229   EXPECT_NEAR(viewport_width / (float)wide_div.width, scale, 0.1);
3230   EXPECT_NEAR(wide_div.x, scroll.X(), 20);
3231   EXPECT_EQ(0, scroll.Y());
3232 
3233   SetScaleAndScrollAndLayout(web_view_helper.GetWebView(), scroll, scale);
3234 
3235   // Test zoom out back to minimum scale.
3236   wide_block_bound = ComputeBlockBoundHelper(web_view_helper.GetWebView(),
3237                                              double_tap_point_wide, false);
3238   web_view_helper.GetWebView()->ComputeScaleAndScrollForBlockRect(
3239       double_tap_point_wide, wide_block_bound, kTouchPointPadding,
3240       double_tap_zoom_already_legible_scale, scale, scroll);
3241   // FIXME: Looks like we are missing EXPECTs here.
3242 
3243   scale = web_view_helper.GetWebView()->MinimumPageScaleFactor();
3244   SetScaleAndScrollAndLayout(web_view_helper.GetWebView(), gfx::Point(), scale);
3245 
3246   // Test double-tap zooming into tall div.
3247   WebRect tall_block_bound = ComputeBlockBoundHelper(
3248       web_view_helper.GetWebView(), double_tap_point_tall, false);
3249   web_view_helper.GetWebView()->ComputeScaleAndScrollForBlockRect(
3250       double_tap_point_tall, tall_block_bound, kTouchPointPadding,
3251       double_tap_zoom_already_legible_scale, scale, scroll);
3252   // The div should start at the top left of the viewport.
3253   EXPECT_NEAR(viewport_width / (float)tall_div.width, scale, 0.1);
3254   EXPECT_NEAR(tall_div.x, scroll.X(), 20);
3255   EXPECT_NEAR(tall_div.y, scroll.Y(), 20);
3256 }
3257 
TEST_F(WebFrameTest,DivAutoZoomWideDivTest)3258 TEST_F(WebFrameTest, DivAutoZoomWideDivTest) {
3259   RegisterMockedHttpURLLoad("get_wide_div_for_auto_zoom_test.html");
3260 
3261   const float kDeviceScaleFactor = 2.0f;
3262   int viewport_width = 640 / kDeviceScaleFactor;
3263   int viewport_height = 1280 / kDeviceScaleFactor;
3264   float double_tap_zoom_already_legible_ratio = 1.2f;
3265   frame_test_helpers::WebViewHelper web_view_helper;
3266   web_view_helper.InitializeAndLoad(
3267       base_url_ + "get_wide_div_for_auto_zoom_test.html", nullptr, nullptr,
3268       nullptr, ConfigureAndroid);
3269   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
3270   web_view_helper.GetWebView()->SetDeviceScaleFactor(kDeviceScaleFactor);
3271   web_view_helper.GetWebView()->SetPageScaleFactor(1.0f);
3272   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
3273 
3274   web_view_helper.GetWebView()->EnableFakePageScaleAnimationForTesting(true);
3275 
3276   float double_tap_zoom_already_legible_scale =
3277       web_view_helper.GetWebView()->MinimumPageScaleFactor() *
3278       double_tap_zoom_already_legible_ratio;
3279 
3280   WebRect div(0, 100, viewport_width, 150);
3281   gfx::Point point(div.x + 50, div.y + 50);
3282   float scale;
3283   SetScaleAndScrollAndLayout(
3284       web_view_helper.GetWebView(), gfx::Point(),
3285       (web_view_helper.GetWebView()->MinimumPageScaleFactor()) *
3286           (1 + double_tap_zoom_already_legible_ratio) / 2);
3287 
3288   SimulateDoubleTap(web_view_helper.GetWebView(), point, scale);
3289   EXPECT_FLOAT_EQ(double_tap_zoom_already_legible_scale, scale);
3290   SimulateDoubleTap(web_view_helper.GetWebView(), point, scale);
3291   EXPECT_FLOAT_EQ(web_view_helper.GetWebView()->MinimumPageScaleFactor(),
3292                   scale);
3293 }
3294 
TEST_F(WebFrameTest,DivAutoZoomVeryTallTest)3295 TEST_F(WebFrameTest, DivAutoZoomVeryTallTest) {
3296   // When a block is taller than the viewport and a zoom targets a lower part
3297   // of it, then we should keep the target point onscreen instead of snapping
3298   // back up the top of the block.
3299   RegisterMockedHttpURLLoad("very_tall_div.html");
3300 
3301   const float kDeviceScaleFactor = 2.0f;
3302   int viewport_width = 640 / kDeviceScaleFactor;
3303   int viewport_height = 1280 / kDeviceScaleFactor;
3304   frame_test_helpers::WebViewHelper web_view_helper;
3305   web_view_helper.InitializeAndLoad(base_url_ + "very_tall_div.html", nullptr,
3306                                     nullptr, nullptr, ConfigureAndroid);
3307   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
3308   web_view_helper.GetWebView()->SetDeviceScaleFactor(kDeviceScaleFactor);
3309   web_view_helper.GetWebView()->SetPageScaleFactor(1.0f);
3310   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
3311 
3312   WebRect div(200, 300, 400, 5000);
3313   gfx::Point point(div.x + 50, div.y + 3000);
3314   float scale;
3315   IntPoint scroll;
3316 
3317   WebRect block_bound =
3318       ComputeBlockBoundHelper(web_view_helper.GetWebView(), point, true);
3319   web_view_helper.GetWebView()->ComputeScaleAndScrollForBlockRect(
3320       point, block_bound, 0, 1.0f, scale, scroll);
3321   EXPECT_EQ(scale, 1.0f);
3322   EXPECT_EQ(scroll.Y(), 2660);
3323 }
3324 
TEST_F(WebFrameTest,DivAutoZoomMultipleDivsTest)3325 TEST_F(WebFrameTest, DivAutoZoomMultipleDivsTest) {
3326   RegisterMockedHttpURLLoad("get_multiple_divs_for_auto_zoom_test.html");
3327 
3328   const float kDeviceScaleFactor = 2.0f;
3329   int viewport_width = 640 / kDeviceScaleFactor;
3330   int viewport_height = 1280 / kDeviceScaleFactor;
3331   float double_tap_zoom_already_legible_ratio = 1.2f;
3332   frame_test_helpers::WebViewHelper web_view_helper;
3333   web_view_helper.InitializeAndLoad(
3334       base_url_ + "get_multiple_divs_for_auto_zoom_test.html", nullptr, nullptr,
3335       nullptr, ConfigureAndroid);
3336   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
3337   web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.5f, 4);
3338   web_view_helper.GetWebView()->SetDeviceScaleFactor(kDeviceScaleFactor);
3339   web_view_helper.GetWebView()->SetPageScaleFactor(0.5f);
3340   web_view_helper.GetWebView()->SetMaximumLegibleScale(1.f);
3341   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
3342 
3343   web_view_helper.GetWebView()->EnableFakePageScaleAnimationForTesting(true);
3344 
3345   WebRect top_div(200, 100, 200, 150);
3346   WebRect bottom_div(200, 300, 200, 150);
3347   gfx::Point top_point(top_div.x + 50, top_div.y + 50);
3348   gfx::Point bottom_point(bottom_div.x + 50, bottom_div.y + 50);
3349   float scale;
3350   SetScaleAndScrollAndLayout(
3351       web_view_helper.GetWebView(), gfx::Point(),
3352       (web_view_helper.GetWebView()->MinimumPageScaleFactor()) *
3353           (1 + double_tap_zoom_already_legible_ratio) / 2);
3354 
3355   // Test double tap on two different divs.  After first zoom, we should go back
3356   // to minimum page scale with a second double tap.
3357   SimulateDoubleTap(web_view_helper.GetWebView(), top_point, scale);
3358   EXPECT_FLOAT_EQ(1, scale);
3359   SimulateDoubleTap(web_view_helper.GetWebView(), bottom_point, scale);
3360   EXPECT_FLOAT_EQ(web_view_helper.GetWebView()->MinimumPageScaleFactor(),
3361                   scale);
3362 
3363   // If the user pinch zooms after double tap, a second double tap should zoom
3364   // back to the div.
3365   SimulateDoubleTap(web_view_helper.GetWebView(), top_point, scale);
3366   EXPECT_FLOAT_EQ(1, scale);
3367   web_view_helper.GetWebView()
3368       ->MainFrameWidget()
3369       ->ApplyViewportChangesForTesting({gfx::ScrollOffset(), gfx::Vector2dF(),
3370                                         0.6f, false, 0, 0,
3371                                         cc::BrowserControlsState::kBoth});
3372   SimulateDoubleTap(web_view_helper.GetWebView(), bottom_point, scale);
3373   EXPECT_FLOAT_EQ(1, scale);
3374   SimulateDoubleTap(web_view_helper.GetWebView(), bottom_point, scale);
3375   EXPECT_FLOAT_EQ(web_view_helper.GetWebView()->MinimumPageScaleFactor(),
3376                   scale);
3377 
3378   // If we didn't yet get an auto-zoom update and a second double-tap arrives,
3379   // should go back to minimum scale.
3380   web_view_helper.GetWebView()
3381       ->MainFrameWidget()
3382       ->ApplyViewportChangesForTesting({gfx::ScrollOffset(), gfx::Vector2dF(),
3383                                         1.1f, false, 0, 0,
3384                                         cc::BrowserControlsState::kBoth});
3385 
3386   WebRect block_bounds =
3387       ComputeBlockBoundHelper(web_view_helper.GetWebView(), top_point, false);
3388   web_view_helper.GetWebView()->AnimateDoubleTapZoom(IntPoint(top_point),
3389                                                      block_bounds);
3390   EXPECT_TRUE(
3391       web_view_helper.GetWebView()->FakeDoubleTapAnimationPendingForTesting());
3392   SimulateDoubleTap(web_view_helper.GetWebView(), bottom_point, scale);
3393   EXPECT_FLOAT_EQ(web_view_helper.GetWebView()->MinimumPageScaleFactor(),
3394                   scale);
3395 }
3396 
TEST_F(WebFrameTest,DivAutoZoomScaleBoundsTest)3397 TEST_F(WebFrameTest, DivAutoZoomScaleBoundsTest) {
3398   RegisterMockedHttpURLLoad("get_scale_bounds_check_for_auto_zoom_test.html");
3399 
3400   int viewport_width = 320;
3401   int viewport_height = 480;
3402   float double_tap_zoom_already_legible_ratio = 1.2f;
3403   frame_test_helpers::WebViewHelper web_view_helper;
3404   web_view_helper.InitializeAndLoad(
3405       base_url_ + "get_scale_bounds_check_for_auto_zoom_test.html", nullptr,
3406       nullptr, nullptr, ConfigureAndroid);
3407   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
3408   web_view_helper.GetWebView()->SetDeviceScaleFactor(1.5f);
3409   web_view_helper.GetWebView()->SetMaximumLegibleScale(1.f);
3410   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
3411 
3412   web_view_helper.GetWebView()->EnableFakePageScaleAnimationForTesting(true);
3413 
3414   WebRect div(200, 100, 200, 150);
3415   gfx::Point double_tap_point(div.x + 50, div.y + 50);
3416   float scale;
3417 
3418   // Test double tap scale bounds.
3419   // minimumPageScale < doubleTapZoomAlreadyLegibleScale < 1
3420   web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.5f, 4);
3421   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
3422   float double_tap_zoom_already_legible_scale =
3423       web_view_helper.GetWebView()->MinimumPageScaleFactor() *
3424       double_tap_zoom_already_legible_ratio;
3425   SetScaleAndScrollAndLayout(
3426       web_view_helper.GetWebView(), gfx::Point(),
3427       (web_view_helper.GetWebView()->MinimumPageScaleFactor()) *
3428           (1 + double_tap_zoom_already_legible_ratio) / 2);
3429   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3430   EXPECT_FLOAT_EQ(1, scale);
3431   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3432   EXPECT_FLOAT_EQ(web_view_helper.GetWebView()->MinimumPageScaleFactor(),
3433                   scale);
3434   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3435   EXPECT_FLOAT_EQ(1, scale);
3436 
3437   // Zoom in to reset double_tap_zoom_in_effect flag.
3438   web_view_helper.GetWebView()
3439       ->MainFrameWidget()
3440       ->ApplyViewportChangesForTesting({gfx::ScrollOffset(), gfx::Vector2dF(),
3441                                         1.1f, false, 0, 0,
3442                                         cc::BrowserControlsState::kBoth});
3443   // 1 < minimumPageScale < doubleTapZoomAlreadyLegibleScale
3444   web_view_helper.GetWebView()->SetDefaultPageScaleLimits(1.1f, 4);
3445   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
3446   double_tap_zoom_already_legible_scale =
3447       web_view_helper.GetWebView()->MinimumPageScaleFactor() *
3448       double_tap_zoom_already_legible_ratio;
3449   SetScaleAndScrollAndLayout(
3450       web_view_helper.GetWebView(), gfx::Point(),
3451       (web_view_helper.GetWebView()->MinimumPageScaleFactor()) *
3452           (1 + double_tap_zoom_already_legible_ratio) / 2);
3453   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3454   EXPECT_FLOAT_EQ(double_tap_zoom_already_legible_scale, scale);
3455   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3456   EXPECT_FLOAT_EQ(web_view_helper.GetWebView()->MinimumPageScaleFactor(),
3457                   scale);
3458   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3459   EXPECT_FLOAT_EQ(double_tap_zoom_already_legible_scale, scale);
3460 
3461   // Zoom in to reset double_tap_zoom_in_effect flag.
3462   web_view_helper.GetWebView()
3463       ->MainFrameWidget()
3464       ->ApplyViewportChangesForTesting({gfx::ScrollOffset(), gfx::Vector2dF(),
3465                                         1.1f, false, 0, 0,
3466                                         cc::BrowserControlsState::kBoth});
3467   // minimumPageScale < 1 < doubleTapZoomAlreadyLegibleScale
3468   web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.95f, 4);
3469   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
3470   double_tap_zoom_already_legible_scale =
3471       web_view_helper.GetWebView()->MinimumPageScaleFactor() *
3472       double_tap_zoom_already_legible_ratio;
3473   SetScaleAndScrollAndLayout(
3474       web_view_helper.GetWebView(), gfx::Point(),
3475       (web_view_helper.GetWebView()->MinimumPageScaleFactor()) *
3476           (1 + double_tap_zoom_already_legible_ratio) / 2);
3477   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3478   EXPECT_FLOAT_EQ(double_tap_zoom_already_legible_scale, scale);
3479   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3480   EXPECT_FLOAT_EQ(web_view_helper.GetWebView()->MinimumPageScaleFactor(),
3481                   scale);
3482   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3483   EXPECT_FLOAT_EQ(double_tap_zoom_already_legible_scale, scale);
3484 }
3485 
TEST_F(WebFrameTest,DivAutoZoomScaleLegibleScaleTest)3486 TEST_F(WebFrameTest, DivAutoZoomScaleLegibleScaleTest) {
3487   RegisterMockedHttpURLLoad("get_scale_bounds_check_for_auto_zoom_test.html");
3488 
3489   int viewport_width = 320;
3490   int viewport_height = 480;
3491   float double_tap_zoom_already_legible_ratio = 1.2f;
3492   float maximum_legible_scale_factor = 1.13f;
3493   frame_test_helpers::WebViewHelper web_view_helper;
3494   web_view_helper.InitializeAndLoad(
3495       base_url_ + "get_scale_bounds_check_for_auto_zoom_test.html", nullptr,
3496       nullptr, nullptr, ConfigureAndroid);
3497   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
3498   web_view_helper.GetWebView()->SetMaximumLegibleScale(
3499       maximum_legible_scale_factor);
3500   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
3501 
3502   web_view_helper.GetWebView()->EnableFakePageScaleAnimationForTesting(true);
3503   web_view_helper.GetWebView()
3504       ->GetPage()
3505       ->GetSettings()
3506       .SetTextAutosizingEnabled(true);
3507 
3508   WebRect div(200, 100, 200, 150);
3509   gfx::Point double_tap_point(div.x + 50, div.y + 50);
3510   float scale;
3511 
3512   // Test double tap scale bounds.
3513   // minimumPageScale < doubleTapZoomAlreadyLegibleScale < 1 <
3514   //     maximumLegibleScaleFactor
3515   float legible_scale = maximum_legible_scale_factor;
3516   SetScaleAndScrollAndLayout(
3517       web_view_helper.GetWebView(), gfx::Point(),
3518       (web_view_helper.GetWebView()->MinimumPageScaleFactor()) *
3519           (1 + double_tap_zoom_already_legible_ratio) / 2);
3520   float double_tap_zoom_already_legible_scale =
3521       web_view_helper.GetWebView()->MinimumPageScaleFactor() *
3522       double_tap_zoom_already_legible_ratio;
3523   web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.5f, 4);
3524   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
3525   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3526   EXPECT_FLOAT_EQ(legible_scale, scale);
3527   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3528   EXPECT_FLOAT_EQ(web_view_helper.GetWebView()->MinimumPageScaleFactor(),
3529                   scale);
3530   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3531   EXPECT_FLOAT_EQ(legible_scale, scale);
3532 
3533   // Zoom in to reset double_tap_zoom_in_effect flag.
3534   web_view_helper.GetWebView()
3535       ->MainFrameWidget()
3536       ->ApplyViewportChangesForTesting({gfx::ScrollOffset(), gfx::Vector2dF(),
3537                                         1.1f, false, 0, 0,
3538                                         cc::BrowserControlsState::kBoth});
3539   // 1 < maximumLegibleScaleFactor < minimumPageScale <
3540   //     doubleTapZoomAlreadyLegibleScale
3541   web_view_helper.GetWebView()->SetDefaultPageScaleLimits(1.0f, 4);
3542   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
3543   double_tap_zoom_already_legible_scale =
3544       web_view_helper.GetWebView()->MinimumPageScaleFactor() *
3545       double_tap_zoom_already_legible_ratio;
3546   SetScaleAndScrollAndLayout(
3547       web_view_helper.GetWebView(), gfx::Point(),
3548       (web_view_helper.GetWebView()->MinimumPageScaleFactor()) *
3549           (1 + double_tap_zoom_already_legible_ratio) / 2);
3550   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3551   EXPECT_FLOAT_EQ(double_tap_zoom_already_legible_scale, scale);
3552   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3553   EXPECT_FLOAT_EQ(web_view_helper.GetWebView()->MinimumPageScaleFactor(),
3554                   scale);
3555   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3556   EXPECT_FLOAT_EQ(double_tap_zoom_already_legible_scale, scale);
3557 
3558   // Zoom in to reset double_tap_zoom_in_effect flag.
3559   web_view_helper.GetWebView()
3560       ->MainFrameWidget()
3561       ->ApplyViewportChangesForTesting({gfx::ScrollOffset(), gfx::Vector2dF(),
3562                                         1.1f, false, 0, 0,
3563                                         cc::BrowserControlsState::kBoth});
3564   // minimumPageScale < 1 < maximumLegibleScaleFactor <
3565   //     doubleTapZoomAlreadyLegibleScale
3566   web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.95f, 4);
3567   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
3568   double_tap_zoom_already_legible_scale =
3569       web_view_helper.GetWebView()->MinimumPageScaleFactor() *
3570       double_tap_zoom_already_legible_ratio;
3571   SetScaleAndScrollAndLayout(
3572       web_view_helper.GetWebView(), gfx::Point(),
3573       (web_view_helper.GetWebView()->MinimumPageScaleFactor()) *
3574           (1 + double_tap_zoom_already_legible_ratio) / 2);
3575   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3576   EXPECT_FLOAT_EQ(double_tap_zoom_already_legible_scale, scale);
3577   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3578   EXPECT_FLOAT_EQ(web_view_helper.GetWebView()->MinimumPageScaleFactor(),
3579                   scale);
3580   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3581   EXPECT_FLOAT_EQ(double_tap_zoom_already_legible_scale, scale);
3582 
3583   // Zoom in to reset double_tap_zoom_in_effect flag.
3584   web_view_helper.GetWebView()
3585       ->MainFrameWidget()
3586       ->ApplyViewportChangesForTesting({gfx::ScrollOffset(), gfx::Vector2dF(),
3587                                         1.1f, false, 0, 0,
3588                                         cc::BrowserControlsState::kBoth});
3589   // minimumPageScale < 1 < doubleTapZoomAlreadyLegibleScale <
3590   //     maximumLegibleScaleFactor
3591   web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.9f, 4);
3592   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
3593   double_tap_zoom_already_legible_scale =
3594       web_view_helper.GetWebView()->MinimumPageScaleFactor() *
3595       double_tap_zoom_already_legible_ratio;
3596   SetScaleAndScrollAndLayout(
3597       web_view_helper.GetWebView(), gfx::Point(),
3598       (web_view_helper.GetWebView()->MinimumPageScaleFactor()) *
3599           (1 + double_tap_zoom_already_legible_ratio) / 2);
3600   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3601   EXPECT_FLOAT_EQ(legible_scale, scale);
3602   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3603   EXPECT_FLOAT_EQ(web_view_helper.GetWebView()->MinimumPageScaleFactor(),
3604                   scale);
3605   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3606   EXPECT_FLOAT_EQ(legible_scale, scale);
3607 }
3608 
TEST_F(WebFrameTest,DivAutoZoomScaleFontScaleFactorTest)3609 TEST_F(WebFrameTest, DivAutoZoomScaleFontScaleFactorTest) {
3610   RegisterMockedHttpURLLoad("get_scale_bounds_check_for_auto_zoom_test.html");
3611 
3612   int viewport_width = 320;
3613   int viewport_height = 480;
3614   float double_tap_zoom_already_legible_ratio = 1.2f;
3615   float accessibility_font_scale_factor = 1.13f;
3616   frame_test_helpers::WebViewHelper web_view_helper;
3617   web_view_helper.InitializeAndLoad(
3618       base_url_ + "get_scale_bounds_check_for_auto_zoom_test.html", nullptr,
3619       nullptr, nullptr, ConfigureAndroid);
3620   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
3621   web_view_helper.GetWebView()->SetMaximumLegibleScale(1.f);
3622   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
3623 
3624   web_view_helper.GetWebView()->EnableFakePageScaleAnimationForTesting(true);
3625   web_view_helper.GetWebView()
3626       ->GetPage()
3627       ->GetSettings()
3628       .SetTextAutosizingEnabled(true);
3629   web_view_helper.GetWebView()
3630       ->GetPage()
3631       ->GetSettings()
3632       .SetAccessibilityFontScaleFactor(accessibility_font_scale_factor);
3633 
3634   WebRect div(200, 100, 200, 150);
3635   gfx::Point double_tap_point(div.x + 50, div.y + 50);
3636   float scale;
3637 
3638   // Test double tap scale bounds.
3639   // minimumPageScale < doubleTapZoomAlreadyLegibleScale < 1 <
3640   //     accessibilityFontScaleFactor
3641   float legible_scale = accessibility_font_scale_factor;
3642   SetScaleAndScrollAndLayout(
3643       web_view_helper.GetWebView(), gfx::Point(),
3644       (web_view_helper.GetWebView()->MinimumPageScaleFactor()) *
3645           (1 + double_tap_zoom_already_legible_ratio) / 2);
3646   float double_tap_zoom_already_legible_scale =
3647       web_view_helper.GetWebView()->MinimumPageScaleFactor() *
3648       double_tap_zoom_already_legible_ratio;
3649   web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.5f, 4);
3650   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
3651   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3652   EXPECT_FLOAT_EQ(legible_scale, scale);
3653   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3654   EXPECT_FLOAT_EQ(web_view_helper.GetWebView()->MinimumPageScaleFactor(),
3655                   scale);
3656   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3657   EXPECT_FLOAT_EQ(legible_scale, scale);
3658 
3659   // Zoom in to reset double_tap_zoom_in_effect flag.
3660   web_view_helper.GetWebView()
3661       ->MainFrameWidget()
3662       ->ApplyViewportChangesForTesting({gfx::ScrollOffset(), gfx::Vector2dF(),
3663                                         1.1f, false, 0, 0,
3664                                         cc::BrowserControlsState::kBoth});
3665   // 1 < accessibilityFontScaleFactor < minimumPageScale <
3666   //     doubleTapZoomAlreadyLegibleScale
3667   web_view_helper.GetWebView()->SetDefaultPageScaleLimits(1.0f, 4);
3668   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
3669   double_tap_zoom_already_legible_scale =
3670       web_view_helper.GetWebView()->MinimumPageScaleFactor() *
3671       double_tap_zoom_already_legible_ratio;
3672   SetScaleAndScrollAndLayout(
3673       web_view_helper.GetWebView(), gfx::Point(),
3674       (web_view_helper.GetWebView()->MinimumPageScaleFactor()) *
3675           (1 + double_tap_zoom_already_legible_ratio) / 2);
3676   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3677   EXPECT_FLOAT_EQ(double_tap_zoom_already_legible_scale, scale);
3678   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3679   EXPECT_FLOAT_EQ(web_view_helper.GetWebView()->MinimumPageScaleFactor(),
3680                   scale);
3681   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3682   EXPECT_FLOAT_EQ(double_tap_zoom_already_legible_scale, scale);
3683 
3684   // Zoom in to reset double_tap_zoom_in_effect flag.
3685   web_view_helper.GetWebView()
3686       ->MainFrameWidget()
3687       ->ApplyViewportChangesForTesting({gfx::ScrollOffset(), gfx::Vector2dF(),
3688                                         1.1f, false, 0, 0,
3689                                         cc::BrowserControlsState::kBoth});
3690   // minimumPageScale < 1 < accessibilityFontScaleFactor <
3691   //     doubleTapZoomAlreadyLegibleScale
3692   web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.95f, 4);
3693   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
3694   double_tap_zoom_already_legible_scale =
3695       web_view_helper.GetWebView()->MinimumPageScaleFactor() *
3696       double_tap_zoom_already_legible_ratio;
3697   SetScaleAndScrollAndLayout(
3698       web_view_helper.GetWebView(), gfx::Point(),
3699       (web_view_helper.GetWebView()->MinimumPageScaleFactor()) *
3700           (1 + double_tap_zoom_already_legible_ratio) / 2);
3701   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3702   EXPECT_FLOAT_EQ(double_tap_zoom_already_legible_scale, scale);
3703   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3704   EXPECT_FLOAT_EQ(web_view_helper.GetWebView()->MinimumPageScaleFactor(),
3705                   scale);
3706   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3707   EXPECT_FLOAT_EQ(double_tap_zoom_already_legible_scale, scale);
3708 
3709   // Zoom in to reset double_tap_zoom_in_effect flag.
3710   web_view_helper.GetWebView()
3711       ->MainFrameWidget()
3712       ->ApplyViewportChangesForTesting({gfx::ScrollOffset(), gfx::Vector2dF(),
3713                                         1.1f, false, 0, 0,
3714                                         cc::BrowserControlsState::kBoth});
3715   // minimumPageScale < 1 < doubleTapZoomAlreadyLegibleScale <
3716   //     accessibilityFontScaleFactor
3717   web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.9f, 4);
3718   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
3719   double_tap_zoom_already_legible_scale =
3720       web_view_helper.GetWebView()->MinimumPageScaleFactor() *
3721       double_tap_zoom_already_legible_ratio;
3722   SetScaleAndScrollAndLayout(
3723       web_view_helper.GetWebView(), gfx::Point(),
3724       (web_view_helper.GetWebView()->MinimumPageScaleFactor()) *
3725           (1 + double_tap_zoom_already_legible_ratio) / 2);
3726   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3727   EXPECT_FLOAT_EQ(legible_scale, scale);
3728   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3729   EXPECT_FLOAT_EQ(web_view_helper.GetWebView()->MinimumPageScaleFactor(),
3730                   scale);
3731   SimulateDoubleTap(web_view_helper.GetWebView(), double_tap_point, scale);
3732   EXPECT_FLOAT_EQ(legible_scale, scale);
3733 }
3734 
TEST_F(WebFrameTest,BlockBoundTest)3735 TEST_F(WebFrameTest, BlockBoundTest) {
3736   RegisterMockedHttpURLLoad("block_bound.html");
3737 
3738   frame_test_helpers::WebViewHelper web_view_helper;
3739   web_view_helper.InitializeAndLoad(base_url_ + "block_bound.html", nullptr,
3740                                     nullptr, nullptr, ConfigureAndroid);
3741   web_view_helper.Resize(gfx::Size(300, 300));
3742 
3743   IntRect rect_back = IntRect(0, 0, 200, 200);
3744   IntRect rect_left_top = IntRect(10, 10, 80, 80);
3745   IntRect rect_right_bottom = IntRect(110, 110, 80, 80);
3746   IntRect block_bound;
3747 
3748   block_bound = IntRect(ComputeBlockBoundHelper(web_view_helper.GetWebView(),
3749                                                 gfx::Point(9, 9), true));
3750   EXPECT_EQ(rect_back, block_bound);
3751 
3752   block_bound = IntRect(ComputeBlockBoundHelper(web_view_helper.GetWebView(),
3753                                                 gfx::Point(10, 10), true));
3754   EXPECT_EQ(rect_left_top, block_bound);
3755 
3756   block_bound = IntRect(ComputeBlockBoundHelper(web_view_helper.GetWebView(),
3757                                                 gfx::Point(50, 50), true));
3758   EXPECT_EQ(rect_left_top, block_bound);
3759 
3760   block_bound = IntRect(ComputeBlockBoundHelper(web_view_helper.GetWebView(),
3761                                                 gfx::Point(89, 89), true));
3762   EXPECT_EQ(rect_left_top, block_bound);
3763 
3764   block_bound = IntRect(ComputeBlockBoundHelper(web_view_helper.GetWebView(),
3765                                                 gfx::Point(90, 90), true));
3766   EXPECT_EQ(rect_back, block_bound);
3767 
3768   block_bound = IntRect(ComputeBlockBoundHelper(web_view_helper.GetWebView(),
3769                                                 gfx::Point(109, 109), true));
3770   EXPECT_EQ(rect_back, block_bound);
3771 
3772   block_bound = IntRect(ComputeBlockBoundHelper(web_view_helper.GetWebView(),
3773                                                 gfx::Point(110, 110), true));
3774   EXPECT_EQ(rect_right_bottom, block_bound);
3775 }
3776 
TEST_F(WebFrameTest,DontZoomInOnFocusedInTouchAction)3777 TEST_F(WebFrameTest, DontZoomInOnFocusedInTouchAction) {
3778   RegisterMockedHttpURLLoad("textbox_in_touch_action.html");
3779 
3780   int viewport_width = 600;
3781   int viewport_height = 1000;
3782 
3783   frame_test_helpers::WebViewHelper web_view_helper;
3784   web_view_helper.InitializeAndLoad(base_url_ + "textbox_in_touch_action.html");
3785   web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.25f, 4);
3786   web_view_helper.GetWebView()->EnableFakePageScaleAnimationForTesting(true);
3787   web_view_helper.GetWebView()
3788       ->GetPage()
3789       ->GetSettings()
3790       .SetTextAutosizingEnabled(false);
3791   web_view_helper.GetWebView()
3792       ->GetSettings()
3793       ->SetAutoZoomFocusedNodeToLegibleScale(true);
3794   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
3795 
3796   float initial_scale = web_view_helper.GetWebView()->PageScaleFactor();
3797 
3798   // Focus the first textbox that's in a touch-action: pan-x ancestor, this
3799   // shouldn't cause an autozoom since pan-x disables pinch-zoom.
3800   web_view_helper.GetWebView()->AdvanceFocus(false);
3801   web_view_helper.GetWebView()
3802       ->MainFrameImpl()
3803       ->FrameWidget()
3804       ->ScrollFocusedEditableElementIntoView();
3805   EXPECT_EQ(
3806       web_view_helper.GetWebView()->FakePageScaleAnimationPageScaleForTesting(),
3807       0);
3808 
3809   SetScaleAndScrollAndLayout(web_view_helper.GetWebView(), gfx::Point(),
3810                              initial_scale);
3811   ASSERT_EQ(initial_scale, web_view_helper.GetWebView()->PageScaleFactor());
3812 
3813   // Focus the second textbox that's in a touch-action: manipulation ancestor,
3814   // this should cause an autozoom since it allows pinch-zoom.
3815   web_view_helper.GetWebView()->AdvanceFocus(false);
3816   web_view_helper.GetWebView()
3817       ->MainFrameImpl()
3818       ->FrameWidget()
3819       ->ScrollFocusedEditableElementIntoView();
3820   EXPECT_GT(
3821       web_view_helper.GetWebView()->FakePageScaleAnimationPageScaleForTesting(),
3822       initial_scale);
3823 
3824   SetScaleAndScrollAndLayout(web_view_helper.GetWebView(), gfx::Point(),
3825                              initial_scale);
3826   ASSERT_EQ(initial_scale, web_view_helper.GetWebView()->PageScaleFactor());
3827 
3828   // Focus the third textbox that has a touch-action: pan-x ancestor, this
3829   // should cause an autozoom since it's seperated from the node with the
3830   // touch-action by an overflow:scroll element.
3831   web_view_helper.GetWebView()->AdvanceFocus(false);
3832   web_view_helper.GetWebView()
3833       ->MainFrameImpl()
3834       ->FrameWidget()
3835       ->ScrollFocusedEditableElementIntoView();
3836   EXPECT_GT(
3837       web_view_helper.GetWebView()->FakePageScaleAnimationPageScaleForTesting(),
3838       initial_scale);
3839 }
3840 
TEST_F(WebFrameTest,DivScrollIntoEditableTest)3841 TEST_F(WebFrameTest, DivScrollIntoEditableTest) {
3842   RegisterMockedHttpURLLoad("get_scale_for_zoom_into_editable_test.html");
3843 
3844   const bool kAutoZoomToLegibleScale = true;
3845   int viewport_width = 450;
3846   int viewport_height = 300;
3847   float left_box_ratio = 0.3f;
3848   int caret_padding = 10;
3849   float min_readable_caret_height = 16.0f;
3850   frame_test_helpers::WebViewHelper web_view_helper;
3851   web_view_helper.InitializeAndLoad(
3852       base_url_ + "get_scale_for_zoom_into_editable_test.html");
3853   web_view_helper.GetWebView()
3854       ->GetPage()
3855       ->GetSettings()
3856       .SetTextAutosizingEnabled(false);
3857   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
3858   web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.25f, 4);
3859 
3860   web_view_helper.GetWebView()->EnableFakePageScaleAnimationForTesting(true);
3861 
3862   WebRect edit_box_with_text(200, 200, 250, 20);
3863   WebRect edit_box_with_no_text(200, 250, 250, 20);
3864 
3865   // Test scrolling the focused node
3866   // The edit box is shorter and narrower than the viewport when legible.
3867   web_view_helper.GetWebView()->AdvanceFocus(false);
3868   // Set the caret to the end of the input box.
3869   web_view_helper.GetWebView()
3870       ->MainFrameImpl()
3871       ->GetDocument()
3872       .GetElementById("EditBoxWithText")
3873       .To<WebInputElement>()
3874       .SetSelectionRange(1000, 1000);
3875   SetScaleAndScrollAndLayout(web_view_helper.GetWebView(), gfx::Point(), 1);
3876   gfx::Rect rect, caret;
3877   web_view_helper.GetWebView()->MainFrameViewWidget()->CalculateSelectionBounds(
3878       caret, rect);
3879 
3880   // Set the page scale to be smaller than the minimal readable scale.
3881   float initial_scale = min_readable_caret_height / caret.height() * 0.5f;
3882   SetScaleAndScrollAndLayout(web_view_helper.GetWebView(), gfx::Point(),
3883                              initial_scale);
3884 
3885   float scale;
3886   IntPoint scroll;
3887   bool need_animation;
3888   IntRect element_bounds, caret_bounds;
3889   GetElementAndCaretBoundsForFocusedEditableElement(
3890       web_view_helper, element_bounds, caret_bounds);
3891   web_view_helper.GetWebView()->ComputeScaleAndScrollForEditableElementRects(
3892       element_bounds, caret_bounds, kAutoZoomToLegibleScale, scale, scroll,
3893       need_animation);
3894   EXPECT_TRUE(need_animation);
3895   // The edit box should be left aligned with a margin for possible label.
3896   int h_scroll = edit_box_with_text.x - left_box_ratio * viewport_width / scale;
3897   EXPECT_NEAR(h_scroll, scroll.X(), 2);
3898   int v_scroll = edit_box_with_text.y -
3899                  (viewport_height / scale - edit_box_with_text.height) / 2;
3900   EXPECT_NEAR(v_scroll, scroll.Y(), 2);
3901   EXPECT_NEAR(min_readable_caret_height / caret.height(), scale, 0.1);
3902 
3903   // The edit box is wider than the viewport when legible.
3904   viewport_width = 200;
3905   viewport_height = 150;
3906   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
3907   SetScaleAndScrollAndLayout(web_view_helper.GetWebView(), gfx::Point(),
3908                              initial_scale);
3909   GetElementAndCaretBoundsForFocusedEditableElement(
3910       web_view_helper, element_bounds, caret_bounds);
3911   web_view_helper.GetWebView()->ComputeScaleAndScrollForEditableElementRects(
3912       element_bounds, caret_bounds, kAutoZoomToLegibleScale, scale, scroll,
3913       need_animation);
3914   EXPECT_TRUE(need_animation);
3915   // The caret should be right aligned since the caret would be offscreen when
3916   // the edit box is left aligned.
3917   h_scroll = caret.x() + caret.width() + caret_padding - viewport_width / scale;
3918   EXPECT_NEAR(h_scroll, scroll.X(), 2);
3919   EXPECT_NEAR(min_readable_caret_height / caret.height(), scale, 0.1);
3920 
3921   SetScaleAndScrollAndLayout(web_view_helper.GetWebView(), gfx::Point(),
3922                              initial_scale);
3923   // Move focus to edit box with text.
3924   web_view_helper.GetWebView()->AdvanceFocus(false);
3925   GetElementAndCaretBoundsForFocusedEditableElement(
3926       web_view_helper, element_bounds, caret_bounds);
3927   web_view_helper.GetWebView()->ComputeScaleAndScrollForEditableElementRects(
3928       element_bounds, caret_bounds, kAutoZoomToLegibleScale, scale, scroll,
3929       need_animation);
3930   EXPECT_TRUE(need_animation);
3931   // The edit box should be left aligned.
3932   h_scroll = edit_box_with_no_text.x;
3933   EXPECT_NEAR(h_scroll, scroll.X(), 2);
3934   v_scroll = edit_box_with_no_text.y -
3935              (viewport_height / scale - edit_box_with_no_text.height) / 2;
3936   EXPECT_NEAR(v_scroll, scroll.Y(), 2);
3937   EXPECT_NEAR(min_readable_caret_height / caret.height(), scale, 0.1);
3938 
3939   // Move focus back to the first edit box.
3940   web_view_helper.GetWebView()->AdvanceFocus(true);
3941   // Zoom out slightly.
3942   const float within_tolerance_scale = scale * 0.9f;
3943   SetScaleAndScrollAndLayout(web_view_helper.GetWebView(), scroll,
3944                              within_tolerance_scale);
3945   // Move focus back to the second edit box.
3946   web_view_helper.GetWebView()->AdvanceFocus(false);
3947   GetElementAndCaretBoundsForFocusedEditableElement(
3948       web_view_helper, element_bounds, caret_bounds);
3949   web_view_helper.GetWebView()->ComputeScaleAndScrollForEditableElementRects(
3950       element_bounds, caret_bounds, kAutoZoomToLegibleScale, scale, scroll,
3951       need_animation);
3952   // The scale should not be adjusted as the zoomed out scale was sufficiently
3953   // close to the previously focused scale.
3954   EXPECT_FALSE(need_animation);
3955 }
3956 
TEST_F(WebFrameTest,DivScrollIntoEditablePreservePageScaleTest)3957 TEST_F(WebFrameTest, DivScrollIntoEditablePreservePageScaleTest) {
3958   RegisterMockedHttpURLLoad("get_scale_for_zoom_into_editable_test.html");
3959 
3960   const bool kAutoZoomToLegibleScale = true;
3961   const int kViewportWidth = 450;
3962   const int kViewportHeight = 300;
3963   const float kMinReadableCaretHeight = 16.0f;
3964   frame_test_helpers::WebViewHelper web_view_helper;
3965   web_view_helper.InitializeAndLoad(
3966       base_url_ + "get_scale_for_zoom_into_editable_test.html");
3967   web_view_helper.GetWebView()
3968       ->GetPage()
3969       ->GetSettings()
3970       .SetTextAutosizingEnabled(false);
3971   web_view_helper.Resize(gfx::Size(kViewportWidth, kViewportHeight));
3972   web_view_helper.GetWebView()->EnableFakePageScaleAnimationForTesting(true);
3973 
3974   const WebRect edit_box_with_text(200, 200, 250, 20);
3975 
3976   web_view_helper.GetWebView()->AdvanceFocus(false);
3977   // Set the caret to the begining of the input box.
3978   web_view_helper.GetWebView()
3979       ->MainFrameImpl()
3980       ->GetDocument()
3981       .GetElementById("EditBoxWithText")
3982       .To<WebInputElement>()
3983       .SetSelectionRange(0, 0);
3984   SetScaleAndScrollAndLayout(web_view_helper.GetWebView(), gfx::Point(), 1);
3985   gfx::Rect rect, caret;
3986   web_view_helper.GetWebView()->MainFrameViewWidget()->CalculateSelectionBounds(
3987       caret, rect);
3988 
3989   // Set the page scale to be twice as large as the minimal readable scale.
3990   float new_scale = kMinReadableCaretHeight / caret.height() * 2.0;
3991   SetScaleAndScrollAndLayout(web_view_helper.GetWebView(), gfx::Point(),
3992                              new_scale);
3993 
3994   float scale;
3995   IntPoint scroll;
3996   bool need_animation;
3997   IntRect element_bounds, caret_bounds;
3998   GetElementAndCaretBoundsForFocusedEditableElement(
3999       web_view_helper, element_bounds, caret_bounds);
4000   web_view_helper.GetWebView()->ComputeScaleAndScrollForEditableElementRects(
4001       element_bounds, caret_bounds, kAutoZoomToLegibleScale, scale, scroll,
4002       need_animation);
4003   EXPECT_TRUE(need_animation);
4004   // Edit box and caret should be left alinged
4005   int h_scroll = edit_box_with_text.x;
4006   EXPECT_NEAR(h_scroll, scroll.X(), 1);
4007   int v_scroll = edit_box_with_text.y -
4008                  (kViewportHeight / scale - edit_box_with_text.height) / 2;
4009   EXPECT_NEAR(v_scroll, scroll.Y(), 1);
4010   // Page scale have to be unchanged
4011   EXPECT_EQ(new_scale, scale);
4012 
4013   // Set page scale and scroll such that edit box will be under the screen
4014   new_scale = 3.0;
4015   h_scroll = 200;
4016   SetScaleAndScrollAndLayout(web_view_helper.GetWebView(),
4017                              gfx::Point(h_scroll, 0), new_scale);
4018   GetElementAndCaretBoundsForFocusedEditableElement(
4019       web_view_helper, element_bounds, caret_bounds);
4020   web_view_helper.GetWebView()->ComputeScaleAndScrollForEditableElementRects(
4021       element_bounds, caret_bounds, kAutoZoomToLegibleScale, scale, scroll,
4022       need_animation);
4023   EXPECT_TRUE(need_animation);
4024   // Horizontal scroll have to be the same
4025   EXPECT_NEAR(h_scroll, scroll.X(), 1);
4026   v_scroll = edit_box_with_text.y -
4027              (kViewportHeight / scale - edit_box_with_text.height) / 2;
4028   EXPECT_NEAR(v_scroll, scroll.Y(), 1);
4029   // Page scale have to be unchanged
4030   EXPECT_EQ(new_scale, scale);
4031 }
4032 
4033 // Tests the scroll into view functionality when
4034 // autoZoomeFocusedNodeToLegibleScale set to false. i.e. The path non-Android
4035 // platforms take.
TEST_F(WebFrameTest,DivScrollIntoEditableTestZoomToLegibleScaleDisabled)4036 TEST_F(WebFrameTest, DivScrollIntoEditableTestZoomToLegibleScaleDisabled) {
4037   RegisterMockedHttpURLLoad("get_scale_for_zoom_into_editable_test.html");
4038 
4039   const bool kAutoZoomToLegibleScale = false;
4040   int viewport_width = 100;
4041   int viewport_height = 100;
4042   float left_box_ratio = 0.3f;
4043   frame_test_helpers::WebViewHelper web_view_helper;
4044   web_view_helper.InitializeAndLoad(
4045       base_url_ + "get_scale_for_zoom_into_editable_test.html");
4046   web_view_helper.GetWebView()
4047       ->GetPage()
4048       ->GetSettings()
4049       .SetTextAutosizingEnabled(false);
4050   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
4051   web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.25f, 4);
4052 
4053   web_view_helper.GetWebView()->EnableFakePageScaleAnimationForTesting(true);
4054 
4055   WebRect edit_box_with_no_text(200, 250, 250, 20);
4056 
4057   // Test scrolling the focused node
4058   // Since we're zoomed out, the caret is considered too small to be legible and
4059   // so we'd normally zoom in. Make sure we don't change scale since the
4060   // auto-zoom setting is off.
4061 
4062   // Focus the second empty textbox.
4063   web_view_helper.GetWebView()->AdvanceFocus(false);
4064   web_view_helper.GetWebView()->AdvanceFocus(false);
4065 
4066   // Set the page scale to be smaller than the minimal readable scale.
4067   float initial_scale = 0.25f;
4068   SetScaleAndScrollAndLayout(web_view_helper.GetWebView(), gfx::Point(),
4069                              initial_scale);
4070 
4071   float scale;
4072   IntPoint scroll;
4073   bool need_animation;
4074   IntRect element_bounds, caret_bounds;
4075   GetElementAndCaretBoundsForFocusedEditableElement(
4076       web_view_helper, element_bounds, caret_bounds);
4077   web_view_helper.GetWebView()->ComputeScaleAndScrollForEditableElementRects(
4078       element_bounds, caret_bounds, kAutoZoomToLegibleScale, scale, scroll,
4079       need_animation);
4080 
4081   // There should be no change in page scale.
4082   EXPECT_EQ(initial_scale, scale);
4083   // The edit box should be left aligned with a margin for possible label.
4084   EXPECT_TRUE(need_animation);
4085   int h_scroll =
4086       edit_box_with_no_text.x - left_box_ratio * viewport_width / scale;
4087   EXPECT_NEAR(h_scroll, scroll.X(), 2);
4088   int v_scroll = edit_box_with_no_text.y -
4089                  (viewport_height / scale - edit_box_with_no_text.height) / 2;
4090   EXPECT_NEAR(v_scroll, scroll.Y(), 2);
4091 
4092   SetScaleAndScrollAndLayout(web_view_helper.GetWebView(), scroll, scale);
4093 
4094   // Select the first textbox.
4095   web_view_helper.GetWebView()->AdvanceFocus(true);
4096   gfx::Rect rect, caret;
4097   web_view_helper.GetWebView()->MainFrameViewWidget()->CalculateSelectionBounds(
4098       caret, rect);
4099   GetElementAndCaretBoundsForFocusedEditableElement(
4100       web_view_helper, element_bounds, caret_bounds);
4101   web_view_helper.GetWebView()->ComputeScaleAndScrollForEditableElementRects(
4102       element_bounds, caret_bounds, kAutoZoomToLegibleScale, scale, scroll,
4103       need_animation);
4104 
4105   // There should be no change at all since the textbox is fully visible
4106   // already.
4107   EXPECT_EQ(initial_scale, scale);
4108   EXPECT_FALSE(need_animation);
4109 }
4110 
4111 // Tests zoom into editable zoom and scroll correctly when zoom-for-dsf enabled.
TEST_F(WebFrameTest,DivScrollIntoEditableTestWithDeviceScaleFactor)4112 TEST_F(WebFrameTest, DivScrollIntoEditableTestWithDeviceScaleFactor) {
4113   RegisterMockedHttpURLLoad("get_scale_for_zoom_into_editable_test.html");
4114 
4115   bool kAutoZoomToLegibleScale = true;
4116   const float kDeviceScaleFactor = 2.f;
4117   int viewport_width = 200 * kDeviceScaleFactor;
4118   int viewport_height = 150 * kDeviceScaleFactor;
4119   float min_readable_caret_height = 16.0f * kDeviceScaleFactor;
4120 
4121   frame_test_helpers::WebViewHelper web_view_helper;
4122   web_view_helper.InitializeAndLoad(
4123       base_url_ + "get_scale_for_zoom_into_editable_test.html", nullptr,
4124       nullptr, nullptr, ConfigureAndroid);
4125   web_view_helper.GetWebView()
4126       ->GetPage()
4127       ->GetSettings()
4128       .SetTextAutosizingEnabled(false);
4129   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
4130   web_view_helper.GetWebView()->SetZoomFactorForDeviceScaleFactor(
4131       kDeviceScaleFactor);
4132   web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.25f, 4);
4133 
4134   web_view_helper.GetWebView()->EnableFakePageScaleAnimationForTesting(true);
4135 
4136   WebRect edit_box_with_text(200 * kDeviceScaleFactor, 200 * kDeviceScaleFactor,
4137                              250 * kDeviceScaleFactor, 20 * kDeviceScaleFactor);
4138   web_view_helper.GetWebView()->AdvanceFocus(false);
4139 
4140   // Set the page scale to be smaller than the minimal readable scale.
4141   float initial_scale = 0.5f;
4142   SetScaleAndScrollAndLayout(web_view_helper.GetWebView(), gfx::Point(),
4143                              initial_scale);
4144   ASSERT_EQ(web_view_helper.GetWebView()->PageScaleFactor(), initial_scale);
4145 
4146   float scale;
4147   IntPoint scroll;
4148   bool need_animation;
4149   IntRect element_bounds, caret_bounds;
4150   GetElementAndCaretBoundsForFocusedEditableElement(
4151       web_view_helper, element_bounds, caret_bounds);
4152   web_view_helper.GetWebView()->ComputeScaleAndScrollForEditableElementRects(
4153       element_bounds, caret_bounds, kAutoZoomToLegibleScale, scale, scroll,
4154       need_animation);
4155   EXPECT_TRUE(need_animation);
4156   // The edit box wider than the viewport when legible should be left aligned.
4157   int h_scroll = edit_box_with_text.x;
4158   EXPECT_NEAR(h_scroll, scroll.X(), 2);
4159   int v_scroll = edit_box_with_text.y -
4160                  (viewport_height / scale - edit_box_with_text.height) / 2;
4161   EXPECT_NEAR(v_scroll, scroll.Y(), 2);
4162   EXPECT_NEAR(min_readable_caret_height / caret_bounds.Height(), scale, 0.1);
4163 }
4164 
TEST_F(WebFrameTest,FirstRectForCharacterRangeWithPinchZoom)4165 TEST_F(WebFrameTest, FirstRectForCharacterRangeWithPinchZoom) {
4166   RegisterMockedHttpURLLoad("textbox.html");
4167 
4168   frame_test_helpers::WebViewHelper web_view_helper;
4169   web_view_helper.InitializeAndLoad(base_url_ + "textbox.html");
4170   web_view_helper.Resize(gfx::Size(640, 480));
4171 
4172   WebLocalFrame* main_frame = web_view_helper.LocalMainFrame();
4173   main_frame->ExecuteScript(WebScriptSource("selectRange();"));
4174 
4175   WebRect old_rect;
4176   main_frame->FirstRectForCharacterRange(0, 5, old_rect);
4177 
4178   gfx::PointF visual_offset(100, 130);
4179   float scale = 2;
4180   web_view_helper.GetWebView()->SetPageScaleFactor(scale);
4181   web_view_helper.GetWebView()->SetVisualViewportOffset(visual_offset);
4182 
4183   WebRect rect;
4184   main_frame->FirstRectForCharacterRange(0, 5, rect);
4185 
4186   EXPECT_EQ((old_rect.x - visual_offset.x()) * scale, rect.x);
4187   EXPECT_EQ((old_rect.y - visual_offset.y()) * scale, rect.y);
4188   EXPECT_EQ(old_rect.width * scale, rect.width);
4189   EXPECT_EQ(old_rect.height * scale, rect.height);
4190 }
4191 class TestReloadDoesntRedirectWebFrameClient
4192     : public frame_test_helpers::TestWebFrameClient {
4193  public:
4194   TestReloadDoesntRedirectWebFrameClient() = default;
4195   ~TestReloadDoesntRedirectWebFrameClient() override = default;
4196 
4197   // frame_test_helpers::TestWebFrameClient:
BeginNavigation(std::unique_ptr<WebNavigationInfo> info)4198   void BeginNavigation(std::unique_ptr<WebNavigationInfo> info) override {
4199     EXPECT_FALSE(info->is_client_redirect);
4200     TestWebFrameClient::BeginNavigation(std::move(info));
4201   }
4202 };
4203 
TEST_F(WebFrameTest,ReloadDoesntSetRedirect)4204 TEST_F(WebFrameTest, ReloadDoesntSetRedirect) {
4205   // Test for case in http://crbug.com/73104. Reloading a frame very quickly
4206   // would sometimes call BeginNavigation with isRedirect=true
4207   RegisterMockedHttpURLLoad("form.html");
4208 
4209   TestReloadDoesntRedirectWebFrameClient web_frame_client;
4210   frame_test_helpers::WebViewHelper web_view_helper;
4211   web_view_helper.InitializeAndLoad(base_url_ + "form.html", &web_frame_client);
4212 
4213   web_view_helper.GetWebView()->MainFrameImpl()->StartReload(
4214       WebFrameLoadType::kReloadBypassingCache);
4215   // start another reload before request is delivered.
4216   frame_test_helpers::ReloadFrameBypassingCache(
4217       web_view_helper.GetWebView()->MainFrameImpl());
4218 }
4219 
4220 class ClearScrollStateOnCommitWebFrameClient
4221     : public frame_test_helpers::TestWebFrameClient {
4222  public:
4223   ClearScrollStateOnCommitWebFrameClient() = default;
4224   ~ClearScrollStateOnCommitWebFrameClient() override = default;
4225 
4226   // frame_test_helpers::TestWebFrameClient:
DidCommitNavigation(const WebHistoryItem &,WebHistoryCommitType,bool)4227   void DidCommitNavigation(const WebHistoryItem&,
4228                            WebHistoryCommitType,
4229                            bool) override {
4230     Frame()->View()->ResetScrollAndScaleState();
4231   }
4232 };
4233 
TEST_F(WebFrameTest,ReloadPreservesState)4234 TEST_F(WebFrameTest, ReloadPreservesState) {
4235   const std::string url = "200-by-300.html";
4236   const float kPageScaleFactor = 1.1684f;
4237   const int kPageWidth = 120;
4238   const int kPageHeight = 100;
4239 
4240   RegisterMockedHttpURLLoad(url);
4241 
4242   ClearScrollStateOnCommitWebFrameClient client;
4243   frame_test_helpers::WebViewHelper web_view_helper;
4244   web_view_helper.InitializeAndLoad(base_url_ + url, &client);
4245   web_view_helper.Resize(gfx::Size(kPageWidth, kPageHeight));
4246   web_view_helper.LocalMainFrame()->SetScrollOffset(
4247       WebSize(kPageWidth / 4, kPageHeight / 4));
4248   web_view_helper.GetWebView()->SetPageScaleFactor(kPageScaleFactor);
4249 
4250   // Reload the page and end up at the same url. State should not be propagated.
4251   web_view_helper.GetWebView()->MainFrameImpl()->StartReload(
4252       WebFrameLoadType::kReload);
4253   frame_test_helpers::PumpPendingRequestsForFrameToLoad(
4254       web_view_helper.LocalMainFrame());
4255   EXPECT_EQ(0, web_view_helper.LocalMainFrame()->GetScrollOffset().width);
4256   EXPECT_EQ(0, web_view_helper.LocalMainFrame()->GetScrollOffset().height);
4257   EXPECT_EQ(1.0f, web_view_helper.GetWebView()->PageScaleFactor());
4258 }
4259 
TEST_F(WebFrameTest,ReloadWhileProvisional)4260 TEST_F(WebFrameTest, ReloadWhileProvisional) {
4261   // Test that reloading while the previous load is still pending does not cause
4262   // the initial request to get lost.
4263   RegisterMockedHttpURLLoad("fixed_layout.html");
4264 
4265   frame_test_helpers::WebViewHelper web_view_helper;
4266   web_view_helper.Initialize();
4267   WebURLRequest request(ToKURL(base_url_ + "fixed_layout.html"));
4268   web_view_helper.GetWebView()->MainFrameImpl()->StartNavigation(request);
4269   // start reload before first request is delivered.
4270   frame_test_helpers::ReloadFrameBypassingCache(
4271       web_view_helper.GetWebView()->MainFrameImpl());
4272 
4273   WebDocumentLoader* document_loader =
4274       web_view_helper.LocalMainFrame()->GetDocumentLoader();
4275   ASSERT_TRUE(document_loader);
4276   EXPECT_EQ(ToKURL(base_url_ + "fixed_layout.html"),
4277             KURL(document_loader->GetUrl()));
4278 }
4279 
TEST_F(WebFrameTest,RedirectChainContainsInitialUrl)4280 TEST_F(WebFrameTest, RedirectChainContainsInitialUrl) {
4281   const std::string first_url = "data:text/html,foo";
4282 
4283   frame_test_helpers::WebViewHelper web_view_helper;
4284   web_view_helper.InitializeAndLoad(first_url);
4285 
4286   WebDocumentLoader* document_loader =
4287       web_view_helper.LocalMainFrame()->GetDocumentLoader();
4288   ASSERT_TRUE(document_loader);
4289 
4290   WebVector<WebURL> redirects;
4291   document_loader->RedirectChain(redirects);
4292   ASSERT_EQ(1U, redirects.size());
4293   EXPECT_EQ(ToKURL(first_url), KURL(redirects[0]));
4294 }
4295 
TEST_F(WebFrameTest,IframeRedirect)4296 TEST_F(WebFrameTest, IframeRedirect) {
4297   RegisterMockedHttpURLLoad("iframe_redirect.html");
4298   RegisterMockedHttpURLLoad("visible_iframe.html");
4299 
4300   frame_test_helpers::WebViewHelper web_view_helper;
4301   web_view_helper.InitializeAndLoad(base_url_ + "iframe_redirect.html");
4302   // Pump pending requests one more time. The test page loads script that
4303   // navigates.
4304   frame_test_helpers::PumpPendingRequestsForFrameToLoad(
4305       web_view_helper.LocalMainFrame());
4306 
4307   WebFrame* iframe = web_view_helper.LocalMainFrame()->FindFrameByName(
4308       WebString::FromUTF8("ifr"));
4309   ASSERT_TRUE(iframe && iframe->IsWebLocalFrame());
4310   WebDocumentLoader* iframe_document_loader =
4311       iframe->ToWebLocalFrame()->GetDocumentLoader();
4312   ASSERT_TRUE(iframe_document_loader);
4313   WebVector<WebURL> redirects;
4314   iframe_document_loader->RedirectChain(redirects);
4315   ASSERT_EQ(2U, redirects.size());
4316   EXPECT_EQ(ToKURL("about:blank"), KURL(redirects[0]));
4317   EXPECT_EQ(ToKURL("http://internal.test/visible_iframe.html"),
4318             KURL(redirects[1]));
4319 }
4320 
TEST_F(WebFrameTest,ClearFocusedNodeTest)4321 TEST_F(WebFrameTest, ClearFocusedNodeTest) {
4322   RegisterMockedHttpURLLoad("iframe_clear_focused_node_test.html");
4323   RegisterMockedHttpURLLoad("autofocus_input_field_iframe.html");
4324 
4325   frame_test_helpers::WebViewHelper web_view_helper;
4326   web_view_helper.InitializeAndLoad(base_url_ +
4327                                     "iframe_clear_focused_node_test.html");
4328 
4329   // Clear the focused node.
4330   web_view_helper.GetWebView()->FocusedElement()->blur();
4331 
4332   // Now retrieve the FocusedNode and test it should be null.
4333   EXPECT_EQ(nullptr, web_view_helper.GetWebView()->FocusedElement());
4334 }
4335 
4336 class ChangedSelectionCounter : public frame_test_helpers::TestWebFrameClient {
4337  public:
ChangedSelectionCounter()4338   ChangedSelectionCounter() : call_count_(0) {}
DidChangeSelection(bool isSelectionEmpty)4339   void DidChangeSelection(bool isSelectionEmpty) override { ++call_count_; }
Count() const4340   int Count() const { return call_count_; }
Reset()4341   void Reset() { call_count_ = 0; }
4342 
4343  private:
4344   int call_count_;
4345 };
4346 
TEST_F(WebFrameTest,TabKeyCursorMoveTriggersOneSelectionChange)4347 TEST_F(WebFrameTest, TabKeyCursorMoveTriggersOneSelectionChange) {
4348   ChangedSelectionCounter counter;
4349   frame_test_helpers::WebViewHelper web_view_helper;
4350   RegisterMockedHttpURLLoad("editable_elements.html");
4351   WebViewImpl* web_view = web_view_helper.InitializeAndLoad(
4352       base_url_ + "editable_elements.html", &counter);
4353 
4354   WebKeyboardEvent tab_down(WebInputEvent::Type::kKeyDown,
4355                             WebInputEvent::kNoModifiers,
4356                             WebInputEvent::GetStaticTimeStampForTests());
4357   WebKeyboardEvent tab_up(WebInputEvent::Type::kKeyUp,
4358                           WebInputEvent::kNoModifiers,
4359                           WebInputEvent::GetStaticTimeStampForTests());
4360   tab_down.dom_key = ui::DomKey::TAB;
4361   tab_up.dom_key = ui::DomKey::TAB;
4362   tab_down.windows_key_code = VKEY_TAB;
4363   tab_up.windows_key_code = VKEY_TAB;
4364 
4365   // Move to the next text-field: 1 cursor change.
4366   counter.Reset();
4367   web_view->MainFrameWidget()->HandleInputEvent(
4368       WebCoalescedInputEvent(tab_down, ui::LatencyInfo()));
4369   web_view->MainFrameWidget()->HandleInputEvent(
4370       WebCoalescedInputEvent(tab_up, ui::LatencyInfo()));
4371   EXPECT_EQ(1, counter.Count());
4372 
4373   // Move to another text-field: 1 cursor change.
4374   web_view->MainFrameWidget()->HandleInputEvent(
4375       WebCoalescedInputEvent(tab_down, ui::LatencyInfo()));
4376   web_view->MainFrameWidget()->HandleInputEvent(
4377       WebCoalescedInputEvent(tab_up, ui::LatencyInfo()));
4378   EXPECT_EQ(2, counter.Count());
4379 
4380   // Move to a number-field: 1 cursor change.
4381   web_view->MainFrameWidget()->HandleInputEvent(
4382       WebCoalescedInputEvent(tab_down, ui::LatencyInfo()));
4383   web_view->MainFrameWidget()->HandleInputEvent(
4384       WebCoalescedInputEvent(tab_up, ui::LatencyInfo()));
4385   EXPECT_EQ(3, counter.Count());
4386 
4387   // Move to an editable element: 1 cursor change.
4388   web_view->MainFrameWidget()->HandleInputEvent(
4389       WebCoalescedInputEvent(tab_down, ui::LatencyInfo()));
4390   web_view->MainFrameWidget()->HandleInputEvent(
4391       WebCoalescedInputEvent(tab_up, ui::LatencyInfo()));
4392   EXPECT_EQ(4, counter.Count());
4393 
4394   // Move to a non-editable element: 0 cursor changes.
4395   web_view->MainFrameWidget()->HandleInputEvent(
4396       WebCoalescedInputEvent(tab_down, ui::LatencyInfo()));
4397   web_view->MainFrameWidget()->HandleInputEvent(
4398       WebCoalescedInputEvent(tab_up, ui::LatencyInfo()));
4399   EXPECT_EQ(4, counter.Count());
4400 }
4401 
4402 // Implementation of WebLocalFrameClient that tracks the v8 contexts that are
4403 // created and destroyed for verification.
4404 class ContextLifetimeTestWebFrameClient
4405     : public frame_test_helpers::TestWebFrameClient {
4406  public:
4407   struct Notification {
4408    public:
Notificationblink::ContextLifetimeTestWebFrameClient::Notification4409     Notification(WebLocalFrame* frame,
4410                  v8::Local<v8::Context> context,
4411                  int32_t world_id)
4412         : frame(frame),
4413           context(context->GetIsolate(), context),
4414           world_id(world_id) {}
4415 
~Notificationblink::ContextLifetimeTestWebFrameClient::Notification4416     ~Notification() { context.Reset(); }
4417 
Equalsblink::ContextLifetimeTestWebFrameClient::Notification4418     bool Equals(Notification* other) {
4419       return other && frame == other->frame && context == other->context &&
4420              world_id == other->world_id;
4421     }
4422 
4423     WebLocalFrame* frame;
4424     v8::Persistent<v8::Context> context;
4425     int32_t world_id;
4426   };
4427 
ContextLifetimeTestWebFrameClient(Vector<std::unique_ptr<Notification>> & create_notifications,Vector<std::unique_ptr<Notification>> & release_notifications)4428   ContextLifetimeTestWebFrameClient(
4429       Vector<std::unique_ptr<Notification>>& create_notifications,
4430       Vector<std::unique_ptr<Notification>>& release_notifications)
4431       : create_notifications_(create_notifications),
4432         release_notifications_(release_notifications) {}
4433   ~ContextLifetimeTestWebFrameClient() override = default;
4434 
Reset()4435   void Reset() {
4436     create_notifications_.clear();
4437     release_notifications_.clear();
4438   }
4439 
4440   // WebLocalFrameClient:
CreateChildFrame(WebLocalFrame * parent,mojom::blink::TreeScopeType scope,const WebString & name,const WebString & fallback_name,const FramePolicy &,const WebFrameOwnerProperties &,mojom::blink::FrameOwnerElementType)4441   WebLocalFrame* CreateChildFrame(
4442       WebLocalFrame* parent,
4443       mojom::blink::TreeScopeType scope,
4444       const WebString& name,
4445       const WebString& fallback_name,
4446       const FramePolicy&,
4447       const WebFrameOwnerProperties&,
4448       mojom::blink::FrameOwnerElementType) override {
4449     return CreateLocalChild(*parent, scope,
4450                             std::make_unique<ContextLifetimeTestWebFrameClient>(
4451                                 create_notifications_, release_notifications_));
4452   }
4453 
DidCreateScriptContext(v8::Local<v8::Context> context,int32_t world_id)4454   void DidCreateScriptContext(v8::Local<v8::Context> context,
4455                               int32_t world_id) override {
4456     create_notifications_.push_back(
4457         std::make_unique<Notification>(Frame(), context, world_id));
4458   }
4459 
WillReleaseScriptContext(v8::Local<v8::Context> context,int32_t world_id)4460   void WillReleaseScriptContext(v8::Local<v8::Context> context,
4461                                 int32_t world_id) override {
4462     release_notifications_.push_back(
4463         std::make_unique<Notification>(Frame(), context, world_id));
4464   }
4465 
4466  private:
4467   Vector<std::unique_ptr<Notification>>& create_notifications_;
4468   Vector<std::unique_ptr<Notification>>& release_notifications_;
4469 };
4470 
TEST_F(WebFrameTest,ContextNotificationsLoadUnload)4471 TEST_F(WebFrameTest, ContextNotificationsLoadUnload) {
4472   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
4473 
4474   RegisterMockedHttpURLLoad("context_notifications_test.html");
4475   RegisterMockedHttpURLLoad("context_notifications_test_frame.html");
4476 
4477   // Load a frame with an iframe, make sure we get the right create
4478   // notifications.
4479   Vector<std::unique_ptr<ContextLifetimeTestWebFrameClient::Notification>>
4480       create_notifications;
4481   Vector<std::unique_ptr<ContextLifetimeTestWebFrameClient::Notification>>
4482       release_notifications;
4483   ContextLifetimeTestWebFrameClient web_frame_client(create_notifications,
4484                                                      release_notifications);
4485   frame_test_helpers::WebViewHelper web_view_helper;
4486   web_view_helper.InitializeAndLoad(
4487       base_url_ + "context_notifications_test.html", &web_frame_client);
4488 
4489   WebLocalFrameImpl* main_frame = web_view_helper.LocalMainFrame();
4490   WebFrame* child_frame = main_frame->FirstChild();
4491 
4492   ASSERT_EQ(2u, create_notifications.size());
4493   EXPECT_EQ(0u, release_notifications.size());
4494 
4495   auto& first_create_notification = create_notifications[0];
4496   auto& second_create_notification = create_notifications[1];
4497 
4498   EXPECT_EQ(main_frame, first_create_notification->frame);
4499   EXPECT_EQ(main_frame->MainWorldScriptContext(),
4500             first_create_notification->context);
4501   EXPECT_EQ(0, first_create_notification->world_id);
4502 
4503   EXPECT_EQ(child_frame, second_create_notification->frame);
4504   EXPECT_EQ(child_frame->ToWebLocalFrame()->MainWorldScriptContext(),
4505             second_create_notification->context);
4506   EXPECT_EQ(0, second_create_notification->world_id);
4507 
4508   // Close the view. We should get two release notifications that are exactly
4509   // the same as the create ones, in reverse order.
4510   web_view_helper.Reset();
4511 
4512   ASSERT_EQ(2u, release_notifications.size());
4513   auto& first_release_notification = release_notifications[0];
4514   auto& second_release_notification = release_notifications[1];
4515 
4516   ASSERT_TRUE(
4517       first_create_notification->Equals(second_release_notification.get()));
4518   ASSERT_TRUE(
4519       second_create_notification->Equals(first_release_notification.get()));
4520 }
4521 
TEST_F(WebFrameTest,ContextNotificationsReload)4522 TEST_F(WebFrameTest, ContextNotificationsReload) {
4523   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
4524 
4525   RegisterMockedHttpURLLoad("context_notifications_test.html");
4526   RegisterMockedHttpURLLoad("context_notifications_test_frame.html");
4527 
4528   Vector<std::unique_ptr<ContextLifetimeTestWebFrameClient::Notification>>
4529       create_notifications;
4530   Vector<std::unique_ptr<ContextLifetimeTestWebFrameClient::Notification>>
4531       release_notifications;
4532   ContextLifetimeTestWebFrameClient web_frame_client(create_notifications,
4533                                                      release_notifications);
4534   frame_test_helpers::WebViewHelper web_view_helper;
4535   web_view_helper.InitializeAndLoad(
4536       base_url_ + "context_notifications_test.html", &web_frame_client);
4537 
4538   // Refresh, we should get two release notifications and two more create
4539   // notifications.
4540   frame_test_helpers::ReloadFrame(
4541       web_view_helper.GetWebView()->MainFrameImpl());
4542   ASSERT_EQ(4u, create_notifications.size());
4543   ASSERT_EQ(2u, release_notifications.size());
4544 
4545   // The two release notifications we got should be exactly the same as the
4546   // first two create notifications.
4547   for (size_t i = 0; i < release_notifications.size(); ++i) {
4548     EXPECT_TRUE(release_notifications[i]->Equals(
4549         create_notifications[create_notifications.size() - 3 - i].get()));
4550   }
4551 
4552   // The last two create notifications should be for the current frames and
4553   // context.
4554   WebLocalFrameImpl* main_frame = web_view_helper.LocalMainFrame();
4555   WebFrame* child_frame = main_frame->FirstChild();
4556   auto& first_refresh_notification = create_notifications[2];
4557   auto& second_refresh_notification = create_notifications[3];
4558 
4559   EXPECT_EQ(main_frame, first_refresh_notification->frame);
4560   EXPECT_EQ(main_frame->MainWorldScriptContext(),
4561             first_refresh_notification->context);
4562   EXPECT_EQ(0, first_refresh_notification->world_id);
4563 
4564   EXPECT_EQ(child_frame, second_refresh_notification->frame);
4565   EXPECT_EQ(child_frame->ToWebLocalFrame()->MainWorldScriptContext(),
4566             second_refresh_notification->context);
4567   EXPECT_EQ(0, second_refresh_notification->world_id);
4568 }
4569 
TEST_F(WebFrameTest,ContextNotificationsIsolatedWorlds)4570 TEST_F(WebFrameTest, ContextNotificationsIsolatedWorlds) {
4571   v8::Isolate* isolate = v8::Isolate::GetCurrent();
4572   v8::HandleScope handle_scope(isolate);
4573 
4574   RegisterMockedHttpURLLoad("context_notifications_test.html");
4575   RegisterMockedHttpURLLoad("context_notifications_test_frame.html");
4576 
4577   Vector<std::unique_ptr<ContextLifetimeTestWebFrameClient::Notification>>
4578       create_notifications;
4579   Vector<std::unique_ptr<ContextLifetimeTestWebFrameClient::Notification>>
4580       release_notifications;
4581   ContextLifetimeTestWebFrameClient web_frame_client(create_notifications,
4582                                                      release_notifications);
4583   frame_test_helpers::WebViewHelper web_view_helper;
4584   web_view_helper.InitializeAndLoad(
4585       base_url_ + "context_notifications_test.html", &web_frame_client);
4586 
4587   // Add an isolated world.
4588   web_frame_client.Reset();
4589 
4590   int32_t isolated_world_id = 42;
4591   WebScriptSource script_source("hi!");
4592   web_view_helper.LocalMainFrame()->ExecuteScriptInIsolatedWorld(
4593       isolated_world_id, script_source);
4594 
4595   // We should now have a new create notification.
4596   ASSERT_EQ(1u, create_notifications.size());
4597   auto& notification = create_notifications[0];
4598   ASSERT_EQ(isolated_world_id, notification->world_id);
4599   ASSERT_EQ(web_view_helper.GetWebView()->MainFrame(), notification->frame);
4600 
4601   // We don't have an API to enumarate isolated worlds for a frame, but we can
4602   // at least assert that the context we got is *not* the main world's context.
4603   ASSERT_NE(web_view_helper.LocalMainFrame()->MainWorldScriptContext(),
4604             v8::Local<v8::Context>::New(isolate, notification->context));
4605 
4606   // Check that the context we got has the right isolated world id.
4607   ASSERT_EQ(isolated_world_id,
4608             web_view_helper.LocalMainFrame()->GetScriptContextWorldId(
4609                 v8::Local<v8::Context>::New(isolate, notification->context)));
4610 
4611   web_view_helper.Reset();
4612 
4613   // We should have gotten three release notifications (one for each of the
4614   // frames, plus one for the isolated context).
4615   ASSERT_EQ(3u, release_notifications.size());
4616 
4617   // And one of them should be exactly the same as the create notification for
4618   // the isolated context.
4619   int match_count = 0;
4620   for (size_t i = 0; i < release_notifications.size(); ++i) {
4621     if (release_notifications[i]->Equals(create_notifications[0].get()))
4622       ++match_count;
4623   }
4624   EXPECT_EQ(1, match_count);
4625 }
4626 
TEST_F(WebFrameTest,FindInPage)4627 TEST_F(WebFrameTest, FindInPage) {
4628   RegisterMockedHttpURLLoad("find.html");
4629   frame_test_helpers::WebViewHelper web_view_helper;
4630   web_view_helper.InitializeAndLoad(base_url_ + "find.html");
4631   ASSERT_TRUE(web_view_helper.LocalMainFrame());
4632   WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
4633   const int kFindIdentifier = 12345;
4634   auto options = mojom::blink::FindOptions::New();
4635 
4636   // Find in a <div> element.
4637   EXPECT_TRUE(frame->GetFindInPage()->FindInternal(
4638       kFindIdentifier, WebString::FromUTF8("bar1"), *options, false));
4639   frame->GetFindInPage()->StopFinding(
4640       blink::mojom::StopFindAction::kStopFindActionKeepSelection);
4641   WebRange range = frame->SelectionRange();
4642   EXPECT_EQ(5, range.StartOffset());
4643   EXPECT_EQ(9, range.EndOffset());
4644   EXPECT_TRUE(frame->GetDocument().FocusedElement().IsNull());
4645 
4646   // Find in an <input> value.
4647   EXPECT_TRUE(frame->GetFindInPage()->FindInternal(
4648       kFindIdentifier, WebString::FromUTF8("bar2"), *options, false));
4649   // Confirm stopFinding(WebLocalFrame::StopFindActionKeepSelection) sets the
4650   // selection on the found text.
4651   frame->GetFindInPage()->StopFinding(
4652       blink::mojom::StopFindAction::kStopFindActionKeepSelection);
4653   range = frame->SelectionRange();
4654   ASSERT_FALSE(range.IsNull());
4655   EXPECT_EQ(5, range.StartOffset());
4656   EXPECT_EQ(9, range.EndOffset());
4657   EXPECT_TRUE(frame->GetDocument().FocusedElement().HasHTMLTagName("input"));
4658 
4659   // Find in a <textarea> content.
4660   EXPECT_TRUE(frame->GetFindInPage()->FindInternal(
4661       kFindIdentifier, WebString::FromUTF8("bar3"), *options, false));
4662   // Confirm stopFinding(WebLocalFrame::StopFindActionKeepSelection) sets the
4663   // selection on the found text.
4664   frame->GetFindInPage()->StopFinding(
4665       blink::mojom::StopFindAction::kStopFindActionKeepSelection);
4666   range = frame->SelectionRange();
4667   ASSERT_FALSE(range.IsNull());
4668   EXPECT_EQ(5, range.StartOffset());
4669   EXPECT_EQ(9, range.EndOffset());
4670   EXPECT_TRUE(frame->GetDocument().FocusedElement().HasHTMLTagName("textarea"));
4671 
4672   // Find in a contentEditable element.
4673   EXPECT_TRUE(frame->GetFindInPage()->FindInternal(
4674       kFindIdentifier, WebString::FromUTF8("bar4"), *options, false));
4675   // Confirm stopFinding(WebLocalFrame::StopFindActionKeepSelection) sets the
4676   // selection on the found text.
4677   frame->GetFindInPage()->StopFinding(
4678       blink::mojom::StopFindAction::kStopFindActionKeepSelection);
4679   range = frame->SelectionRange();
4680   ASSERT_FALSE(range.IsNull());
4681   EXPECT_EQ(0, range.StartOffset());
4682   EXPECT_EQ(4, range.EndOffset());
4683   // "bar4" is surrounded by <span>, but the focusable node should be the parent
4684   // <div>.
4685   EXPECT_TRUE(frame->GetDocument().FocusedElement().HasHTMLTagName("div"));
4686 
4687   // Find in <select> content.
4688   EXPECT_FALSE(frame->GetFindInPage()->FindInternal(
4689       kFindIdentifier, WebString::FromUTF8("bar5"), *options, false));
4690   // If there are any matches, stopFinding will set the selection on the found
4691   // text.  However, we do not expect any matches, so check that the selection
4692   // is null.
4693   frame->GetFindInPage()->StopFinding(
4694       blink::mojom::StopFindAction::kStopFindActionKeepSelection);
4695   range = frame->SelectionRange();
4696   ASSERT_TRUE(range.IsNull());
4697 }
4698 
TEST_F(WebFrameTest,GetContentAsPlainText)4699 TEST_F(WebFrameTest, GetContentAsPlainText) {
4700   frame_test_helpers::WebViewHelper web_view_helper;
4701   web_view_helper.InitializeAndLoad("about:blank");
4702   // We set the size because it impacts line wrapping, which changes the
4703   // resulting text value.
4704   web_view_helper.Resize(gfx::Size(640, 480));
4705   WebLocalFrame* frame = web_view_helper.LocalMainFrame();
4706 
4707   // Generate a simple test case.
4708   const char kSimpleSource[] = "<div>Foo bar</div><div></div>baz";
4709   KURL test_url = ToKURL("about:blank");
4710   frame_test_helpers::LoadHTMLString(frame, kSimpleSource, test_url);
4711 
4712   // Make sure it comes out OK.
4713   const std::string expected("Foo bar\nbaz");
4714   WebString text = WebFrameContentDumper::DumpWebViewAsText(
4715       web_view_helper.GetWebView(), std::numeric_limits<size_t>::max());
4716   EXPECT_EQ(expected, text.Utf8());
4717 
4718   // Try reading the same one with clipping of the text.
4719   const int kLength = 5;
4720   text = WebFrameContentDumper::DumpWebViewAsText(web_view_helper.GetWebView(),
4721                                                   kLength);
4722   EXPECT_EQ(expected.substr(0, kLength), text.Utf8());
4723 
4724   // Now do a new test with a subframe.
4725   const char kOuterFrameSource[] = "Hello<iframe></iframe> world";
4726   frame_test_helpers::LoadHTMLString(frame, kOuterFrameSource, test_url);
4727 
4728   // Load something into the subframe.
4729   WebLocalFrame* subframe = frame->FirstChild()->ToWebLocalFrame();
4730   ASSERT_TRUE(subframe);
4731   frame_test_helpers::LoadHTMLString(subframe, "sub<p>text", test_url);
4732 
4733   text = WebFrameContentDumper::DumpWebViewAsText(
4734       web_view_helper.GetWebView(), std::numeric_limits<size_t>::max());
4735   EXPECT_EQ("Hello world\n\nsub\n\ntext", text.Utf8());
4736 
4737   // Get the frame text where the subframe separator falls on the boundary of
4738   // what we'll take. There used to be a crash in this case.
4739   text = WebFrameContentDumper::DumpWebViewAsText(web_view_helper.GetWebView(),
4740                                                   12);
4741   EXPECT_EQ("Hello world", text.Utf8());
4742 }
4743 
TEST_F(WebFrameTest,GetFullHtmlOfPage)4744 TEST_F(WebFrameTest, GetFullHtmlOfPage) {
4745   frame_test_helpers::WebViewHelper web_view_helper;
4746   web_view_helper.InitializeAndLoad("about:blank");
4747   WebLocalFrame* frame = web_view_helper.LocalMainFrame();
4748 
4749   // Generate a simple test case.
4750   const char kSimpleSource[] = "<p>Hello</p><p>World</p>";
4751   KURL test_url = ToKURL("about:blank");
4752   frame_test_helpers::LoadHTMLString(frame, kSimpleSource, test_url);
4753 
4754   WebString text = WebFrameContentDumper::DumpWebViewAsText(
4755       web_view_helper.GetWebView(), std::numeric_limits<size_t>::max());
4756   EXPECT_EQ("Hello\n\nWorld", text.Utf8());
4757 
4758   const std::string html = WebFrameContentDumper::DumpAsMarkup(frame).Utf8();
4759 
4760   // Load again with the output html.
4761   frame_test_helpers::LoadHTMLString(frame, html, test_url);
4762 
4763   EXPECT_EQ(html, WebFrameContentDumper::DumpAsMarkup(frame).Utf8());
4764 
4765   text = WebFrameContentDumper::DumpWebViewAsText(
4766       web_view_helper.GetWebView(), std::numeric_limits<size_t>::max());
4767   EXPECT_EQ("Hello\n\nWorld", text.Utf8());
4768 
4769   // Test selection check
4770   EXPECT_FALSE(frame->HasSelection());
4771   frame->ExecuteCommand(WebString::FromUTF8("SelectAll"));
4772   EXPECT_TRUE(frame->HasSelection());
4773   frame->ExecuteCommand(WebString::FromUTF8("Unselect"));
4774   EXPECT_FALSE(frame->HasSelection());
4775   WebString selection_html = frame->SelectionAsMarkup();
4776   EXPECT_TRUE(selection_html.IsEmpty());
4777 }
4778 
4779 class TestExecuteScriptDuringDidCreateScriptContext
4780     : public frame_test_helpers::TestWebFrameClient {
4781  public:
4782   TestExecuteScriptDuringDidCreateScriptContext() = default;
4783   ~TestExecuteScriptDuringDidCreateScriptContext() override = default;
4784 
4785   // frame_test_helpers::TestWebFrameClient:
DidCreateScriptContext(v8::Local<v8::Context> context,int32_t world_id)4786   void DidCreateScriptContext(v8::Local<v8::Context> context,
4787                               int32_t world_id) override {
4788     Frame()->ExecuteScript(WebScriptSource("window.history = 'replaced';"));
4789   }
4790 };
4791 
TEST_F(WebFrameTest,ExecuteScriptDuringDidCreateScriptContext)4792 TEST_F(WebFrameTest, ExecuteScriptDuringDidCreateScriptContext) {
4793   RegisterMockedHttpURLLoad("hello_world.html");
4794 
4795   TestExecuteScriptDuringDidCreateScriptContext web_frame_client;
4796   frame_test_helpers::WebViewHelper web_view_helper;
4797   web_view_helper.InitializeAndLoad(base_url_ + "hello_world.html",
4798                                     &web_frame_client);
4799 
4800   frame_test_helpers::ReloadFrame(
4801       web_view_helper.GetWebView()->MainFrameImpl());
4802 }
4803 
4804 class TestFindInPageClient : public mojom::blink::FindInPageClient {
4805  public:
TestFindInPageClient()4806   TestFindInPageClient()
4807       : find_results_are_ready_(false), count_(-1), active_index_(-1) {}
4808 
4809   ~TestFindInPageClient() override = default;
4810 
SetFrame(WebLocalFrameImpl * frame)4811   void SetFrame(WebLocalFrameImpl* frame) {
4812     frame->GetFindInPage()->SetClient(receiver_.BindNewPipeAndPassRemote());
4813   }
4814 
SetNumberOfMatches(int request_id,unsigned int current_number_of_matches,mojom::blink::FindMatchUpdateType final_update)4815   void SetNumberOfMatches(
4816       int request_id,
4817       unsigned int current_number_of_matches,
4818       mojom::blink::FindMatchUpdateType final_update) final {
4819     count_ = current_number_of_matches;
4820     find_results_are_ready_ =
4821         (final_update == mojom::blink::FindMatchUpdateType::kFinalUpdate);
4822   }
4823 
SetActiveMatch(int request_id,const gfx::Rect & active_match_rect,int active_match_ordinal,mojom::blink::FindMatchUpdateType final_update)4824   void SetActiveMatch(int request_id,
4825                       const gfx::Rect& active_match_rect,
4826                       int active_match_ordinal,
4827                       mojom::blink::FindMatchUpdateType final_update) final {
4828     active_index_ = active_match_ordinal;
4829     find_results_are_ready_ =
4830         (final_update == mojom::blink::FindMatchUpdateType::kFinalUpdate);
4831   }
4832 
FindResultsAreReady() const4833   bool FindResultsAreReady() const { return find_results_are_ready_; }
Count() const4834   int Count() const { return count_; }
ActiveIndex() const4835   int ActiveIndex() const { return active_index_; }
4836 
4837  private:
4838   bool find_results_are_ready_;
4839   int count_;
4840   int active_index_;
4841   mojo::Receiver<mojom::blink::FindInPageClient> receiver_{this};
4842 };
4843 
TEST_F(WebFrameTest,FindInPageMatchRects)4844 TEST_F(WebFrameTest, FindInPageMatchRects) {
4845   RegisterMockedHttpURLLoad("find_in_page_frame.html");
4846 
4847   frame_test_helpers::TestWebFrameClient frame_client;
4848   frame_test_helpers::WebViewHelper web_view_helper;
4849   web_view_helper.InitializeAndLoad(base_url_ + "find_in_page_frame.html",
4850                                     &frame_client);
4851   web_view_helper.Resize(gfx::Size(640, 480));
4852   web_view_helper.GetWebView()->SetMaximumLegibleScale(1.f);
4853   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
4854   RunPendingTasks();
4855 
4856   // Note that the 'result 19' in the <select> element is not expected to
4857   // produce a match. Also, results 00 and 01 are in a different frame that is
4858   // not included in this test.
4859   const char kFindString[] = "result";
4860   const int kFindIdentifier = 12345;
4861   const int kNumResults = 17;
4862 
4863   auto options = mojom::blink::FindOptions::New();
4864   options->run_synchronously_for_testing = true;
4865   WebString search_text = WebString::FromUTF8(kFindString);
4866   WebLocalFrameImpl* main_frame = web_view_helper.LocalMainFrame();
4867   TestFindInPageClient find_in_page_client;
4868   find_in_page_client.SetFrame(main_frame);
4869   EXPECT_TRUE(main_frame->GetFindInPage()->FindInternal(
4870       kFindIdentifier, search_text, *options, false));
4871 
4872   main_frame->EnsureTextFinder().ResetMatchCount();
4873 
4874   for (WebLocalFrameImpl* frame = main_frame; frame;
4875        frame = To<WebLocalFrameImpl>(frame->TraverseNext())) {
4876     frame->EnsureTextFinder().StartScopingStringMatches(kFindIdentifier,
4877                                                         search_text, *options);
4878   }
4879   RunPendingTasks();
4880   EXPECT_TRUE(find_in_page_client.FindResultsAreReady());
4881 
4882   WebVector<gfx::RectF> web_match_rects =
4883       main_frame->EnsureTextFinder().FindMatchRects();
4884   ASSERT_EQ(static_cast<size_t>(kNumResults), web_match_rects.size());
4885   int rects_version = main_frame->GetFindInPage()->FindMatchMarkersVersion();
4886 
4887   for (int result_index = 0; result_index < kNumResults; ++result_index) {
4888     FloatRect result_rect =
4889         static_cast<FloatRect>(web_match_rects[result_index]);
4890 
4891     // Select the match by the center of its rect.
4892     EXPECT_EQ(main_frame->EnsureTextFinder().SelectNearestFindMatch(
4893                   result_rect.Center(), nullptr),
4894               result_index + 1);
4895 
4896     // Check that the find result ordering matches with our expectations.
4897     Range* result = main_frame->GetTextFinder()->ActiveMatch();
4898     ASSERT_TRUE(result);
4899     result->setEnd(result->endContainer(), result->endOffset() + 3);
4900     EXPECT_EQ(result->GetText(),
4901               String::Format("%s %02d", kFindString, result_index + 2));
4902 
4903     // Verify that the expected match rect also matches the currently active
4904     // match.  Compare the enclosing rects to prevent precision issues caused by
4905     // CSS transforms.
4906     gfx::RectF active_match =
4907         main_frame->GetFindInPage()->ActiveFindMatchRect();
4908     EXPECT_EQ(EnclosingIntRect(FloatRect(active_match)),
4909               EnclosingIntRect(result_rect));
4910 
4911     // The rects version should not have changed.
4912     EXPECT_EQ(main_frame->GetFindInPage()->FindMatchMarkersVersion(),
4913               rects_version);
4914   }
4915 
4916   // Resizing should update the rects version.
4917   web_view_helper.Resize(gfx::Size(800, 600));
4918   RunPendingTasks();
4919   EXPECT_TRUE(main_frame->GetFindInPage()->FindMatchMarkersVersion() !=
4920               rects_version);
4921 }
4922 
TEST_F(WebFrameTest,FindInPageActiveIndex)4923 TEST_F(WebFrameTest, FindInPageActiveIndex) {
4924   RegisterMockedHttpURLLoad("find_match_count.html");
4925 
4926   frame_test_helpers::TestWebFrameClient frame_client;
4927   frame_test_helpers::WebViewHelper web_view_helper;
4928   web_view_helper.InitializeAndLoad(base_url_ + "find_match_count.html",
4929                                     &frame_client);
4930   web_view_helper.GetWebView()->MainFrameViewWidget()->Resize(
4931       gfx::Size(640, 480));
4932   RunPendingTasks();
4933 
4934   const char* kFindString = "a";
4935   const int kFindIdentifier = 7777;
4936   const int kActiveIndex = 1;
4937 
4938   auto options = mojom::blink::FindOptions::New();
4939   options->run_synchronously_for_testing = true;
4940   WebString search_text = WebString::FromUTF8(kFindString);
4941   WebLocalFrameImpl* main_frame = web_view_helper.LocalMainFrame();
4942   TestFindInPageClient find_in_page_client;
4943   find_in_page_client.SetFrame(main_frame);
4944 
4945   EXPECT_TRUE(main_frame->GetFindInPage()->FindInternal(
4946       kFindIdentifier, search_text, *options, false));
4947   main_frame->EnsureTextFinder().ResetMatchCount();
4948 
4949   for (WebLocalFrameImpl* frame = main_frame; frame;
4950        frame = To<WebLocalFrameImpl>(frame->TraverseNext())) {
4951     frame->EnsureTextFinder().StartScopingStringMatches(kFindIdentifier,
4952                                                         search_text, *options);
4953   }
4954   RunPendingTasks();
4955 
4956   EXPECT_TRUE(main_frame->GetFindInPage()->FindInternal(
4957       kFindIdentifier, search_text, *options, false));
4958   main_frame->GetFindInPage()->StopFinding(
4959       mojom::StopFindAction::kStopFindActionClearSelection);
4960 
4961   for (WebLocalFrameImpl* frame = main_frame; frame;
4962        frame = To<WebLocalFrameImpl>(frame->TraverseNext())) {
4963     frame->EnsureTextFinder().StartScopingStringMatches(kFindIdentifier,
4964                                                         search_text, *options);
4965   }
4966 
4967   RunPendingTasks();
4968   EXPECT_TRUE(find_in_page_client.FindResultsAreReady());
4969   EXPECT_EQ(kActiveIndex, find_in_page_client.ActiveIndex());
4970 
4971   const char* kFindStringNew = "e";
4972   WebString search_text_new = WebString::FromUTF8(kFindStringNew);
4973 
4974   EXPECT_TRUE(main_frame->GetFindInPage()->FindInternal(
4975       kFindIdentifier, search_text_new, *options, false));
4976   main_frame->EnsureTextFinder().ResetMatchCount();
4977 
4978   for (WebLocalFrameImpl* frame = main_frame; frame;
4979        frame = To<WebLocalFrameImpl>(frame->TraverseNext())) {
4980     frame->EnsureTextFinder().StartScopingStringMatches(
4981         kFindIdentifier, search_text_new, *options);
4982   }
4983 
4984   RunPendingTasks();
4985   EXPECT_TRUE(find_in_page_client.FindResultsAreReady());
4986   EXPECT_EQ(kActiveIndex, find_in_page_client.ActiveIndex());
4987 }
4988 
TEST_F(WebFrameTest,FindOnDetachedFrame)4989 TEST_F(WebFrameTest, FindOnDetachedFrame) {
4990   RegisterMockedHttpURLLoad("find_in_page.html");
4991   RegisterMockedHttpURLLoad("find_in_page_frame.html");
4992 
4993   frame_test_helpers::TestWebFrameClient frame_client;
4994   frame_test_helpers::WebViewHelper web_view_helper;
4995   web_view_helper.InitializeAndLoad(base_url_ + "find_in_page.html",
4996                                     &frame_client);
4997   web_view_helper.Resize(gfx::Size(640, 480));
4998   RunPendingTasks();
4999 
5000   const char kFindString[] = "result";
5001   const int kFindIdentifier = 12345;
5002 
5003   auto options = mojom::blink::FindOptions::New();
5004   options->run_synchronously_for_testing = true;
5005   WebString search_text = WebString::FromUTF8(kFindString);
5006   WebLocalFrameImpl* main_frame = web_view_helper.LocalMainFrame();
5007   TestFindInPageClient main_find_in_page_client;
5008   main_find_in_page_client.SetFrame(main_frame);
5009 
5010   auto* second_frame = To<WebLocalFrameImpl>(main_frame->TraverseNext());
5011 
5012   // Detach the frame before finding.
5013   RemoveElementById(main_frame, "frame");
5014 
5015   EXPECT_TRUE(main_frame->GetFindInPage()->FindInternal(
5016       kFindIdentifier, search_text, *options, false));
5017   EXPECT_FALSE(second_frame->GetFindInPage()->FindInternal(
5018       kFindIdentifier, search_text, *options, false));
5019 
5020   RunPendingTasks();
5021   EXPECT_FALSE(main_find_in_page_client.FindResultsAreReady());
5022 
5023   main_frame->EnsureTextFinder().ResetMatchCount();
5024 
5025   for (WebLocalFrameImpl* frame = main_frame; frame;
5026        frame = To<WebLocalFrameImpl>(frame->TraverseNext())) {
5027     frame->EnsureTextFinder().StartScopingStringMatches(kFindIdentifier,
5028                                                         search_text, *options);
5029   }
5030 
5031   RunPendingTasks();
5032   EXPECT_TRUE(main_find_in_page_client.FindResultsAreReady());
5033 }
5034 
TEST_F(WebFrameTest,FindDetachFrameBeforeScopeStrings)5035 TEST_F(WebFrameTest, FindDetachFrameBeforeScopeStrings) {
5036   RegisterMockedHttpURLLoad("find_in_page.html");
5037   RegisterMockedHttpURLLoad("find_in_page_frame.html");
5038 
5039   frame_test_helpers::TestWebFrameClient frame_client;
5040   frame_test_helpers::WebViewHelper web_view_helper;
5041   web_view_helper.InitializeAndLoad(base_url_ + "find_in_page.html",
5042                                     &frame_client);
5043   web_view_helper.Resize(gfx::Size(640, 480));
5044   RunPendingTasks();
5045 
5046   const char kFindString[] = "result";
5047   const int kFindIdentifier = 12345;
5048 
5049   auto options = mojom::blink::FindOptions::New();
5050   options->run_synchronously_for_testing = true;
5051   WebString search_text = WebString::FromUTF8(kFindString);
5052   WebLocalFrameImpl* main_frame = web_view_helper.LocalMainFrame();
5053   TestFindInPageClient find_in_page_client;
5054   find_in_page_client.SetFrame(main_frame);
5055 
5056   for (WebLocalFrameImpl* frame = main_frame; frame;
5057        frame = To<WebLocalFrameImpl>(frame->TraverseNext())) {
5058     EXPECT_TRUE(frame->GetFindInPage()->FindInternal(
5059         kFindIdentifier, search_text, *options, false));
5060   }
5061   RunPendingTasks();
5062   EXPECT_FALSE(find_in_page_client.FindResultsAreReady());
5063 
5064   // Detach the frame between finding and scoping.
5065   RemoveElementById(main_frame, "frame");
5066 
5067   main_frame->EnsureTextFinder().ResetMatchCount();
5068 
5069   for (WebLocalFrameImpl* frame = main_frame; frame;
5070        frame = To<WebLocalFrameImpl>(frame->TraverseNext())) {
5071     frame->EnsureTextFinder().StartScopingStringMatches(kFindIdentifier,
5072                                                         search_text, *options);
5073   }
5074 
5075   RunPendingTasks();
5076   EXPECT_TRUE(find_in_page_client.FindResultsAreReady());
5077 }
5078 
TEST_F(WebFrameTest,FindDetachFrameWhileScopingStrings)5079 TEST_F(WebFrameTest, FindDetachFrameWhileScopingStrings) {
5080   RegisterMockedHttpURLLoad("find_in_page.html");
5081   RegisterMockedHttpURLLoad("find_in_page_frame.html");
5082 
5083   frame_test_helpers::TestWebFrameClient frame_client;
5084   frame_test_helpers::WebViewHelper web_view_helper;
5085   web_view_helper.InitializeAndLoad(base_url_ + "find_in_page.html",
5086                                     &frame_client);
5087   web_view_helper.Resize(gfx::Size(640, 480));
5088   RunPendingTasks();
5089 
5090   const char kFindString[] = "result";
5091   const int kFindIdentifier = 12345;
5092 
5093   auto options = mojom::blink::FindOptions::New();
5094   options->run_synchronously_for_testing = true;
5095   WebString search_text = WebString::FromUTF8(kFindString);
5096   WebLocalFrameImpl* main_frame = web_view_helper.LocalMainFrame();
5097   TestFindInPageClient find_in_page_client;
5098   find_in_page_client.SetFrame(main_frame);
5099 
5100   for (WebLocalFrameImpl* frame = main_frame; frame;
5101        frame = To<WebLocalFrameImpl>(frame->TraverseNext())) {
5102     EXPECT_TRUE(frame->GetFindInPage()->FindInternal(
5103         kFindIdentifier, search_text, *options, false));
5104   }
5105   RunPendingTasks();
5106   EXPECT_FALSE(find_in_page_client.FindResultsAreReady());
5107 
5108   main_frame->EnsureTextFinder().ResetMatchCount();
5109 
5110   for (WebLocalFrameImpl* frame = main_frame; frame;
5111        frame = To<WebLocalFrameImpl>(frame->TraverseNext())) {
5112     frame->EnsureTextFinder().StartScopingStringMatches(kFindIdentifier,
5113                                                         search_text, *options);
5114   }
5115 
5116   // The first startScopingStringMatches will have reset the state. Detach
5117   // before it actually scopes.
5118   RemoveElementById(main_frame, "frame");
5119 
5120   for (WebLocalFrameImpl* frame = main_frame; frame;
5121        frame = To<WebLocalFrameImpl>(frame->TraverseNext())) {
5122     frame->EnsureTextFinder().StartScopingStringMatches(kFindIdentifier,
5123                                                         search_text, *options);
5124   }
5125   RunPendingTasks();
5126   EXPECT_TRUE(find_in_page_client.FindResultsAreReady());
5127 }
5128 
TEST_F(WebFrameTest,ResetMatchCount)5129 TEST_F(WebFrameTest, ResetMatchCount) {
5130   RegisterMockedHttpURLLoad("find_in_generated_frame.html");
5131 
5132   frame_test_helpers::TestWebFrameClient frame_client;
5133   frame_test_helpers::WebViewHelper web_view_helper;
5134   web_view_helper.InitializeAndLoad(base_url_ + "find_in_generated_frame.html",
5135                                     &frame_client);
5136   web_view_helper.Resize(gfx::Size(640, 480));
5137   RunPendingTasks();
5138 
5139   const char kFindString[] = "result";
5140   const int kFindIdentifier = 12345;
5141 
5142   auto options = mojom::blink::FindOptions::New();
5143   options->run_synchronously_for_testing = true;
5144   WebString search_text = WebString::FromUTF8(kFindString);
5145   WebLocalFrameImpl* main_frame = web_view_helper.LocalMainFrame();
5146   TestFindInPageClient find_in_page_client;
5147   find_in_page_client.SetFrame(main_frame);
5148 
5149   // Check that child frame exists.
5150   EXPECT_TRUE(!!main_frame->TraverseNext());
5151 
5152   for (WebLocalFrameImpl* frame = main_frame; frame;
5153        frame = To<WebLocalFrameImpl>(frame->TraverseNext())) {
5154     EXPECT_FALSE(frame->GetFindInPage()->FindInternal(
5155         kFindIdentifier, search_text, *options, false));
5156   }
5157 
5158   RunPendingTasks();
5159   EXPECT_FALSE(find_in_page_client.FindResultsAreReady());
5160 
5161   main_frame->EnsureTextFinder().ResetMatchCount();
5162 }
5163 
TEST_F(WebFrameTest,SetTickmarks)5164 TEST_F(WebFrameTest, SetTickmarks) {
5165   RegisterMockedHttpURLLoad("find.html");
5166 
5167   frame_test_helpers::TestWebFrameClient frame_client;
5168   frame_test_helpers::WebViewHelper web_view_helper;
5169   web_view_helper.InitializeAndLoad(base_url_ + "find.html", &frame_client);
5170   web_view_helper.Resize(gfx::Size(640, 480));
5171   RunPendingTasks();
5172 
5173   const char kFindString[] = "foo";
5174   const int kFindIdentifier = 12345;
5175 
5176   auto options = mojom::blink::FindOptions::New();
5177   options->run_synchronously_for_testing = true;
5178   WebString search_text = WebString::FromUTF8(kFindString);
5179   WebLocalFrameImpl* main_frame = web_view_helper.LocalMainFrame();
5180   TestFindInPageClient find_in_page_client;
5181   find_in_page_client.SetFrame(main_frame);
5182   EXPECT_TRUE(main_frame->GetFindInPage()->FindInternal(
5183       kFindIdentifier, search_text, *options, false));
5184 
5185   main_frame->EnsureTextFinder().ResetMatchCount();
5186   main_frame->EnsureTextFinder().StartScopingStringMatches(
5187       kFindIdentifier, search_text, *options);
5188 
5189   RunPendingTasks();
5190   EXPECT_TRUE(find_in_page_client.FindResultsAreReady());
5191 
5192   const Vector<IntRect> kExpectedOverridingTickmarks = {
5193       IntRect(0, 0, 100, 100), IntRect(0, 20, 100, 100),
5194       IntRect(0, 30, 100, 100)};
5195   const Vector<IntRect> kResetTickmarks;
5196 
5197   {
5198     // Test SetTickmarks() with a null target WebElement.
5199     //
5200     // Get the tickmarks for the original find request. It should have 4
5201     // tickmarks, given the search performed above.
5202     LocalFrameView* frame_view =
5203         web_view_helper.LocalMainFrame()->GetFrameView();
5204     ScrollableArea* layout_viewport = frame_view->LayoutViewport();
5205     Vector<IntRect> original_tickmarks = layout_viewport->GetTickmarks();
5206     EXPECT_EQ(4u, original_tickmarks.size());
5207 
5208     // Override the tickmarks.
5209     main_frame->SetTickmarks(WebElement(), kExpectedOverridingTickmarks);
5210 
5211     // Check the tickmarks are overridden correctly.
5212     Vector<IntRect> overriding_tickmarks_actual =
5213         layout_viewport->GetTickmarks();
5214     EXPECT_EQ(kExpectedOverridingTickmarks, overriding_tickmarks_actual);
5215 
5216     // Reset the tickmark behavior.
5217     main_frame->SetTickmarks(WebElement(), kResetTickmarks);
5218 
5219     // Check that the original tickmarks are returned
5220     Vector<IntRect> original_tickmarks_after_reset =
5221         layout_viewport->GetTickmarks();
5222     EXPECT_EQ(original_tickmarks, original_tickmarks_after_reset);
5223   }
5224 
5225   {
5226     // Test SetTickmarks() with a non-null target WebElement.
5227     //
5228     // Use an element from within find.html for testing. It has no tickmarks.
5229     WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
5230     WebElement target = frame->GetDocument().GetElementById("textarea1");
5231     ASSERT_FALSE(target.IsNull());
5232     LayoutBox* box = target.ConstUnwrap<Element>()->GetLayoutBoxForScrolling();
5233     ASSERT_TRUE(box);
5234     ScrollableArea* scrollable_area = box->GetScrollableArea();
5235     ASSERT_TRUE(scrollable_area);
5236     Vector<IntRect> original_tickmarks = scrollable_area->GetTickmarks();
5237     EXPECT_EQ(0u, original_tickmarks.size());
5238 
5239     // Override the tickmarks.
5240     main_frame->SetTickmarks(target, kExpectedOverridingTickmarks);
5241 
5242     // Check the tickmarks are overridden correctly.
5243     Vector<IntRect> overriding_tickmarks_actual =
5244         scrollable_area->GetTickmarks();
5245     EXPECT_EQ(kExpectedOverridingTickmarks, overriding_tickmarks_actual);
5246 
5247     // Reset the tickmark behavior.
5248     main_frame->SetTickmarks(target, kResetTickmarks);
5249 
5250     // Check that the original tickmarks are returned
5251     Vector<IntRect> original_tickmarks_after_reset =
5252         scrollable_area->GetTickmarks();
5253     EXPECT_EQ(original_tickmarks, original_tickmarks_after_reset);
5254   }
5255 }
5256 
TEST_F(WebFrameTest,FindInPageJavaScriptUpdatesDOM)5257 TEST_F(WebFrameTest, FindInPageJavaScriptUpdatesDOM) {
5258   RegisterMockedHttpURLLoad("find.html");
5259 
5260   frame_test_helpers::TestWebFrameClient frame_client;
5261   frame_test_helpers::WebViewHelper web_view_helper;
5262   web_view_helper.InitializeAndLoad(base_url_ + "find.html", &frame_client);
5263   web_view_helper.Resize(gfx::Size(640, 480));
5264   RunPendingTasks();
5265 
5266   WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
5267   TestFindInPageClient find_in_page_client;
5268   find_in_page_client.SetFrame(frame);
5269 
5270   const int kFindIdentifier = 12345;
5271   static const char* kFindString = "foo";
5272   WebString search_text = WebString::FromUTF8(kFindString);
5273   auto options = mojom::blink::FindOptions::New();
5274   options->run_synchronously_for_testing = true;
5275   bool active_now;
5276 
5277   frame->EnsureTextFinder().ResetMatchCount();
5278   frame->EnsureTextFinder().StartScopingStringMatches(kFindIdentifier,
5279                                                       search_text, *options);
5280   RunPendingTasks();
5281   EXPECT_TRUE(find_in_page_client.FindResultsAreReady());
5282 
5283   // Find in a <div> element.
5284   options->new_session = false;
5285   EXPECT_TRUE(frame->GetFindInPage()->FindInternal(
5286       kFindIdentifier, search_text, *options, false, &active_now));
5287   EXPECT_TRUE(active_now);
5288 
5289   // Insert new text, which contains occurence of |searchText|.
5290   frame->ExecuteScript(WebScriptSource(
5291       "var newTextNode = document.createTextNode('bar5 foo5');"
5292       "var textArea = document.getElementsByTagName('textarea')[0];"
5293       "document.body.insertBefore(newTextNode, textArea);"));
5294 
5295   // Find in a <input> element.
5296   EXPECT_TRUE(frame->GetFindInPage()->FindInternal(
5297       kFindIdentifier, search_text, *options, false, &active_now));
5298   EXPECT_TRUE(active_now);
5299 
5300   // Find in the inserted text node.
5301   EXPECT_TRUE(frame->GetFindInPage()->FindInternal(
5302       kFindIdentifier, search_text, *options, false, &active_now));
5303   frame->GetFindInPage()->StopFinding(
5304       blink::mojom::StopFindAction::kStopFindActionKeepSelection);
5305   WebRange range = frame->SelectionRange();
5306   EXPECT_EQ(5, range.StartOffset());
5307   EXPECT_EQ(8, range.EndOffset());
5308   EXPECT_TRUE(frame->GetDocument().FocusedElement().IsNull());
5309   EXPECT_FALSE(active_now);
5310 }
5311 
TEST_F(WebFrameTest,FindInPageJavaScriptUpdatesDOMProperOrdinal)5312 TEST_F(WebFrameTest, FindInPageJavaScriptUpdatesDOMProperOrdinal) {
5313   const WebString search_pattern = WebString::FromUTF8("abc");
5314   // We have 2 occurrences of the pattern in our text.
5315   const char* html =
5316       "foo bar foo bar foo abc bar foo bar foo bar foo bar foo bar foo bar foo "
5317       "bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo "
5318       "bar foo bar foo abc bar <div id='new_text'></div>";
5319 
5320   frame_test_helpers::TestWebFrameClient frame_client;
5321   frame_test_helpers::WebViewHelper web_view_helper;
5322   web_view_helper.Initialize(&frame_client);
5323 
5324   WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
5325   frame_test_helpers::LoadHTMLString(frame, html,
5326                                      url_test_helpers::ToKURL(base_url_));
5327   web_view_helper.Resize(gfx::Size(640, 480));
5328   web_view_helper.GetWebView()->MainFrameWidget()->SetFocus(true);
5329   RunPendingTasks();
5330 
5331   TestFindInPageClient find_in_page_client;
5332   find_in_page_client.SetFrame(frame);
5333   const int kFindIdentifier = 12345;
5334 
5335   auto options = mojom::blink::FindOptions::New();
5336   options->run_synchronously_for_testing = true;
5337   options->new_session = true;
5338   options->forward = true;
5339   // The first search that will start the scoping process.
5340   frame->GetFindInPage()->Find(kFindIdentifier, search_pattern,
5341                                options->Clone());
5342   EXPECT_FALSE(find_in_page_client.FindResultsAreReady());
5343   RunPendingTasks();
5344 
5345   EXPECT_EQ(2, find_in_page_client.Count());
5346   EXPECT_EQ(1, find_in_page_client.ActiveIndex());
5347 
5348   options->new_session = false;
5349   // The second search will jump to the next match without any scoping.
5350   frame->GetFindInPage()->Find(kFindIdentifier, search_pattern,
5351                                options->Clone());
5352   // Run pending tasks to make sure IncreaseMatchCount calls passes.
5353   RunPendingTasks();
5354   EXPECT_EQ(2, find_in_page_client.Count());
5355   EXPECT_EQ(2, find_in_page_client.ActiveIndex());
5356   EXPECT_FALSE(frame->EnsureTextFinder().ScopingInProgress());
5357 
5358   // Insert new text, which contains occurence of |searchText|.
5359   frame->ExecuteScript(
5360       WebScriptSource("var textDiv = document.getElementById('new_text');"
5361                       "textDiv.innerHTML = 'foo abc';"));
5362 
5363   // The third search will find a new match and initiate a new scoping.
5364   frame->GetFindInPage()->Find(kFindIdentifier, search_pattern,
5365                                options->Clone());
5366   RunPendingTasks();
5367 
5368   EXPECT_EQ(3, find_in_page_client.Count());
5369   EXPECT_EQ(3, find_in_page_client.ActiveIndex());
5370 }
5371 
TEST_F(WebFrameTest,FindInPageStopFindActionKeepSelectionInAnotherDocument)5372 TEST_F(WebFrameTest, FindInPageStopFindActionKeepSelectionInAnotherDocument) {
5373   RegisterMockedHttpURLLoad("find.html");
5374   RegisterMockedHttpURLLoad("hello_world.html");
5375   frame_test_helpers::WebViewHelper web_view_helper;
5376   web_view_helper.InitializeAndLoad(base_url_ + "find.html");
5377   ASSERT_TRUE(web_view_helper.LocalMainFrame());
5378   WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
5379   const int kFindIdentifier = 12345;
5380   auto options = mojom::blink::FindOptions::New();
5381 
5382   // Set active match
5383   ASSERT_TRUE(frame->GetFindInPage()->FindInternal(
5384       kFindIdentifier, WebString::FromUTF8("foo"), *options, false));
5385   // Move to another page.
5386   frame_test_helpers::LoadFrame(frame, base_url_ + "hello_world.html");
5387 
5388   // Stop Find-In-Page. |TextFinder::active_match_| still hold a |Range| in
5389   // "find.html".
5390   frame->GetFindInPage()->StopFinding(
5391       blink::mojom::StopFindAction::kStopFindActionKeepSelection);
5392 
5393   // Pass if not crash. See http://crbug.com/719880 for details.
5394 }
5395 
TEST_F(WebFrameTest,FindInPageForcedRedoOfFindInPage)5396 TEST_F(WebFrameTest, FindInPageForcedRedoOfFindInPage) {
5397   const WebString search_pattern = WebString::FromUTF8("bar");
5398   const char* html = "foo bar foo foo bar";
5399   frame_test_helpers::TestWebFrameClient frame_client;
5400   frame_test_helpers::WebViewHelper web_view_helper;
5401   web_view_helper.Initialize(&frame_client);
5402 
5403   WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
5404   frame_test_helpers::LoadHTMLString(frame, html,
5405                                      url_test_helpers::ToKURL(base_url_));
5406   web_view_helper.Resize(gfx::Size(640, 480));
5407   web_view_helper.GetWebView()->MainFrameWidget()->SetFocus(true);
5408   RunPendingTasks();
5409 
5410   TestFindInPageClient find_in_page_client;
5411   find_in_page_client.SetFrame(frame);
5412   const int kFindIdentifier = 12345;
5413 
5414   auto options = mojom::blink::FindOptions::New();
5415   options->run_synchronously_for_testing = true;
5416   options->new_session = true;
5417   options->forward = true;
5418   // First run.
5419   frame->GetFindInPage()->Find(kFindIdentifier, search_pattern,
5420                                options->Clone());
5421   RunPendingTasks();
5422   EXPECT_EQ(2, find_in_page_client.Count());
5423   EXPECT_EQ(1, find_in_page_client.ActiveIndex());
5424 
5425   options->force = true;
5426   frame->GetFindInPage()->Find(kFindIdentifier, search_pattern,
5427                                options->Clone());
5428   RunPendingTasks();
5429   EXPECT_EQ(2, find_in_page_client.Count());
5430   EXPECT_EQ(1, find_in_page_client.ActiveIndex());
5431 
5432   options->new_session = false;
5433   options->force = false;
5434 
5435   frame->GetFindInPage()->Find(kFindIdentifier, search_pattern,
5436                                options->Clone());
5437   RunPendingTasks();
5438   EXPECT_EQ(2, find_in_page_client.Count());
5439   EXPECT_EQ(2, find_in_page_client.ActiveIndex());
5440 
5441   options->new_session = true;
5442   options->force = true;
5443 
5444   frame->GetFindInPage()->Find(kFindIdentifier, search_pattern,
5445                                options->Clone());
5446   RunPendingTasks();
5447   EXPECT_EQ(2, find_in_page_client.Count());
5448   EXPECT_EQ(2, find_in_page_client.ActiveIndex());
5449 }
5450 
BottomRightMinusOne(const gfx::Rect & rect)5451 static gfx::Point BottomRightMinusOne(const gfx::Rect& rect) {
5452   // FIXME: If we don't subtract 1 from the x- and y-coordinates of the
5453   // selection bounds, selectRange() will select the *next* element. That's
5454   // strictly correct, as hit-testing checks the pixel to the lower-right of
5455   // the input coordinate, but it's a wart on the API.
5456   if (rect.width() > 0) {
5457     return gfx::Point(rect.x() + rect.width() - 1,
5458                       rect.y() + rect.height() - 1);
5459   }
5460   return gfx::Point(rect.x() + rect.width(), rect.y() + rect.height() - 1);
5461 }
5462 
ElementBounds(WebLocalFrame * frame,const WebString & id)5463 static gfx::Rect ElementBounds(WebLocalFrame* frame, const WebString& id) {
5464   return gfx::Rect(frame->GetDocument().GetElementById(id).BoundsInViewport());
5465 }
5466 
SelectionAsString(WebFrame * frame)5467 static std::string SelectionAsString(WebFrame* frame) {
5468   return frame->ToWebLocalFrame()->SelectionAsText().Utf8();
5469 }
5470 
TEST_F(WebFrameTest,SelectRange)5471 TEST_F(WebFrameTest, SelectRange) {
5472   WebLocalFrame* frame;
5473   gfx::Rect start_rect;
5474   gfx::Rect end_rect;
5475 
5476   RegisterMockedHttpURLLoad("select_range_basic.html");
5477   RegisterMockedHttpURLLoad("select_range_scroll.html");
5478 
5479   frame_test_helpers::WebViewHelper web_view_helper;
5480   InitializeTextSelectionWebView(base_url_ + "select_range_basic.html",
5481                                  &web_view_helper);
5482   frame = web_view_helper.LocalMainFrame();
5483   EXPECT_EQ("Some test text for testing.", SelectionAsString(frame));
5484   web_view_helper.GetWebView()->MainFrameViewWidget()->CalculateSelectionBounds(
5485       start_rect, end_rect);
5486   frame->ExecuteCommand(WebString::FromUTF8("Unselect"));
5487   EXPECT_EQ("", SelectionAsString(frame));
5488   frame->SelectRange(start_rect.origin(), BottomRightMinusOne(end_rect));
5489   // On some devices, the above bottomRightMinusOne() causes the ending '.' not
5490   // selected.
5491   std::string selection_string = SelectionAsString(frame);
5492   EXPECT_TRUE(selection_string == "Some test text for testing." ||
5493               selection_string == "Some test text for testing");
5494 
5495   InitializeTextSelectionWebView(base_url_ + "select_range_scroll.html",
5496                                  &web_view_helper);
5497   frame = web_view_helper.LocalMainFrame();
5498   EXPECT_EQ("Some offscreen test text for testing.", SelectionAsString(frame));
5499   web_view_helper.GetWebView()->MainFrameViewWidget()->CalculateSelectionBounds(
5500       start_rect, end_rect);
5501   frame->ExecuteCommand(WebString::FromUTF8("Unselect"));
5502   EXPECT_EQ("", SelectionAsString(frame));
5503   frame->SelectRange(start_rect.origin(), BottomRightMinusOne(end_rect));
5504   // On some devices, the above bottomRightMinusOne() causes the ending '.' not
5505   // selected.
5506   selection_string = SelectionAsString(frame);
5507   EXPECT_TRUE(selection_string == "Some offscreen test text for testing." ||
5508               selection_string == "Some offscreen test text for testing");
5509 }
5510 
TEST_F(WebFrameTest,SelectRangeDefaultHandleVisibility)5511 TEST_F(WebFrameTest, SelectRangeDefaultHandleVisibility) {
5512   RegisterMockedHttpURLLoad("select_range_basic.html");
5513 
5514   frame_test_helpers::WebViewHelper web_view_helper;
5515   InitializeTextSelectionWebView(base_url_ + "select_range_basic.html",
5516                                  &web_view_helper);
5517 
5518   WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
5519   frame->SelectRange(WebRange(0, 5), WebLocalFrame::kHideSelectionHandle,
5520                      SelectionMenuBehavior::kHide);
5521   EXPECT_FALSE(frame->SelectionRange().IsNull());
5522 
5523   EXPECT_FALSE(frame->GetFrame()->Selection().IsHandleVisible())
5524       << "By default selection handles should not be visible";
5525 }
5526 
TEST_F(WebFrameTest,SelectRangeHideHandle)5527 TEST_F(WebFrameTest, SelectRangeHideHandle) {
5528   RegisterMockedHttpURLLoad("select_range_basic.html");
5529 
5530   frame_test_helpers::WebViewHelper web_view_helper;
5531   InitializeTextSelectionWebView(base_url_ + "select_range_basic.html",
5532                                  &web_view_helper);
5533 
5534   WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
5535   frame->SelectRange(WebRange(0, 5), WebLocalFrame::kHideSelectionHandle,
5536                      SelectionMenuBehavior::kHide);
5537 
5538   EXPECT_FALSE(frame->GetFrame()->Selection().IsHandleVisible())
5539       << "Selection handle should not be visible with kHideSelectionHandle";
5540 }
5541 
TEST_F(WebFrameTest,SelectRangeShowHandle)5542 TEST_F(WebFrameTest, SelectRangeShowHandle) {
5543   RegisterMockedHttpURLLoad("select_range_basic.html");
5544 
5545   frame_test_helpers::WebViewHelper web_view_helper;
5546   InitializeTextSelectionWebView(base_url_ + "select_range_basic.html",
5547                                  &web_view_helper);
5548 
5549   WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
5550   frame->SelectRange(WebRange(0, 5), WebLocalFrame::kShowSelectionHandle,
5551                      SelectionMenuBehavior::kHide);
5552 
5553   EXPECT_TRUE(frame->GetFrame()->Selection().IsHandleVisible())
5554       << "Selection handle should be visible with kShowSelectionHandle";
5555 }
5556 
TEST_F(WebFrameTest,SelectRangePreserveHandleVisibility)5557 TEST_F(WebFrameTest, SelectRangePreserveHandleVisibility) {
5558   RegisterMockedHttpURLLoad("select_range_basic.html");
5559 
5560   frame_test_helpers::WebViewHelper web_view_helper;
5561   InitializeTextSelectionWebView(base_url_ + "select_range_basic.html",
5562                                  &web_view_helper);
5563 
5564   WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
5565   frame->SelectRange(WebRange(0, 5), WebLocalFrame::kHideSelectionHandle,
5566                      SelectionMenuBehavior::kHide);
5567   frame->SelectRange(WebRange(0, 6), WebLocalFrame::kPreserveHandleVisibility,
5568                      SelectionMenuBehavior::kHide);
5569 
5570   EXPECT_FALSE(frame->GetFrame()->Selection().IsHandleVisible())
5571       << "kPreserveHandleVisibility should keep handles invisible";
5572 
5573   frame->SelectRange(WebRange(0, 5), WebLocalFrame::kShowSelectionHandle,
5574                      SelectionMenuBehavior::kHide);
5575   frame->SelectRange(WebRange(0, 6), WebLocalFrame::kPreserveHandleVisibility,
5576                      SelectionMenuBehavior::kHide);
5577 
5578   EXPECT_TRUE(frame->GetFrame()->Selection().IsHandleVisible())
5579       << "kPreserveHandleVisibility should keep handles visible";
5580 }
5581 
TEST_F(WebFrameTest,SelectRangeInIframe)5582 TEST_F(WebFrameTest, SelectRangeInIframe) {
5583   WebFrame* frame;
5584   gfx::Rect start_rect;
5585   gfx::Rect end_rect;
5586 
5587   RegisterMockedHttpURLLoad("select_range_iframe.html");
5588   RegisterMockedHttpURLLoad("select_range_basic.html");
5589 
5590   frame_test_helpers::WebViewHelper web_view_helper;
5591   InitializeTextSelectionWebView(base_url_ + "select_range_iframe.html",
5592                                  &web_view_helper);
5593   frame = web_view_helper.GetWebView()->MainFrame();
5594   WebLocalFrame* subframe = frame->FirstChild()->ToWebLocalFrame();
5595   EXPECT_EQ("Some test text for testing.", SelectionAsString(subframe));
5596   web_view_helper.GetWebView()->MainFrameViewWidget()->CalculateSelectionBounds(
5597       start_rect, end_rect);
5598   subframe->ExecuteCommand(WebString::FromUTF8("Unselect"));
5599   EXPECT_EQ("", SelectionAsString(subframe));
5600   subframe->SelectRange(start_rect.origin(), BottomRightMinusOne(end_rect));
5601   // On some devices, the above bottomRightMinusOne() causes the ending '.' not
5602   // selected.
5603   std::string selection_string = SelectionAsString(subframe);
5604   EXPECT_TRUE(selection_string == "Some test text for testing." ||
5605               selection_string == "Some test text for testing");
5606 }
5607 
TEST_F(WebFrameTest,SelectRangeDivContentEditable)5608 TEST_F(WebFrameTest, SelectRangeDivContentEditable) {
5609   WebLocalFrame* frame;
5610   gfx::Rect start_rect;
5611   gfx::Rect end_rect;
5612 
5613   RegisterMockedHttpURLLoad("select_range_div_editable.html");
5614 
5615   // Select the middle of an editable element, then try to extend the selection
5616   // to the top of the document.  The selection range should be clipped to the
5617   // bounds of the editable element.
5618   frame_test_helpers::WebViewHelper web_view_helper;
5619   InitializeTextSelectionWebView(base_url_ + "select_range_div_editable.html",
5620                                  &web_view_helper);
5621   frame = web_view_helper.LocalMainFrame();
5622   EXPECT_EQ("This text is initially selected.", SelectionAsString(frame));
5623   web_view_helper.GetWebView()->MainFrameViewWidget()->CalculateSelectionBounds(
5624       start_rect, end_rect);
5625 
5626   frame->SelectRange(BottomRightMinusOne(end_rect), gfx::Point());
5627   EXPECT_EQ("16-char header. This text is initially selected.",
5628             SelectionAsString(frame));
5629 
5630   // As above, but extending the selection to the bottom of the document.
5631   InitializeTextSelectionWebView(base_url_ + "select_range_div_editable.html",
5632                                  &web_view_helper);
5633   frame = web_view_helper.LocalMainFrame();
5634 
5635   web_view_helper.GetWebView()->MainFrameViewWidget()->CalculateSelectionBounds(
5636       start_rect, end_rect);
5637   frame->SelectRange(start_rect.origin(), BottomRightMinusOne(end_rect));
5638   EXPECT_EQ("This text is initially selected.", SelectionAsString(frame));
5639   web_view_helper.GetWebView()->MainFrameViewWidget()->CalculateSelectionBounds(
5640       start_rect, end_rect);
5641 
5642   web_view_helper.GetWebView()->MainFrameViewWidget()->CalculateSelectionBounds(
5643       start_rect, end_rect);
5644   frame->SelectRange(start_rect.origin(), gfx::Point(640, 480));
5645   EXPECT_EQ("This text is initially selected. 16-char footer.",
5646             SelectionAsString(frame));
5647 }
5648 
5649 // positionForPoint returns the wrong values for contenteditable spans. See
5650 // http://crbug.com/238334.
TEST_F(WebFrameTest,DISABLED_SelectRangeSpanContentEditable)5651 TEST_F(WebFrameTest, DISABLED_SelectRangeSpanContentEditable) {
5652   WebLocalFrame* frame;
5653   gfx::Rect start_rect;
5654   gfx::Rect end_rect;
5655 
5656   RegisterMockedHttpURLLoad("select_range_span_editable.html");
5657 
5658   // Select the middle of an editable element, then try to extend the selection
5659   // to the top of the document.
5660   // The selection range should be clipped to the bounds of the editable
5661   // element.
5662   frame_test_helpers::WebViewHelper web_view_helper;
5663   InitializeTextSelectionWebView(base_url_ + "select_range_span_editable.html",
5664                                  &web_view_helper);
5665   frame = web_view_helper.LocalMainFrame();
5666   EXPECT_EQ("This text is initially selected.", SelectionAsString(frame));
5667   web_view_helper.GetWebView()->MainFrameViewWidget()->CalculateSelectionBounds(
5668       start_rect, end_rect);
5669 
5670   frame->SelectRange(BottomRightMinusOne(end_rect), gfx::Point());
5671   EXPECT_EQ("16-char header. This text is initially selected.",
5672             SelectionAsString(frame));
5673 
5674   // As above, but extending the selection to the bottom of the document.
5675   InitializeTextSelectionWebView(base_url_ + "select_range_span_editable.html",
5676                                  &web_view_helper);
5677   frame = web_view_helper.LocalMainFrame();
5678 
5679   web_view_helper.GetWebView()->MainFrameViewWidget()->CalculateSelectionBounds(
5680       start_rect, end_rect);
5681   frame->SelectRange(start_rect.origin(), BottomRightMinusOne(end_rect));
5682   EXPECT_EQ("This text is initially selected.", SelectionAsString(frame));
5683   web_view_helper.GetWebView()->MainFrameViewWidget()->CalculateSelectionBounds(
5684       start_rect, end_rect);
5685 
5686   EXPECT_EQ("This text is initially selected.", SelectionAsString(frame));
5687   web_view_helper.GetWebView()->MainFrameViewWidget()->CalculateSelectionBounds(
5688       start_rect, end_rect);
5689   frame->SelectRange(start_rect.origin(), gfx::Point(640, 480));
5690   EXPECT_EQ("This text is initially selected. 16-char footer.",
5691             SelectionAsString(frame));
5692 }
5693 
TEST_F(WebFrameTest,SelectRangeCanMoveSelectionStart)5694 TEST_F(WebFrameTest, SelectRangeCanMoveSelectionStart) {
5695   RegisterMockedHttpURLLoad("text_selection.html");
5696   frame_test_helpers::WebViewHelper web_view_helper;
5697   InitializeTextSelectionWebView(base_url_ + "text_selection.html",
5698                                  &web_view_helper);
5699   WebLocalFrame* frame = web_view_helper.LocalMainFrame();
5700 
5701   // Select second span. We can move the start to include the first span.
5702   frame->ExecuteScript(WebScriptSource("selectElement('header_2');"));
5703   EXPECT_EQ("Header 2.", SelectionAsString(frame));
5704   frame->SelectRange(BottomRightMinusOne(ElementBounds(frame, "header_2")),
5705                      ElementBounds(frame, "header_1").origin());
5706   EXPECT_EQ("Header 1. Header 2.", SelectionAsString(frame));
5707 
5708   // We can move the start and end together.
5709   frame->ExecuteScript(WebScriptSource("selectElement('header_1');"));
5710   EXPECT_EQ("Header 1.", SelectionAsString(frame));
5711   frame->SelectRange(BottomRightMinusOne(ElementBounds(frame, "header_1")),
5712                      BottomRightMinusOne(ElementBounds(frame, "header_1")));
5713   EXPECT_EQ("", SelectionAsString(frame));
5714   // Selection is a caret, not empty.
5715   EXPECT_FALSE(frame->SelectionRange().IsNull());
5716 
5717   // We can move the start across the end.
5718   frame->ExecuteScript(WebScriptSource("selectElement('header_1');"));
5719   EXPECT_EQ("Header 1.", SelectionAsString(frame));
5720   frame->SelectRange(BottomRightMinusOne(ElementBounds(frame, "header_1")),
5721                      BottomRightMinusOne(ElementBounds(frame, "header_2")));
5722   EXPECT_EQ(" Header 2.", SelectionAsString(frame));
5723 
5724   // Can't extend the selection part-way into an editable element.
5725   frame->ExecuteScript(WebScriptSource("selectElement('footer_2');"));
5726   EXPECT_EQ("Footer 2.", SelectionAsString(frame));
5727   frame->SelectRange(BottomRightMinusOne(ElementBounds(frame, "footer_2")),
5728                      ElementBounds(frame, "editable_2").origin());
5729   EXPECT_EQ(" [ Footer 1. Footer 2.", SelectionAsString(frame));
5730 
5731   // Can extend the selection completely across editable elements.
5732   frame->ExecuteScript(WebScriptSource("selectElement('footer_2');"));
5733   EXPECT_EQ("Footer 2.", SelectionAsString(frame));
5734   frame->SelectRange(BottomRightMinusOne(ElementBounds(frame, "footer_2")),
5735                      ElementBounds(frame, "header_2").origin());
5736   EXPECT_EQ("Header 2. ] [ Editable 1. Editable 2. ] [ Footer 1. Footer 2.",
5737             SelectionAsString(frame));
5738 
5739   // If the selection is editable text, we can't extend it into non-editable
5740   // text.
5741   frame->ExecuteScript(WebScriptSource("selectElement('editable_2');"));
5742   EXPECT_EQ("Editable 2.", SelectionAsString(frame));
5743   frame->SelectRange(BottomRightMinusOne(ElementBounds(frame, "editable_2")),
5744                      ElementBounds(frame, "header_2").origin());
5745   EXPECT_EQ("[ Editable 1. Editable 2.", SelectionAsString(frame));
5746 }
5747 
TEST_F(WebFrameTest,SelectRangeCanMoveSelectionEnd)5748 TEST_F(WebFrameTest, SelectRangeCanMoveSelectionEnd) {
5749   RegisterMockedHttpURLLoad("text_selection.html");
5750   frame_test_helpers::WebViewHelper web_view_helper;
5751   InitializeTextSelectionWebView(base_url_ + "text_selection.html",
5752                                  &web_view_helper);
5753   WebLocalFrame* frame = web_view_helper.LocalMainFrame();
5754 
5755   // Select first span. We can move the end to include the second span.
5756   frame->ExecuteScript(WebScriptSource("selectElement('header_1');"));
5757   EXPECT_EQ("Header 1.", SelectionAsString(frame));
5758   frame->SelectRange(ElementBounds(frame, "header_1").origin(),
5759                      BottomRightMinusOne(ElementBounds(frame, "header_2")));
5760   EXPECT_EQ("Header 1. Header 2.", SelectionAsString(frame));
5761 
5762   // We can move the start and end together.
5763   frame->ExecuteScript(WebScriptSource("selectElement('header_2');"));
5764   EXPECT_EQ("Header 2.", SelectionAsString(frame));
5765   frame->SelectRange(ElementBounds(frame, "header_2").origin(),
5766                      ElementBounds(frame, "header_2").origin());
5767   EXPECT_EQ("", SelectionAsString(frame));
5768   // Selection is a caret, not empty.
5769   EXPECT_FALSE(frame->SelectionRange().IsNull());
5770 
5771   // We can move the end across the start.
5772   frame->ExecuteScript(WebScriptSource("selectElement('header_2');"));
5773   EXPECT_EQ("Header 2.", SelectionAsString(frame));
5774   frame->SelectRange(ElementBounds(frame, "header_2").origin(),
5775                      ElementBounds(frame, "header_1").origin());
5776   EXPECT_EQ("Header 1. ", SelectionAsString(frame));
5777 
5778   // Can't extend the selection part-way into an editable element.
5779   frame->ExecuteScript(WebScriptSource("selectElement('header_1');"));
5780   EXPECT_EQ("Header 1.", SelectionAsString(frame));
5781   frame->SelectRange(ElementBounds(frame, "header_1").origin(),
5782                      BottomRightMinusOne(ElementBounds(frame, "editable_1")));
5783   EXPECT_EQ("Header 1. Header 2. ] ", SelectionAsString(frame));
5784 
5785   // Can extend the selection completely across editable elements.
5786   frame->ExecuteScript(WebScriptSource("selectElement('header_1');"));
5787   EXPECT_EQ("Header 1.", SelectionAsString(frame));
5788   frame->SelectRange(ElementBounds(frame, "header_1").origin(),
5789                      BottomRightMinusOne(ElementBounds(frame, "footer_1")));
5790   EXPECT_EQ("Header 1. Header 2. ] [ Editable 1. Editable 2. ] [ Footer 1.",
5791             SelectionAsString(frame));
5792 
5793   // If the selection is editable text, we can't extend it into non-editable
5794   // text.
5795   frame->ExecuteScript(WebScriptSource("selectElement('editable_1');"));
5796   EXPECT_EQ("Editable 1.", SelectionAsString(frame));
5797   frame->SelectRange(ElementBounds(frame, "editable_1").origin(),
5798                      BottomRightMinusOne(ElementBounds(frame, "footer_1")));
5799   EXPECT_EQ("Editable 1. Editable 2. ]", SelectionAsString(frame));
5800 }
5801 
TEST_F(WebFrameTest,MoveRangeSelectionExtent)5802 TEST_F(WebFrameTest, MoveRangeSelectionExtent) {
5803   WebLocalFrameImpl* frame;
5804   gfx::Rect start_rect;
5805   gfx::Rect end_rect;
5806 
5807   RegisterMockedHttpURLLoad("move_range_selection_extent.html");
5808 
5809   frame_test_helpers::WebViewHelper web_view_helper;
5810   InitializeTextSelectionWebView(base_url_ + "move_range_selection_extent.html",
5811                                  &web_view_helper);
5812   frame = web_view_helper.LocalMainFrame();
5813   EXPECT_EQ("This text is initially selected.", SelectionAsString(frame));
5814   web_view_helper.GetWebView()->MainFrameViewWidget()->CalculateSelectionBounds(
5815       start_rect, end_rect);
5816 
5817   frame->MoveRangeSelectionExtent(gfx::Point(640, 480));
5818   EXPECT_EQ("This text is initially selected. 16-char footer.",
5819             SelectionAsString(frame));
5820 
5821   frame->MoveRangeSelectionExtent(gfx::Point());
5822   EXPECT_EQ("16-char header. ", SelectionAsString(frame));
5823 
5824   // Reset with swapped base and extent.
5825   frame->SelectRange(end_rect.origin(), BottomRightMinusOne(start_rect));
5826   EXPECT_EQ("This text is initially selected.", SelectionAsString(frame));
5827 
5828   frame->MoveRangeSelectionExtent(gfx::Point(640, 480));
5829   EXPECT_EQ(" 16-char footer.", SelectionAsString(frame));
5830 
5831   frame->MoveRangeSelectionExtent(gfx::Point());
5832   EXPECT_EQ("16-char header. This text is initially selected.",
5833             SelectionAsString(frame));
5834 
5835   frame->ExecuteCommand(WebString::FromUTF8("Unselect"));
5836   EXPECT_EQ("", SelectionAsString(frame));
5837 }
5838 
TEST_F(WebFrameTest,MoveRangeSelectionExtentCannotCollapse)5839 TEST_F(WebFrameTest, MoveRangeSelectionExtentCannotCollapse) {
5840   WebLocalFrameImpl* frame;
5841   gfx::Rect start_rect;
5842   gfx::Rect end_rect;
5843 
5844   RegisterMockedHttpURLLoad("move_range_selection_extent.html");
5845 
5846   frame_test_helpers::WebViewHelper web_view_helper;
5847   InitializeTextSelectionWebView(base_url_ + "move_range_selection_extent.html",
5848                                  &web_view_helper);
5849   frame = web_view_helper.LocalMainFrame();
5850   EXPECT_EQ("This text is initially selected.", SelectionAsString(frame));
5851   web_view_helper.GetWebView()->MainFrameViewWidget()->CalculateSelectionBounds(
5852       start_rect, end_rect);
5853 
5854   frame->MoveRangeSelectionExtent(BottomRightMinusOne(start_rect));
5855   EXPECT_EQ("This text is initially selected.", SelectionAsString(frame));
5856 
5857   // Reset with swapped base and extent.
5858   frame->SelectRange(end_rect.origin(), BottomRightMinusOne(start_rect));
5859   EXPECT_EQ("This text is initially selected.", SelectionAsString(frame));
5860 
5861   frame->MoveRangeSelectionExtent(BottomRightMinusOne(end_rect));
5862   EXPECT_EQ("This text is initially selected.", SelectionAsString(frame));
5863 }
5864 
TEST_F(WebFrameTest,MoveRangeSelectionExtentScollsInputField)5865 TEST_F(WebFrameTest, MoveRangeSelectionExtentScollsInputField) {
5866   WebLocalFrameImpl* frame;
5867   gfx::Rect start_rect;
5868   gfx::Rect end_rect;
5869 
5870   RegisterMockedHttpURLLoad("move_range_selection_extent_input_field.html");
5871 
5872   frame_test_helpers::WebViewHelper web_view_helper;
5873   InitializeTextSelectionWebView(
5874       base_url_ + "move_range_selection_extent_input_field.html",
5875       &web_view_helper);
5876   frame = web_view_helper.LocalMainFrame();
5877   EXPECT_EQ("Length", SelectionAsString(frame));
5878   web_view_helper.GetWebView()->MainFrameViewWidget()->CalculateSelectionBounds(
5879       start_rect, end_rect);
5880 
5881   EXPECT_EQ(0, frame->GetFrame()
5882                    ->Selection()
5883                    .ComputeVisibleSelectionInDOMTree()
5884                    .RootEditableElement()
5885                    ->scrollLeft());
5886   frame->MoveRangeSelectionExtent(gfx::Point(end_rect.x() + 500, end_rect.y()));
5887   EXPECT_GE(frame->GetFrame()
5888                 ->Selection()
5889                 .ComputeVisibleSelectionInDOMTree()
5890                 .RootEditableElement()
5891                 ->scrollLeft(),
5892             1);
5893   EXPECT_EQ("Lengthy text goes here.", SelectionAsString(frame));
5894 }
5895 
TEST_F(WebFrameTest,SmartClipData)5896 TEST_F(WebFrameTest, SmartClipData) {
5897   static const char kExpectedClipText[] = "\nPrice 10,000,000won";
5898   static const char kExpectedClipHtml[] =
5899       "<div id=\"div4\" style=\"padding: 10px; margin: 10px; border: 2px solid "
5900       "skyblue; float: left; width: 190px; height: 30px; color: rgb(0, 0, 0); "
5901       "font-family: myahem; font-size: 8px; font-style: normal; "
5902       "font-variant-ligatures: normal; font-variant-caps: normal; font-weight: "
5903       "400; letter-spacing: normal; orphans: 2; text-align: start; "
5904       "text-indent: 0px; text-transform: none; white-space: normal; widows: 2; "
5905       "word-spacing: 0px; -webkit-text-stroke-width: 0px; "
5906       "text-decoration-thickness: initial; text-decoration-style: initial; "
5907       "text-decoration-color: initial;\">Air conditioner</div><div id=\"div5\" "
5908       "style=\"padding: 10px; margin: 10px; border: 2px solid skyblue; float: "
5909       "left; width: 190px; height: 30px; color: rgb(0, 0, 0); font-family: "
5910       "myahem; font-size: 8px; font-style: normal; font-variant-ligatures: "
5911       "normal; font-variant-caps: normal; font-weight: 400; letter-spacing: "
5912       "normal; orphans: 2; text-align: start; text-indent: 0px; "
5913       "text-transform: none; white-space: normal; widows: 2; word-spacing: "
5914       "0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: "
5915       "initial; text-decoration-style: initial; text-decoration-color: "
5916       "initial;\">Price 10,000,000won</div>";
5917   WebString clip_text;
5918   WebString clip_html;
5919   WebRect clip_rect;
5920   RegisterMockedHttpURLLoad("Ahem.ttf");
5921   RegisterMockedHttpURLLoad("smartclip.html");
5922   frame_test_helpers::WebViewHelper web_view_helper;
5923   web_view_helper.InitializeAndLoad(base_url_ + "smartclip.html");
5924   WebLocalFrame* frame = web_view_helper.LocalMainFrame();
5925   web_view_helper.Resize(gfx::Size(500, 500));
5926   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
5927   WebRect crop_rect(300, 125, 152, 50);
5928   frame->ExtractSmartClipData(crop_rect, clip_text, clip_html, clip_rect);
5929   EXPECT_EQ(kExpectedClipText, clip_text);
5930   EXPECT_EQ(kExpectedClipHtml, clip_html);
5931 }
5932 
TEST_F(WebFrameTest,SmartClipDataWithPinchZoom)5933 TEST_F(WebFrameTest, SmartClipDataWithPinchZoom) {
5934   static const char kExpectedClipText[] = "\nPrice 10,000,000won";
5935   static const char kExpectedClipHtml[] =
5936       "<div id=\"div4\" style=\"padding: 10px; margin: 10px; border: 2px solid "
5937       "skyblue; float: left; width: 190px; height: 30px; color: rgb(0, 0, 0); "
5938       "font-family: myahem; font-size: 8px; font-style: normal; "
5939       "font-variant-ligatures: normal; font-variant-caps: normal; font-weight: "
5940       "400; letter-spacing: normal; orphans: 2; text-align: start; "
5941       "text-indent: 0px; text-transform: none; white-space: normal; widows: 2; "
5942       "word-spacing: 0px; -webkit-text-stroke-width: 0px; "
5943       "text-decoration-thickness: initial; text-decoration-style: initial; "
5944       "text-decoration-color: initial;\">Air conditioner</div><div id=\"div5\" "
5945       "style=\"padding: 10px; margin: 10px; border: 2px solid skyblue; float: "
5946       "left; width: 190px; height: 30px; color: rgb(0, 0, 0); font-family: "
5947       "myahem; font-size: 8px; font-style: normal; font-variant-ligatures: "
5948       "normal; font-variant-caps: normal; font-weight: 400; letter-spacing: "
5949       "normal; orphans: 2; text-align: start; text-indent: 0px; "
5950       "text-transform: none; white-space: normal; widows: 2; word-spacing: "
5951       "0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: "
5952       "initial; text-decoration-style: initial; text-decoration-color: "
5953       "initial;\">Price 10,000,000won</div>";
5954   WebString clip_text;
5955   WebString clip_html;
5956   WebRect clip_rect;
5957   RegisterMockedHttpURLLoad("Ahem.ttf");
5958   RegisterMockedHttpURLLoad("smartclip.html");
5959   frame_test_helpers::WebViewHelper web_view_helper;
5960   web_view_helper.InitializeAndLoad(base_url_ + "smartclip.html");
5961   WebLocalFrame* frame = web_view_helper.LocalMainFrame();
5962   web_view_helper.Resize(gfx::Size(500, 500));
5963   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
5964   web_view_helper.GetWebView()->SetPageScaleFactor(1.5);
5965   web_view_helper.GetWebView()->SetVisualViewportOffset(gfx::PointF(167, 100));
5966   WebRect crop_rect(200, 38, 228, 75);
5967   frame->ExtractSmartClipData(crop_rect, clip_text, clip_html, clip_rect);
5968   EXPECT_EQ(kExpectedClipText, clip_text);
5969   EXPECT_EQ(kExpectedClipHtml, clip_html);
5970 }
5971 
TEST_F(WebFrameTest,SmartClipReturnsEmptyStringsWhenUserSelectIsNone)5972 TEST_F(WebFrameTest, SmartClipReturnsEmptyStringsWhenUserSelectIsNone) {
5973   WebString clip_text;
5974   WebString clip_html;
5975   WebRect clip_rect;
5976   RegisterMockedHttpURLLoad("Ahem.ttf");
5977   RegisterMockedHttpURLLoad("smartclip_user_select_none.html");
5978   frame_test_helpers::WebViewHelper web_view_helper;
5979   web_view_helper.InitializeAndLoad(base_url_ +
5980                                     "smartclip_user_select_none.html");
5981   WebLocalFrame* frame = web_view_helper.LocalMainFrame();
5982   web_view_helper.Resize(gfx::Size(500, 500));
5983   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
5984   WebRect crop_rect(0, 0, 100, 100);
5985   frame->ExtractSmartClipData(crop_rect, clip_text, clip_html, clip_rect);
5986   EXPECT_STREQ("", clip_text.Utf8().c_str());
5987   EXPECT_STREQ("", clip_html.Utf8().c_str());
5988 }
5989 
TEST_F(WebFrameTest,SmartClipDoesNotCrashPositionReversed)5990 TEST_F(WebFrameTest, SmartClipDoesNotCrashPositionReversed) {
5991   WebString clip_text;
5992   WebString clip_html;
5993   WebRect clip_rect;
5994   RegisterMockedHttpURLLoad("Ahem.ttf");
5995   RegisterMockedHttpURLLoad("smartclip_reversed_positions.html");
5996   frame_test_helpers::WebViewHelper web_view_helper;
5997   web_view_helper.InitializeAndLoad(base_url_ +
5998                                     "smartclip_reversed_positions.html");
5999   WebLocalFrame* frame = web_view_helper.LocalMainFrame();
6000   web_view_helper.Resize(gfx::Size(500, 500));
6001   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
6002   // Left upper corner of the rect will be end position in the DOM hierarchy.
6003   WebRect crop_rect(30, 110, 400, 250);
6004   // This should not still crash. See crbug.com/589082 for more details.
6005   frame->ExtractSmartClipData(crop_rect, clip_text, clip_html, clip_rect);
6006 }
6007 
ComputeOffset(LayoutObject * layout_object,int x,int y)6008 static int ComputeOffset(LayoutObject* layout_object, int x, int y) {
6009   return layout_object->PositionForPoint(PhysicalOffset(x, y))
6010       .GetPosition()
6011       .ComputeOffsetInContainerNode();
6012 }
6013 
6014 // positionForPoint returns the wrong values for contenteditable spans. See
6015 // http://crbug.com/238334.
TEST_F(WebFrameTest,DISABLED_PositionForPointTest)6016 TEST_F(WebFrameTest, DISABLED_PositionForPointTest) {
6017   RegisterMockedHttpURLLoad("select_range_span_editable.html");
6018   frame_test_helpers::WebViewHelper web_view_helper;
6019   InitializeTextSelectionWebView(base_url_ + "select_range_span_editable.html",
6020                                  &web_view_helper);
6021   WebLocalFrameImpl* main_frame = web_view_helper.LocalMainFrame();
6022   LayoutObject* layout_object = main_frame->GetFrame()
6023                                     ->Selection()
6024                                     .ComputeVisibleSelectionInDOMTree()
6025                                     .RootEditableElement()
6026                                     ->GetLayoutObject();
6027   EXPECT_EQ(0, ComputeOffset(layout_object, -1, -1));
6028   EXPECT_EQ(64, ComputeOffset(layout_object, 1000, 1000));
6029 
6030   RegisterMockedHttpURLLoad("select_range_div_editable.html");
6031   InitializeTextSelectionWebView(base_url_ + "select_range_div_editable.html",
6032                                  &web_view_helper);
6033   main_frame = web_view_helper.LocalMainFrame();
6034   layout_object = main_frame->GetFrame()
6035                       ->Selection()
6036                       .ComputeVisibleSelectionInDOMTree()
6037                       .RootEditableElement()
6038                       ->GetLayoutObject();
6039   EXPECT_EQ(0, ComputeOffset(layout_object, -1, -1));
6040   EXPECT_EQ(64, ComputeOffset(layout_object, 1000, 1000));
6041 }
6042 
6043 #if !defined(OS_MAC) && !defined(OS_LINUX) && !defined(OS_CHROMEOS)
TEST_F(WebFrameTest,SelectRangeStaysHorizontallyAlignedWhenMoved)6044 TEST_F(WebFrameTest, SelectRangeStaysHorizontallyAlignedWhenMoved) {
6045   RegisterMockedHttpURLLoad("move_caret.html");
6046 
6047   frame_test_helpers::WebViewHelper web_view_helper;
6048   InitializeTextSelectionWebView(base_url_ + "move_caret.html",
6049                                  &web_view_helper);
6050   WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
6051 
6052   gfx::Rect initial_start_rect;
6053   gfx::Rect initial_end_rect;
6054   gfx::Rect start_rect;
6055   gfx::Rect end_rect;
6056 
6057   frame->ExecuteScript(WebScriptSource("selectRange();"));
6058   web_view_helper.GetWebView()->MainFrameViewWidget()->CalculateSelectionBounds(
6059       initial_start_rect, initial_end_rect);
6060   gfx::Point moved_start(initial_start_rect.origin());
6061 
6062   moved_start.Offset(0, 40);
6063   frame->SelectRange(moved_start, BottomRightMinusOne(initial_end_rect));
6064   web_view_helper.GetWebView()->MainFrameViewWidget()->CalculateSelectionBounds(
6065       start_rect, end_rect);
6066   EXPECT_EQ(start_rect, initial_start_rect);
6067   EXPECT_EQ(end_rect, initial_end_rect);
6068 
6069   moved_start.Offset(0, -80);
6070   frame->SelectRange(moved_start, BottomRightMinusOne(initial_end_rect));
6071   web_view_helper.GetWebView()->MainFrameViewWidget()->CalculateSelectionBounds(
6072       start_rect, end_rect);
6073   EXPECT_EQ(start_rect, initial_start_rect);
6074   EXPECT_EQ(end_rect, initial_end_rect);
6075 
6076   gfx::Point moved_end(BottomRightMinusOne(initial_end_rect));
6077 
6078   moved_end.Offset(0, 40);
6079   frame->SelectRange(initial_start_rect.origin(), moved_end);
6080   web_view_helper.GetWebView()->MainFrameViewWidget()->CalculateSelectionBounds(
6081       start_rect, end_rect);
6082   EXPECT_EQ(start_rect, initial_start_rect);
6083   EXPECT_EQ(end_rect, initial_end_rect);
6084 
6085   moved_end.Offset(0, -80);
6086   frame->SelectRange(initial_start_rect.origin(), moved_end);
6087   web_view_helper.GetWebView()->MainFrameViewWidget()->CalculateSelectionBounds(
6088       start_rect, end_rect);
6089   EXPECT_EQ(start_rect, initial_start_rect);
6090   EXPECT_EQ(end_rect, initial_end_rect);
6091 }
6092 
TEST_F(WebFrameTest,MoveCaretStaysHorizontallyAlignedWhenMoved)6093 TEST_F(WebFrameTest, MoveCaretStaysHorizontallyAlignedWhenMoved) {
6094   WebLocalFrameImpl* frame;
6095   RegisterMockedHttpURLLoad("move_caret.html");
6096 
6097   frame_test_helpers::WebViewHelper web_view_helper;
6098   InitializeTextSelectionWebView(base_url_ + "move_caret.html",
6099                                  &web_view_helper);
6100   frame = (WebLocalFrameImpl*)web_view_helper.GetWebView()->MainFrame();
6101 
6102   gfx::Rect initial_start_rect;
6103   gfx::Rect initial_end_rect;
6104   gfx::Rect start_rect;
6105   gfx::Rect end_rect;
6106 
6107   frame->ExecuteScript(WebScriptSource("selectCaret();"));
6108   web_view_helper.GetWebView()->MainFrameViewWidget()->CalculateSelectionBounds(
6109       initial_start_rect, initial_end_rect);
6110   gfx::Point move_to(initial_start_rect.origin());
6111 
6112   move_to.Offset(0, 40);
6113   frame->MoveCaretSelection(move_to);
6114   web_view_helper.GetWebView()->MainFrameViewWidget()->CalculateSelectionBounds(
6115       start_rect, end_rect);
6116   EXPECT_EQ(start_rect, initial_start_rect);
6117   EXPECT_EQ(end_rect, initial_end_rect);
6118 
6119   move_to.Offset(0, -80);
6120   frame->MoveCaretSelection(move_to);
6121   web_view_helper.GetWebView()->MainFrameViewWidget()->CalculateSelectionBounds(
6122       start_rect, end_rect);
6123   EXPECT_EQ(start_rect, initial_start_rect);
6124   EXPECT_EQ(end_rect, initial_end_rect);
6125 }
6126 #endif
6127 
6128 class CompositedSelectionBoundsTest
6129     : public WebFrameTest,
6130       private ScopedCompositedSelectionUpdateForTest {
6131  protected:
CompositedSelectionBoundsTest()6132   CompositedSelectionBoundsTest()
6133       : ScopedCompositedSelectionUpdateForTest(true) {
6134     RegisterMockedHttpURLLoad("Ahem.ttf");
6135 
6136     web_view_helper_.Initialize(nullptr, nullptr, &web_widget_client_);
6137     web_view_helper_.GetWebView()->GetSettings()->SetDefaultFontSize(12);
6138     web_view_helper_.GetWebView()->SetDefaultPageScaleLimits(1, 1);
6139     web_view_helper_.Resize(gfx::Size(640, 480));
6140   }
6141 
RunTestWithNoSelection(const char * test_file)6142   void RunTestWithNoSelection(const char* test_file) {
6143     RegisterMockedHttpURLLoad(test_file);
6144     web_view_helper_.GetWebView()->MainFrameWidget()->SetFocus(true);
6145     frame_test_helpers::LoadFrame(
6146         web_view_helper_.GetWebView()->MainFrameImpl(), base_url_ + test_file);
6147     UpdateAllLifecyclePhases(web_view_helper_.GetWebView());
6148 
6149     cc::LayerTreeHost* layer_tree_host = web_widget_client_.layer_tree_host();
6150     const cc::LayerSelection& selection = layer_tree_host->selection();
6151 
6152     ASSERT_EQ(selection, cc::LayerSelection());
6153     ASSERT_EQ(selection.start, cc::LayerSelectionBound());
6154     ASSERT_EQ(selection.end, cc::LayerSelectionBound());
6155   }
6156 
RunTest(const char * test_file)6157   void RunTest(const char* test_file) {
6158     RegisterMockedHttpURLLoad(test_file);
6159     web_view_helper_.GetWebView()->MainFrameWidget()->SetFocus(true);
6160     frame_test_helpers::LoadFrame(
6161         web_view_helper_.GetWebView()->MainFrameImpl(), base_url_ + test_file);
6162     UpdateAllLifecyclePhases(web_view_helper_.GetWebView());
6163 
6164     v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6165     v8::Local<v8::Value> result =
6166         web_view_helper_.GetWebView()
6167             ->MainFrameImpl()
6168             ->ExecuteScriptAndReturnValue(WebScriptSource("expectedResult"));
6169     ASSERT_FALSE(result.IsEmpty() || (*result)->IsUndefined());
6170 
6171     ASSERT_TRUE((*result)->IsArray());
6172     v8::Array& expected_result = *v8::Array::Cast(*result);
6173     ASSERT_GE(expected_result.Length(), 10u);
6174 
6175     v8::Local<v8::Context> context =
6176         v8::Isolate::GetCurrent()->GetCurrentContext();
6177 
6178     const int start_edge_start_in_layer_x = expected_result.Get(context, 1)
6179                                                 .ToLocalChecked()
6180                                                 .As<v8::Int32>()
6181                                                 ->Value();
6182     const int start_edge_start_in_layer_y = expected_result.Get(context, 2)
6183                                                 .ToLocalChecked()
6184                                                 .As<v8::Int32>()
6185                                                 ->Value();
6186     const int start_edge_end_in_layer_x = expected_result.Get(context, 3)
6187                                               .ToLocalChecked()
6188                                               .As<v8::Int32>()
6189                                               ->Value();
6190     const int start_edge_end_in_layer_y = expected_result.Get(context, 4)
6191                                               .ToLocalChecked()
6192                                               .As<v8::Int32>()
6193                                               ->Value();
6194 
6195     const int end_edge_start_in_layer_x = expected_result.Get(context, 6)
6196                                               .ToLocalChecked()
6197                                               .As<v8::Int32>()
6198                                               ->Value();
6199     const int end_edge_start_in_layer_y = expected_result.Get(context, 7)
6200                                               .ToLocalChecked()
6201                                               .As<v8::Int32>()
6202                                               ->Value();
6203     const int end_edge_end_in_layer_x = expected_result.Get(context, 8)
6204                                             .ToLocalChecked()
6205                                             .As<v8::Int32>()
6206                                             ->Value();
6207     const int end_edge_end_in_layer_y = expected_result.Get(context, 9)
6208                                             .ToLocalChecked()
6209                                             .As<v8::Int32>()
6210                                             ->Value();
6211 
6212     FloatPoint hit_point;
6213 
6214     if (expected_result.Length() >= 17) {
6215       hit_point = FloatPoint(expected_result.Get(context, 15)
6216                                  .ToLocalChecked()
6217                                  .As<v8::Int32>()
6218                                  ->Value(),
6219                              expected_result.Get(context, 16)
6220                                  .ToLocalChecked()
6221                                  .As<v8::Int32>()
6222                                  ->Value());
6223     } else {
6224       hit_point =
6225           FloatPoint((start_edge_start_in_layer_x + start_edge_end_in_layer_x +
6226                       end_edge_start_in_layer_x + end_edge_end_in_layer_x) /
6227                          4,
6228                      (start_edge_start_in_layer_y + start_edge_end_in_layer_y +
6229                       end_edge_start_in_layer_y + end_edge_end_in_layer_y) /
6230                              4 +
6231                          3);
6232     }
6233 
6234     WebGestureEvent gesture_event(WebInputEvent::Type::kGestureTap,
6235                                   WebInputEvent::kNoModifiers,
6236                                   WebInputEvent::GetStaticTimeStampForTests(),
6237                                   WebGestureDevice::kTouchscreen);
6238     gesture_event.SetFrameScale(1);
6239     gesture_event.SetPositionInWidget(hit_point);
6240     gesture_event.SetPositionInScreen(hit_point);
6241 
6242     web_view_helper_.GetWebView()
6243         ->MainFrameImpl()
6244         ->GetFrame()
6245         ->GetEventHandler()
6246         .HandleGestureEvent(gesture_event);
6247 
6248     cc::LayerTreeHost* layer_tree_host = web_widget_client_.layer_tree_host();
6249     const cc::LayerSelection& selection = layer_tree_host->selection();
6250 
6251     ASSERT_NE(selection, cc::LayerSelection());
6252     ASSERT_NE(selection.start, cc::LayerSelectionBound());
6253     ASSERT_NE(selection.end, cc::LayerSelectionBound());
6254 
6255     blink::Node* layer_owner_node_for_start = V8Node::ToImplWithTypeCheck(
6256         v8::Isolate::GetCurrent(),
6257         expected_result.Get(context, 0).ToLocalChecked());
6258     ASSERT_TRUE(layer_owner_node_for_start);
6259     EXPECT_EQ(GetExpectedLayerForSelection(layer_owner_node_for_start)
6260                   ->CcLayer()
6261                   .id(),
6262               selection.start.layer_id);
6263 
6264     EXPECT_EQ(start_edge_start_in_layer_x, selection.start.edge_start.x());
6265     EXPECT_EQ(start_edge_start_in_layer_y, selection.start.edge_start.y());
6266     EXPECT_EQ(start_edge_end_in_layer_x, selection.start.edge_end.x());
6267 
6268     blink::Node* layer_owner_node_for_end = V8Node::ToImplWithTypeCheck(
6269         v8::Isolate::GetCurrent(),
6270         expected_result.Get(context, 5).ToLocalChecked());
6271 
6272     ASSERT_TRUE(layer_owner_node_for_end);
6273     EXPECT_EQ(
6274         GetExpectedLayerForSelection(layer_owner_node_for_end)->CcLayer().id(),
6275         selection.end.layer_id);
6276 
6277     EXPECT_EQ(end_edge_start_in_layer_x, selection.end.edge_start.x());
6278     EXPECT_EQ(end_edge_start_in_layer_y, selection.end.edge_start.y());
6279     EXPECT_EQ(end_edge_end_in_layer_x, selection.end.edge_end.x());
6280 
6281     // Platform differences can introduce small stylistic deviations in
6282     // y-axis positioning, the details of which aren't relevant to
6283     // selection behavior. However, such deviations from the expected value
6284     // should be consistent for the corresponding y coordinates.
6285     int y_bottom_epsilon = 0;
6286     if (expected_result.Length() == 13) {
6287       y_bottom_epsilon = expected_result.Get(context, 12)
6288                              .ToLocalChecked()
6289                              .As<v8::Int32>()
6290                              ->Value();
6291     }
6292 
6293     int y_bottom_deviation =
6294         start_edge_end_in_layer_y - selection.start.edge_end.y();
6295     EXPECT_GE(y_bottom_epsilon, std::abs(y_bottom_deviation));
6296     EXPECT_EQ(y_bottom_deviation,
6297               end_edge_end_in_layer_y - selection.end.edge_end.y());
6298 
6299     if (expected_result.Length() >= 15) {
6300       bool start_hidden = expected_result.Get(context, 13)
6301                               .ToLocalChecked()
6302                               .As<v8::Boolean>()
6303                               ->Value();
6304       bool end_hidden = expected_result.Get(context, 14)
6305                             .ToLocalChecked()
6306                             .As<v8::Boolean>()
6307                             ->Value();
6308 
6309       EXPECT_EQ(start_hidden, selection.start.hidden);
6310       EXPECT_EQ(end_hidden, selection.end.hidden);
6311     }
6312   }
6313 
RunTestWithMultipleFiles(const char * test_file,std::initializer_list<const char * > auxiliary_files)6314   void RunTestWithMultipleFiles(
6315       const char* test_file,
6316       std::initializer_list<const char*> auxiliary_files) {
6317     for (const char* auxiliary_file : auxiliary_files) {
6318       RegisterMockedHttpURLLoad(auxiliary_file);
6319     }
6320 
6321     RunTest(test_file);
6322   }
6323 
GetExpectedLayerForSelection(blink::Node * node) const6324   GraphicsLayer* GetExpectedLayerForSelection(blink::Node* node) const {
6325     CompositedLayerMapping* clm = node->GetLayoutObject()
6326                                       ->EnclosingLayer()
6327                                       ->EnclosingLayerForPaintInvalidation()
6328                                       ->GetCompositedLayerMapping();
6329 
6330     // If the Node is a scroller, the selection will be relative to its
6331     // scrolling contents layer.
6332     return clm->ScrollingContentsLayer() ? clm->ScrollingContentsLayer()
6333                                          : clm->MainGraphicsLayer();
6334   }
6335 
6336   frame_test_helpers::TestWebWidgetClient web_widget_client_;
6337   frame_test_helpers::WebViewHelper web_view_helper_;
6338 };
6339 
TEST_F(CompositedSelectionBoundsTest,None)6340 TEST_F(CompositedSelectionBoundsTest, None) {
6341   RunTestWithNoSelection("composited_selection_bounds_none.html");
6342 }
TEST_F(CompositedSelectionBoundsTest,NoneReadonlyCaret)6343 TEST_F(CompositedSelectionBoundsTest, NoneReadonlyCaret) {
6344   RunTestWithNoSelection(
6345       "composited_selection_bounds_none_readonly_caret.html");
6346 }
TEST_F(CompositedSelectionBoundsTest,DetachedFrame)6347 TEST_F(CompositedSelectionBoundsTest, DetachedFrame) {
6348   RunTestWithNoSelection("composited_selection_bounds_detached_frame.html");
6349 }
6350 
TEST_F(CompositedSelectionBoundsTest,Basic)6351 TEST_F(CompositedSelectionBoundsTest, Basic) {
6352   RunTest("composited_selection_bounds_basic.html");
6353 }
TEST_F(CompositedSelectionBoundsTest,Transformed)6354 TEST_F(CompositedSelectionBoundsTest, Transformed) {
6355   RunTest("composited_selection_bounds_transformed.html");
6356 }
TEST_F(CompositedSelectionBoundsTest,VerticalRightToLeft)6357 TEST_F(CompositedSelectionBoundsTest, VerticalRightToLeft) {
6358   RunTest("composited_selection_bounds_vertical_rl.html");
6359 }
TEST_F(CompositedSelectionBoundsTest,VerticalLeftToRight)6360 TEST_F(CompositedSelectionBoundsTest, VerticalLeftToRight) {
6361   RunTest("composited_selection_bounds_vertical_lr.html");
6362 }
TEST_F(CompositedSelectionBoundsTest,SplitLayer)6363 TEST_F(CompositedSelectionBoundsTest, SplitLayer) {
6364   RunTest("composited_selection_bounds_split_layer.html");
6365 }
TEST_F(CompositedSelectionBoundsTest,Iframe)6366 TEST_F(CompositedSelectionBoundsTest, Iframe) {
6367   RunTestWithMultipleFiles("composited_selection_bounds_iframe.html",
6368                            {"composited_selection_bounds_basic.html"});
6369 }
TEST_F(CompositedSelectionBoundsTest,Editable)6370 TEST_F(CompositedSelectionBoundsTest, Editable) {
6371   RunTest("composited_selection_bounds_editable.html");
6372 }
TEST_F(CompositedSelectionBoundsTest,EditableDiv)6373 TEST_F(CompositedSelectionBoundsTest, EditableDiv) {
6374   RunTest("composited_selection_bounds_editable_div.html");
6375 }
6376 #if defined(OS_LINUX) || defined(OS_CHROMEOS)
6377 #if !defined(OS_ANDROID)
TEST_F(CompositedSelectionBoundsTest,Input)6378 TEST_F(CompositedSelectionBoundsTest, Input) {
6379   RunTest("composited_selection_bounds_input.html");
6380 }
TEST_F(CompositedSelectionBoundsTest,InputScrolled)6381 TEST_F(CompositedSelectionBoundsTest, InputScrolled) {
6382   RunTest("composited_selection_bounds_input_scrolled.html");
6383 }
6384 #endif
6385 #endif
6386 
6387 class TestWillInsertBodyWebFrameClient
6388     : public frame_test_helpers::TestWebFrameClient {
6389  public:
TestWillInsertBodyWebFrameClient()6390   TestWillInsertBodyWebFrameClient() : did_load_(false) {}
6391   ~TestWillInsertBodyWebFrameClient() override = default;
6392 
6393   // frame_test_helpers::TestWebFrameClient:
DidCommitNavigation(const WebHistoryItem &,WebHistoryCommitType,bool)6394   void DidCommitNavigation(const WebHistoryItem&,
6395                            WebHistoryCommitType,
6396                            bool) override {
6397     did_load_ = true;
6398   }
6399 
6400   bool did_load_;
6401 };
6402 
TEST_F(WebFrameTest,HTMLDocument)6403 TEST_F(WebFrameTest, HTMLDocument) {
6404   RegisterMockedHttpURLLoad("clipped-body.html");
6405 
6406   TestWillInsertBodyWebFrameClient web_frame_client;
6407   frame_test_helpers::WebViewHelper web_view_helper;
6408   web_view_helper.InitializeAndLoad(base_url_ + "clipped-body.html",
6409                                     &web_frame_client);
6410 
6411   EXPECT_TRUE(web_frame_client.did_load_);
6412 }
6413 
TEST_F(WebFrameTest,EmptyDocument)6414 TEST_F(WebFrameTest, EmptyDocument) {
6415   RegisterMockedHttpURLLoad("frameserializer/svg/green_rectangle.svg");
6416 
6417   TestWillInsertBodyWebFrameClient web_frame_client;
6418   frame_test_helpers::WebViewHelper web_view_helper;
6419   web_view_helper.Initialize(&web_frame_client);
6420 
6421   EXPECT_FALSE(web_frame_client.did_load_);
6422 }
6423 
TEST_F(WebFrameTest,MoveCaretSelectionTowardsWindowPointWithNoSelection)6424 TEST_F(WebFrameTest, MoveCaretSelectionTowardsWindowPointWithNoSelection) {
6425   frame_test_helpers::WebViewHelper web_view_helper;
6426   web_view_helper.InitializeAndLoad("about:blank");
6427   WebFrame* frame = web_view_helper.GetWebView()->MainFrame();
6428 
6429   // This test passes if this doesn't crash.
6430   frame->ToWebLocalFrame()->MoveCaretSelection(gfx::Point());
6431 }
6432 
6433 class TextCheckClient : public WebTextCheckClient {
6434  public:
TextCheckClient()6435   TextCheckClient() : number_of_times_checked_(0) {}
6436   ~TextCheckClient() override = default;
6437 
6438   // WebTextCheckClient:
IsSpellCheckingEnabled() const6439   bool IsSpellCheckingEnabled() const override { return true; }
RequestCheckingOfText(const WebString &,std::unique_ptr<WebTextCheckingCompletion> completion)6440   void RequestCheckingOfText(
6441       const WebString&,
6442       std::unique_ptr<WebTextCheckingCompletion> completion) override {
6443     ++number_of_times_checked_;
6444     Vector<WebTextCheckingResult> results;
6445     const int kMisspellingStartOffset = 1;
6446     const int kMisspellingLength = 8;
6447     results.push_back(WebTextCheckingResult(
6448         kWebTextDecorationTypeSpelling, kMisspellingStartOffset,
6449         kMisspellingLength, WebVector<WebString>()));
6450     completion->DidFinishCheckingText(results);
6451   }
6452 
NumberOfTimesChecked() const6453   int NumberOfTimesChecked() const { return number_of_times_checked_; }
6454 
6455  private:
6456   int number_of_times_checked_;
6457 };
6458 
TEST_F(WebFrameTest,ReplaceMisspelledRange)6459 TEST_F(WebFrameTest, ReplaceMisspelledRange) {
6460   RegisterMockedHttpURLLoad("spell.html");
6461   frame_test_helpers::WebViewHelper web_view_helper;
6462   InitializeTextSelectionWebView(base_url_ + "spell.html", &web_view_helper);
6463 
6464   WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
6465   TextCheckClient textcheck;
6466   frame->SetTextCheckClient(&textcheck);
6467 
6468   Document* document = frame->GetFrame()->GetDocument();
6469   Element* element = document->getElementById("data");
6470 
6471   web_view_helper.GetWebView()->GetSettings()->SetEditingBehavior(
6472       mojom::EditingBehavior::kEditingWindowsBehavior);
6473 
6474   element->focus();
6475   NonThrowableExceptionState exception_state;
6476   document->execCommand("InsertText", false, "_wellcome_.", exception_state);
6477   EXPECT_FALSE(exception_state.HadException());
6478 
6479   document->GetFrame()
6480       ->GetSpellChecker()
6481       .GetIdleSpellCheckController()
6482       .ForceInvocationForTesting();
6483 
6484   const int kAllTextBeginOffset = 0;
6485   const int kAllTextLength = 11;
6486   frame->SelectRange(WebRange(kAllTextBeginOffset, kAllTextLength),
6487                      WebLocalFrame::kHideSelectionHandle,
6488                      SelectionMenuBehavior::kHide);
6489   EphemeralRange selection_range = frame->GetFrame()
6490                                        ->Selection()
6491                                        .ComputeVisibleSelectionInDOMTree()
6492                                        .ToNormalizedEphemeralRange();
6493 
6494   EXPECT_EQ(1, textcheck.NumberOfTimesChecked());
6495   EXPECT_EQ(1, NumMarkersInRange(document, selection_range,
6496                                  DocumentMarker::MarkerTypes::Spelling()));
6497 
6498   frame->ReplaceMisspelledRange("welcome");
6499   EXPECT_EQ("_welcome_.", WebFrameContentDumper::DumpWebViewAsText(
6500                               web_view_helper.GetWebView(),
6501                               std::numeric_limits<size_t>::max())
6502                               .Utf8());
6503 }
6504 
TEST_F(WebFrameTest,RemoveSpellingMarkers)6505 TEST_F(WebFrameTest, RemoveSpellingMarkers) {
6506   RegisterMockedHttpURLLoad("spell.html");
6507   frame_test_helpers::WebViewHelper web_view_helper;
6508   InitializeTextSelectionWebView(base_url_ + "spell.html", &web_view_helper);
6509 
6510   WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
6511   TextCheckClient textcheck;
6512   frame->SetTextCheckClient(&textcheck);
6513 
6514   Document* document = frame->GetFrame()->GetDocument();
6515   Element* element = document->getElementById("data");
6516 
6517   web_view_helper.GetWebView()->GetSettings()->SetEditingBehavior(
6518       mojom::EditingBehavior::kEditingWindowsBehavior);
6519 
6520   element->focus();
6521   NonThrowableExceptionState exception_state;
6522   document->execCommand("InsertText", false, "_wellcome_.", exception_state);
6523   EXPECT_FALSE(exception_state.HadException());
6524 
6525   document->GetFrame()
6526       ->GetSpellChecker()
6527       .GetIdleSpellCheckController()
6528       .ForceInvocationForTesting();
6529 
6530   frame->RemoveSpellingMarkers();
6531 
6532   const int kAllTextBeginOffset = 0;
6533   const int kAllTextLength = 11;
6534   frame->SelectRange(WebRange(kAllTextBeginOffset, kAllTextLength),
6535                      WebLocalFrame::kHideSelectionHandle,
6536                      SelectionMenuBehavior::kHide);
6537   EphemeralRange selection_range = frame->GetFrame()
6538                                        ->Selection()
6539                                        .ComputeVisibleSelectionInDOMTree()
6540                                        .ToNormalizedEphemeralRange();
6541 
6542   EXPECT_EQ(0, NumMarkersInRange(document, selection_range,
6543                                  DocumentMarker::MarkerTypes::Spelling()));
6544 }
6545 
GetSpellingMarkerOffsets(WebVector<unsigned> * offsets,const Document & document)6546 static void GetSpellingMarkerOffsets(WebVector<unsigned>* offsets,
6547                                      const Document& document) {
6548   Vector<unsigned> result;
6549   const DocumentMarkerVector& document_markers = document.Markers().Markers();
6550   for (size_t i = 0; i < document_markers.size(); ++i)
6551     result.push_back(document_markers[i]->StartOffset());
6552   offsets->Assign(result);
6553 }
6554 
TEST_F(WebFrameTest,RemoveSpellingMarkersUnderWords)6555 TEST_F(WebFrameTest, RemoveSpellingMarkersUnderWords) {
6556   RegisterMockedHttpURLLoad("spell.html");
6557   frame_test_helpers::WebViewHelper web_view_helper;
6558   InitializeTextSelectionWebView(base_url_ + "spell.html", &web_view_helper);
6559 
6560   WebLocalFrameImpl* web_frame = web_view_helper.LocalMainFrame();
6561   TextCheckClient textcheck;
6562   web_frame->SetTextCheckClient(&textcheck);
6563 
6564   LocalFrame* frame = web_frame->GetFrame();
6565   Document* document = frame->GetDocument();
6566   Element* element = document->getElementById("data");
6567 
6568   web_view_helper.GetWebView()->GetSettings()->SetEditingBehavior(
6569       mojom::EditingBehavior::kEditingWindowsBehavior);
6570 
6571   element->focus();
6572   NonThrowableExceptionState exception_state;
6573   document->execCommand("InsertText", false, " wellcome ", exception_state);
6574   EXPECT_FALSE(exception_state.HadException());
6575 
6576   frame->GetSpellChecker()
6577       .GetIdleSpellCheckController()
6578       .ForceInvocationForTesting();
6579 
6580   WebVector<unsigned> offsets1;
6581   GetSpellingMarkerOffsets(&offsets1, *frame->GetDocument());
6582   EXPECT_EQ(1U, offsets1.size());
6583 
6584   Vector<String> words;
6585   words.push_back("wellcome");
6586   frame->RemoveSpellingMarkersUnderWords(words);
6587 
6588   WebVector<unsigned> offsets2;
6589   GetSpellingMarkerOffsets(&offsets2, *frame->GetDocument());
6590   EXPECT_EQ(0U, offsets2.size());
6591 }
6592 
6593 class StubbornTextCheckClient : public WebTextCheckClient {
6594  public:
StubbornTextCheckClient()6595   StubbornTextCheckClient() : completion_(nullptr) {}
6596   ~StubbornTextCheckClient() override = default;
6597 
6598   // WebTextCheckClient:
IsSpellCheckingEnabled() const6599   bool IsSpellCheckingEnabled() const override { return true; }
RequestCheckingOfText(const WebString &,std::unique_ptr<WebTextCheckingCompletion> completion)6600   void RequestCheckingOfText(
6601       const WebString&,
6602       std::unique_ptr<WebTextCheckingCompletion> completion) override {
6603     completion_ = std::move(completion);
6604   }
6605 
KickNoResults()6606   void KickNoResults() { Kick(-1, -1, kWebTextDecorationTypeSpelling); }
6607 
Kick()6608   void Kick() { Kick(1, 8, kWebTextDecorationTypeSpelling); }
6609 
KickGrammar()6610   void KickGrammar() { Kick(1, 8, kWebTextDecorationTypeGrammar); }
6611 
6612  private:
Kick(int misspelling_start_offset,int misspelling_length,WebTextDecorationType type)6613   void Kick(int misspelling_start_offset,
6614             int misspelling_length,
6615             WebTextDecorationType type) {
6616     if (!completion_)
6617       return;
6618     Vector<WebTextCheckingResult> results;
6619     if (misspelling_start_offset >= 0 && misspelling_length > 0) {
6620       results.push_back(WebTextCheckingResult(type, misspelling_start_offset,
6621                                               misspelling_length));
6622     }
6623     completion_->DidFinishCheckingText(results);
6624     completion_.reset();
6625   }
6626 
6627   std::unique_ptr<WebTextCheckingCompletion> completion_;
6628 };
6629 
TEST_F(WebFrameTest,SlowSpellcheckMarkerPosition)6630 TEST_F(WebFrameTest, SlowSpellcheckMarkerPosition) {
6631   RegisterMockedHttpURLLoad("spell.html");
6632   frame_test_helpers::WebViewHelper web_view_helper;
6633   InitializeTextSelectionWebView(base_url_ + "spell.html", &web_view_helper);
6634 
6635   WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
6636   StubbornTextCheckClient textcheck;
6637   frame->SetTextCheckClient(&textcheck);
6638 
6639   Document* document = frame->GetFrame()->GetDocument();
6640   Element* element = document->getElementById("data");
6641 
6642   web_view_helper.GetWebView()->GetSettings()->SetEditingBehavior(
6643       mojom::EditingBehavior::kEditingWindowsBehavior);
6644 
6645   element->focus();
6646   NonThrowableExceptionState exception_state;
6647   document->execCommand("InsertText", false, "wellcome ", exception_state);
6648   EXPECT_FALSE(exception_state.HadException());
6649   document->execCommand("InsertText", false, "he", exception_state);
6650   EXPECT_FALSE(exception_state.HadException());
6651 
6652   document->GetFrame()
6653       ->GetSpellChecker()
6654       .GetIdleSpellCheckController()
6655       .ForceInvocationForTesting();
6656 
6657   textcheck.Kick();
6658 
6659   WebVector<unsigned> offsets;
6660   GetSpellingMarkerOffsets(&offsets, *frame->GetFrame()->GetDocument());
6661   EXPECT_EQ(0U, offsets.size());
6662 }
6663 
TEST_F(WebFrameTest,SpellcheckResultErasesMarkers)6664 TEST_F(WebFrameTest, SpellcheckResultErasesMarkers) {
6665   RegisterMockedHttpURLLoad("spell.html");
6666   frame_test_helpers::WebViewHelper web_view_helper;
6667   InitializeTextSelectionWebView(base_url_ + "spell.html", &web_view_helper);
6668 
6669   WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
6670   StubbornTextCheckClient textcheck;
6671   frame->SetTextCheckClient(&textcheck);
6672 
6673   Document* document = frame->GetFrame()->GetDocument();
6674   Element* element = document->getElementById("data");
6675 
6676   web_view_helper.GetWebView()->GetSettings()->SetEditingBehavior(
6677       mojom::EditingBehavior::kEditingWindowsBehavior);
6678 
6679   element->focus();
6680   NonThrowableExceptionState exception_state;
6681   document->execCommand("InsertText", false, "welcome ", exception_state);
6682 
6683   document->GetFrame()
6684       ->GetSpellChecker()
6685       .GetIdleSpellCheckController()
6686       .ForceInvocationForTesting();
6687 
6688   document->UpdateStyleAndLayout(DocumentUpdateReason::kTest);
6689 
6690   EXPECT_FALSE(exception_state.HadException());
6691   auto range = EphemeralRange::RangeOfContents(*element);
6692   document->Markers().AddSpellingMarker(range);
6693   document->Markers().AddGrammarMarker(range);
6694   EXPECT_EQ(2U, document->Markers().Markers().size());
6695 
6696   textcheck.KickNoResults();
6697   EXPECT_EQ(0U, document->Markers().Markers().size());
6698 }
6699 
TEST_F(WebFrameTest,SpellcheckResultsSavedInDocument)6700 TEST_F(WebFrameTest, SpellcheckResultsSavedInDocument) {
6701   RegisterMockedHttpURLLoad("spell.html");
6702   frame_test_helpers::WebViewHelper web_view_helper;
6703   InitializeTextSelectionWebView(base_url_ + "spell.html", &web_view_helper);
6704 
6705   WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
6706   StubbornTextCheckClient textcheck;
6707   frame->SetTextCheckClient(&textcheck);
6708 
6709   Document* document = frame->GetFrame()->GetDocument();
6710   Element* element = document->getElementById("data");
6711 
6712   web_view_helper.GetWebView()->GetSettings()->SetEditingBehavior(
6713       mojom::EditingBehavior::kEditingWindowsBehavior);
6714 
6715   element->focus();
6716   NonThrowableExceptionState exception_state;
6717   document->execCommand("InsertText", false, "wellcome ", exception_state);
6718   EXPECT_FALSE(exception_state.HadException());
6719 
6720   document->GetFrame()
6721       ->GetSpellChecker()
6722       .GetIdleSpellCheckController()
6723       .ForceInvocationForTesting();
6724 
6725   textcheck.Kick();
6726   ASSERT_EQ(1U, document->Markers().Markers().size());
6727   ASSERT_NE(static_cast<DocumentMarker*>(nullptr),
6728             document->Markers().Markers()[0]);
6729   EXPECT_EQ(DocumentMarker::kSpelling,
6730             document->Markers().Markers()[0]->GetType());
6731 
6732   document->execCommand("InsertText", false, "wellcome ", exception_state);
6733   EXPECT_FALSE(exception_state.HadException());
6734 
6735   document->GetFrame()
6736       ->GetSpellChecker()
6737       .GetIdleSpellCheckController()
6738       .ForceInvocationForTesting();
6739 
6740   textcheck.KickGrammar();
6741   ASSERT_EQ(1U, document->Markers().Markers().size());
6742   ASSERT_NE(static_cast<DocumentMarker*>(nullptr),
6743             document->Markers().Markers()[0]);
6744   EXPECT_EQ(DocumentMarker::kGrammar,
6745             document->Markers().Markers()[0]->GetType());
6746 }
6747 
6748 class TestAccessInitialDocumentLocalFrameHost : public FakeLocalFrameHost {
6749  public:
6750   TestAccessInitialDocumentLocalFrameHost() = default;
6751   ~TestAccessInitialDocumentLocalFrameHost() override = default;
6752 
6753   // FakeLocalFrameHost:
DidAccessInitialDocument()6754   void DidAccessInitialDocument() override { ++did_access_initial_document_; }
6755 
6756   // !!!!!!!!!!!!!!!!!! IMPORTANT !!!!!!!!!!!!!!!!!!
6757   // If the actual counts in the tests below increase, this could be an
6758   // indicator of a bug that causes DidAccessInitialDocument() to always be
6759   // invoked, regardless of whether or not the initial document is accessed.
6760   // Please do not simply increment the expected counts in the below tests
6761   // without understanding what's causing the increased count.
6762   int did_access_initial_document_ = 0;
6763 };
6764 
TEST_F(WebFrameTest,DidAccessInitialDocumentBody)6765 TEST_F(WebFrameTest, DidAccessInitialDocumentBody) {
6766   TestAccessInitialDocumentLocalFrameHost frame_host;
6767   frame_test_helpers::TestWebFrameClient web_frame_client;
6768   frame_host.Init(web_frame_client.GetRemoteNavigationAssociatedInterfaces());
6769   frame_test_helpers::WebViewHelper web_view_helper;
6770   web_view_helper.Initialize(&web_frame_client);
6771   RunPendingTasks();
6772   EXPECT_EQ(0, frame_host.did_access_initial_document_);
6773 
6774   // Create another window that will try to access it.
6775   frame_test_helpers::WebViewHelper new_web_view_helper;
6776   WebViewImpl* new_view = new_web_view_helper.InitializeWithOpener(
6777       web_view_helper.GetWebView()->MainFrame());
6778   RunPendingTasks();
6779   EXPECT_EQ(0, frame_host.did_access_initial_document_);
6780 
6781   // Access the initial document by modifying the body.
6782   new_view->MainFrameImpl()->ExecuteScript(
6783       WebScriptSource("window.opener.document.body.innerHTML += 'Modified';"));
6784   RunPendingTasks();
6785   EXPECT_EQ(1, frame_host.did_access_initial_document_);
6786 
6787   web_view_helper.Reset();
6788 }
6789 
TEST_F(WebFrameTest,DidAccessInitialDocumentOpen)6790 TEST_F(WebFrameTest, DidAccessInitialDocumentOpen) {
6791   TestAccessInitialDocumentLocalFrameHost frame_host;
6792   frame_test_helpers::TestWebFrameClient web_frame_client;
6793   frame_host.Init(web_frame_client.GetRemoteNavigationAssociatedInterfaces());
6794   frame_test_helpers::WebViewHelper web_view_helper;
6795   web_view_helper.Initialize(&web_frame_client);
6796   RunPendingTasks();
6797   EXPECT_EQ(0, frame_host.did_access_initial_document_);
6798 
6799   // Create another window that will try to access it.
6800   frame_test_helpers::WebViewHelper new_web_view_helper;
6801   WebViewImpl* new_view = new_web_view_helper.InitializeWithOpener(
6802       web_view_helper.GetWebView()->MainFrame());
6803   RunPendingTasks();
6804   EXPECT_EQ(0, frame_host.did_access_initial_document_);
6805 
6806   // Access the initial document by calling document.open(), which allows
6807   // arbitrary modification of the initial document.
6808   new_view->MainFrameImpl()->ExecuteScript(
6809       WebScriptSource("window.opener.document.open();"));
6810   RunPendingTasks();
6811   EXPECT_EQ(1, frame_host.did_access_initial_document_);
6812 
6813   web_view_helper.Reset();
6814 }
6815 
TEST_F(WebFrameTest,DidAccessInitialDocumentNavigator)6816 TEST_F(WebFrameTest, DidAccessInitialDocumentNavigator) {
6817   TestAccessInitialDocumentLocalFrameHost frame_host;
6818   frame_test_helpers::TestWebFrameClient web_frame_client;
6819   frame_host.Init(web_frame_client.GetRemoteNavigationAssociatedInterfaces());
6820   frame_test_helpers::WebViewHelper web_view_helper;
6821   web_view_helper.Initialize(&web_frame_client);
6822   RunPendingTasks();
6823   EXPECT_EQ(0, frame_host.did_access_initial_document_);
6824 
6825   // Create another window that will try to access it.
6826   frame_test_helpers::WebViewHelper new_web_view_helper;
6827   WebViewImpl* new_view = new_web_view_helper.InitializeWithOpener(
6828       web_view_helper.GetWebView()->MainFrame());
6829   RunPendingTasks();
6830   EXPECT_EQ(0, frame_host.did_access_initial_document_);
6831 
6832   // Access the initial document to get to the navigator object.
6833   new_view->MainFrameImpl()->ExecuteScript(
6834       WebScriptSource("console.log(window.opener.navigator);"));
6835   RunPendingTasks();
6836   EXPECT_EQ(1, frame_host.did_access_initial_document_);
6837 
6838   web_view_helper.Reset();
6839 }
6840 
TEST_F(WebFrameTest,DidAccessInitialDocumentViaJavascriptUrl)6841 TEST_F(WebFrameTest, DidAccessInitialDocumentViaJavascriptUrl) {
6842   TestAccessInitialDocumentLocalFrameHost frame_host;
6843   frame_test_helpers::TestWebFrameClient web_frame_client;
6844   frame_host.Init(web_frame_client.GetRemoteNavigationAssociatedInterfaces());
6845   frame_test_helpers::WebViewHelper web_view_helper;
6846   web_view_helper.Initialize(&web_frame_client);
6847   RunPendingTasks();
6848   EXPECT_EQ(0, frame_host.did_access_initial_document_);
6849 
6850   // Access the initial document from a javascript: URL.
6851   frame_test_helpers::LoadFrame(web_view_helper.GetWebView()->MainFrameImpl(),
6852                                 "javascript:document.body.appendChild(document."
6853                                 "createTextNode('Modified'))");
6854   EXPECT_EQ(1, frame_host.did_access_initial_document_);
6855 
6856   web_view_helper.Reset();
6857 }
6858 
TEST_F(WebFrameTest,DidAccessInitialDocumentBodyBeforeModalDialog)6859 TEST_F(WebFrameTest, DidAccessInitialDocumentBodyBeforeModalDialog) {
6860   TestAccessInitialDocumentLocalFrameHost frame_host;
6861   frame_test_helpers::TestWebFrameClient web_frame_client;
6862   frame_host.Init(web_frame_client.GetRemoteNavigationAssociatedInterfaces());
6863   frame_test_helpers::WebViewHelper web_view_helper;
6864   web_view_helper.Initialize(&web_frame_client);
6865   RunPendingTasks();
6866   EXPECT_EQ(0, frame_host.did_access_initial_document_);
6867 
6868   // Create another window that will try to access it.
6869   frame_test_helpers::WebViewHelper new_web_view_helper;
6870   WebViewImpl* new_view = new_web_view_helper.InitializeWithOpener(
6871       web_view_helper.GetWebView()->MainFrame());
6872   RunPendingTasks();
6873   EXPECT_EQ(0, frame_host.did_access_initial_document_);
6874 
6875   // Access the initial document by modifying the body.
6876   new_view->MainFrameImpl()->ExecuteScript(
6877       WebScriptSource("window.opener.document.body.innerHTML += 'Modified';"));
6878   RunPendingTasks();
6879   EXPECT_EQ(1, frame_host.did_access_initial_document_);
6880 
6881   // Run a modal dialog, which used to run a nested run loop and require
6882   // a special case for notifying about the access.
6883   new_view->MainFrameImpl()->ExecuteScript(
6884       WebScriptSource("window.opener.confirm('Modal');"));
6885   RunPendingTasks();
6886   EXPECT_EQ(1, frame_host.did_access_initial_document_);
6887 
6888   // Ensure that we don't notify again later.
6889   RunPendingTasks();
6890   EXPECT_EQ(1, frame_host.did_access_initial_document_);
6891 
6892   web_view_helper.Reset();
6893 }
6894 
TEST_F(WebFrameTest,DidWriteToInitialDocumentBeforeModalDialog)6895 TEST_F(WebFrameTest, DidWriteToInitialDocumentBeforeModalDialog) {
6896   TestAccessInitialDocumentLocalFrameHost frame_host;
6897   frame_test_helpers::TestWebFrameClient web_frame_client;
6898   frame_host.Init(web_frame_client.GetRemoteNavigationAssociatedInterfaces());
6899   frame_test_helpers::WebViewHelper web_view_helper;
6900   web_view_helper.Initialize(&web_frame_client);
6901   RunPendingTasks();
6902   EXPECT_EQ(0, frame_host.did_access_initial_document_);
6903 
6904   // Create another window that will try to access it.
6905   frame_test_helpers::WebViewHelper new_web_view_helper;
6906   WebViewImpl* new_view = new_web_view_helper.InitializeWithOpener(
6907       web_view_helper.GetWebView()->MainFrame());
6908   RunPendingTasks();
6909   EXPECT_EQ(0, frame_host.did_access_initial_document_);
6910 
6911   // Access the initial document with document.write, which moves us past the
6912   // initial empty document state of the state machine.
6913   new_view->MainFrameImpl()->ExecuteScript(
6914       WebScriptSource("window.opener.document.write('Modified'); "
6915                       "window.opener.document.close();"));
6916   RunPendingTasks();
6917   EXPECT_EQ(1, frame_host.did_access_initial_document_);
6918 
6919   // Run a modal dialog, which used to run a nested run loop and require
6920   // a special case for notifying about the access.
6921   new_view->MainFrameImpl()->ExecuteScript(
6922       WebScriptSource("window.opener.confirm('Modal');"));
6923   RunPendingTasks();
6924   EXPECT_EQ(1, frame_host.did_access_initial_document_);
6925 
6926   // Ensure that we don't notify again later.
6927   RunPendingTasks();
6928   EXPECT_EQ(1, frame_host.did_access_initial_document_);
6929 
6930   web_view_helper.Reset();
6931 }
6932 
6933 class TestScrolledFrameClient : public frame_test_helpers::TestWebFrameClient {
6934  public:
TestScrolledFrameClient()6935   TestScrolledFrameClient() { Reset(); }
6936   ~TestScrolledFrameClient() override = default;
6937 
Reset()6938   void Reset() { did_scroll_frame_ = false; }
WasFrameScrolled() const6939   bool WasFrameScrolled() const { return did_scroll_frame_; }
6940 
6941   // WebLocalFrameClient:
DidChangeScrollOffset()6942   void DidChangeScrollOffset() override {
6943     if (Frame()->Parent())
6944       return;
6945     EXPECT_FALSE(did_scroll_frame_);
6946     LocalFrameView* view = To<WebLocalFrameImpl>(Frame())->GetFrameView();
6947     // LocalFrameView can be scrolled in
6948     // LocalFrameView::SetFixedVisibleContentRect which is called from
6949     // LocalFrame::CreateView (before the frame is associated with the the
6950     // view).
6951     if (view)
6952       did_scroll_frame_ = true;
6953   }
6954 
6955  private:
6956   bool did_scroll_frame_;
6957 };
6958 
TEST_F(WebFrameTest,CompositorScrollIsUserScrollLongPage)6959 TEST_F(WebFrameTest, CompositorScrollIsUserScrollLongPage) {
6960   RegisterMockedHttpURLLoad("long_scroll.html");
6961   TestScrolledFrameClient client;
6962 
6963   // Make sure we initialize to minimum scale, even if the window size
6964   // only becomes available after the load begins.
6965   frame_test_helpers::WebViewHelper web_view_helper;
6966   web_view_helper.InitializeAndLoad(base_url_ + "long_scroll.html", &client);
6967   web_view_helper.Resize(gfx::Size(1000, 1000));
6968 
6969   WebLocalFrameImpl* frame_impl = web_view_helper.LocalMainFrame();
6970   DocumentLoader::InitialScrollState& initial_scroll_state =
6971       frame_impl->GetFrame()
6972           ->Loader()
6973           .GetDocumentLoader()
6974           ->GetInitialScrollState();
6975 
6976   EXPECT_FALSE(client.WasFrameScrolled());
6977   EXPECT_FALSE(initial_scroll_state.was_scrolled_by_user);
6978 
6979   auto* scrollable_area = frame_impl->GetFrameView()->LayoutViewport();
6980 
6981   // Do a compositor scroll, verify that this is counted as a user scroll.
6982   scrollable_area->DidScroll(FloatPoint(0, 1));
6983   web_view_helper.GetWebView()
6984       ->MainFrameWidget()
6985       ->ApplyViewportChangesForTesting({gfx::ScrollOffset(), gfx::Vector2dF(),
6986                                         1.7f, false, 0, 0,
6987                                         cc::BrowserControlsState::kBoth});
6988   EXPECT_TRUE(client.WasFrameScrolled());
6989   EXPECT_TRUE(initial_scroll_state.was_scrolled_by_user);
6990 
6991   client.Reset();
6992   initial_scroll_state.was_scrolled_by_user = false;
6993 
6994   // The page scale 1.0f and scroll.
6995   scrollable_area->DidScroll(FloatPoint(0, 2));
6996   web_view_helper.GetWebView()
6997       ->MainFrameWidget()
6998       ->ApplyViewportChangesForTesting({gfx::ScrollOffset(), gfx::Vector2dF(),
6999                                         1.0f, false, 0, 0,
7000                                         cc::BrowserControlsState::kBoth});
7001   EXPECT_TRUE(client.WasFrameScrolled());
7002   EXPECT_TRUE(initial_scroll_state.was_scrolled_by_user);
7003   client.Reset();
7004   initial_scroll_state.was_scrolled_by_user = false;
7005 
7006   // No scroll event if there is no scroll delta.
7007   scrollable_area->DidScroll(FloatPoint(0, 2));
7008   web_view_helper.GetWebView()
7009       ->MainFrameWidget()
7010       ->ApplyViewportChangesForTesting({gfx::ScrollOffset(), gfx::Vector2dF(),
7011                                         1.0f, false, 0, 0,
7012                                         cc::BrowserControlsState::kBoth});
7013   EXPECT_FALSE(client.WasFrameScrolled());
7014   EXPECT_FALSE(initial_scroll_state.was_scrolled_by_user);
7015   client.Reset();
7016 
7017   // Non zero page scale and scroll.
7018   scrollable_area->DidScroll(FloatPoint(9, 15));
7019   web_view_helper.GetWebView()
7020       ->MainFrameWidget()
7021       ->ApplyViewportChangesForTesting({gfx::ScrollOffset(), gfx::Vector2dF(),
7022                                         0.6f, false, 0, 0,
7023                                         cc::BrowserControlsState::kBoth});
7024   EXPECT_TRUE(client.WasFrameScrolled());
7025   EXPECT_TRUE(initial_scroll_state.was_scrolled_by_user);
7026   client.Reset();
7027   initial_scroll_state.was_scrolled_by_user = false;
7028 
7029   // Programmatic scroll.
7030   frame_impl->ExecuteScript(WebScriptSource("window.scrollTo(0, 20);"));
7031   EXPECT_TRUE(client.WasFrameScrolled());
7032   EXPECT_FALSE(initial_scroll_state.was_scrolled_by_user);
7033   client.Reset();
7034 
7035   // Programmatic scroll to same offset. No scroll event should be generated.
7036   frame_impl->ExecuteScript(WebScriptSource("window.scrollTo(0, 20);"));
7037   EXPECT_FALSE(client.WasFrameScrolled());
7038   EXPECT_FALSE(initial_scroll_state.was_scrolled_by_user);
7039   client.Reset();
7040 }
7041 
TEST_F(WebFrameTest,SiteForCookiesForRedirect)7042 TEST_F(WebFrameTest, SiteForCookiesForRedirect) {
7043   String file_path = test::CoreTestDataPath("first_party.html");
7044 
7045   WebURL test_url(ToKURL("http://internal.test/first_party_redirect.html"));
7046   char redirect[] = "http://internal.test/first_party.html";
7047   WebURL redirect_url(ToKURL(redirect));
7048   WebURLResponse redirect_response;
7049   redirect_response.SetMimeType("text/html");
7050   redirect_response.SetHttpStatusCode(302);
7051   redirect_response.SetHttpHeaderField("Location", redirect);
7052   RegisterMockedURLLoadWithCustomResponse(test_url, file_path,
7053                                           redirect_response);
7054 
7055   WebURLResponse final_response;
7056   final_response.SetMimeType("text/html");
7057   RegisterMockedURLLoadWithCustomResponse(redirect_url, file_path,
7058                                           final_response);
7059 
7060   frame_test_helpers::WebViewHelper web_view_helper;
7061   web_view_helper.InitializeAndLoad(base_url_ + "first_party_redirect.html");
7062   EXPECT_TRUE(
7063       web_view_helper.GetWebView()
7064           ->MainFrameImpl()
7065           ->GetDocument()
7066           .SiteForCookies()
7067           .IsEquivalent(net::SiteForCookies::FromUrl(ToKURL(redirect))));
7068 }
7069 
7070 class TestNewWindowWebViewClient
7071     : public frame_test_helpers::TestWebViewClient {
7072  public:
7073   TestNewWindowWebViewClient() = default;
7074   ~TestNewWindowWebViewClient() override = default;
7075 
7076   // frame_test_helpers::TestWebFrameClient:
CreateView(WebLocalFrame *,const WebURLRequest &,const WebWindowFeatures &,const WebString &,WebNavigationPolicy,network::mojom::blink::WebSandboxFlags,const FeaturePolicyFeatureState &,const SessionStorageNamespaceId &,bool & consumed_user_gesture)7077   WebView* CreateView(WebLocalFrame*,
7078                       const WebURLRequest&,
7079                       const WebWindowFeatures&,
7080                       const WebString&,
7081                       WebNavigationPolicy,
7082                       network::mojom::blink::WebSandboxFlags,
7083                       const FeaturePolicyFeatureState&,
7084                       const SessionStorageNamespaceId&,
7085                       bool& consumed_user_gesture) override {
7086     EXPECT_TRUE(false);
7087     return nullptr;
7088   }
7089 };
7090 
7091 class TestNewWindowWebFrameClient
7092     : public frame_test_helpers::TestWebFrameClient {
7093  public:
TestNewWindowWebFrameClient()7094   TestNewWindowWebFrameClient() : begin_navigation_call_count_(0) {}
7095   ~TestNewWindowWebFrameClient() override = default;
7096 
7097   // frame_test_helpers::TestWebFrameClient:
BeginNavigation(std::unique_ptr<WebNavigationInfo> info)7098   void BeginNavigation(std::unique_ptr<WebNavigationInfo> info) override {
7099     if (ignore_navigations_) {
7100       begin_navigation_call_count_++;
7101       return;
7102     }
7103     TestWebFrameClient::BeginNavigation(std::move(info));
7104   }
7105 
BeginNavigationCallCount() const7106   int BeginNavigationCallCount() const { return begin_navigation_call_count_; }
IgnoreNavigations()7107   void IgnoreNavigations() { ignore_navigations_ = true; }
7108 
7109  private:
7110   bool ignore_navigations_ = false;
7111   int begin_navigation_call_count_;
7112 };
7113 
TEST_F(WebFrameTest,ModifiedClickNewWindow)7114 TEST_F(WebFrameTest, ModifiedClickNewWindow) {
7115   // This test checks that ctrl+click does not just open a new window,
7116   // but instead goes to client to decide the navigation policy.
7117   RegisterMockedHttpURLLoad("ctrl_click.html");
7118   RegisterMockedHttpURLLoad("hello_world.html");
7119   TestNewWindowWebViewClient web_view_client;
7120   TestNewWindowWebFrameClient web_frame_client;
7121   frame_test_helpers::WebViewHelper web_view_helper;
7122   web_view_helper.InitializeAndLoad(base_url_ + "ctrl_click.html",
7123                                     &web_frame_client, &web_view_client);
7124 
7125   auto* frame =
7126       To<LocalFrame>(web_view_helper.GetWebView()->GetPage()->MainFrame());
7127   LocalDOMWindow* window = frame->DomWindow();
7128   KURL destination = ToKURL(base_url_ + "hello_world.html");
7129 
7130   // ctrl+click event
7131   MouseEventInit* mouse_initializer = MouseEventInit::Create();
7132   mouse_initializer->setView(window);
7133   mouse_initializer->setButton(1);
7134   mouse_initializer->setCtrlKey(true);
7135 
7136   Event* event =
7137       MouseEvent::Create(nullptr, event_type_names::kClick, mouse_initializer);
7138   FrameLoadRequest frame_request(window, ResourceRequest(destination));
7139   frame_request.SetNavigationPolicy(NavigationPolicyFromEvent(event));
7140   frame_request.SetTriggeringEventInfo(TriggeringEventInfo::kFromTrustedEvent);
7141   LocalFrame::NotifyUserActivation(
7142       frame, mojom::UserActivationNotificationType::kTest);
7143   web_frame_client.IgnoreNavigations();
7144   frame->Loader().StartNavigation(frame_request, WebFrameLoadType::kStandard);
7145   frame_test_helpers::PumpPendingRequestsForFrameToLoad(
7146       web_view_helper.LocalMainFrame());
7147 
7148   // BeginNavigation should be called for the ctrl+click.
7149   EXPECT_EQ(1, web_frame_client.BeginNavigationCallCount());
7150 }
7151 
7152 class TestBeginNavigationCacheModeClient
7153     : public frame_test_helpers::TestWebFrameClient {
7154  public:
TestBeginNavigationCacheModeClient()7155   TestBeginNavigationCacheModeClient()
7156       : cache_mode_(mojom::FetchCacheMode::kDefault) {}
7157   ~TestBeginNavigationCacheModeClient() override = default;
7158 
GetCacheMode() const7159   mojom::FetchCacheMode GetCacheMode() const { return cache_mode_; }
7160 
BeginNavigation(std::unique_ptr<WebNavigationInfo> info)7161   void BeginNavigation(std::unique_ptr<WebNavigationInfo> info) override {
7162     cache_mode_ = info->url_request.GetCacheMode();
7163     TestWebFrameClient::BeginNavigation(std::move(info));
7164   }
7165 
7166  private:
7167   mojom::FetchCacheMode cache_mode_;
7168 };
7169 
TEST_F(WebFrameTest,BackToReload)7170 TEST_F(WebFrameTest, BackToReload) {
7171   RegisterMockedHttpURLLoad("fragment_middle_click.html");
7172   TestBeginNavigationCacheModeClient client;
7173   frame_test_helpers::WebViewHelper web_view_helper;
7174   web_view_helper.InitializeAndLoad(base_url_ + "fragment_middle_click.html",
7175                                     &client);
7176   WebLocalFrame* frame = web_view_helper.LocalMainFrame();
7177   const FrameLoader& main_frame_loader =
7178       web_view_helper.LocalMainFrame()->GetFrame()->Loader();
7179   Persistent<HistoryItem> first_item =
7180       main_frame_loader.GetDocumentLoader()->GetHistoryItem();
7181   EXPECT_TRUE(first_item);
7182 
7183   RegisterMockedHttpURLLoad("white-1x1.png");
7184   frame_test_helpers::LoadFrame(frame, base_url_ + "white-1x1.png");
7185   EXPECT_NE(first_item.Get(),
7186             main_frame_loader.GetDocumentLoader()->GetHistoryItem());
7187 
7188   frame_test_helpers::LoadHistoryItem(frame, WebHistoryItem(first_item.Get()),
7189                                       mojom::FetchCacheMode::kDefault);
7190   EXPECT_EQ(first_item.Get(),
7191             main_frame_loader.GetDocumentLoader()->GetHistoryItem());
7192 
7193   frame_test_helpers::ReloadFrame(frame);
7194   EXPECT_EQ(mojom::FetchCacheMode::kValidateCache, client.GetCacheMode());
7195 }
7196 
TEST_F(WebFrameTest,ReloadPost)7197 TEST_F(WebFrameTest, ReloadPost) {
7198   RegisterMockedHttpURLLoad("reload_post.html");
7199   TestBeginNavigationCacheModeClient client;
7200   frame_test_helpers::WebViewHelper web_view_helper;
7201   web_view_helper.InitializeAndLoad(base_url_ + "reload_post.html", &client);
7202   WebLocalFrame* frame = web_view_helper.LocalMainFrame();
7203 
7204   frame_test_helpers::LoadFrame(web_view_helper.GetWebView()->MainFrameImpl(),
7205                                 "javascript:document.forms[0].submit()");
7206   // Pump requests one more time after the javascript URL has executed to
7207   // trigger the actual POST load request.
7208   frame_test_helpers::PumpPendingRequestsForFrameToLoad(
7209       web_view_helper.LocalMainFrame());
7210   EXPECT_EQ(WebString::FromUTF8("POST"),
7211             frame->GetDocumentLoader()->HttpMethod());
7212 
7213   frame_test_helpers::ReloadFrame(frame);
7214   EXPECT_EQ(mojom::FetchCacheMode::kValidateCache, client.GetCacheMode());
7215   EXPECT_EQ(kWebNavigationTypeFormResubmitted,
7216             frame->GetDocumentLoader()->GetNavigationType());
7217 }
7218 
7219 class TestCachePolicyWebFrameClient
7220     : public frame_test_helpers::TestWebFrameClient {
7221  public:
TestCachePolicyWebFrameClient()7222   TestCachePolicyWebFrameClient()
7223       : cache_mode_(mojom::FetchCacheMode::kDefault),
7224         begin_navigation_call_count_(0) {}
7225   ~TestCachePolicyWebFrameClient() override = default;
7226 
GetCacheMode() const7227   mojom::FetchCacheMode GetCacheMode() const { return cache_mode_; }
BeginNavigationCallCount() const7228   int BeginNavigationCallCount() const { return begin_navigation_call_count_; }
ChildClient(size_t i)7229   TestCachePolicyWebFrameClient& ChildClient(size_t i) {
7230     return *child_clients_[i].get();
7231   }
ChildFrameCreationCount() const7232   size_t ChildFrameCreationCount() const { return child_clients_.size(); }
7233 
7234   // frame_test_helpers::TestWebFrameClient:
CreateChildFrame(WebLocalFrame * parent,mojom::blink::TreeScopeType scope,const WebString &,const WebString &,const FramePolicy &,const WebFrameOwnerProperties & frame_owner_properties,mojom::blink::FrameOwnerElementType)7235   WebLocalFrame* CreateChildFrame(
7236       WebLocalFrame* parent,
7237       mojom::blink::TreeScopeType scope,
7238       const WebString&,
7239       const WebString&,
7240       const FramePolicy&,
7241       const WebFrameOwnerProperties& frame_owner_properties,
7242       mojom::blink::FrameOwnerElementType) override {
7243     auto child = std::make_unique<TestCachePolicyWebFrameClient>();
7244     auto* child_ptr = child.get();
7245     child_clients_.push_back(std::move(child));
7246     return CreateLocalChild(*parent, scope, child_ptr);
7247   }
BeginNavigation(std::unique_ptr<WebNavigationInfo> info)7248   void BeginNavigation(std::unique_ptr<WebNavigationInfo> info) override {
7249     cache_mode_ = info->url_request.GetCacheMode();
7250     begin_navigation_call_count_++;
7251     TestWebFrameClient::BeginNavigation(std::move(info));
7252   }
7253 
7254  private:
7255   mojom::FetchCacheMode cache_mode_;
7256   Vector<std::unique_ptr<TestCachePolicyWebFrameClient>> child_clients_;
7257   int begin_navigation_call_count_;
7258 };
7259 
TEST_F(WebFrameTest,ReloadIframe)7260 TEST_F(WebFrameTest, ReloadIframe) {
7261   RegisterMockedHttpURLLoad("iframe_reload.html");
7262   RegisterMockedHttpURLLoad("visible_iframe.html");
7263 
7264   TestCachePolicyWebFrameClient main_frame_client;
7265   frame_test_helpers::WebViewHelper web_view_helper;
7266   web_view_helper.InitializeAndLoad(base_url_ + "iframe_reload.html",
7267                                     &main_frame_client);
7268   WebLocalFrameImpl* main_frame = web_view_helper.LocalMainFrame();
7269 
7270   ASSERT_EQ(1U, main_frame_client.ChildFrameCreationCount());
7271   TestCachePolicyWebFrameClient* child_client =
7272       &main_frame_client.ChildClient(0);
7273   auto* child_frame = To<WebLocalFrameImpl>(main_frame->FirstChild());
7274   EXPECT_EQ(child_client, child_frame->Client());
7275   EXPECT_EQ(1u, main_frame->GetFrame()->Tree().ScopedChildCount());
7276   EXPECT_EQ(1, child_client->BeginNavigationCallCount());
7277   EXPECT_EQ(mojom::FetchCacheMode::kDefault, child_client->GetCacheMode());
7278 
7279   frame_test_helpers::ReloadFrame(main_frame);
7280 
7281   // A new child WebLocalFrame should have been created with a new client.
7282   ASSERT_EQ(2U, main_frame_client.ChildFrameCreationCount());
7283   TestCachePolicyWebFrameClient* new_child_client =
7284       &main_frame_client.ChildClient(1);
7285   auto* new_child_frame = To<WebLocalFrameImpl>(main_frame->FirstChild());
7286   EXPECT_EQ(new_child_client, new_child_frame->Client());
7287   ASSERT_NE(child_client, new_child_client);
7288   ASSERT_NE(child_frame, new_child_frame);
7289   // But there should still only be one subframe.
7290   EXPECT_EQ(1u, main_frame->GetFrame()->Tree().ScopedChildCount());
7291 
7292   EXPECT_EQ(1, new_child_client->BeginNavigationCallCount());
7293   // Sub-frames should not be forcibly revalidated.
7294   // TODO(toyoshim): Will consider to revalidate main resources in sub-frames
7295   // on reloads. Or will do only for bypassingCache.
7296   EXPECT_EQ(mojom::FetchCacheMode::kDefault, new_child_client->GetCacheMode());
7297 }
7298 
7299 class TestSameDocumentWebFrameClient
7300     : public frame_test_helpers::TestWebFrameClient {
7301  public:
TestSameDocumentWebFrameClient()7302   TestSameDocumentWebFrameClient() : frame_load_type_reload_seen_(false) {}
7303   ~TestSameDocumentWebFrameClient() override = default;
7304 
7305   // frame_test_helpers::TestWebFrameClient:
BeginNavigation(std::unique_ptr<WebNavigationInfo> info)7306   void BeginNavigation(std::unique_ptr<WebNavigationInfo> info) override {
7307     if (info->frame_load_type == WebFrameLoadType::kReload)
7308       frame_load_type_reload_seen_ = true;
7309     TestWebFrameClient::BeginNavigation(std::move(info));
7310   }
7311 
FrameLoadTypeReloadSeen() const7312   bool FrameLoadTypeReloadSeen() const { return frame_load_type_reload_seen_; }
7313 
7314  private:
7315   bool frame_load_type_reload_seen_;
7316 };
7317 
TEST_F(WebFrameTest,NavigateToSame)7318 TEST_F(WebFrameTest, NavigateToSame) {
7319   RegisterMockedHttpURLLoad("navigate_to_same.html");
7320   TestSameDocumentWebFrameClient client;
7321   frame_test_helpers::WebViewHelper web_view_helper;
7322   web_view_helper.InitializeAndLoad(base_url_ + "navigate_to_same.html",
7323                                     &client);
7324   EXPECT_FALSE(client.FrameLoadTypeReloadSeen());
7325 
7326   auto* local_frame =
7327       To<LocalFrame>(web_view_helper.GetWebView()->GetPage()->MainFrame());
7328   FrameLoadRequest frame_request(
7329       nullptr, ResourceRequest(local_frame->GetDocument()->Url()));
7330   local_frame->Loader().StartNavigation(frame_request);
7331   frame_test_helpers::PumpPendingRequestsForFrameToLoad(
7332       web_view_helper.LocalMainFrame());
7333 
7334   EXPECT_TRUE(client.FrameLoadTypeReloadSeen());
7335 }
7336 
7337 class TestMainFrameIntersectionChanged
7338     : public frame_test_helpers::TestWebFrameClient {
7339  public:
7340   TestMainFrameIntersectionChanged() = default;
7341   ~TestMainFrameIntersectionChanged() override = default;
7342 
7343   // frame_test_helpers::TestWebFrameClient:
OnMainFrameIntersectionChanged(const WebRect & intersection_rect)7344   void OnMainFrameIntersectionChanged(
7345       const WebRect& intersection_rect) override {
7346     main_frame_intersection_ = intersection_rect;
7347   }
7348 
MainFrameIntersection() const7349   WebRect MainFrameIntersection() const { return main_frame_intersection_; }
7350 
7351  private:
7352   WebRect main_frame_intersection_;
7353 };
7354 
TEST_F(WebFrameTest,MainFrameIntersectionChanged)7355 TEST_F(WebFrameTest, MainFrameIntersectionChanged) {
7356   TestMainFrameIntersectionChanged client;
7357   frame_test_helpers::WebViewHelper helper;
7358   helper.InitializeRemote();
7359 
7360   WebLocalFrameImpl* local_frame = frame_test_helpers::CreateLocalChild(
7361       *helper.RemoteMainFrame(), "frameName", WebFrameOwnerProperties(),
7362       nullptr, &client);
7363 
7364   WebFrameWidget* widget = local_frame->FrameWidget();
7365   ASSERT_TRUE(widget);
7366 
7367   gfx::Rect viewport_intersection(0, 11, 200, 89);
7368   gfx::Rect mainframe_intersection(0, 0, 200, 140);
7369   blink::mojom::FrameOcclusionState occlusion_state =
7370       blink::mojom::FrameOcclusionState::kUnknown;
7371   gfx::Transform transform;
7372   transform.Translate(100, 100);
7373 
7374   auto intersection_state = blink::mojom::blink::ViewportIntersectionState(
7375       viewport_intersection, mainframe_intersection, gfx::Rect(),
7376       occlusion_state, gfx::Size(), gfx::Point(), transform);
7377   static_cast<WebFrameWidgetBase*>(widget)->SetRemoteViewportIntersection(
7378       intersection_state);
7379   EXPECT_EQ(client.MainFrameIntersection(), blink::WebRect(100, 100, 200, 140));
7380 }
7381 
7382 class TestSameDocumentWithImageWebFrameClient
7383     : public frame_test_helpers::TestWebFrameClient {
7384  public:
TestSameDocumentWithImageWebFrameClient()7385   TestSameDocumentWithImageWebFrameClient() : num_of_image_requests_(0) {}
7386   ~TestSameDocumentWithImageWebFrameClient() override = default;
7387 
7388   // frame_test_helpers::TestWebFrameClient:
WillSendRequest(WebURLRequest & request,ForRedirect for_redirect)7389   void WillSendRequest(WebURLRequest& request,
7390                        ForRedirect for_redirect) override {
7391     if (request.GetRequestContext() ==
7392         mojom::blink::RequestContextType::IMAGE) {
7393       num_of_image_requests_++;
7394       EXPECT_EQ(mojom::FetchCacheMode::kDefault, request.GetCacheMode());
7395     }
7396   }
7397 
NumOfImageRequests() const7398   int NumOfImageRequests() const { return num_of_image_requests_; }
7399 
7400  private:
7401   int num_of_image_requests_;
7402 };
7403 
TEST_F(WebFrameTest,NavigateToSameNoConditionalRequestForSubresource)7404 TEST_F(WebFrameTest, NavigateToSameNoConditionalRequestForSubresource) {
7405   RegisterMockedHttpURLLoad("foo_with_image.html");
7406   RegisterMockedHttpURLLoad("white-1x1.png");
7407   TestSameDocumentWithImageWebFrameClient client;
7408   frame_test_helpers::WebViewHelper web_view_helper;
7409   web_view_helper.InitializeAndLoad(base_url_ + "foo_with_image.html", &client,
7410                                     nullptr, nullptr,
7411                                     &ConfigureLoadsImagesAutomatically);
7412 
7413   WebCache::Clear();
7414   frame_test_helpers::LoadFrame(web_view_helper.GetWebView()->MainFrameImpl(),
7415                                 base_url_ + "foo_with_image.html");
7416 
7417   // 2 images are requested, and each triggers 2 willSendRequest() calls,
7418   // once for preloading and once for the real request.
7419   EXPECT_EQ(client.NumOfImageRequests(), 4);
7420 }
7421 
TEST_F(WebFrameTest,WebNodeImageContents)7422 TEST_F(WebFrameTest, WebNodeImageContents) {
7423   frame_test_helpers::WebViewHelper web_view_helper;
7424   web_view_helper.InitializeAndLoad("about:blank");
7425   WebLocalFrame* frame = web_view_helper.LocalMainFrame();
7426 
7427   static const char kBluePNG[] =
7428       "<img "
7429       "src=\"data:image/"
7430       "png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+"
7431       "9AAAAGElEQVQYV2NkYPj/n4EIwDiqEF8oUT94AFIQE/cCn90IAAAAAElFTkSuQmCC\">";
7432 
7433   // Load up the image and test that we can extract the contents.
7434   KURL test_url = ToKURL("about:blank");
7435   frame_test_helpers::LoadHTMLString(frame, kBluePNG, test_url);
7436 
7437   WebNode node = frame->GetDocument().Body().FirstChild();
7438   EXPECT_TRUE(node.IsElementNode());
7439   WebElement element = node.To<WebElement>();
7440   SkBitmap image = element.ImageContents();
7441   ASSERT_FALSE(image.isNull());
7442   EXPECT_EQ(image.width(), 10);
7443   EXPECT_EQ(image.height(), 10);
7444   EXPECT_EQ(image.getColor(0, 0), SK_ColorBLUE);
7445 }
7446 
TEST_F(WebFrameTest,WebNodeImageContentsWithOrientation)7447 TEST_F(WebFrameTest, WebNodeImageContentsWithOrientation) {
7448   frame_test_helpers::WebViewHelper web_view_helper;
7449   web_view_helper.InitializeAndLoad("about:blank");
7450   WebLocalFrame* frame = web_view_helper.LocalMainFrame();
7451 
7452   // 4x8 jpg with orientation = 6 ( 90 degree CW rotation ).
7453   // w - white, b - blue.
7454   //   raw      =>       oriented
7455   // w w w w          b b b b w w w w
7456   // w w w w          b b b b w w w w
7457   // w w w w          b b b b w w w w
7458   // w w w w          b b b b w w w w
7459   // b b b b
7460   // b b b b
7461   // b b b b
7462   // b b b b
7463   static const char kBlueJPGWithOrientation[] =
7464       "<img "
7465       "src=\"data:image/"
7466       "jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QBiRXhpZgAATU0AKgAAAAgABQESAAM"
7467       "AAAABAAYAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIAAAITAAMAAAABAA"
7468       "EAAAAAAAAAAABgAAAAAQAAAGAAAAAB/9sAQwACAQECAQECAgICAgICAgMFAwMDAwMGBAQDB"
7469       "QcGBwcHBgcHCAkLCQgICggHBwoNCgoLDAwMDAcJDg8NDA4LDAwM/9sAQwECAgIDAwMGAwMG"
7470       "DAgHCAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw"
7471       "M/8AAEQgACAAEAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC/"
7472       "/EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJ"
7473       "DNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3"
7474       "eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tf"
7475       "Y2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCA"
7476       "kKC//EALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM"
7477       "1LwFWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpz"
7478       "dHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytL"
7479       "T1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/aAAwDAQACEQMRAD8A7j/iMz/6tv8A/Mgf/e"
7480       "2iiiv9ff8AiVzwx/6Fn/lbEf8Ay0+A/tvG/wA/4L/I/9k=\">";
7481 
7482   // Load up the image and test that we can extract the contents.
7483   KURL test_url = ToKURL("about:blank");
7484   frame_test_helpers::LoadHTMLString(frame, kBlueJPGWithOrientation, test_url);
7485 
7486   WebNode node = frame->GetDocument().Body().FirstChild();
7487   EXPECT_TRUE(node.IsElementNode());
7488   WebElement element = node.To<WebElement>();
7489 
7490   SkBitmap image_with_orientation = element.ImageContents();
7491   ASSERT_FALSE(image_with_orientation.isNull());
7492   EXPECT_EQ(image_with_orientation.width(), 8);
7493   EXPECT_EQ(image_with_orientation.height(), 4);
7494   // Should be almost blue.
7495   SkColor oriented_color = image_with_orientation.getColor(0, 0);
7496   EXPECT_NEAR(SkColorGetR(oriented_color), SkColorGetR(SK_ColorBLUE), 5);
7497   EXPECT_NEAR(SkColorGetG(oriented_color), SkColorGetG(SK_ColorBLUE), 5);
7498   EXPECT_NEAR(SkColorGetB(oriented_color), SkColorGetB(SK_ColorBLUE), 5);
7499   EXPECT_NEAR(SkColorGetA(oriented_color), SkColorGetA(SK_ColorBLUE), 5);
7500 }
7501 
7502 class TestStartStopCallbackWebFrameClient
7503     : public frame_test_helpers::TestWebFrameClient {
7504  public:
TestStartStopCallbackWebFrameClient()7505   TestStartStopCallbackWebFrameClient()
7506       : start_loading_count_(0), stop_loading_count_(0) {}
7507   ~TestStartStopCallbackWebFrameClient() override = default;
7508 
7509   // frame_test_helpers::TestWebFrameClient:
DidStartLoading()7510   void DidStartLoading() override {
7511     TestWebFrameClient::DidStartLoading();
7512     start_loading_count_++;
7513   }
DidStopLoading()7514   void DidStopLoading() override {
7515     TestWebFrameClient::DidStopLoading();
7516     stop_loading_count_++;
7517   }
7518 
StartLoadingCount() const7519   int StartLoadingCount() const { return start_loading_count_; }
StopLoadingCount() const7520   int StopLoadingCount() const { return stop_loading_count_; }
7521 
7522  private:
7523   int start_loading_count_;
7524   int stop_loading_count_;
7525 };
7526 
TEST_F(WebFrameTest,PushStateStartsAndStops)7527 TEST_F(WebFrameTest, PushStateStartsAndStops) {
7528   RegisterMockedHttpURLLoad("push_state.html");
7529   TestStartStopCallbackWebFrameClient client;
7530   frame_test_helpers::WebViewHelper web_view_helper;
7531   web_view_helper.InitializeAndLoad(base_url_ + "push_state.html", &client);
7532 
7533   // Wait for push state navigation to complete.
7534   frame_test_helpers::PumpPendingRequestsForFrameToLoad(
7535       web_view_helper.LocalMainFrame());
7536   EXPECT_EQ(client.StartLoadingCount(), 2);
7537   EXPECT_EQ(client.StopLoadingCount(), 2);
7538 }
7539 
TEST_F(WebFrameTest,IPAddressSpace)7540 TEST_F(WebFrameTest, IPAddressSpace) {
7541   frame_test_helpers::WebViewHelper web_view_helper;
7542   WebViewImpl* web_view =
7543       web_view_helper.InitializeAndLoad("data:text/html,ip_address_space");
7544 
7545   network::mojom::IPAddressSpace values[] = {
7546       network::mojom::IPAddressSpace::kUnknown,
7547       network::mojom::IPAddressSpace::kLocal,
7548       network::mojom::IPAddressSpace::kPrivate,
7549       network::mojom::IPAddressSpace::kPublic};
7550 
7551   for (auto value : values) {
7552     auto params = std::make_unique<WebNavigationParams>();
7553     params->url = url_test_helpers::ToKURL("about:blank");
7554     params->navigation_timings.navigation_start = base::TimeTicks::Now();
7555     params->navigation_timings.fetch_start = base::TimeTicks::Now();
7556     params->is_browser_initiated = true;
7557     params->ip_address_space = value;
7558     web_view_helper.LocalMainFrame()->CommitNavigation(std::move(params),
7559                                                        nullptr);
7560     frame_test_helpers::PumpPendingRequestsForFrameToLoad(
7561         web_view_helper.LocalMainFrame());
7562 
7563     ExecutionContext* context =
7564         web_view->MainFrameImpl()->GetFrame()->DomWindow();
7565     EXPECT_EQ(value, context->AddressSpace());
7566   }
7567 }
7568 
7569 class TestDidNavigateCommitTypeWebFrameClient
7570     : public frame_test_helpers::TestWebFrameClient {
7571  public:
TestDidNavigateCommitTypeWebFrameClient()7572   TestDidNavigateCommitTypeWebFrameClient()
7573       : last_commit_type_(kWebHistoryInertCommit) {}
7574   ~TestDidNavigateCommitTypeWebFrameClient() override = default;
7575 
7576   // frame_test_helpers::TestWebFrameClient:
DidFinishSameDocumentNavigation(const WebHistoryItem &,WebHistoryCommitType type,bool content_initiated)7577   void DidFinishSameDocumentNavigation(const WebHistoryItem&,
7578                                        WebHistoryCommitType type,
7579                                        bool content_initiated) override {
7580     last_commit_type_ = type;
7581   }
7582 
LastCommitType() const7583   WebHistoryCommitType LastCommitType() const { return last_commit_type_; }
7584 
7585  private:
7586   WebHistoryCommitType last_commit_type_;
7587 };
7588 
TEST_F(WebFrameTest,SameDocumentHistoryNavigationCommitType)7589 TEST_F(WebFrameTest, SameDocumentHistoryNavigationCommitType) {
7590   RegisterMockedHttpURLLoad("push_state.html");
7591   TestDidNavigateCommitTypeWebFrameClient client;
7592   frame_test_helpers::WebViewHelper web_view_helper;
7593   WebViewImpl* web_view_impl =
7594       web_view_helper.InitializeAndLoad(base_url_ + "push_state.html", &client);
7595   auto* local_frame = To<LocalFrame>(web_view_impl->GetPage()->MainFrame());
7596   Persistent<HistoryItem> item =
7597       local_frame->Loader().GetDocumentLoader()->GetHistoryItem();
7598   RunPendingTasks();
7599 
7600   local_frame->Loader().GetDocumentLoader()->CommitSameDocumentNavigation(
7601       item->Url(), WebFrameLoadType::kBackForward, item.Get(),
7602       ClientRedirectPolicy::kNotClientRedirect, nullptr, /* origin_document */
7603       false,                                             /* has_event */
7604       nullptr /* extra_data */);
7605   EXPECT_EQ(kWebBackForwardCommit, client.LastCommitType());
7606 }
7607 
7608 // Tests that the first navigation in an initially blank subframe will result in
7609 // a history entry being replaced and not a new one being added.
TEST_F(WebFrameTest,FirstBlankSubframeNavigation)7610 TEST_F(WebFrameTest, FirstBlankSubframeNavigation) {
7611   RegisterMockedHttpURLLoad("history.html");
7612   RegisterMockedHttpURLLoad("find.html");
7613 
7614   frame_test_helpers::WebViewHelper web_view_helper;
7615   web_view_helper.InitializeAndLoad("about:blank");
7616 
7617   WebLocalFrame* frame = web_view_helper.LocalMainFrame();
7618 
7619   frame->ExecuteScript(WebScriptSource(WebString::FromUTF8(
7620       "document.body.appendChild(document.createElement('iframe'))")));
7621 
7622   auto* iframe = To<WebLocalFrameImpl>(frame->FirstChild());
7623 
7624   std::string url1 = base_url_ + "history.html";
7625   frame_test_helpers::LoadFrame(iframe, url1);
7626   EXPECT_EQ(url1, iframe->GetDocument().Url().GetString().Utf8());
7627   EXPECT_TRUE(iframe->GetDocumentLoader()->ReplacesCurrentHistoryItem());
7628 
7629   std::string url2 = base_url_ + "find.html";
7630   frame_test_helpers::LoadFrame(iframe, url2);
7631   EXPECT_EQ(url2, iframe->GetDocument().Url().GetString().Utf8());
7632   EXPECT_FALSE(iframe->GetDocumentLoader()->ReplacesCurrentHistoryItem());
7633 }
7634 
7635 // Tests that a navigation in a frame with a non-blank initial URL will create
7636 // a new history item, unlike the case above.
TEST_F(WebFrameTest,FirstNonBlankSubframeNavigation)7637 TEST_F(WebFrameTest, FirstNonBlankSubframeNavigation) {
7638   RegisterMockedHttpURLLoad("history.html");
7639   RegisterMockedHttpURLLoad("find.html");
7640 
7641   frame_test_helpers::WebViewHelper web_view_helper;
7642   web_view_helper.InitializeAndLoad("about:blank");
7643 
7644   WebLocalFrame* frame = web_view_helper.LocalMainFrame();
7645 
7646   std::string url1 = base_url_ + "history.html";
7647   std::string load_frame_js =
7648       "javascript:var f = document.createElement('iframe'); "
7649       "f.src = '";
7650   load_frame_js += url1 + "';" + "document.body.appendChild(f)";
7651   frame_test_helpers::LoadFrame(frame, load_frame_js);
7652 
7653   WebLocalFrame* iframe = frame->FirstChild()->ToWebLocalFrame();
7654   EXPECT_EQ(url1, iframe->GetDocument().Url().GetString().Utf8());
7655 
7656   std::string url2 = base_url_ + "find.html";
7657   frame_test_helpers::LoadFrame(iframe, url2);
7658   EXPECT_EQ(url2, iframe->GetDocument().Url().GetString().Utf8());
7659   EXPECT_FALSE(iframe->GetDocumentLoader()->ReplacesCurrentHistoryItem());
7660 }
7661 
7662 // Test verifies that layout will change a layer's scrollable attibutes
TEST_F(WebFrameTest,overflowHiddenRewrite)7663 TEST_F(WebFrameTest, overflowHiddenRewrite) {
7664   RegisterMockedHttpURLLoad("non-scrollable.html");
7665   FixedLayoutTestWebWidgetClient client;
7666   frame_test_helpers::WebViewHelper web_view_helper;
7667   web_view_helper.Initialize(nullptr, nullptr, &client,
7668                              &ConfigureCompositingWebView);
7669 
7670   web_view_helper.Resize(gfx::Size(100, 100));
7671   frame_test_helpers::LoadFrame(web_view_helper.GetWebView()->MainFrameImpl(),
7672                                 base_url_ + "non-scrollable.html");
7673 
7674   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
7675 
7676   auto* frame_view = web_view_helper.LocalMainFrame()->GetFrameView();
7677   auto* cc_scroll_layer = frame_view->GetScrollableArea()->LayerForScrolling();
7678   ASSERT_TRUE(cc_scroll_layer);
7679 
7680   // Verify that the cc::Layer is not scrollable initially.
7681   auto* scroll_node = GetScrollNode(cc_scroll_layer);
7682   ASSERT_FALSE(scroll_node->user_scrollable_horizontal);
7683   ASSERT_FALSE(scroll_node->user_scrollable_vertical);
7684 
7685   // Call javascript to make the layer scrollable, and verify it.
7686   WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
7687   frame->ExecuteScript(WebScriptSource("allowScroll();"));
7688   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
7689 
7690   cc_scroll_layer = frame_view->GetScrollableArea()->LayerForScrolling();
7691   scroll_node = GetScrollNode(cc_scroll_layer);
7692   ASSERT_TRUE(scroll_node->user_scrollable_horizontal);
7693   ASSERT_TRUE(scroll_node->user_scrollable_vertical);
7694 }
7695 
7696 // Test that currentHistoryItem reflects the current page, not the provisional
7697 // load.
TEST_F(WebFrameTest,CurrentHistoryItem)7698 TEST_F(WebFrameTest, CurrentHistoryItem) {
7699   RegisterMockedHttpURLLoad("fixed_layout.html");
7700   std::string url = base_url_ + "fixed_layout.html";
7701 
7702   frame_test_helpers::WebViewHelper web_view_helper;
7703   web_view_helper.Initialize();
7704   WebLocalFrame* frame = web_view_helper.GetWebView()->MainFrameImpl();
7705   const FrameLoader& main_frame_loader =
7706       web_view_helper.LocalMainFrame()->GetFrame()->Loader();
7707   WebURLRequest request(ToKURL(url));
7708 
7709   // Before navigation, there is no history item.
7710   EXPECT_FALSE(main_frame_loader.GetDocumentLoader()->GetHistoryItem());
7711 
7712   frame->StartNavigation(request);
7713   frame_test_helpers::PumpPendingRequestsForFrameToLoad(
7714       web_view_helper.LocalMainFrame());
7715 
7716   // After navigation, there is.
7717   HistoryItem* item = main_frame_loader.GetDocumentLoader()->GetHistoryItem();
7718   ASSERT_TRUE(item);
7719   EXPECT_EQ(WTF::String(url.data()), item->UrlString());
7720 }
7721 
7722 class FailCreateChildFrame : public frame_test_helpers::TestWebFrameClient {
7723  public:
FailCreateChildFrame()7724   FailCreateChildFrame() : call_count_(0) {}
7725   ~FailCreateChildFrame() override = default;
7726 
7727   // frame_test_helpers::TestWebFrameClient:
CreateChildFrame(WebLocalFrame * parent,mojom::blink::TreeScopeType scope,const WebString & name,const WebString & fallback_name,const FramePolicy &,const WebFrameOwnerProperties & frame_owner_properties,mojom::blink::FrameOwnerElementType)7728   WebLocalFrame* CreateChildFrame(
7729       WebLocalFrame* parent,
7730       mojom::blink::TreeScopeType scope,
7731       const WebString& name,
7732       const WebString& fallback_name,
7733       const FramePolicy&,
7734       const WebFrameOwnerProperties& frame_owner_properties,
7735       mojom::blink::FrameOwnerElementType) override {
7736     ++call_count_;
7737     return nullptr;
7738   }
7739 
CallCount() const7740   int CallCount() const { return call_count_; }
7741 
7742  private:
7743   int call_count_;
7744 };
7745 
7746 // Test that we don't crash if WebLocalFrameClient::createChildFrame() fails.
TEST_F(WebFrameTest,CreateChildFrameFailure)7747 TEST_F(WebFrameTest, CreateChildFrameFailure) {
7748   RegisterMockedHttpURLLoad("create_child_frame_fail.html");
7749   FailCreateChildFrame client;
7750   frame_test_helpers::WebViewHelper web_view_helper;
7751   web_view_helper.InitializeAndLoad(base_url_ + "create_child_frame_fail.html",
7752                                     &client);
7753 
7754   EXPECT_EQ(1, client.CallCount());
7755 }
7756 
TEST_F(WebFrameTest,fixedPositionInFixedViewport)7757 TEST_F(WebFrameTest, fixedPositionInFixedViewport) {
7758   RegisterMockedHttpURLLoad("fixed-position-in-fixed-viewport.html");
7759   frame_test_helpers::WebViewHelper web_view_helper;
7760   web_view_helper.InitializeAndLoad(
7761       base_url_ + "fixed-position-in-fixed-viewport.html", nullptr, nullptr,
7762       nullptr, ConfigureAndroid);
7763 
7764   WebViewImpl* web_view = web_view_helper.GetWebView();
7765   web_view_helper.Resize(gfx::Size(100, 100));
7766 
7767   Document* document = web_view->MainFrameImpl()->GetFrame()->GetDocument();
7768   Element* bottom_fixed = document->getElementById("bottom-fixed");
7769   Element* top_bottom_fixed = document->getElementById("top-bottom-fixed");
7770   Element* right_fixed = document->getElementById("right-fixed");
7771   Element* left_right_fixed = document->getElementById("left-right-fixed");
7772 
7773   // The layout viewport will hit the min-scale limit of 0.25, so it'll be
7774   // 400x800.
7775   web_view_helper.Resize(gfx::Size(100, 200));
7776   EXPECT_EQ(800, bottom_fixed->OffsetTop() + bottom_fixed->OffsetHeight());
7777   EXPECT_EQ(800, top_bottom_fixed->OffsetHeight());
7778 
7779   // Now the layout viewport hits the content width limit of 500px so it'll be
7780   // 500x500.
7781   web_view_helper.Resize(gfx::Size(200, 200));
7782   EXPECT_EQ(500, right_fixed->OffsetLeft() + right_fixed->OffsetWidth());
7783   EXPECT_EQ(500, left_right_fixed->OffsetWidth());
7784 }
7785 
TEST_F(WebFrameTest,FrameViewMoveWithSetFrameRect)7786 TEST_F(WebFrameTest, FrameViewMoveWithSetFrameRect) {
7787   frame_test_helpers::WebViewHelper web_view_helper;
7788   web_view_helper.InitializeAndLoad("about:blank");
7789   web_view_helper.Resize(gfx::Size(200, 200));
7790   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
7791 
7792   LocalFrameView* frame_view = web_view_helper.LocalMainFrame()->GetFrameView();
7793   EXPECT_EQ(IntRect(0, 0, 200, 200), frame_view->FrameRect());
7794   frame_view->SetFrameRect(IntRect(100, 100, 200, 200));
7795   EXPECT_EQ(IntRect(100, 100, 200, 200), frame_view->FrameRect());
7796 }
7797 
TEST_F(WebFrameTest,FrameViewScrollAccountsForBrowserControls)7798 TEST_F(WebFrameTest, FrameViewScrollAccountsForBrowserControls) {
7799   FixedLayoutTestWebWidgetClient client;
7800   RegisterMockedHttpURLLoad("long_scroll.html");
7801   frame_test_helpers::WebViewHelper web_view_helper;
7802   web_view_helper.InitializeAndLoad(base_url_ + "long_scroll.html", nullptr,
7803                                     nullptr, &client, ConfigureAndroid);
7804 
7805   WebViewImpl* web_view = web_view_helper.GetWebView();
7806   LocalFrameView* frame_view = web_view_helper.LocalMainFrame()->GetFrameView();
7807 
7808   float browser_controls_height = 40;
7809   web_view->ResizeWithBrowserControls(gfx::Size(100, 100),
7810                                       browser_controls_height, 0, false);
7811   web_view->SetPageScaleFactor(2.0f);
7812   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
7813 
7814   web_view->MainFrameImpl()->SetScrollOffset(WebSize(0, 2000));
7815   EXPECT_EQ(ScrollOffset(0, 1900),
7816             frame_view->LayoutViewport()->GetScrollOffset());
7817 
7818   // Simulate the browser controls showing by 20px, thus shrinking the viewport
7819   // and allowing it to scroll an additional 20px.
7820   web_view->MainFrameWidget()->ApplyViewportChangesForTesting(
7821       {gfx::ScrollOffset(), gfx::Vector2dF(), 1.0f, false,
7822        20.0f / browser_controls_height, 0, cc::BrowserControlsState::kBoth});
7823   EXPECT_EQ(ScrollOffset(0, 1920),
7824             frame_view->LayoutViewport()->MaximumScrollOffset());
7825 
7826   // Show more, make sure the scroll actually gets clamped.
7827   web_view->MainFrameWidget()->ApplyViewportChangesForTesting(
7828       {gfx::ScrollOffset(), gfx::Vector2dF(), 1.0f, false,
7829        20.0f / browser_controls_height, 0, cc::BrowserControlsState::kBoth});
7830   web_view->MainFrameImpl()->SetScrollOffset(WebSize(0, 2000));
7831   EXPECT_EQ(ScrollOffset(0, 1940),
7832             frame_view->LayoutViewport()->GetScrollOffset());
7833 
7834   // Hide until there's 10px showing.
7835   web_view->MainFrameWidget()->ApplyViewportChangesForTesting(
7836       {gfx::ScrollOffset(), gfx::Vector2dF(), 1.0f, false,
7837        -30.0f / browser_controls_height, 0, cc::BrowserControlsState::kBoth});
7838   EXPECT_EQ(ScrollOffset(0, 1910),
7839             frame_view->LayoutViewport()->MaximumScrollOffset());
7840 
7841   // Simulate a LayoutEmbeddedContent::resize. The frame is resized to
7842   // accommodate the browser controls and Blink's view of the browser controls
7843   // matches that of the CC
7844   web_view->MainFrameWidget()->ApplyViewportChangesForTesting(
7845       {gfx::ScrollOffset(), gfx::Vector2dF(), 1.0f, false,
7846        30.0f / browser_controls_height, 0, cc::BrowserControlsState::kBoth});
7847   web_view->ResizeWithBrowserControls(gfx::Size(100, 60), 40.0f, 0, true);
7848   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
7849   EXPECT_EQ(ScrollOffset(0, 1940),
7850             frame_view->LayoutViewport()->MaximumScrollOffset());
7851 
7852   // Now simulate hiding.
7853   web_view->MainFrameWidget()->ApplyViewportChangesForTesting(
7854       {gfx::ScrollOffset(), gfx::Vector2dF(), 1.0f, false,
7855        -10.0f / browser_controls_height, 0, cc::BrowserControlsState::kBoth});
7856   EXPECT_EQ(ScrollOffset(0, 1930),
7857             frame_view->LayoutViewport()->MaximumScrollOffset());
7858 
7859   // Reset to original state: 100px widget height, browser controls fully
7860   // hidden.
7861   web_view->MainFrameWidget()->ApplyViewportChangesForTesting(
7862       {gfx::ScrollOffset(), gfx::Vector2dF(), 1.0f, false,
7863        -30.0f / browser_controls_height, 0, cc::BrowserControlsState::kBoth});
7864   web_view->ResizeWithBrowserControls(gfx::Size(100, 100),
7865                                       browser_controls_height, 0, false);
7866   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
7867   EXPECT_EQ(ScrollOffset(0, 1900),
7868             frame_view->LayoutViewport()->MaximumScrollOffset());
7869 
7870   // Show the browser controls by just 1px, since we're zoomed in to 2X, that
7871   // should allow an extra 0.5px of scrolling in the visual viewport. Make
7872   // sure we're not losing any pixels when applying the adjustment on the
7873   // main frame.
7874   web_view->MainFrameWidget()->ApplyViewportChangesForTesting(
7875       {gfx::ScrollOffset(), gfx::Vector2dF(), 1.0f, false,
7876        1.0f / browser_controls_height, 0, cc::BrowserControlsState::kBoth});
7877   EXPECT_EQ(ScrollOffset(0, 1901),
7878             frame_view->LayoutViewport()->MaximumScrollOffset());
7879 
7880   web_view->MainFrameWidget()->ApplyViewportChangesForTesting(
7881       {gfx::ScrollOffset(), gfx::Vector2dF(), 1.0f, false,
7882        2.0f / browser_controls_height, 0, cc::BrowserControlsState::kBoth});
7883   EXPECT_EQ(ScrollOffset(0, 1903),
7884             frame_view->LayoutViewport()->MaximumScrollOffset());
7885 }
7886 
TEST_F(WebFrameTest,MaximumScrollPositionCanBeNegative)7887 TEST_F(WebFrameTest, MaximumScrollPositionCanBeNegative) {
7888   RegisterMockedHttpURLLoad("rtl-overview-mode.html");
7889 
7890   FixedLayoutTestWebWidgetClient client;
7891   client.screen_info_.device_scale_factor = 1;
7892   int viewport_width = 640;
7893   int viewport_height = 480;
7894 
7895   frame_test_helpers::WebViewHelper web_view_helper;
7896   web_view_helper.InitializeAndLoad(base_url_ + "rtl-overview-mode.html",
7897                                     nullptr, nullptr, &client,
7898                                     ConfigureAndroid);
7899   web_view_helper.GetWebView()->SetInitialPageScaleOverride(-1);
7900   web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
7901       true);
7902   web_view_helper.GetWebView()->GetSettings()->SetLoadWithOverviewMode(true);
7903   web_view_helper.GetWebView()->GetSettings()->SetUseWideViewport(true);
7904   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
7905   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
7906 
7907   LocalFrameView* frame_view = web_view_helper.LocalMainFrame()->GetFrameView();
7908   ScrollableArea* layout_viewport = frame_view->LayoutViewport();
7909   EXPECT_LT(layout_viewport->MaximumScrollOffset().Width(), 0);
7910 }
7911 
TEST_F(WebFrameTest,FullscreenLayerSize)7912 TEST_F(WebFrameTest, FullscreenLayerSize) {
7913   FixedLayoutTestWebWidgetClient client;
7914   RegisterMockedHttpURLLoad("fullscreen_div.html");
7915   frame_test_helpers::WebViewHelper web_view_helper;
7916   int viewport_width = 640;
7917   int viewport_height = 480;
7918   client.screen_info_.rect = gfx::Rect(viewport_width, viewport_height);
7919   WebViewImpl* web_view_impl = web_view_helper.InitializeAndLoad(
7920       base_url_ + "fullscreen_div.html", nullptr, nullptr, &client,
7921       ConfigureAndroid);
7922   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
7923   UpdateAllLifecyclePhases(web_view_impl);
7924 
7925   LocalFrame* frame = web_view_impl->MainFrameImpl()->GetFrame();
7926   Document* document = frame->GetDocument();
7927   LocalFrame::NotifyUserActivation(
7928       frame, mojom::UserActivationNotificationType::kTest);
7929   Element* div_fullscreen = document->getElementById("div1");
7930   Fullscreen::RequestFullscreen(*div_fullscreen);
7931   EXPECT_EQ(nullptr, Fullscreen::FullscreenElementFrom(*document));
7932   web_view_impl->DidEnterFullscreen();
7933   EXPECT_EQ(div_fullscreen, Fullscreen::FullscreenElementFrom(*document));
7934   UpdateAllLifecyclePhases(web_view_impl);
7935   EXPECT_EQ(div_fullscreen, Fullscreen::FullscreenElementFrom(*document));
7936 
7937   // Verify that the element is sized to the viewport.
7938   auto* fullscreen_layout_object =
7939       To<LayoutBox>(div_fullscreen->GetLayoutObject());
7940   EXPECT_EQ(viewport_width, fullscreen_layout_object->LogicalWidth().ToInt());
7941   EXPECT_EQ(viewport_height, fullscreen_layout_object->LogicalHeight().ToInt());
7942 
7943   // Verify it's updated after a device rotation.
7944   UpdateScreenInfoAndResizeView(&client, &web_view_helper, viewport_height,
7945                                 viewport_width);
7946   UpdateAllLifecyclePhases(web_view_impl);
7947   EXPECT_EQ(viewport_height, fullscreen_layout_object->LogicalWidth().ToInt());
7948   EXPECT_EQ(viewport_width, fullscreen_layout_object->LogicalHeight().ToInt());
7949 }
7950 
TEST_F(WebFrameTest,FullscreenLayerNonScrollable)7951 TEST_F(WebFrameTest, FullscreenLayerNonScrollable) {
7952   FixedLayoutTestWebWidgetClient client;
7953   RegisterMockedHttpURLLoad("fullscreen_div.html");
7954   frame_test_helpers::WebViewHelper web_view_helper;
7955   int viewport_width = 640;
7956   int viewport_height = 480;
7957   WebViewImpl* web_view_impl = web_view_helper.InitializeAndLoad(
7958       base_url_ + "fullscreen_div.html", nullptr, nullptr, &client,
7959       ConfigureAndroid);
7960   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
7961   UpdateAllLifecyclePhases(web_view_impl);
7962 
7963   LocalFrame* frame = web_view_impl->MainFrameImpl()->GetFrame();
7964   Document* document = frame->GetDocument();
7965   LocalFrame::NotifyUserActivation(
7966       frame, mojom::UserActivationNotificationType::kTest);
7967   Element* div_fullscreen = document->getElementById("div1");
7968   Fullscreen::RequestFullscreen(*div_fullscreen);
7969   EXPECT_EQ(nullptr, Fullscreen::FullscreenElementFrom(*document));
7970   web_view_impl->DidEnterFullscreen();
7971   EXPECT_EQ(div_fullscreen, Fullscreen::FullscreenElementFrom(*document));
7972   UpdateAllLifecyclePhases(web_view_impl);
7973   EXPECT_EQ(div_fullscreen, Fullscreen::FullscreenElementFrom(*document));
7974 
7975   // Verify that the viewports are nonscrollable.
7976   LocalFrameView* frame_view = web_view_helper.LocalMainFrame()->GetFrameView();
7977   cc::Layer* layout_viewport_scroll_layer =
7978       frame_view->GetScrollableArea()->LayerForScrolling();
7979   cc::Layer* visual_viewport_scroll_layer =
7980       frame_view->GetPage()->GetVisualViewport().LayerForScrolling();
7981 
7982   auto* layout_viewport_scroll_node =
7983       GetScrollNode(layout_viewport_scroll_layer);
7984   ASSERT_FALSE(layout_viewport_scroll_node->user_scrollable_horizontal);
7985   ASSERT_FALSE(layout_viewport_scroll_node->user_scrollable_vertical);
7986   auto* visual_viewport_scroll_node =
7987       GetScrollNode(visual_viewport_scroll_layer);
7988   ASSERT_FALSE(visual_viewport_scroll_node->user_scrollable_horizontal);
7989   ASSERT_FALSE(visual_viewport_scroll_node->user_scrollable_vertical);
7990 
7991   // Verify that the viewports are scrollable upon exiting fullscreen.
7992   EXPECT_EQ(div_fullscreen, Fullscreen::FullscreenElementFrom(*document));
7993   web_view_impl->DidExitFullscreen();
7994   EXPECT_EQ(nullptr, Fullscreen::FullscreenElementFrom(*document));
7995   UpdateAllLifecyclePhases(web_view_impl);
7996   EXPECT_EQ(nullptr, Fullscreen::FullscreenElementFrom(*document));
7997   layout_viewport_scroll_layer =
7998       frame_view->GetScrollableArea()->LayerForScrolling();
7999   visual_viewport_scroll_layer =
8000       frame_view->GetPage()->GetVisualViewport().LayerForScrolling();
8001   layout_viewport_scroll_node = GetScrollNode(layout_viewport_scroll_layer);
8002   ASSERT_TRUE(layout_viewport_scroll_node->user_scrollable_horizontal);
8003   ASSERT_TRUE(layout_viewport_scroll_node->user_scrollable_vertical);
8004   visual_viewport_scroll_node = GetScrollNode(visual_viewport_scroll_layer);
8005   ASSERT_TRUE(visual_viewport_scroll_node->user_scrollable_horizontal);
8006   ASSERT_TRUE(visual_viewport_scroll_node->user_scrollable_vertical);
8007 }
8008 
TEST_F(WebFrameTest,FullscreenMainFrame)8009 TEST_F(WebFrameTest, FullscreenMainFrame) {
8010   FixedLayoutTestWebWidgetClient client;
8011   RegisterMockedHttpURLLoad("fullscreen_div.html");
8012   frame_test_helpers::WebViewHelper web_view_helper;
8013   int viewport_width = 640;
8014   int viewport_height = 480;
8015   WebViewImpl* web_view_impl = web_view_helper.InitializeAndLoad(
8016       base_url_ + "fullscreen_div.html", nullptr, nullptr, &client,
8017       ConfigureAndroid);
8018   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
8019   UpdateAllLifecyclePhases(web_view_impl);
8020 
8021   cc::Layer* cc_scroll_layer = web_view_impl->MainFrameImpl()
8022                                    ->GetFrame()
8023                                    ->View()
8024                                    ->LayoutViewport()
8025                                    ->LayerForScrolling();
8026   auto* scroll_node = GetScrollNode(cc_scroll_layer);
8027   ASSERT_TRUE(scroll_node->scrollable);
8028   ASSERT_TRUE(scroll_node->user_scrollable_horizontal);
8029   ASSERT_TRUE(scroll_node->user_scrollable_vertical);
8030 
8031   LocalFrame* frame = web_view_impl->MainFrameImpl()->GetFrame();
8032   Document* document = frame->GetDocument();
8033   LocalFrame::NotifyUserActivation(
8034       frame, mojom::UserActivationNotificationType::kTest);
8035   Fullscreen::RequestFullscreen(*document->documentElement());
8036   EXPECT_EQ(nullptr, Fullscreen::FullscreenElementFrom(*document));
8037   web_view_impl->DidEnterFullscreen();
8038   EXPECT_EQ(document->documentElement(),
8039             Fullscreen::FullscreenElementFrom(*document));
8040 
8041   UpdateAllLifecyclePhases(web_view_impl);
8042   EXPECT_EQ(document->documentElement(),
8043             Fullscreen::FullscreenElementFrom(*document));
8044 
8045   // Verify that the main frame is still scrollable.
8046   cc_scroll_layer = web_view_impl->MainFrameImpl()
8047                         ->GetFrame()
8048                         ->View()
8049                         ->LayoutViewport()
8050                         ->LayerForScrolling();
8051   scroll_node = GetScrollNode(cc_scroll_layer);
8052   ASSERT_TRUE(scroll_node->scrollable);
8053   ASSERT_TRUE(scroll_node->user_scrollable_horizontal);
8054   ASSERT_TRUE(scroll_node->user_scrollable_vertical);
8055 
8056   // Verify the main frame still behaves correctly after a resize.
8057   web_view_helper.Resize(gfx::Size(viewport_height, viewport_width));
8058   scroll_node = GetScrollNode(cc_scroll_layer);
8059   ASSERT_TRUE(scroll_node->scrollable);
8060   ASSERT_TRUE(scroll_node->user_scrollable_horizontal);
8061   ASSERT_TRUE(scroll_node->user_scrollable_vertical);
8062 }
8063 
TEST_F(WebFrameTest,FullscreenSubframe)8064 TEST_F(WebFrameTest, FullscreenSubframe) {
8065   FixedLayoutTestWebWidgetClient client;
8066   RegisterMockedHttpURLLoad("fullscreen_iframe.html");
8067   RegisterMockedHttpURLLoad("fullscreen_div.html");
8068   frame_test_helpers::WebViewHelper web_view_helper;
8069   WebViewImpl* web_view_impl = web_view_helper.InitializeAndLoad(
8070       base_url_ + "fullscreen_iframe.html", nullptr, nullptr, &client,
8071       ConfigureAndroid);
8072   int viewport_width = 640;
8073   int viewport_height = 480;
8074   UpdateScreenInfoAndResizeView(&client, &web_view_helper, viewport_width,
8075                                 viewport_height);
8076   UpdateAllLifecyclePhases(web_view_impl);
8077 
8078   LocalFrame* frame =
8079       To<WebLocalFrameImpl>(
8080           web_view_helper.GetWebView()->MainFrame()->FirstChild())
8081           ->GetFrame();
8082   Document* document = frame->GetDocument();
8083   LocalFrame::NotifyUserActivation(
8084       frame, mojom::UserActivationNotificationType::kTest);
8085   Element* div_fullscreen = document->getElementById("div1");
8086   Fullscreen::RequestFullscreen(*div_fullscreen);
8087   web_view_impl->DidEnterFullscreen();
8088   UpdateAllLifecyclePhases(web_view_impl);
8089 
8090   // Verify that the element is sized to the viewport.
8091   auto* fullscreen_layout_object =
8092       To<LayoutBox>(div_fullscreen->GetLayoutObject());
8093   EXPECT_EQ(viewport_width, fullscreen_layout_object->LogicalWidth().ToInt());
8094   EXPECT_EQ(viewport_height, fullscreen_layout_object->LogicalHeight().ToInt());
8095 
8096   // Verify it's updated after a device rotation.
8097   UpdateScreenInfoAndResizeView(&client, &web_view_helper, viewport_height,
8098                                 viewport_width);
8099   UpdateAllLifecyclePhases(web_view_impl);
8100   EXPECT_EQ(viewport_height, fullscreen_layout_object->LogicalWidth().ToInt());
8101   EXPECT_EQ(viewport_width, fullscreen_layout_object->LogicalHeight().ToInt());
8102 }
8103 
8104 // Tests entering nested fullscreen and then exiting via the same code path
8105 // that's used when the browser process exits fullscreen.
TEST_F(WebFrameTest,FullscreenNestedExit)8106 TEST_F(WebFrameTest, FullscreenNestedExit) {
8107   RegisterMockedHttpURLLoad("fullscreen_iframe.html");
8108   RegisterMockedHttpURLLoad("fullscreen_div.html");
8109   frame_test_helpers::WebViewHelper web_view_helper;
8110   WebViewImpl* web_view_impl =
8111       web_view_helper.InitializeAndLoad(base_url_ + "fullscreen_iframe.html");
8112 
8113   UpdateAllLifecyclePhases(web_view_impl);
8114 
8115   Document* top_doc = web_view_impl->MainFrameImpl()->GetFrame()->GetDocument();
8116   Element* top_body = top_doc->body();
8117 
8118   auto* iframe = To<HTMLIFrameElement>(top_doc->QuerySelector("iframe"));
8119   Document* iframe_doc = iframe->contentDocument();
8120   Element* iframe_body = iframe_doc->body();
8121 
8122   LocalFrame::NotifyUserActivation(
8123       top_doc->GetFrame(), mojom::UserActivationNotificationType::kTest);
8124   Fullscreen::RequestFullscreen(*top_body);
8125 
8126   web_view_impl->DidEnterFullscreen();
8127   UpdateAllLifecyclePhases(web_view_impl);
8128 
8129   LocalFrame::NotifyUserActivation(
8130       iframe_doc->GetFrame(), mojom::UserActivationNotificationType::kTest);
8131   Fullscreen::RequestFullscreen(*iframe_body);
8132 
8133   web_view_impl->DidEnterFullscreen();
8134   Microtask::PerformCheckpoint(V8PerIsolateData::MainThreadIsolate());
8135   UpdateAllLifecyclePhases(web_view_impl);
8136 
8137   // We are now in nested fullscreen, with both documents having a non-empty
8138   // fullscreen element stack.
8139   EXPECT_EQ(iframe, Fullscreen::FullscreenElementFrom(*top_doc));
8140   EXPECT_EQ(iframe_body, Fullscreen::FullscreenElementFrom(*iframe_doc));
8141 
8142   web_view_impl->DidExitFullscreen();
8143   UpdateAllLifecyclePhases(web_view_impl);
8144 
8145   // We should now have fully exited fullscreen.
8146   EXPECT_EQ(nullptr, Fullscreen::FullscreenElementFrom(*top_doc));
8147   EXPECT_EQ(nullptr, Fullscreen::FullscreenElementFrom(*iframe_doc));
8148 }
8149 
TEST_F(WebFrameTest,FullscreenWithTinyViewport)8150 TEST_F(WebFrameTest, FullscreenWithTinyViewport) {
8151   FixedLayoutTestWebWidgetClient client;
8152   RegisterMockedHttpURLLoad("viewport-tiny.html");
8153   frame_test_helpers::WebViewHelper web_view_helper;
8154   WebViewImpl* web_view_impl = web_view_helper.InitializeAndLoad(
8155       base_url_ + "viewport-tiny.html", nullptr, nullptr, &client,
8156       ConfigureAndroid);
8157   int viewport_width = 384;
8158   int viewport_height = 640;
8159   UpdateScreenInfoAndResizeView(&client, &web_view_helper, viewport_width,
8160                                 viewport_height);
8161   UpdateAllLifecyclePhases(web_view_impl);
8162 
8163   auto* layout_view = web_view_helper.GetWebView()
8164                           ->MainFrameImpl()
8165                           ->GetFrameView()
8166                           ->GetLayoutView();
8167   EXPECT_EQ(320, layout_view->LogicalWidth().Floor());
8168   EXPECT_EQ(533, layout_view->LogicalHeight().Floor());
8169   EXPECT_FLOAT_EQ(1.2, web_view_impl->PageScaleFactor());
8170   EXPECT_FLOAT_EQ(1.2, web_view_impl->MinimumPageScaleFactor());
8171   EXPECT_FLOAT_EQ(5.0, web_view_impl->MaximumPageScaleFactor());
8172 
8173   LocalFrame* frame = web_view_impl->MainFrameImpl()->GetFrame();
8174   LocalFrame::NotifyUserActivation(
8175       frame, mojom::UserActivationNotificationType::kTest);
8176   Fullscreen::RequestFullscreen(*frame->GetDocument()->documentElement());
8177   web_view_impl->DidEnterFullscreen();
8178   UpdateAllLifecyclePhases(web_view_impl);
8179   EXPECT_EQ(384, layout_view->LogicalWidth().Floor());
8180   EXPECT_EQ(640, layout_view->LogicalHeight().Floor());
8181   EXPECT_FLOAT_EQ(1.0, web_view_impl->PageScaleFactor());
8182   EXPECT_FLOAT_EQ(1.0, web_view_impl->MinimumPageScaleFactor());
8183   EXPECT_FLOAT_EQ(1.0, web_view_impl->MaximumPageScaleFactor());
8184 
8185   web_view_impl->DidExitFullscreen();
8186   UpdateAllLifecyclePhases(web_view_impl);
8187   EXPECT_EQ(320, layout_view->LogicalWidth().Floor());
8188   EXPECT_EQ(533, layout_view->LogicalHeight().Floor());
8189   EXPECT_FLOAT_EQ(1.2, web_view_impl->PageScaleFactor());
8190   EXPECT_FLOAT_EQ(1.2, web_view_impl->MinimumPageScaleFactor());
8191   EXPECT_FLOAT_EQ(5.0, web_view_impl->MaximumPageScaleFactor());
8192 }
8193 
TEST_F(WebFrameTest,FullscreenResizeWithTinyViewport)8194 TEST_F(WebFrameTest, FullscreenResizeWithTinyViewport) {
8195   FixedLayoutTestWebWidgetClient client;
8196   RegisterMockedHttpURLLoad("viewport-tiny.html");
8197   frame_test_helpers::WebViewHelper web_view_helper;
8198   WebViewImpl* web_view_impl = web_view_helper.InitializeAndLoad(
8199       base_url_ + "viewport-tiny.html", nullptr, nullptr, &client,
8200       ConfigureAndroid);
8201   int viewport_width = 384;
8202   int viewport_height = 640;
8203   UpdateScreenInfoAndResizeView(&client, &web_view_helper, viewport_width,
8204                                 viewport_height);
8205   UpdateAllLifecyclePhases(web_view_impl);
8206 
8207   auto* layout_view = web_view_helper.GetWebView()
8208                           ->MainFrameImpl()
8209                           ->GetFrameView()
8210                           ->GetLayoutView();
8211   LocalFrame* frame = web_view_impl->MainFrameImpl()->GetFrame();
8212   LocalFrame::NotifyUserActivation(
8213       frame, mojom::UserActivationNotificationType::kTest);
8214   Fullscreen::RequestFullscreen(*frame->GetDocument()->documentElement());
8215   web_view_impl->DidEnterFullscreen();
8216   UpdateAllLifecyclePhases(web_view_impl);
8217   EXPECT_EQ(384, layout_view->LogicalWidth().Floor());
8218   EXPECT_EQ(640, layout_view->LogicalHeight().Floor());
8219   EXPECT_FLOAT_EQ(1.0, web_view_impl->PageScaleFactor());
8220   EXPECT_FLOAT_EQ(1.0, web_view_impl->MinimumPageScaleFactor());
8221   EXPECT_FLOAT_EQ(1.0, web_view_impl->MaximumPageScaleFactor());
8222 
8223   viewport_width = 640;
8224   viewport_height = 384;
8225   UpdateScreenInfoAndResizeView(&client, &web_view_helper, viewport_width,
8226                                 viewport_height);
8227   UpdateAllLifecyclePhases(web_view_impl);
8228   EXPECT_EQ(640, layout_view->LogicalWidth().Floor());
8229   EXPECT_EQ(384, layout_view->LogicalHeight().Floor());
8230   EXPECT_FLOAT_EQ(1.0, web_view_impl->PageScaleFactor());
8231   EXPECT_FLOAT_EQ(1.0, web_view_impl->MinimumPageScaleFactor());
8232   EXPECT_FLOAT_EQ(1.0, web_view_impl->MaximumPageScaleFactor());
8233 
8234   web_view_impl->DidExitFullscreen();
8235   UpdateAllLifecyclePhases(web_view_impl);
8236   EXPECT_EQ(320, layout_view->LogicalWidth().Floor());
8237   EXPECT_EQ(192, layout_view->LogicalHeight().Floor());
8238   EXPECT_FLOAT_EQ(2, web_view_impl->PageScaleFactor());
8239   EXPECT_FLOAT_EQ(2, web_view_impl->MinimumPageScaleFactor());
8240   EXPECT_FLOAT_EQ(5.0, web_view_impl->MaximumPageScaleFactor());
8241 }
8242 
TEST_F(WebFrameTest,FullscreenRestoreScaleFactorUponExiting)8243 TEST_F(WebFrameTest, FullscreenRestoreScaleFactorUponExiting) {
8244   // The purpose of this test is to more precisely simulate the sequence of
8245   // resize and switching fullscreen state operations on WebView, with the
8246   // interference from Android status bars like a real device does.
8247   // This verifies we handle the transition and restore states correctly.
8248   WebSize screen_size_minus_status_bars_minus_url_bar(598, 303);
8249   WebSize screen_size_minus_status_bars(598, 359);
8250   WebSize screen_size(640, 384);
8251 
8252   FixedLayoutTestWebWidgetClient client;
8253   RegisterMockedHttpURLLoad("fullscreen_restore_scale_factor.html");
8254   frame_test_helpers::WebViewHelper web_view_helper;
8255   WebViewImpl* web_view_impl = web_view_helper.InitializeAndLoad(
8256       base_url_ + "fullscreen_restore_scale_factor.html", nullptr, nullptr,
8257       &client, &ConfigureAndroid);
8258   UpdateScreenInfoAndResizeView(
8259       &client, &web_view_helper,
8260       screen_size_minus_status_bars_minus_url_bar.width,
8261       screen_size_minus_status_bars_minus_url_bar.height);
8262   auto* layout_view = web_view_helper.GetWebView()
8263                           ->MainFrameImpl()
8264                           ->GetFrameView()
8265                           ->GetLayoutView();
8266   EXPECT_EQ(screen_size_minus_status_bars_minus_url_bar.width,
8267             layout_view->LogicalWidth().Floor());
8268   EXPECT_EQ(screen_size_minus_status_bars_minus_url_bar.height,
8269             layout_view->LogicalHeight().Floor());
8270   EXPECT_FLOAT_EQ(1.0, web_view_impl->PageScaleFactor());
8271   EXPECT_FLOAT_EQ(1.0, web_view_impl->MinimumPageScaleFactor());
8272   EXPECT_FLOAT_EQ(5.0, web_view_impl->MaximumPageScaleFactor());
8273 
8274   {
8275     LocalFrame* frame = web_view_impl->MainFrameImpl()->GetFrame();
8276     LocalFrame::NotifyUserActivation(
8277         frame, mojom::UserActivationNotificationType::kTest);
8278     Fullscreen::RequestFullscreen(*frame->GetDocument()->body());
8279   }
8280 
8281   web_view_impl->DidEnterFullscreen();
8282   UpdateAllLifecyclePhases(web_view_impl);
8283   UpdateScreenInfoAndResizeView(&client, &web_view_helper,
8284                                 screen_size_minus_status_bars.width,
8285                                 screen_size_minus_status_bars.height);
8286   UpdateScreenInfoAndResizeView(&client, &web_view_helper, screen_size.width,
8287                                 screen_size.height);
8288   EXPECT_EQ(screen_size.width, layout_view->LogicalWidth().Floor());
8289   EXPECT_EQ(screen_size.height, layout_view->LogicalHeight().Floor());
8290   EXPECT_FLOAT_EQ(1.0, web_view_impl->PageScaleFactor());
8291   EXPECT_FLOAT_EQ(1.0, web_view_impl->MinimumPageScaleFactor());
8292   EXPECT_FLOAT_EQ(1.0, web_view_impl->MaximumPageScaleFactor());
8293 
8294   web_view_impl->DidExitFullscreen();
8295   UpdateAllLifecyclePhases(web_view_impl);
8296   UpdateScreenInfoAndResizeView(&client, &web_view_helper,
8297                                 screen_size_minus_status_bars.width,
8298                                 screen_size_minus_status_bars.height);
8299   UpdateScreenInfoAndResizeView(
8300       &client, &web_view_helper,
8301       screen_size_minus_status_bars_minus_url_bar.width,
8302       screen_size_minus_status_bars_minus_url_bar.height);
8303   EXPECT_EQ(screen_size_minus_status_bars_minus_url_bar.width,
8304             layout_view->LogicalWidth().Floor());
8305   EXPECT_EQ(screen_size_minus_status_bars_minus_url_bar.height,
8306             layout_view->LogicalHeight().Floor());
8307   EXPECT_FLOAT_EQ(1.0, web_view_impl->PageScaleFactor());
8308   EXPECT_FLOAT_EQ(1.0, web_view_impl->MinimumPageScaleFactor());
8309   EXPECT_FLOAT_EQ(5.0, web_view_impl->MaximumPageScaleFactor());
8310 }
8311 
8312 // Tests that leaving fullscreen by navigating to a new page resets the
8313 // fullscreen page scale constraints.
TEST_F(WebFrameTest,ClearFullscreenConstraintsOnNavigation)8314 TEST_F(WebFrameTest, ClearFullscreenConstraintsOnNavigation) {
8315   RegisterMockedHttpURLLoad("viewport-tiny.html");
8316   frame_test_helpers::WebViewHelper web_view_helper;
8317   int viewport_width = 100;
8318   int viewport_height = 200;
8319 
8320   WebViewImpl* web_view_impl = web_view_helper.InitializeAndLoad(
8321       base_url_ + "viewport-tiny.html", nullptr, nullptr, nullptr,
8322       ConfigureAndroid);
8323 
8324   web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
8325   UpdateAllLifecyclePhases(web_view_impl);
8326 
8327   // viewport-tiny.html specifies a 320px layout width.
8328   auto* layout_view =
8329       web_view_impl->MainFrameImpl()->GetFrameView()->GetLayoutView();
8330   EXPECT_EQ(320, layout_view->LogicalWidth().Floor());
8331   EXPECT_EQ(640, layout_view->LogicalHeight().Floor());
8332   EXPECT_FLOAT_EQ(0.3125, web_view_impl->PageScaleFactor());
8333   EXPECT_FLOAT_EQ(0.3125, web_view_impl->MinimumPageScaleFactor());
8334   EXPECT_FLOAT_EQ(5.0, web_view_impl->MaximumPageScaleFactor());
8335 
8336   LocalFrame* frame = web_view_impl->MainFrameImpl()->GetFrame();
8337   LocalFrame::NotifyUserActivation(
8338       frame, mojom::UserActivationNotificationType::kTest);
8339   Fullscreen::RequestFullscreen(*frame->GetDocument()->documentElement());
8340   web_view_impl->DidEnterFullscreen();
8341   UpdateAllLifecyclePhases(web_view_impl);
8342 
8343   // Entering fullscreen causes layout size and page scale limits to be
8344   // overridden.
8345   EXPECT_EQ(100, layout_view->LogicalWidth().Floor());
8346   EXPECT_EQ(200, layout_view->LogicalHeight().Floor());
8347   EXPECT_FLOAT_EQ(1.0, web_view_impl->PageScaleFactor());
8348   EXPECT_FLOAT_EQ(1.0, web_view_impl->MinimumPageScaleFactor());
8349   EXPECT_FLOAT_EQ(1.0, web_view_impl->MaximumPageScaleFactor());
8350 
8351   const char kSource[] = "<meta name=\"viewport\" content=\"width=200\">";
8352 
8353   // Load a new page before exiting fullscreen.
8354   KURL test_url = ToKURL("about:blank");
8355   WebLocalFrame* web_frame = web_view_helper.LocalMainFrame();
8356   frame_test_helpers::LoadHTMLString(web_frame, kSource, test_url);
8357   web_view_impl->DidExitFullscreen();
8358   UpdateAllLifecyclePhases(web_view_impl);
8359 
8360   // Make sure the new page's layout size and scale factor limits aren't
8361   // overridden.
8362   layout_view = web_view_impl->MainFrameImpl()->GetFrameView()->GetLayoutView();
8363   EXPECT_EQ(200, layout_view->LogicalWidth().Floor());
8364   EXPECT_EQ(400, layout_view->LogicalHeight().Floor());
8365   EXPECT_FLOAT_EQ(0.5, web_view_impl->MinimumPageScaleFactor());
8366   EXPECT_FLOAT_EQ(5.0, web_view_impl->MaximumPageScaleFactor());
8367 }
8368 
TEST_F(WebFrameTest,OverlayFullscreenVideo)8369 TEST_F(WebFrameTest, OverlayFullscreenVideo) {
8370   ScopedForceOverlayFullscreenVideoForTest force_overlay_fullscreen_video(true);
8371   RegisterMockedHttpURLLoad("fullscreen_video.html");
8372   frame_test_helpers::TestWebWidgetClient web_widget_client;
8373   frame_test_helpers::WebViewHelper web_view_helper;
8374   WebViewImpl* web_view_impl =
8375       web_view_helper.InitializeAndLoad(base_url_ + "fullscreen_video.html",
8376                                         nullptr, nullptr, &web_widget_client);
8377 
8378   // Ensure that the local frame view has a paint artifact compositor. It's
8379   // created lazily, and doing so after entering fullscreen would undo the
8380   // overlay video layer modification.
8381   UpdateAllLifecyclePhases(web_view_impl);
8382 
8383   const cc::LayerTreeHost* layer_tree_host =
8384       web_widget_client.layer_tree_host();
8385 
8386   LocalFrame* frame = web_view_impl->MainFrameImpl()->GetFrame();
8387   LocalFrame::NotifyUserActivation(
8388       frame, mojom::UserActivationNotificationType::kTest);
8389   auto* video =
8390       To<HTMLVideoElement>(frame->GetDocument()->getElementById("video"));
8391   EXPECT_TRUE(video->UsesOverlayFullscreenVideo());
8392   EXPECT_FALSE(video->IsFullscreen());
8393   EXPECT_EQ(SkColorGetA(layer_tree_host->background_color()), SK_AlphaOPAQUE);
8394 
8395   const cc::Layer* root_layer = layer_tree_host->root_layer();
8396   EXPECT_EQ(1u, CcLayersByName(root_layer, "Scrolling Contents Layer").size());
8397   EXPECT_EQ(1u, CcLayersByDOMElementId(root_layer, "other").size());
8398   // The video is not composited when it's not in full screen.
8399   EXPECT_EQ(0u, CcLayersByDOMElementId(root_layer, "video").size());
8400 
8401   video->webkitEnterFullscreen();
8402   web_view_impl->DidEnterFullscreen();
8403   UpdateAllLifecyclePhases(web_view_impl);
8404   EXPECT_TRUE(video->IsFullscreen());
8405   EXPECT_EQ(SkColorGetA(layer_tree_host->background_color()),
8406             SK_AlphaTRANSPARENT);
8407 
8408   root_layer = layer_tree_host->root_layer();
8409   EXPECT_EQ(0u, CcLayersByName(root_layer, "Scrolling Contents Layer").size());
8410   EXPECT_EQ(0u, CcLayersByDOMElementId(root_layer, "other").size());
8411   EXPECT_EQ(1u, CcLayersByDOMElementId(root_layer, "video").size());
8412 
8413   web_view_impl->DidExitFullscreen();
8414   UpdateAllLifecyclePhases(web_view_impl);
8415   EXPECT_FALSE(video->IsFullscreen());
8416   EXPECT_EQ(SkColorGetA(layer_tree_host->background_color()), SK_AlphaOPAQUE);
8417 
8418   root_layer = layer_tree_host->root_layer();
8419   EXPECT_EQ(1u, CcLayersByName(root_layer, "Scrolling Contents Layer").size());
8420   EXPECT_EQ(1u, CcLayersByDOMElementId(root_layer, "other").size());
8421   // The video is not composited when it's not in full screen.
8422   EXPECT_EQ(0u, CcLayersByDOMElementId(root_layer, "video").size());
8423 }
8424 
TEST_F(WebFrameTest,OverlayFullscreenVideoInIframe)8425 TEST_F(WebFrameTest, OverlayFullscreenVideoInIframe) {
8426   ScopedForceOverlayFullscreenVideoForTest force_overlay_fullscreen_video(true);
8427   RegisterMockedHttpURLLoad("fullscreen_video_in_iframe.html");
8428   RegisterMockedHttpURLLoad("fullscreen_video.html");
8429   frame_test_helpers::TestWebWidgetClient web_widget_client;
8430   frame_test_helpers::WebViewHelper web_view_helper;
8431   WebViewImpl* web_view_impl = web_view_helper.InitializeAndLoad(
8432       base_url_ + "fullscreen_video_in_iframe.html", nullptr, nullptr,
8433       &web_widget_client);
8434 
8435   const cc::LayerTreeHost* layer_tree_host =
8436       web_widget_client.layer_tree_host();
8437   LocalFrame* iframe =
8438       To<WebLocalFrameImpl>(
8439           web_view_helper.GetWebView()->MainFrame()->FirstChild())
8440           ->GetFrame();
8441   LocalFrame::NotifyUserActivation(
8442       iframe, mojom::UserActivationNotificationType::kTest);
8443   auto* video =
8444       To<HTMLVideoElement>(iframe->GetDocument()->getElementById("video"));
8445   EXPECT_TRUE(video->UsesOverlayFullscreenVideo());
8446   EXPECT_FALSE(video->IsFullscreen());
8447   EXPECT_EQ(SkColorGetA(layer_tree_host->background_color()), SK_AlphaOPAQUE);
8448 
8449   video->webkitEnterFullscreen();
8450   web_view_impl->DidEnterFullscreen();
8451   UpdateAllLifecyclePhases(web_view_impl);
8452   EXPECT_TRUE(video->IsFullscreen());
8453   EXPECT_EQ(SkColorGetA(layer_tree_host->background_color()),
8454             SK_AlphaTRANSPARENT);
8455 
8456   web_view_impl->DidExitFullscreen();
8457   UpdateAllLifecyclePhases(web_view_impl);
8458   EXPECT_FALSE(video->IsFullscreen());
8459   EXPECT_EQ(SkColorGetA(layer_tree_host->background_color()), SK_AlphaOPAQUE);
8460 }
8461 
TEST_F(WebFrameTest,WebXrImmersiveOverlay)8462 TEST_F(WebFrameTest, WebXrImmersiveOverlay) {
8463   RegisterMockedHttpURLLoad("webxr_overlay.html");
8464   frame_test_helpers::TestWebWidgetClient web_widget_client;
8465   frame_test_helpers::WebViewHelper web_view_helper;
8466   WebViewImpl* web_view_impl = web_view_helper.InitializeAndLoad(
8467       base_url_ + "webxr_overlay.html", nullptr, nullptr, &web_widget_client);
8468   web_view_helper.Resize(gfx::Size(640, 480));
8469 
8470   // Ensure that the local frame view has a paint artifact compositor. It's
8471   // created lazily, and doing so after entering fullscreen would undo the
8472   // overlay layer modification.
8473   UpdateAllLifecyclePhases(web_view_impl);
8474 
8475   const cc::LayerTreeHost* layer_tree_host =
8476       web_widget_client.layer_tree_host();
8477 
8478   LocalFrame* frame = web_view_impl->MainFrameImpl()->GetFrame();
8479   Document* document = frame->GetDocument();
8480 
8481   Element* overlay = document->getElementById("overlay");
8482   EXPECT_FALSE(Fullscreen::IsFullscreenElement(*overlay));
8483   EXPECT_EQ(SkColorGetA(layer_tree_host->background_color()), SK_AlphaOPAQUE);
8484 
8485   // It's not legal to switch the fullscreen element while in immersive-ar mode,
8486   // so set the fullscreen element first before activating that. This requires
8487   // user activation.
8488   LocalFrame::NotifyUserActivation(
8489       frame, mojom::UserActivationNotificationType::kTest);
8490   Fullscreen::RequestFullscreen(*overlay);
8491   EXPECT_FALSE(document->IsXrOverlay());
8492   document->SetIsXrOverlay(true, overlay);
8493   EXPECT_TRUE(document->IsXrOverlay());
8494 
8495   const cc::Layer* root_layer = layer_tree_host->root_layer();
8496   EXPECT_EQ(1u, CcLayersByName(root_layer, "Scrolling Contents Layer").size());
8497   EXPECT_EQ(1u, CcLayersByDOMElementId(root_layer, "other").size());
8498   // The overlay is not composited when it's not in full screen.
8499   EXPECT_EQ(0u, CcLayersByDOMElementId(root_layer, "overlay").size());
8500   EXPECT_EQ(1u, CcLayersByDOMElementId(root_layer, "inner").size());
8501 
8502   web_view_impl->DidEnterFullscreen();
8503   UpdateAllLifecyclePhases(web_view_impl);
8504   EXPECT_TRUE(Fullscreen::IsFullscreenElement(*overlay));
8505   EXPECT_EQ(SkColorGetA(layer_tree_host->background_color()),
8506             SK_AlphaTRANSPARENT);
8507 
8508   GraphicsLayer* inner_layer =
8509       To<LayoutBoxModelObject>(
8510           frame->GetDocument()->getElementById("inner")->GetLayoutObject())
8511           ->Layer()
8512           ->GetCompositedLayerMapping()
8513           ->MainGraphicsLayer();
8514   EXPECT_TRUE(inner_layer);
8515 
8516   root_layer = layer_tree_host->root_layer();
8517   EXPECT_EQ(0u, CcLayersByName(root_layer, "Scrolling Contents Layer").size());
8518   EXPECT_EQ(0u, CcLayersByDOMElementId(root_layer, "other").size());
8519   EXPECT_EQ(1u, CcLayersByDOMElementId(root_layer, "overlay").size());
8520   EXPECT_EQ(1u, CcLayersByDOMElementId(root_layer, "inner").size());
8521 
8522   web_view_impl->DidExitFullscreen();
8523   UpdateAllLifecyclePhases(web_view_impl);
8524   EXPECT_FALSE(Fullscreen::IsFullscreenElement(*overlay));
8525   EXPECT_EQ(SkColorGetA(layer_tree_host->background_color()), SK_AlphaOPAQUE);
8526   document->SetIsXrOverlay(false, overlay);
8527 
8528   root_layer = layer_tree_host->root_layer();
8529   EXPECT_EQ(1u, CcLayersByName(root_layer, "Scrolling Contents Layer").size());
8530   EXPECT_EQ(1u, CcLayersByDOMElementId(root_layer, "other").size());
8531   // The overlay is not composited when it's not in full screen.
8532   EXPECT_EQ(0u, CcLayersByDOMElementId(root_layer, "overlay").size());
8533   EXPECT_EQ(1u, CcLayersByDOMElementId(root_layer, "inner").size());
8534 }
8535 
TEST_F(WebFrameTest,LayoutBlockPercentHeightDescendants)8536 TEST_F(WebFrameTest, LayoutBlockPercentHeightDescendants) {
8537   RegisterMockedHttpURLLoad("percent-height-descendants.html");
8538   frame_test_helpers::WebViewHelper web_view_helper;
8539   web_view_helper.InitializeAndLoad(base_url_ +
8540                                     "percent-height-descendants.html");
8541 
8542   WebViewImpl* web_view = web_view_helper.GetWebView();
8543   web_view_helper.Resize(gfx::Size(800, 800));
8544   UpdateAllLifecyclePhases(web_view);
8545 
8546   Document* document = web_view->MainFrameImpl()->GetFrame()->GetDocument();
8547   LayoutBlock* container =
8548       To<LayoutBlock>(document->getElementById("container")->GetLayoutObject());
8549   auto* percent_height_in_anonymous =
8550       To<LayoutBox>(document->getElementById("percent-height-in-anonymous")
8551                         ->GetLayoutObject());
8552   auto* percent_height_direct_child =
8553       To<LayoutBox>(document->getElementById("percent-height-direct-child")
8554                         ->GetLayoutObject());
8555 
8556   EXPECT_TRUE(
8557       container->HasPercentHeightDescendant(percent_height_in_anonymous));
8558   EXPECT_TRUE(
8559       container->HasPercentHeightDescendant(percent_height_direct_child));
8560 
8561   ASSERT_TRUE(container->PercentHeightDescendants());
8562   ASSERT_TRUE(container->HasPercentHeightDescendants());
8563   EXPECT_EQ(2U, container->PercentHeightDescendants()->size());
8564   EXPECT_TRUE(container->PercentHeightDescendants()->Contains(
8565       percent_height_in_anonymous));
8566   EXPECT_TRUE(container->PercentHeightDescendants()->Contains(
8567       percent_height_direct_child));
8568 
8569   LayoutBlock* anonymous_block = percent_height_in_anonymous->ContainingBlock();
8570   EXPECT_TRUE(anonymous_block->IsAnonymous());
8571   EXPECT_FALSE(anonymous_block->HasPercentHeightDescendants());
8572 }
8573 
TEST_F(WebFrameTest,HasVisibleContentOnVisibleFrames)8574 TEST_F(WebFrameTest, HasVisibleContentOnVisibleFrames) {
8575   RegisterMockedHttpURLLoad("visible_frames.html");
8576   frame_test_helpers::WebViewHelper web_view_helper;
8577   WebViewImpl* web_view_impl =
8578       web_view_helper.InitializeAndLoad(base_url_ + "visible_frames.html");
8579   for (WebFrame* frame = web_view_impl->MainFrameImpl()->TraverseNext(); frame;
8580        frame = frame->TraverseNext()) {
8581     EXPECT_TRUE(frame->ToWebLocalFrame()->HasVisibleContent());
8582   }
8583 }
8584 
TEST_F(WebFrameTest,HasVisibleContentOnHiddenFrames)8585 TEST_F(WebFrameTest, HasVisibleContentOnHiddenFrames) {
8586   RegisterMockedHttpURLLoad("hidden_frames.html");
8587   frame_test_helpers::WebViewHelper web_view_helper;
8588   WebViewImpl* web_view_impl =
8589       web_view_helper.InitializeAndLoad(base_url_ + "hidden_frames.html");
8590   for (WebFrame* frame = web_view_impl->MainFrameImpl()->TraverseNext(); frame;
8591        frame = frame->TraverseNext()) {
8592     EXPECT_FALSE(frame->ToWebLocalFrame()->HasVisibleContent());
8593   }
8594 }
8595 
FetchManifest(Document * document,const KURL & url)8596 static Resource* FetchManifest(Document* document, const KURL& url) {
8597   FetchParameters fetch_parameters =
8598       FetchParameters::CreateForTest(ResourceRequest(url));
8599   fetch_parameters.SetRequestContext(
8600       mojom::blink::RequestContextType::MANIFEST);
8601 
8602   return RawResource::FetchSynchronously(fetch_parameters, document->Fetcher());
8603 }
8604 
TEST_F(WebFrameTest,ManifestFetch)8605 TEST_F(WebFrameTest, ManifestFetch) {
8606   RegisterMockedHttpURLLoad("foo.html");
8607   RegisterMockedHttpURLLoad("link-manifest-fetch.json");
8608 
8609   frame_test_helpers::WebViewHelper web_view_helper;
8610   web_view_helper.InitializeAndLoad(base_url_ + "foo.html");
8611   Document* document =
8612       web_view_helper.LocalMainFrame()->GetFrame()->GetDocument();
8613 
8614   Resource* resource =
8615       FetchManifest(document, ToKURL(base_url_ + "link-manifest-fetch.json"));
8616 
8617   EXPECT_TRUE(resource->IsLoaded());
8618 }
8619 
TEST_F(WebFrameTest,ManifestCSPFetchAllow)8620 TEST_F(WebFrameTest, ManifestCSPFetchAllow) {
8621   // TODO(crbug.com/751425): We should use the mock functionality
8622   // via the WebViewHelper instance in each test case.
8623   RegisterMockedURLLoadFromBase(not_base_url_, "link-manifest-fetch.json");
8624   RegisterMockedHttpURLLoadWithCSP("foo.html", "manifest-src *");
8625 
8626   frame_test_helpers::WebViewHelper web_view_helper;
8627   web_view_helper.InitializeAndLoad(base_url_ + "foo.html");
8628   Document* document =
8629       web_view_helper.LocalMainFrame()->GetFrame()->GetDocument();
8630 
8631   Resource* resource = FetchManifest(
8632       document, ToKURL(not_base_url_ + "link-manifest-fetch.json"));
8633 
8634   EXPECT_TRUE(resource->IsLoaded());
8635 }
8636 
TEST_F(WebFrameTest,ManifestCSPFetchSelf)8637 TEST_F(WebFrameTest, ManifestCSPFetchSelf) {
8638   // TODO(crbug.com/751425): We should use the mock functionality
8639   // via the WebViewHelper instance in each test case.
8640   RegisterMockedURLLoadFromBase(not_base_url_, "link-manifest-fetch.json");
8641   RegisterMockedHttpURLLoadWithCSP("foo.html", "manifest-src 'self'");
8642 
8643   frame_test_helpers::WebViewHelper web_view_helper;
8644   web_view_helper.InitializeAndLoad(base_url_ + "foo.html");
8645   Document* document =
8646       web_view_helper.LocalMainFrame()->GetFrame()->GetDocument();
8647 
8648   Resource* resource = FetchManifest(
8649       document, ToKURL(not_base_url_ + "link-manifest-fetch.json"));
8650 
8651   // Fetching resource wasn't allowed.
8652   ASSERT_TRUE(resource);
8653   EXPECT_TRUE(resource->ErrorOccurred());
8654   EXPECT_TRUE(resource->GetResourceError().IsAccessCheck());
8655 }
8656 
TEST_F(WebFrameTest,ManifestCSPFetchSelfReportOnly)8657 TEST_F(WebFrameTest, ManifestCSPFetchSelfReportOnly) {
8658   // TODO(crbug.com/751425): We should use the mock functionality
8659   // via the WebViewHelper instance in each test case.
8660   RegisterMockedURLLoadFromBase(not_base_url_, "link-manifest-fetch.json");
8661   RegisterMockedHttpURLLoadWithCSP("foo.html", "manifest-src 'self'",
8662                                    /* report only */ true);
8663 
8664   frame_test_helpers::WebViewHelper web_view_helper;
8665   web_view_helper.InitializeAndLoad(base_url_ + "foo.html");
8666   Document* document =
8667       web_view_helper.LocalMainFrame()->GetFrame()->GetDocument();
8668 
8669   Resource* resource = FetchManifest(
8670       document, ToKURL(not_base_url_ + "link-manifest-fetch.json"));
8671 
8672   EXPECT_TRUE(resource->IsLoaded());
8673 }
8674 
TEST_F(WebFrameTest,ReloadBypassingCache)8675 TEST_F(WebFrameTest, ReloadBypassingCache) {
8676   // Check that a reload bypassing cache on a frame will result in the cache
8677   // policy of the request being set to ReloadBypassingCache.
8678   RegisterMockedHttpURLLoad("foo.html");
8679   TestBeginNavigationCacheModeClient client;
8680   frame_test_helpers::WebViewHelper web_view_helper;
8681   web_view_helper.InitializeAndLoad(base_url_ + "foo.html", &client);
8682   WebLocalFrame* frame = web_view_helper.LocalMainFrame();
8683   frame_test_helpers::ReloadFrameBypassingCache(frame);
8684   EXPECT_EQ(mojom::FetchCacheMode::kBypassCache, client.GetCacheMode());
8685 }
8686 
NodeImageTestValidation(const IntSize & reference_bitmap_size,DragImage * drag_image)8687 static void NodeImageTestValidation(const IntSize& reference_bitmap_size,
8688                                     DragImage* drag_image) {
8689   // Prepare the reference bitmap.
8690   SkBitmap bitmap;
8691   bitmap.allocN32Pixels(reference_bitmap_size.Width(),
8692                         reference_bitmap_size.Height());
8693   SkCanvas canvas(bitmap, SkSurfaceProps{});
8694   canvas.drawColor(SK_ColorGREEN);
8695 
8696   EXPECT_EQ(reference_bitmap_size.Width(), drag_image->Size().Width());
8697   EXPECT_EQ(reference_bitmap_size.Height(), drag_image->Size().Height());
8698   const SkBitmap& drag_bitmap = drag_image->Bitmap();
8699   EXPECT_EQ(0, memcmp(bitmap.getPixels(), drag_bitmap.getPixels(),
8700                       bitmap.computeByteSize()));
8701 }
8702 
TEST_F(WebFrameTest,NodeImageTestCSSTransformDescendant)8703 TEST_F(WebFrameTest, NodeImageTestCSSTransformDescendant) {
8704   frame_test_helpers::WebViewHelper web_view_helper;
8705   std::unique_ptr<DragImage> drag_image = NodeImageTestSetup(
8706       &web_view_helper, std::string("case-css-3dtransform-descendant"));
8707   EXPECT_TRUE(drag_image);
8708 
8709   NodeImageTestValidation(IntSize(40, 40), drag_image.get());
8710 }
8711 
TEST_F(WebFrameTest,NodeImageTestCSSTransform)8712 TEST_F(WebFrameTest, NodeImageTestCSSTransform) {
8713   frame_test_helpers::WebViewHelper web_view_helper;
8714   std::unique_ptr<DragImage> drag_image =
8715       NodeImageTestSetup(&web_view_helper, std::string("case-css-transform"));
8716   EXPECT_TRUE(drag_image);
8717 
8718   NodeImageTestValidation(IntSize(40, 40), drag_image.get());
8719 }
8720 
TEST_F(WebFrameTest,NodeImageTestCSS3DTransform)8721 TEST_F(WebFrameTest, NodeImageTestCSS3DTransform) {
8722   frame_test_helpers::WebViewHelper web_view_helper;
8723   std::unique_ptr<DragImage> drag_image =
8724       NodeImageTestSetup(&web_view_helper, std::string("case-css-3dtransform"));
8725   EXPECT_TRUE(drag_image);
8726 
8727   NodeImageTestValidation(IntSize(40, 40), drag_image.get());
8728 }
8729 
TEST_F(WebFrameTest,NodeImageTestInlineBlock)8730 TEST_F(WebFrameTest, NodeImageTestInlineBlock) {
8731   frame_test_helpers::WebViewHelper web_view_helper;
8732   std::unique_ptr<DragImage> drag_image =
8733       NodeImageTestSetup(&web_view_helper, std::string("case-inlineblock"));
8734   EXPECT_TRUE(drag_image);
8735 
8736   NodeImageTestValidation(IntSize(40, 40), drag_image.get());
8737 }
8738 
TEST_F(WebFrameTest,NodeImageTestFloatLeft)8739 TEST_F(WebFrameTest, NodeImageTestFloatLeft) {
8740   frame_test_helpers::WebViewHelper web_view_helper;
8741   std::unique_ptr<DragImage> drag_image = NodeImageTestSetup(
8742       &web_view_helper, std::string("case-float-left-overflow-hidden"));
8743   EXPECT_TRUE(drag_image);
8744 
8745   NodeImageTestValidation(IntSize(40, 40), drag_image.get());
8746 }
8747 
8748 // Crashes on Android: http://crbug.com/403804
8749 #if defined(OS_ANDROID)
TEST_F(WebFrameTest,DISABLED_PrintingBasic)8750 TEST_F(WebFrameTest, DISABLED_PrintingBasic)
8751 #else
8752 TEST_F(WebFrameTest, PrintingBasic)
8753 #endif
8754 {
8755   frame_test_helpers::WebViewHelper web_view_helper;
8756   web_view_helper.InitializeAndLoad("data:text/html,Hello, world.");
8757 
8758   WebLocalFrame* frame = web_view_helper.LocalMainFrame();
8759 
8760   WebPrintParams print_params;
8761   print_params.print_content_area.width = 500;
8762   print_params.print_content_area.height = 500;
8763 
8764   uint32_t page_count = frame->PrintBegin(print_params, WebNode());
8765   EXPECT_EQ(1u, page_count);
8766   frame->PrintEnd();
8767 }
8768 
8769 class ThemeColorTestLocalFrameHost : public FakeLocalFrameHost {
8770  public:
8771   ThemeColorTestLocalFrameHost() = default;
8772   ~ThemeColorTestLocalFrameHost() override = default;
8773 
Reset()8774   void Reset() { did_notify_ = false; }
8775 
DidNotify() const8776   bool DidNotify() const { return did_notify_; }
8777 
8778  private:
8779   // FakeLocalFrameHost:
DidChangeThemeColor(base::Optional<::SkColor> theme_color)8780   void DidChangeThemeColor(base::Optional<::SkColor> theme_color) override {
8781     did_notify_ = true;
8782   }
8783 
8784   bool did_notify_ = false;
8785 };
8786 
TEST_F(WebFrameTest,ThemeColor)8787 TEST_F(WebFrameTest, ThemeColor) {
8788   RegisterMockedHttpURLLoad("theme_color_test.html");
8789   ThemeColorTestLocalFrameHost host;
8790   frame_test_helpers::TestWebFrameClient client;
8791   host.Init(client.GetRemoteNavigationAssociatedInterfaces());
8792   frame_test_helpers::WebViewHelper web_view_helper;
8793   web_view_helper.InitializeAndLoad(base_url_ + "theme_color_test.html",
8794                                     &client);
8795   EXPECT_TRUE(host.DidNotify());
8796   WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
8797   EXPECT_EQ(Color(0, 0, 255), frame->GetDocument().ThemeColor());
8798   // Change color by rgb.
8799   host.Reset();
8800   frame->ExecuteScript(
8801       WebScriptSource("document.getElementById('tc1').setAttribute('content', "
8802                       "'rgb(0, 0, 0)');"));
8803   RunPendingTasks();
8804   EXPECT_TRUE(host.DidNotify());
8805   EXPECT_EQ(Color::kBlack, frame->GetDocument().ThemeColor());
8806   // Change color by hsl.
8807   host.Reset();
8808   frame->ExecuteScript(
8809       WebScriptSource("document.getElementById('tc1').setAttribute('content', "
8810                       "'hsl(240,100%, 50%)');"));
8811   RunPendingTasks();
8812   EXPECT_TRUE(host.DidNotify());
8813   EXPECT_EQ(Color(0, 0, 255), frame->GetDocument().ThemeColor());
8814   // Change of second theme-color meta tag will not change frame's theme
8815   // color.
8816   host.Reset();
8817   frame->ExecuteScript(WebScriptSource(
8818       "document.getElementById('tc2').setAttribute('content', '#00FF00');"));
8819   RunPendingTasks();
8820   EXPECT_TRUE(host.DidNotify());
8821   EXPECT_EQ(Color(0, 0, 255), frame->GetDocument().ThemeColor());
8822   // Remove the first theme-color meta tag to apply the second.
8823   host.Reset();
8824   frame->ExecuteScript(
8825       WebScriptSource("document.getElementById('tc1').remove();"));
8826   RunPendingTasks();
8827   EXPECT_TRUE(host.DidNotify());
8828   EXPECT_EQ(Color(0, 255, 0), frame->GetDocument().ThemeColor());
8829   // Remove the name attribute of the remaining meta.
8830   host.Reset();
8831   frame->ExecuteScript(WebScriptSource(
8832       "document.getElementById('tc2').removeAttribute('name');"));
8833   RunPendingTasks();
8834   EXPECT_TRUE(host.DidNotify());
8835   EXPECT_EQ(base::nullopt, frame->GetDocument().ThemeColor());
8836 }
8837 
8838 // Make sure that an embedder-triggered detach with a remote frame parent
8839 // doesn't leave behind dangling pointers.
TEST_F(WebFrameTest,EmbedderTriggeredDetachWithRemoteMainFrame)8840 TEST_F(WebFrameTest, EmbedderTriggeredDetachWithRemoteMainFrame) {
8841   frame_test_helpers::WebViewHelper helper;
8842   helper.InitializeRemote();
8843   WebLocalFrame* child_frame =
8844       frame_test_helpers::CreateLocalChild(*helper.RemoteMainFrame());
8845 
8846   // Purposely keep the LocalFrame alive so it's the last thing to be destroyed.
8847   Persistent<Frame> child_core_frame = WebFrame::ToCoreFrame(*child_frame);
8848   helper.Reset();
8849   child_core_frame.Clear();
8850 }
8851 
8852 class WebFrameSwapTestClient : public frame_test_helpers::TestWebFrameClient {
8853  public:
WebFrameSwapTestClient(WebFrameSwapTestClient * parent=nullptr)8854   explicit WebFrameSwapTestClient(WebFrameSwapTestClient* parent = nullptr) {
8855     local_frame_host_ =
8856         std::make_unique<TestLocalFrameHostForFrameOwnerPropertiesChanges>(
8857             parent);
8858     local_frame_host_->Init(GetRemoteNavigationAssociatedInterfaces());
8859   }
8860 
CreateChildFrame(WebLocalFrame * parent,mojom::blink::TreeScopeType scope,const WebString & name,const WebString & fallback_name,const FramePolicy &,const WebFrameOwnerProperties &,mojom::blink::FrameOwnerElementType)8861   WebLocalFrame* CreateChildFrame(
8862       WebLocalFrame* parent,
8863       mojom::blink::TreeScopeType scope,
8864       const WebString& name,
8865       const WebString& fallback_name,
8866       const FramePolicy&,
8867       const WebFrameOwnerProperties&,
8868       mojom::blink::FrameOwnerElementType) override {
8869     return CreateLocalChild(*parent, scope,
8870                             std::make_unique<WebFrameSwapTestClient>(this));
8871   }
8872 
DidChangeFrameOwnerProperties(mojom::blink::FrameOwnerPropertiesPtr properties)8873   void DidChangeFrameOwnerProperties(
8874       mojom::blink::FrameOwnerPropertiesPtr properties) {
8875     did_propagate_display_none_ |= properties->is_display_none;
8876   }
8877 
DidPropagateDisplayNoneProperty() const8878   bool DidPropagateDisplayNoneProperty() const {
8879     return did_propagate_display_none_;
8880   }
8881 
8882  private:
8883   class TestLocalFrameHostForFrameOwnerPropertiesChanges
8884       : public FakeLocalFrameHost {
8885    public:
TestLocalFrameHostForFrameOwnerPropertiesChanges(WebFrameSwapTestClient * parent)8886     explicit TestLocalFrameHostForFrameOwnerPropertiesChanges(
8887         WebFrameSwapTestClient* parent)
8888         : parent_(parent) {}
8889     ~TestLocalFrameHostForFrameOwnerPropertiesChanges() override = default;
8890 
8891     // FakeLocalFrameHost:
DidChangeFrameOwnerProperties(const base::UnguessableToken & child_frame_token,mojom::blink::FrameOwnerPropertiesPtr properties)8892     void DidChangeFrameOwnerProperties(
8893         const base::UnguessableToken& child_frame_token,
8894         mojom::blink::FrameOwnerPropertiesPtr properties) override {
8895       if (parent_)
8896         parent_->DidChangeFrameOwnerProperties(std::move(properties));
8897     }
8898 
8899     bool did_propagate_display_none_ = false;
8900     WebFrameSwapTestClient* parent_ = nullptr;
8901   };
8902 
8903   std::unique_ptr<TestLocalFrameHostForFrameOwnerPropertiesChanges>
8904       local_frame_host_;
8905   bool did_propagate_display_none_ = false;
8906 };
8907 
8908 class WebFrameSwapTest : public WebFrameTest {
8909  protected:
WebFrameSwapTest()8910   WebFrameSwapTest() {
8911     RegisterMockedHttpURLLoad("frame-a-b-c.html");
8912     RegisterMockedHttpURLLoad("subframe-a.html");
8913     RegisterMockedHttpURLLoad("subframe-b.html");
8914     RegisterMockedHttpURLLoad("subframe-c.html");
8915     RegisterMockedHttpURLLoad("subframe-hello.html");
8916 
8917     web_view_helper_.InitializeAndLoad(base_url_ + "frame-a-b-c.html",
8918                                        &main_frame_client_);
8919   }
8920 
Reset()8921   void Reset() { web_view_helper_.Reset(); }
MainFrame() const8922   WebLocalFrame* MainFrame() const { return web_view_helper_.LocalMainFrame(); }
WebView() const8923   WebViewImpl* WebView() const { return web_view_helper_.GetWebView(); }
8924 
8925  private:
8926   frame_test_helpers::WebViewHelper web_view_helper_;
8927   WebFrameSwapTestClient main_frame_client_;
8928 };
8929 
TEST_F(WebFrameSwapTest,SwapMainFrame)8930 TEST_F(WebFrameSwapTest, SwapMainFrame) {
8931   WebRemoteFrame* remote_frame = frame_test_helpers::CreateRemote();
8932   MainFrame()->Swap(remote_frame);
8933 
8934   WebLocalFrame* local_frame =
8935       frame_test_helpers::CreateProvisional(*remote_frame);
8936   remote_frame->Swap(local_frame);
8937 
8938   // Finally, make sure an embedder triggered load in the local frame swapped
8939   // back in works.
8940   frame_test_helpers::LoadFrame(local_frame, base_url_ + "subframe-hello.html");
8941 
8942   std::string content =
8943       WebFrameContentDumper::DumpWebViewAsText(WebView(), 1024).Utf8();
8944   EXPECT_EQ("hello", content);
8945 }
8946 
TEST_F(WebFrameSwapTest,ValidateSizeOnRemoteToLocalMainFrameSwap)8947 TEST_F(WebFrameSwapTest, ValidateSizeOnRemoteToLocalMainFrameSwap) {
8948   gfx::Size size(111, 222);
8949 
8950   WebRemoteFrame* remote_frame = frame_test_helpers::CreateRemote();
8951   MainFrame()->Swap(remote_frame);
8952 
8953   remote_frame->View()->Resize(size);
8954 
8955   WebLocalFrame* local_frame =
8956       frame_test_helpers::CreateProvisional(*remote_frame);
8957   remote_frame->Swap(local_frame);
8958 
8959   // Verify that the size that was set with a remote main frame is correct
8960   // after swapping to a local frame.
8961   Page* page = static_cast<WebViewImpl*>(local_frame->View())
8962                    ->GetPage()
8963                    ->MainFrame()
8964                    ->GetPage();
8965   EXPECT_EQ(size.width(), page->GetVisualViewport().Size().Width());
8966   EXPECT_EQ(size.height(), page->GetVisualViewport().Size().Height());
8967 }
8968 
8969 // Verify that size changes to browser controls while the main frame is remote
8970 // are preserved when the main frame swaps to a local frame.  See
8971 // https://crbug.com/769321.
TEST_F(WebFrameSwapTest,ValidateBrowserControlsSizeOnRemoteToLocalMainFrameSwap)8972 TEST_F(WebFrameSwapTest,
8973        ValidateBrowserControlsSizeOnRemoteToLocalMainFrameSwap) {
8974   WebRemoteFrame* remote_frame = frame_test_helpers::CreateRemote();
8975   MainFrame()->Swap(remote_frame);
8976 
8977   // Create a provisional main frame frame but don't swap it in yet.
8978   WebLocalFrame* local_frame =
8979       frame_test_helpers::CreateProvisional(*remote_frame);
8980 
8981   WebViewImpl* web_view = static_cast<WebViewImpl*>(local_frame->View());
8982   EXPECT_TRUE(web_view->MainFrame() &&
8983               web_view->MainFrame()->IsWebRemoteFrame());
8984 
8985   // Resize the browser controls.
8986   float top_browser_controls_height = 40;
8987   float bottom_browser_controls_height = 60;
8988   web_view->ResizeWithBrowserControls(gfx::Size(100, 100),
8989                                       top_browser_controls_height,
8990                                       bottom_browser_controls_height, false);
8991 
8992   // Swap the provisional frame in and verify that the browser controls size is
8993   // correct.
8994   remote_frame->Swap(local_frame);
8995   Page* page = static_cast<WebViewImpl*>(local_frame->View())
8996                    ->GetPage()
8997                    ->MainFrame()
8998                    ->GetPage();
8999   EXPECT_EQ(top_browser_controls_height,
9000             page->GetBrowserControls().TopHeight());
9001   EXPECT_EQ(bottom_browser_controls_height,
9002             page->GetBrowserControls().BottomHeight());
9003 }
9004 
9005 namespace {
9006 
9007 class SwapMainFrameWhenTitleChangesWebFrameClient
9008     : public frame_test_helpers::TestWebFrameClient {
9009  public:
9010   SwapMainFrameWhenTitleChangesWebFrameClient() = default;
9011   ~SwapMainFrameWhenTitleChangesWebFrameClient() override = default;
9012 
9013   // frame_test_helpers::TestWebFrameClient:
DidReceiveTitle(const WebString & title)9014   void DidReceiveTitle(const WebString& title) override {
9015     if (title.IsEmpty())
9016       return;
9017 
9018     if (!Frame()->Parent())
9019       Frame()->Swap(frame_test_helpers::CreateRemote());
9020   }
9021 };
9022 
9023 }  // namespace
9024 
TEST_F(WebFrameTest,SwapMainFrameWhileLoading)9025 TEST_F(WebFrameTest, SwapMainFrameWhileLoading) {
9026   SwapMainFrameWhenTitleChangesWebFrameClient frame_client;
9027 
9028   frame_test_helpers::WebViewHelper web_view_helper;
9029   RegisterMockedHttpURLLoad("frame-a-b-c.html");
9030   RegisterMockedHttpURLLoad("subframe-a.html");
9031   RegisterMockedHttpURLLoad("subframe-b.html");
9032   RegisterMockedHttpURLLoad("subframe-c.html");
9033   RegisterMockedHttpURLLoad("subframe-hello.html");
9034 
9035   web_view_helper.InitializeAndLoad(base_url_ + "frame-a-b-c.html",
9036                                     &frame_client);
9037 }
9038 
SwapAndVerifyFirstChildConsistency(const char * const message,WebFrame * parent,WebFrame * new_child)9039 void WebFrameTest::SwapAndVerifyFirstChildConsistency(const char* const message,
9040                                                       WebFrame* parent,
9041                                                       WebFrame* new_child) {
9042   SCOPED_TRACE(message);
9043   parent->FirstChild()->Swap(new_child);
9044 
9045   EXPECT_EQ(new_child, parent->FirstChild());
9046   EXPECT_EQ(new_child->Parent(), parent);
9047   EXPECT_EQ(new_child,
9048             parent->LastChild()->PreviousSibling()->PreviousSibling());
9049   EXPECT_EQ(new_child->NextSibling(), parent->LastChild()->PreviousSibling());
9050 }
9051 
TEST_F(WebFrameSwapTest,SwapFirstChild)9052 TEST_F(WebFrameSwapTest, SwapFirstChild) {
9053   WebRemoteFrame* remote_frame = frame_test_helpers::CreateRemote();
9054   SwapAndVerifyFirstChildConsistency("local->remote", MainFrame(),
9055                                      remote_frame);
9056 
9057   WebLocalFrame* local_frame =
9058       frame_test_helpers::CreateProvisional(*remote_frame);
9059   SwapAndVerifyFirstChildConsistency("remote->local", MainFrame(), local_frame);
9060 
9061   // FIXME: This almost certainly fires more load events on the iframe element
9062   // than it should.
9063   // Finally, make sure an embedder triggered load in the local frame swapped
9064   // back in works.
9065   frame_test_helpers::LoadFrame(local_frame, base_url_ + "subframe-hello.html");
9066   std::string content =
9067       WebFrameContentDumper::DumpWebViewAsText(WebView(), 1024).Utf8();
9068   EXPECT_EQ("  \n\nhello\n\nb \n\na\n\nc", content);
9069 }
9070 
TEST_F(WebFrameSwapTest,DoNotPropagateDisplayNonePropertyOnSwap)9071 TEST_F(WebFrameSwapTest, DoNotPropagateDisplayNonePropertyOnSwap) {
9072   WebFrameSwapTestClient* main_frame_client =
9073       static_cast<WebFrameSwapTestClient*>(MainFrame()->Client());
9074   EXPECT_FALSE(main_frame_client->DidPropagateDisplayNoneProperty());
9075 
9076   WebLocalFrame* child_frame = MainFrame()->FirstChild()->ToWebLocalFrame();
9077   frame_test_helpers::LoadFrame(child_frame, "subframe-hello.html");
9078   EXPECT_FALSE(main_frame_client->DidPropagateDisplayNoneProperty());
9079 
9080   WebRemoteFrame* remote_frame = frame_test_helpers::CreateRemote();
9081   child_frame->Swap(remote_frame);
9082   EXPECT_FALSE(main_frame_client->DidPropagateDisplayNoneProperty());
9083 
9084   WebLocalFrame* local_frame =
9085       frame_test_helpers::CreateProvisional(*remote_frame);
9086   remote_frame->Swap(local_frame);
9087   EXPECT_FALSE(main_frame_client->DidPropagateDisplayNoneProperty());
9088   Reset();
9089 }
9090 
SwapAndVerifyMiddleChildConsistency(const char * const message,WebFrame * parent,WebFrame * new_child)9091 void WebFrameTest::SwapAndVerifyMiddleChildConsistency(
9092     const char* const message,
9093     WebFrame* parent,
9094     WebFrame* new_child) {
9095   SCOPED_TRACE(message);
9096   parent->FirstChild()->NextSibling()->Swap(new_child);
9097 
9098   Frame* parent_frame = WebFrame::ToCoreFrame(*parent);
9099   Frame* new_child_frame = WebFrame::ToCoreFrame(*new_child);
9100 
9101   EXPECT_EQ(new_child_frame, parent_frame->FirstChild()->NextSibling());
9102   EXPECT_EQ(new_child_frame, parent_frame->LastChild()->PreviousSibling());
9103   EXPECT_EQ(new_child_frame->Parent(), parent_frame);
9104   EXPECT_EQ(new_child_frame, parent_frame->FirstChild()->NextSibling());
9105   EXPECT_EQ(new_child_frame->PreviousSibling(), parent_frame->FirstChild());
9106   EXPECT_EQ(new_child_frame, parent_frame->LastChild()->PreviousSibling());
9107   EXPECT_EQ(new_child_frame->NextSibling(), parent_frame->LastChild());
9108 }
9109 
TEST_F(WebFrameSwapTest,SwapMiddleChild)9110 TEST_F(WebFrameSwapTest, SwapMiddleChild) {
9111   WebRemoteFrame* remote_frame = frame_test_helpers::CreateRemote();
9112   SwapAndVerifyMiddleChildConsistency("local->remote", MainFrame(),
9113                                       remote_frame);
9114 
9115   WebLocalFrame* local_frame =
9116       frame_test_helpers::CreateProvisional(*remote_frame);
9117   SwapAndVerifyMiddleChildConsistency("remote->local", MainFrame(),
9118                                       local_frame);
9119 
9120   // FIXME: This almost certainly fires more load events on the iframe element
9121   // than it should.
9122   // Finally, make sure an embedder triggered load in the local frame swapped
9123   // back in works.
9124   frame_test_helpers::LoadFrame(local_frame, base_url_ + "subframe-hello.html");
9125   std::string content =
9126       WebFrameContentDumper::DumpWebViewAsText(WebView(), 1024).Utf8();
9127   EXPECT_EQ("  \n\na\n\nhello\n\nc", content);
9128 }
9129 
SwapAndVerifyLastChildConsistency(const char * const message,WebFrame * parent,WebFrame * new_child)9130 void WebFrameTest::SwapAndVerifyLastChildConsistency(const char* const message,
9131                                                      WebFrame* parent,
9132                                                      WebFrame* new_child) {
9133   SCOPED_TRACE(message);
9134   parent->LastChild()->Swap(new_child);
9135 
9136   EXPECT_EQ(new_child, parent->LastChild());
9137   EXPECT_EQ(new_child->Parent(), parent);
9138   EXPECT_EQ(new_child, parent->LastChild()->PreviousSibling()->NextSibling());
9139   EXPECT_EQ(new_child, parent->FirstChild()->NextSibling()->NextSibling());
9140   EXPECT_EQ(new_child->PreviousSibling(), parent->FirstChild()->NextSibling());
9141 }
9142 
TEST_F(WebFrameSwapTest,SwapLastChild)9143 TEST_F(WebFrameSwapTest, SwapLastChild) {
9144   WebRemoteFrame* remote_frame = frame_test_helpers::CreateRemote();
9145   SwapAndVerifyLastChildConsistency("local->remote", MainFrame(), remote_frame);
9146 
9147   WebLocalFrame* local_frame =
9148       frame_test_helpers::CreateProvisional(*remote_frame);
9149   SwapAndVerifyLastChildConsistency("remote->local", MainFrame(), local_frame);
9150 
9151   // FIXME: This almost certainly fires more load events on the iframe element
9152   // than it should.
9153   // Finally, make sure an embedder triggered load in the local frame swapped
9154   // back in works.
9155   frame_test_helpers::LoadFrame(local_frame, base_url_ + "subframe-hello.html");
9156   std::string content =
9157       WebFrameContentDumper::DumpWebViewAsText(WebView(), 1024).Utf8();
9158   EXPECT_EQ("  \n\na\n\nb \n\na\n\nhello", content);
9159 }
9160 
TEST_F(WebFrameSwapTest,DetachProvisionalFrame)9161 TEST_F(WebFrameSwapTest, DetachProvisionalFrame) {
9162   WebRemoteFrameImpl* remote_frame = frame_test_helpers::CreateRemote();
9163   SwapAndVerifyMiddleChildConsistency("local->remote", MainFrame(),
9164                                       remote_frame);
9165 
9166   WebLocalFrameImpl* provisional_frame =
9167       frame_test_helpers::CreateProvisional(*remote_frame);
9168 
9169   // The provisional frame should have a local frame owner.
9170   FrameOwner* owner = provisional_frame->GetFrame()->Owner();
9171   ASSERT_TRUE(owner->IsLocal());
9172 
9173   // But the owner should point to |remoteFrame|, since the new frame is still
9174   // provisional.
9175   EXPECT_EQ(remote_frame->GetFrame(), owner->ContentFrame());
9176 
9177   // After detaching the provisional frame, the frame owner should still point
9178   // at |remoteFrame|.
9179   provisional_frame->Detach();
9180 
9181   // The owner should not be affected by detaching the provisional frame, so it
9182   // should still point to |remoteFrame|.
9183   EXPECT_EQ(remote_frame->GetFrame(), owner->ContentFrame());
9184 }
9185 
SwapAndVerifySubframeConsistency(const char * const message,WebFrame * old_frame,WebFrame * new_frame)9186 void WebFrameTest::SwapAndVerifySubframeConsistency(const char* const message,
9187                                                     WebFrame* old_frame,
9188                                                     WebFrame* new_frame) {
9189   SCOPED_TRACE(message);
9190 
9191   EXPECT_TRUE(old_frame->FirstChild());
9192   old_frame->Swap(new_frame);
9193 
9194   EXPECT_FALSE(new_frame->FirstChild());
9195   EXPECT_FALSE(new_frame->LastChild());
9196 }
9197 
TEST_F(WebFrameSwapTest,EventsOnDisconnectedSubDocumentSkipped)9198 TEST_F(WebFrameSwapTest, EventsOnDisconnectedSubDocumentSkipped) {
9199   WebRemoteFrame* remote_frame = frame_test_helpers::CreateRemote();
9200   WebFrame* target_frame = MainFrame()->FirstChild()->NextSibling();
9201   EXPECT_TRUE(target_frame);
9202   SwapAndVerifySubframeConsistency("local->remote", target_frame, remote_frame);
9203   remote_frame->SetReplicatedOrigin(
9204       WebSecurityOrigin(SecurityOrigin::CreateUniqueOpaque()), false);
9205 
9206   WebLocalFrameImpl* local_child = frame_test_helpers::CreateLocalChild(
9207       *remote_frame, "local-inside-remote");
9208 
9209   LocalFrame* main_frame = WebView()->MainFrameImpl()->GetFrame();
9210   Document* child_document = local_child->GetFrame()->GetDocument();
9211   EventHandlerRegistry& event_registry =
9212       local_child->GetFrame()->GetEventHandlerRegistry();
9213 
9214   // Add the non-connected, but local, child document as having an event.
9215   event_registry.DidAddEventHandler(
9216       *child_document, EventHandlerRegistry::kTouchStartOrMoveEventBlocking);
9217   // Passes if this does not crash or DCHECK.
9218   main_frame->View()->UpdateAllLifecyclePhasesForTest();
9219 }
9220 
TEST_F(WebFrameSwapTest,EventsOnDisconnectedElementSkipped)9221 TEST_F(WebFrameSwapTest, EventsOnDisconnectedElementSkipped) {
9222   WebRemoteFrame* remote_frame = frame_test_helpers::CreateRemote();
9223   WebFrame* target_frame = MainFrame()->FirstChild()->NextSibling();
9224   EXPECT_TRUE(target_frame);
9225   SwapAndVerifySubframeConsistency("local->remote", target_frame, remote_frame);
9226   remote_frame->SetReplicatedOrigin(
9227       WebSecurityOrigin(SecurityOrigin::CreateUniqueOpaque()), false);
9228 
9229   WebLocalFrameImpl* local_child = frame_test_helpers::CreateLocalChild(
9230       *remote_frame, "local-inside-remote");
9231 
9232   LocalFrame* main_frame = WebView()->MainFrameImpl()->GetFrame();
9233 
9234   // Layout ensures that elements in the local_child frame get LayoutObjects
9235   // attached, but doesn't paint, because the child frame needs to not have
9236   // been composited for the purpose of this test.
9237   local_child->GetFrameView()->UpdateLayout();
9238   Document* child_document = local_child->GetFrame()->GetDocument();
9239   EventHandlerRegistry& event_registry =
9240       local_child->GetFrame()->GetEventHandlerRegistry();
9241 
9242   // Add the non-connected body element as having an event.
9243   event_registry.DidAddEventHandler(
9244       *child_document->body(),
9245       EventHandlerRegistry::kTouchStartOrMoveEventBlocking);
9246   // Passes if this does not crash or DCHECK.
9247   main_frame->View()->UpdateAllLifecyclePhasesForTest();
9248 }
9249 
TEST_F(WebFrameSwapTest,SwapParentShouldDetachChildren)9250 TEST_F(WebFrameSwapTest, SwapParentShouldDetachChildren) {
9251   WebRemoteFrame* remote_frame = frame_test_helpers::CreateRemote();
9252   WebFrame* target_frame = MainFrame()->FirstChild()->NextSibling();
9253   EXPECT_TRUE(target_frame);
9254   SwapAndVerifySubframeConsistency("local->remote", target_frame, remote_frame);
9255 
9256   target_frame = MainFrame()->FirstChild()->NextSibling();
9257   EXPECT_TRUE(target_frame);
9258 
9259   // Create child frames in the target frame before testing the swap.
9260   frame_test_helpers::CreateRemoteChild(*remote_frame);
9261 
9262   WebLocalFrame* local_frame =
9263       frame_test_helpers::CreateProvisional(*remote_frame);
9264   SwapAndVerifySubframeConsistency("remote->local", target_frame, local_frame);
9265 
9266   // FIXME: This almost certainly fires more load events on the iframe element
9267   // than it should.
9268   // Finally, make sure an embedder triggered load in the local frame swapped
9269   // back in works.
9270   frame_test_helpers::LoadFrame(local_frame, base_url_ + "subframe-hello.html");
9271   std::string content =
9272       WebFrameContentDumper::DumpWebViewAsText(WebView(), 1024).Utf8();
9273   EXPECT_EQ("  \n\na\n\nhello\n\nc", content);
9274 }
9275 
TEST_F(WebFrameSwapTest,SwapPreservesGlobalContext)9276 TEST_F(WebFrameSwapTest, SwapPreservesGlobalContext) {
9277   v8::HandleScope scope(v8::Isolate::GetCurrent());
9278   v8::Local<v8::Value> window_top =
9279       MainFrame()->ExecuteScriptAndReturnValue(WebScriptSource("window"));
9280   ASSERT_TRUE(window_top->IsObject());
9281   v8::Local<v8::Value> original_window =
9282       MainFrame()->ExecuteScriptAndReturnValue(
9283           WebScriptSource("document.querySelector('#frame2').contentWindow;"));
9284   ASSERT_TRUE(original_window->IsObject());
9285 
9286   // Make sure window reference stays the same when swapping to a remote frame.
9287   WebRemoteFrame* remote_frame = frame_test_helpers::CreateRemote();
9288   WebFrame* target_frame = MainFrame()->FirstChild()->NextSibling();
9289   target_frame->Swap(remote_frame);
9290   v8::Local<v8::Value> remote_window = MainFrame()->ExecuteScriptAndReturnValue(
9291       WebScriptSource("document.querySelector('#frame2').contentWindow;"));
9292   EXPECT_TRUE(original_window->StrictEquals(remote_window));
9293   // Check that its view is consistent with the world.
9294   v8::Local<v8::Value> remote_window_top =
9295       MainFrame()->ExecuteScriptAndReturnValue(WebScriptSource(
9296           "document.querySelector('#frame2').contentWindow.top;"));
9297   EXPECT_TRUE(window_top->StrictEquals(remote_window_top));
9298 
9299   // Now check that remote -> local works too, since it goes through a different
9300   // code path.
9301   WebLocalFrame* local_frame =
9302       frame_test_helpers::CreateProvisional(*remote_frame);
9303   remote_frame->Swap(local_frame);
9304   v8::Local<v8::Value> local_window = MainFrame()->ExecuteScriptAndReturnValue(
9305       WebScriptSource("document.querySelector('#frame2').contentWindow;"));
9306   EXPECT_TRUE(original_window->StrictEquals(local_window));
9307   v8::Local<v8::Value> local_window_top =
9308       MainFrame()->ExecuteScriptAndReturnValue(WebScriptSource(
9309           "document.querySelector('#frame2').contentWindow.top;"));
9310   EXPECT_TRUE(window_top->StrictEquals(local_window_top));
9311 }
9312 
TEST_F(WebFrameSwapTest,SetTimeoutAfterSwap)9313 TEST_F(WebFrameSwapTest, SetTimeoutAfterSwap) {
9314   v8::Isolate* isolate = v8::Isolate::GetCurrent();
9315   v8::HandleScope scope(isolate);
9316   MainFrame()->ExecuteScript(
9317       WebScriptSource("savedSetTimeout = window[0].setTimeout"));
9318 
9319   // Swap the frame to a remote frame.
9320   WebRemoteFrame* remote_frame = frame_test_helpers::CreateRemote();
9321   WebFrame* target_frame = MainFrame()->FirstChild();
9322   target_frame->Swap(remote_frame);
9323   remote_frame->SetReplicatedOrigin(
9324       WebSecurityOrigin(SecurityOrigin::CreateUniqueOpaque()), false);
9325 
9326   // Invoking setTimeout should throw a security error.
9327   {
9328     v8::Local<v8::Value> exception = MainFrame()->ExecuteScriptAndReturnValue(
9329         WebScriptSource("try {\n"
9330                         "  savedSetTimeout.call(window[0], () => {}, 0);\n"
9331                         "} catch (e) { e; }"));
9332     ASSERT_TRUE(!exception.IsEmpty());
9333     EXPECT_EQ(
9334         "SecurityError: Blocked a frame with origin \"http://internal.test\" "
9335         "from accessing a cross-origin frame.",
9336         ToCoreString(exception
9337                          ->ToString(ToScriptStateForMainWorld(
9338                                         WebView()->MainFrameImpl()->GetFrame())
9339                                         ->GetContext())
9340                          .ToLocalChecked()));
9341   }
9342 }
9343 
TEST_F(WebFrameSwapTest,SwapInitializesGlobal)9344 TEST_F(WebFrameSwapTest, SwapInitializesGlobal) {
9345   v8::HandleScope scope(v8::Isolate::GetCurrent());
9346 
9347   v8::Local<v8::Value> window_top =
9348       MainFrame()->ExecuteScriptAndReturnValue(WebScriptSource("window"));
9349   ASSERT_TRUE(window_top->IsObject());
9350 
9351   v8::Local<v8::Value> last_child = MainFrame()->ExecuteScriptAndReturnValue(
9352       WebScriptSource("saved = window[2]"));
9353   ASSERT_TRUE(last_child->IsObject());
9354 
9355   WebRemoteFrame* remote_frame = frame_test_helpers::CreateRemote();
9356   MainFrame()->LastChild()->Swap(remote_frame);
9357   v8::Local<v8::Value> remote_window_top =
9358       MainFrame()->ExecuteScriptAndReturnValue(WebScriptSource("saved.top"));
9359   EXPECT_TRUE(remote_window_top->IsObject());
9360   EXPECT_TRUE(window_top->StrictEquals(remote_window_top));
9361 
9362   WebLocalFrame* local_frame =
9363       frame_test_helpers::CreateProvisional(*remote_frame);
9364   remote_frame->Swap(local_frame);
9365   v8::Local<v8::Value> local_window_top =
9366       MainFrame()->ExecuteScriptAndReturnValue(WebScriptSource("saved.top"));
9367   EXPECT_TRUE(local_window_top->IsObject());
9368   EXPECT_TRUE(window_top->StrictEquals(local_window_top));
9369 }
9370 
TEST_F(WebFrameSwapTest,RemoteFramesAreIndexable)9371 TEST_F(WebFrameSwapTest, RemoteFramesAreIndexable) {
9372   v8::HandleScope scope(v8::Isolate::GetCurrent());
9373 
9374   WebRemoteFrame* remote_frame = frame_test_helpers::CreateRemote();
9375   MainFrame()->LastChild()->Swap(remote_frame);
9376   v8::Local<v8::Value> remote_window =
9377       MainFrame()->ExecuteScriptAndReturnValue(WebScriptSource("window[2]"));
9378   EXPECT_TRUE(remote_window->IsObject());
9379   v8::Local<v8::Value> window_length = MainFrame()->ExecuteScriptAndReturnValue(
9380       WebScriptSource("window.length"));
9381   ASSERT_TRUE(window_length->IsInt32());
9382   EXPECT_EQ(3, window_length.As<v8::Int32>()->Value());
9383 }
9384 
TEST_F(WebFrameSwapTest,RemoteFrameLengthAccess)9385 TEST_F(WebFrameSwapTest, RemoteFrameLengthAccess) {
9386   v8::HandleScope scope(v8::Isolate::GetCurrent());
9387 
9388   WebRemoteFrame* remote_frame = frame_test_helpers::CreateRemote();
9389   MainFrame()->LastChild()->Swap(remote_frame);
9390   v8::Local<v8::Value> remote_window_length =
9391       MainFrame()->ExecuteScriptAndReturnValue(
9392           WebScriptSource("window[2].length"));
9393   ASSERT_TRUE(remote_window_length->IsInt32());
9394   EXPECT_EQ(0, remote_window_length.As<v8::Int32>()->Value());
9395 }
9396 
TEST_F(WebFrameSwapTest,RemoteWindowNamedAccess)9397 TEST_F(WebFrameSwapTest, RemoteWindowNamedAccess) {
9398   v8::HandleScope scope(v8::Isolate::GetCurrent());
9399 
9400   // TODO(dcheng): Once OOPIF unit test infrastructure is in place, test that
9401   // named window access on a remote window works. For now, just test that
9402   // accessing a named property doesn't crash.
9403   WebRemoteFrame* remote_frame = frame_test_helpers::CreateRemote();
9404   MainFrame()->LastChild()->Swap(remote_frame);
9405   remote_frame->SetReplicatedOrigin(
9406       WebSecurityOrigin(SecurityOrigin::CreateUniqueOpaque()), false);
9407   v8::Local<v8::Value> remote_window_property =
9408       MainFrame()->ExecuteScriptAndReturnValue(
9409           WebScriptSource("window[2].foo"));
9410   EXPECT_TRUE(remote_window_property.IsEmpty());
9411 }
9412 
TEST_F(WebFrameSwapTest,RemoteWindowToString)9413 TEST_F(WebFrameSwapTest, RemoteWindowToString) {
9414   v8::Isolate* isolate = v8::Isolate::GetCurrent();
9415   v8::HandleScope scope(isolate);
9416 
9417   WebRemoteFrame* remote_frame = frame_test_helpers::CreateRemote();
9418   MainFrame()->LastChild()->Swap(remote_frame);
9419   v8::Local<v8::Value> to_string_result =
9420       MainFrame()->ExecuteScriptAndReturnValue(
9421           WebScriptSource("Object.prototype.toString.call(window[2])"));
9422   ASSERT_FALSE(to_string_result.IsEmpty());
9423   EXPECT_STREQ("[object Object]",
9424                *v8::String::Utf8Value(isolate, to_string_result));
9425 }
9426 
9427 // TODO(alexmos, dcheng): This test and some other OOPIF tests use
9428 // very little of the test fixture support in WebFrameSwapTest.  We should
9429 // clean these tests up.
TEST_F(WebFrameSwapTest,FramesOfRemoteParentAreIndexable)9430 TEST_F(WebFrameSwapTest, FramesOfRemoteParentAreIndexable) {
9431   v8::HandleScope scope(v8::Isolate::GetCurrent());
9432 
9433   WebRemoteFrame* remote_parent_frame = frame_test_helpers::CreateRemote();
9434   MainFrame()->Swap(remote_parent_frame);
9435   remote_parent_frame->SetReplicatedOrigin(
9436       WebSecurityOrigin(SecurityOrigin::CreateUniqueOpaque()), false);
9437 
9438   WebLocalFrame* child_frame =
9439       frame_test_helpers::CreateLocalChild(*remote_parent_frame);
9440   frame_test_helpers::LoadFrame(child_frame, base_url_ + "subframe-hello.html");
9441 
9442   v8::Local<v8::Value> window =
9443       child_frame->ExecuteScriptAndReturnValue(WebScriptSource("window"));
9444   v8::Local<v8::Value> child_of_remote_parent =
9445       child_frame->ExecuteScriptAndReturnValue(
9446           WebScriptSource("parent.frames[0]"));
9447   EXPECT_TRUE(child_of_remote_parent->IsObject());
9448   EXPECT_TRUE(window->StrictEquals(child_of_remote_parent));
9449 
9450   v8::Local<v8::Value> window_length = child_frame->ExecuteScriptAndReturnValue(
9451       WebScriptSource("parent.frames.length"));
9452   ASSERT_TRUE(window_length->IsInt32());
9453   EXPECT_EQ(1, window_length.As<v8::Int32>()->Value());
9454 }
9455 
9456 // Check that frames with a remote parent don't crash while accessing
9457 // window.frameElement.
TEST_F(WebFrameSwapTest,FrameElementInFramesWithRemoteParent)9458 TEST_F(WebFrameSwapTest, FrameElementInFramesWithRemoteParent) {
9459   v8::HandleScope scope(v8::Isolate::GetCurrent());
9460 
9461   WebRemoteFrame* remote_parent_frame = frame_test_helpers::CreateRemote();
9462   MainFrame()->Swap(remote_parent_frame);
9463   remote_parent_frame->SetReplicatedOrigin(
9464       WebSecurityOrigin(SecurityOrigin::CreateUniqueOpaque()), false);
9465 
9466   WebLocalFrame* child_frame =
9467       frame_test_helpers::CreateLocalChild(*remote_parent_frame);
9468   frame_test_helpers::LoadFrame(child_frame, base_url_ + "subframe-hello.html");
9469 
9470   v8::Local<v8::Value> frame_element = child_frame->ExecuteScriptAndReturnValue(
9471       WebScriptSource("window.frameElement"));
9472   // frameElement should be null if cross-origin.
9473   ASSERT_FALSE(frame_element.IsEmpty());
9474   EXPECT_TRUE(frame_element->IsNull());
9475 }
9476 
9477 class RemoteToLocalSwapWebFrameClient
9478     : public frame_test_helpers::TestWebFrameClient {
9479  public:
RemoteToLocalSwapWebFrameClient(WebRemoteFrame * remote_frame)9480   explicit RemoteToLocalSwapWebFrameClient(WebRemoteFrame* remote_frame)
9481       : history_commit_type_(kWebHistoryInertCommit),
9482         remote_frame_(remote_frame) {}
9483   ~RemoteToLocalSwapWebFrameClient() override = default;
9484 
9485   // frame_test_helpers::TestWebFrameClient:
DidCommitNavigation(const WebHistoryItem &,WebHistoryCommitType history_commit_type,bool)9486   void DidCommitNavigation(const WebHistoryItem&,
9487                            WebHistoryCommitType history_commit_type,
9488                            bool) override {
9489     history_commit_type_ = history_commit_type;
9490     remote_frame_->Swap(Frame());
9491   }
9492 
HistoryCommitType() const9493   WebHistoryCommitType HistoryCommitType() const {
9494     return history_commit_type_;
9495   }
9496 
9497   WebHistoryCommitType history_commit_type_;
9498   WebRemoteFrame* remote_frame_;
9499 };
9500 
9501 // The commit type should be Initial if we are swapping a RemoteFrame to a
9502 // LocalFrame as it is first being created.  This happens when another frame
9503 // exists in the same process, such that we create the RemoteFrame before the
9504 // first navigation occurs.
TEST_F(WebFrameSwapTest,HistoryCommitTypeAfterNewRemoteToLocalSwap)9505 TEST_F(WebFrameSwapTest, HistoryCommitTypeAfterNewRemoteToLocalSwap) {
9506   WebRemoteFrame* remote_frame = frame_test_helpers::CreateRemote();
9507   WebFrame* target_frame = MainFrame()->FirstChild();
9508   ASSERT_TRUE(target_frame);
9509   target_frame->Swap(remote_frame);
9510   ASSERT_TRUE(MainFrame()->FirstChild());
9511   ASSERT_EQ(MainFrame()->FirstChild(), remote_frame);
9512 
9513   RemoteToLocalSwapWebFrameClient client(remote_frame);
9514   WebLocalFrame* local_frame =
9515       frame_test_helpers::CreateProvisional(*remote_frame, &client);
9516   frame_test_helpers::LoadFrame(local_frame, base_url_ + "subframe-hello.html");
9517   EXPECT_EQ(kWebHistoryInertCommit, client.HistoryCommitType());
9518 
9519   // Manually reset to break WebViewHelper's dependency on the stack allocated
9520   // TestWebFrameClient.
9521   Reset();
9522 }
9523 
9524 // The commit type should be Standard if we are swapping a RemoteFrame to a
9525 // LocalFrame after commits have already happened in the frame.  The browser
9526 // process will inform us via setCommittedFirstRealLoad.
TEST_F(WebFrameSwapTest,HistoryCommitTypeAfterExistingRemoteToLocalSwap)9527 TEST_F(WebFrameSwapTest, HistoryCommitTypeAfterExistingRemoteToLocalSwap) {
9528   WebRemoteFrame* remote_frame = frame_test_helpers::CreateRemote();
9529   WebFrame* target_frame = MainFrame()->FirstChild();
9530   ASSERT_TRUE(target_frame);
9531   target_frame->Swap(remote_frame);
9532   ASSERT_TRUE(MainFrame()->FirstChild());
9533   ASSERT_EQ(MainFrame()->FirstChild(), remote_frame);
9534 
9535   RemoteToLocalSwapWebFrameClient client(remote_frame);
9536   WebLocalFrameImpl* local_frame =
9537       frame_test_helpers::CreateProvisional(*remote_frame, &client);
9538   local_frame->SetCommittedFirstRealLoad();
9539   frame_test_helpers::LoadFrame(local_frame, base_url_ + "subframe-hello.html");
9540   EXPECT_EQ(kWebStandardCommit, client.HistoryCommitType());
9541 
9542   // Manually reset to break WebViewHelper's dependency on the stack allocated
9543   // TestWebFrameClient.
9544   Reset();
9545 }
9546 
9547 class RemoteNavigationClient
9548     : public frame_test_helpers::TestWebRemoteFrameClient {
9549  public:
9550   RemoteNavigationClient() = default;
9551   ~RemoteNavigationClient() override = default;
9552 
9553   // frame_test_helpers::TestWebRemoteFrameClient:
Navigate(const WebURLRequest & request,blink::WebLocalFrame * initiator_frame,bool should_replace_current_entry,bool is_opener_navigation,bool initiator_frame_has_download_sandbox_flag,bool blocking_downloads_in_sandbox_enabled,bool initiator_frame_is_ad,CrossVariantMojoRemote<mojom::blink::BlobURLTokenInterfaceBase>,const base::Optional<WebImpression> & impression)9554   void Navigate(const WebURLRequest& request,
9555                 blink::WebLocalFrame* initiator_frame,
9556                 bool should_replace_current_entry,
9557                 bool is_opener_navigation,
9558                 bool initiator_frame_has_download_sandbox_flag,
9559                 bool blocking_downloads_in_sandbox_enabled,
9560                 bool initiator_frame_is_ad,
9561                 CrossVariantMojoRemote<mojom::blink::BlobURLTokenInterfaceBase>,
9562                 const base::Optional<WebImpression>& impression) override {
9563     last_request_.CopyFrom(request);
9564   }
9565 
LastRequest() const9566   const WebURLRequest& LastRequest() const { return last_request_; }
9567 
9568  private:
9569   WebURLRequest last_request_;
9570 };
9571 
TEST_F(WebFrameSwapTest,NavigateRemoteFrameViaLocation)9572 TEST_F(WebFrameSwapTest, NavigateRemoteFrameViaLocation) {
9573   RemoteNavigationClient client;
9574   WebRemoteFrame* remote_frame = frame_test_helpers::CreateRemote(&client);
9575   WebFrame* target_frame = MainFrame()->FirstChild();
9576   ASSERT_TRUE(target_frame);
9577   target_frame->Swap(remote_frame);
9578   ASSERT_TRUE(MainFrame()->FirstChild());
9579   ASSERT_EQ(MainFrame()->FirstChild(), remote_frame);
9580 
9581   remote_frame->SetReplicatedOrigin(
9582       WebSecurityOrigin::CreateFromString("http://127.0.0.1"), false);
9583   MainFrame()->ExecuteScript(
9584       WebScriptSource("document.getElementsByTagName('iframe')[0]."
9585                       "contentWindow.location = 'data:text/html,hi'"));
9586   ASSERT_FALSE(client.LastRequest().IsNull());
9587   EXPECT_EQ(WebURL(ToKURL("data:text/html,hi")), client.LastRequest().Url());
9588 
9589   // Manually reset to break WebViewHelper's dependency on the stack allocated
9590   // TestWebFrameClient.
9591   Reset();
9592 }
9593 
TEST_F(WebFrameSwapTest,WindowOpenOnRemoteFrame)9594 TEST_F(WebFrameSwapTest, WindowOpenOnRemoteFrame) {
9595   RemoteNavigationClient remote_client;
9596   WebRemoteFrame* remote_frame =
9597       frame_test_helpers::CreateRemote(&remote_client);
9598   MainFrame()->FirstChild()->Swap(remote_frame);
9599   remote_frame->SetReplicatedOrigin(
9600       WebSecurityOrigin(SecurityOrigin::CreateUniqueOpaque()), false);
9601 
9602   ASSERT_TRUE(MainFrame()->FirstChild()->IsWebRemoteFrame());
9603   LocalDOMWindow* main_window =
9604       To<WebLocalFrameImpl>(MainFrame())->GetFrame()->DomWindow();
9605 
9606   String destination = "data:text/html:destination";
9607   NonThrowableExceptionState exception_state;
9608   ScriptState* script_state =
9609       ToScriptStateForMainWorld(main_window->GetFrame());
9610   ScriptState::Scope entered_context_scope(script_state);
9611   v8::Context::BackupIncumbentScope incumbent_context_scope(
9612       script_state->GetContext());
9613   main_window->open(script_state->GetIsolate(), destination, "frame1", "",
9614                     exception_state);
9615   ASSERT_FALSE(remote_client.LastRequest().IsNull());
9616   EXPECT_EQ(remote_client.LastRequest().Url(), WebURL(KURL(destination)));
9617 
9618   // Pointing a named frame to an empty URL should just return a reference to
9619   // the frame's window without navigating it.
9620   DOMWindow* result = main_window->open(script_state->GetIsolate(), "",
9621                                         "frame1", "", exception_state);
9622   EXPECT_EQ(remote_client.LastRequest().Url(), WebURL(KURL(destination)));
9623   EXPECT_EQ(result, WebFrame::ToCoreFrame(*remote_frame)->DomWindow());
9624 
9625   Reset();
9626 }
9627 
9628 // blink::mojom::RemoteMainFrameHost instance that intecepts CloseWindowSoon()
9629 // mojo calls and provides a getter to know if it was ever called.
9630 class TestRemoteMainFrameHostForWindowClose : public FakeRemoteMainFrameHost {
9631  public:
9632   TestRemoteMainFrameHostForWindowClose() = default;
9633   ~TestRemoteMainFrameHostForWindowClose() override = default;
9634 
9635   // FakeRemoteMainFrameHost:
RouteCloseEvent()9636   void RouteCloseEvent() override { remote_window_closed_ = true; }
9637 
remote_window_closed() const9638   bool remote_window_closed() const { return remote_window_closed_; }
9639 
9640  private:
9641   bool remote_window_closed_ = false;
9642 };
9643 
9644 class RemoteWindowCloseTest : public WebFrameTest {
9645  public:
RemoteWindowCloseTest()9646   RemoteWindowCloseTest() {
9647     remote_main_frame_host_.Init(
9648         remote_frame_client_.GetRemoteAssociatedInterfaces());
9649   }
9650 
9651   ~RemoteWindowCloseTest() override = default;
9652 
remote_frame_client()9653   frame_test_helpers::TestWebRemoteFrameClient* remote_frame_client() {
9654     return &remote_frame_client_;
9655   }
9656 
Closed() const9657   bool Closed() const { return remote_main_frame_host_.remote_window_closed(); }
9658 
9659  private:
9660   TestRemoteMainFrameHostForWindowClose remote_main_frame_host_;
9661   frame_test_helpers::TestWebRemoteFrameClient remote_frame_client_;
9662 };
9663 
TEST_F(RemoteWindowCloseTest,WindowOpenRemoteClose)9664 TEST_F(RemoteWindowCloseTest, WindowOpenRemoteClose) {
9665   frame_test_helpers::WebViewHelper main_web_view;
9666   main_web_view.Initialize();
9667 
9668   // Create a remote window that will be closed later in the test.
9669   frame_test_helpers::WebViewHelper popup;
9670   popup.InitializeRemote(remote_frame_client(), nullptr, nullptr);
9671   popup.GetWebView()->DidAttachRemoteMainFrame();
9672 
9673   LocalFrame* local_frame = main_web_view.LocalMainFrame()->GetFrame();
9674   RemoteFrame* remote_frame = popup.RemoteMainFrame()->GetFrame();
9675 
9676   remote_frame->SetOpenerDoNotNotify(local_frame);
9677 
9678   // Attempt to close the window, which should fail as it isn't opened
9679   // by a script.
9680   ScriptState* local_script_state = ToScriptStateForMainWorld(local_frame);
9681   ScriptState::Scope entered_context_scope(local_script_state);
9682   v8::Context::BackupIncumbentScope incumbent_context_scope(
9683       local_script_state->GetContext());
9684   remote_frame->DomWindow()->close(local_script_state->GetIsolate());
9685   EXPECT_FALSE(Closed());
9686 
9687   // Marking it as opened by a script should now allow it to be closed.
9688   remote_frame->GetPage()->SetOpenedByDOM();
9689   remote_frame->DomWindow()->close(local_script_state->GetIsolate());
9690 
9691   // The request to close the remote window is not immediately sent to make sure
9692   // that the JS finishes executing, so we need to wait for pending tasks first.
9693   RunPendingTasks();
9694   EXPECT_TRUE(Closed());
9695 }
9696 
TEST_F(WebFrameTest,NavigateRemoteToLocalWithOpener)9697 TEST_F(WebFrameTest, NavigateRemoteToLocalWithOpener) {
9698   frame_test_helpers::WebViewHelper main_web_view;
9699   main_web_view.Initialize();
9700   WebLocalFrame* main_frame = main_web_view.LocalMainFrame();
9701 
9702   // Create a popup with a remote frame and set its opener to the main frame.
9703   frame_test_helpers::WebViewHelper popup_helper;
9704   popup_helper.InitializeRemoteWithOpener(
9705       main_frame, nullptr, SecurityOrigin::CreateFromString("http://foo.com"));
9706   WebRemoteFrame* popup_remote_frame = popup_helper.RemoteMainFrame();
9707   EXPECT_FALSE(main_frame->GetSecurityOrigin().CanAccess(
9708       popup_remote_frame->GetSecurityOrigin()));
9709 
9710   // Do a remote-to-local swap in the popup.
9711   WebLocalFrame* popup_local_frame =
9712       frame_test_helpers::CreateProvisional(*popup_remote_frame);
9713   popup_remote_frame->Swap(popup_local_frame);
9714 
9715   // The initial document created during the remote-to-local swap should have
9716   // inherited its opener's SecurityOrigin.
9717   EXPECT_TRUE(main_frame->GetSecurityOrigin().CanAccess(
9718       popup_helper.LocalMainFrame()->GetSecurityOrigin()));
9719 }
9720 
TEST_F(WebFrameTest,SwapWithOpenerCycle)9721 TEST_F(WebFrameTest, SwapWithOpenerCycle) {
9722   // First, create a remote main frame with itself as the opener.
9723   frame_test_helpers::WebViewHelper helper;
9724   helper.InitializeRemote();
9725   WebRemoteFrame* remote_frame = helper.RemoteMainFrame();
9726   WebFrame::ToCoreFrame(*helper.RemoteMainFrame())
9727       ->SetOpenerDoNotNotify(WebFrame::ToCoreFrame(*remote_frame));
9728 
9729   // Now swap in a local frame. It shouldn't crash.
9730   WebLocalFrame* local_frame =
9731       frame_test_helpers::CreateProvisional(*remote_frame);
9732   remote_frame->Swap(local_frame);
9733 
9734   // And the opener cycle should still be preserved.
9735   EXPECT_EQ(local_frame, local_frame->Opener());
9736 }
9737 
9738 class CommitTypeWebFrameClient : public frame_test_helpers::TestWebFrameClient {
9739  public:
CommitTypeWebFrameClient()9740   CommitTypeWebFrameClient() : history_commit_type_(kWebHistoryInertCommit) {}
9741   ~CommitTypeWebFrameClient() override = default;
9742 
9743   // frame_test_helpers::TestWebFrameClient:
DidCommitNavigation(const WebHistoryItem &,WebHistoryCommitType history_commit_type,bool)9744   void DidCommitNavigation(const WebHistoryItem&,
9745                            WebHistoryCommitType history_commit_type,
9746                            bool) override {
9747     history_commit_type_ = history_commit_type;
9748   }
9749 
HistoryCommitType() const9750   WebHistoryCommitType HistoryCommitType() const {
9751     return history_commit_type_;
9752   }
9753 
9754  private:
9755   WebHistoryCommitType history_commit_type_;
9756 };
9757 
TEST_F(WebFrameTest,RemoteFrameInitialCommitType)9758 TEST_F(WebFrameTest, RemoteFrameInitialCommitType) {
9759   frame_test_helpers::WebViewHelper helper;
9760   helper.InitializeRemote(nullptr, SecurityOrigin::CreateFromString(
9761                                        WebString::FromUTF8(base_url_)));
9762 
9763   // If an iframe has a remote main frame, ensure the inital commit is correctly
9764   // identified as kWebHistoryInertCommit.
9765   CommitTypeWebFrameClient child_frame_client;
9766   WebLocalFrame* child_frame = frame_test_helpers::CreateLocalChild(
9767       *helper.RemoteMainFrame(), "frameName", WebFrameOwnerProperties(),
9768       nullptr, &child_frame_client);
9769   RegisterMockedHttpURLLoad("foo.html");
9770   frame_test_helpers::LoadFrame(child_frame, base_url_ + "foo.html");
9771   EXPECT_EQ(kWebHistoryInertCommit, child_frame_client.HistoryCommitType());
9772 
9773   helper.Reset();
9774 }
9775 
TEST_F(WebFrameTest,DetachRemoteFrame)9776 TEST_F(WebFrameTest, DetachRemoteFrame) {
9777   frame_test_helpers::WebViewHelper helper;
9778   helper.InitializeRemote();
9779   WebRemoteFrame* child_frame =
9780       frame_test_helpers::CreateRemoteChild(*helper.RemoteMainFrame());
9781   child_frame->Detach();
9782 }
9783 
9784 class TestConsoleMessageWebFrameClient
9785     : public frame_test_helpers::TestWebFrameClient {
9786  public:
9787   TestConsoleMessageWebFrameClient() = default;
9788   ~TestConsoleMessageWebFrameClient() override = default;
9789 
9790   // frame_test_helpers::TestWebFrameClient:
DidAddMessageToConsole(const WebConsoleMessage & message,const WebString & source_name,unsigned source_line,const WebString & stack_trace)9791   void DidAddMessageToConsole(const WebConsoleMessage& message,
9792                               const WebString& source_name,
9793                               unsigned source_line,
9794                               const WebString& stack_trace) override {
9795     messages.push_back(message);
9796   }
9797 
9798   Vector<WebConsoleMessage> messages;
9799 };
9800 
TEST_F(WebFrameTest,CrossDomainAccessErrorsUseCallingWindow)9801 TEST_F(WebFrameTest, CrossDomainAccessErrorsUseCallingWindow) {
9802   RegisterMockedHttpURLLoad("hidden_frames.html");
9803   RegisterMockedChromeURLLoad("hello_world.html");
9804 
9805   frame_test_helpers::WebViewHelper web_view_helper;
9806   TestConsoleMessageWebFrameClient web_frame_client;
9807   web_view_helper.InitializeAndLoad(base_url_ + "hidden_frames.html",
9808                                     &web_frame_client);
9809 
9810   // Create another window with a cross-origin page, and point its opener to
9811   // first window.
9812   frame_test_helpers::WebViewHelper popup_web_view_helper;
9813   TestConsoleMessageWebFrameClient popup_web_frame_client;
9814   WebViewImpl* popup_view = popup_web_view_helper.InitializeAndLoad(
9815       chrome_url_ + "hello_world.html", &popup_web_frame_client);
9816   WebFrame::ToCoreFrame(*popup_view->MainFrame())
9817       ->SetOpenerDoNotNotify(
9818           WebFrame::ToCoreFrame(*web_view_helper.GetWebView()->MainFrame()));
9819 
9820   // Attempt a blocked navigation of an opener's subframe, and ensure that
9821   // the error shows up on the popup (calling) window's console, rather than
9822   // the target window.
9823   popup_view->MainFrameImpl()->ExecuteScript(WebScriptSource(
9824       "try { opener.frames[1].location.href='data:text/html,foo'; } catch (e) "
9825       "{}"));
9826   EXPECT_TRUE(web_frame_client.messages.IsEmpty());
9827   ASSERT_EQ(1u, popup_web_frame_client.messages.size());
9828   EXPECT_TRUE(std::string::npos !=
9829               popup_web_frame_client.messages[0].text.Utf8().find(
9830                   "Unsafe JavaScript attempt to initiate navigation"));
9831 
9832   // Try setting a cross-origin iframe element's source to a javascript: URL,
9833   // and check that this error is also printed on the calling window.
9834   popup_view->MainFrameImpl()->ExecuteScript(
9835       WebScriptSource("opener.document.querySelectorAll('iframe')[1].src='"
9836                       "javascript:alert()'"));
9837   EXPECT_TRUE(web_frame_client.messages.IsEmpty());
9838   ASSERT_EQ(2u, popup_web_frame_client.messages.size());
9839   EXPECT_TRUE(
9840       std::string::npos !=
9841       popup_web_frame_client.messages[1].text.Utf8().find("Blocked a frame"));
9842 
9843   // Manually reset to break WebViewHelpers' dependencies on the stack
9844   // allocated WebLocalFrameClients.
9845   web_view_helper.Reset();
9846   popup_web_view_helper.Reset();
9847 }
9848 
TEST_F(WebFrameTest,ResizeInvalidatesDeviceMediaQueries)9849 TEST_F(WebFrameTest, ResizeInvalidatesDeviceMediaQueries) {
9850   RegisterMockedHttpURLLoad("device_media_queries.html");
9851   FixedLayoutTestWebWidgetClient client;
9852   frame_test_helpers::WebViewHelper web_view_helper;
9853   web_view_helper.InitializeAndLoad(base_url_ + "device_media_queries.html",
9854                                     nullptr, nullptr, &client,
9855                                     ConfigureAndroid);
9856   auto* frame =
9857       To<LocalFrame>(web_view_helper.GetWebView()->GetPage()->MainFrame());
9858   Element* element = frame->GetDocument()->getElementById("test");
9859   ASSERT_TRUE(element);
9860 
9861   client.screen_info_.available_rect = gfx::Rect(700, 500);
9862   UpdateScreenInfoAndResizeView(&client, &web_view_helper,
9863                                 client.screen_info_.available_rect.width(),
9864                                 client.screen_info_.available_rect.height());
9865   EXPECT_EQ(300, element->OffsetWidth());
9866   EXPECT_EQ(300, element->OffsetHeight());
9867 
9868   client.screen_info_.available_rect = gfx::Rect(710, 500);
9869   UpdateScreenInfoAndResizeView(&client, &web_view_helper,
9870                                 client.screen_info_.available_rect.width(),
9871                                 client.screen_info_.available_rect.height());
9872   EXPECT_EQ(400, element->OffsetWidth());
9873   EXPECT_EQ(300, element->OffsetHeight());
9874 
9875   client.screen_info_.available_rect = gfx::Rect(690, 500);
9876   UpdateScreenInfoAndResizeView(&client, &web_view_helper,
9877                                 client.screen_info_.available_rect.width(),
9878                                 client.screen_info_.available_rect.height());
9879   EXPECT_EQ(200, element->OffsetWidth());
9880   EXPECT_EQ(300, element->OffsetHeight());
9881 
9882   client.screen_info_.available_rect = gfx::Rect(700, 510);
9883   UpdateScreenInfoAndResizeView(&client, &web_view_helper,
9884                                 client.screen_info_.available_rect.width(),
9885                                 client.screen_info_.available_rect.height());
9886   EXPECT_EQ(300, element->OffsetWidth());
9887   EXPECT_EQ(400, element->OffsetHeight());
9888 
9889   client.screen_info_.available_rect = gfx::Rect(700, 490);
9890   UpdateScreenInfoAndResizeView(&client, &web_view_helper,
9891                                 client.screen_info_.available_rect.width(),
9892                                 client.screen_info_.available_rect.height());
9893   EXPECT_EQ(300, element->OffsetWidth());
9894   EXPECT_EQ(200, element->OffsetHeight());
9895 
9896   client.screen_info_.available_rect = gfx::Rect(690, 510);
9897   UpdateScreenInfoAndResizeView(&client, &web_view_helper,
9898                                 client.screen_info_.available_rect.width(),
9899                                 client.screen_info_.available_rect.height());
9900   EXPECT_EQ(200, element->OffsetWidth());
9901   EXPECT_EQ(400, element->OffsetHeight());
9902 }
9903 
9904 class DeviceEmulationTest : public WebFrameTest {
9905  protected:
DeviceEmulationTest()9906   DeviceEmulationTest() {
9907     RegisterMockedHttpURLLoad("device_emulation.html");
9908     client_.screen_info_.device_scale_factor = 1;
9909     web_view_helper_.InitializeAndLoad(base_url_ + "device_emulation.html",
9910                                        nullptr, nullptr, &client_);
9911   }
9912 
TestResize(const gfx::Size & size,const String & expected_size)9913   void TestResize(const gfx::Size& size, const String& expected_size) {
9914     client_.screen_info_.available_rect = gfx::Rect(size);
9915     UpdateScreenInfoAndResizeView(&client_, &web_view_helper_,
9916                                   client_.screen_info_.available_rect.width(),
9917                                   client_.screen_info_.available_rect.height());
9918     EXPECT_EQ(expected_size, DumpSize("test"));
9919   }
9920 
DumpSize(const String & id)9921   String DumpSize(const String& id) {
9922     String code = "dumpSize('" + id + "')";
9923     v8::HandleScope scope(v8::Isolate::GetCurrent());
9924     ScriptExecutionCallbackHelper callback_helper(
9925         web_view_helper_.LocalMainFrame()->MainWorldScriptContext());
9926     web_view_helper_.GetWebView()
9927         ->MainFrameImpl()
9928         ->RequestExecuteScriptAndReturnValue(WebScriptSource(WebString(code)),
9929                                              false, &callback_helper);
9930     RunPendingTasks();
9931     EXPECT_TRUE(callback_helper.DidComplete());
9932     return callback_helper.StringValue();
9933   }
9934 
9935   FixedLayoutTestWebWidgetClient client_;
9936   frame_test_helpers::WebViewHelper web_view_helper_;
9937 };
9938 
TEST_F(DeviceEmulationTest,DeviceSizeInvalidatedOnResize)9939 TEST_F(DeviceEmulationTest, DeviceSizeInvalidatedOnResize) {
9940   DeviceEmulationParams params;
9941   params.screen_type = mojom::EmulatedScreenType::kMobile;
9942   web_view_helper_.GetWebView()->EnableDeviceEmulation(params);
9943 
9944   TestResize(gfx::Size(700, 500), "300x300");
9945   TestResize(gfx::Size(710, 500), "400x300");
9946   TestResize(gfx::Size(690, 500), "200x300");
9947   TestResize(gfx::Size(700, 510), "300x400");
9948   TestResize(gfx::Size(700, 490), "300x200");
9949   TestResize(gfx::Size(710, 510), "400x400");
9950   TestResize(gfx::Size(690, 490), "200x200");
9951   TestResize(gfx::Size(800, 600), "400x400");
9952 
9953   web_view_helper_.GetWebView()->DisableDeviceEmulation();
9954 }
9955 
TEST_F(DeviceEmulationTest,PointerAndHoverTypes)9956 TEST_F(DeviceEmulationTest, PointerAndHoverTypes) {
9957   web_view_helper_.GetWebView()
9958       ->GetDevToolsEmulator()
9959       ->SetTouchEventEmulationEnabled(true, 1);
9960   EXPECT_EQ("20x20", DumpSize("pointer"));
9961   web_view_helper_.GetWebView()
9962       ->GetDevToolsEmulator()
9963       ->SetTouchEventEmulationEnabled(false, 1);
9964 }
9965 
TEST_F(WebFrameTest,CreateLocalChildWithPreviousSibling)9966 TEST_F(WebFrameTest, CreateLocalChildWithPreviousSibling) {
9967   frame_test_helpers::WebViewHelper helper;
9968   helper.InitializeRemote();
9969   WebRemoteFrame* parent = helper.RemoteMainFrame();
9970 
9971   WebLocalFrame* second_frame(
9972       frame_test_helpers::CreateLocalChild(*parent, "name2"));
9973   WebLocalFrame* fourth_frame(frame_test_helpers::CreateLocalChild(
9974       *parent, "name4", WebFrameOwnerProperties(), second_frame));
9975   WebLocalFrame* third_frame(frame_test_helpers::CreateLocalChild(
9976       *parent, "name3", WebFrameOwnerProperties(), second_frame));
9977   WebLocalFrame* first_frame(
9978       frame_test_helpers::CreateLocalChild(*parent, "name1"));
9979 
9980   EXPECT_EQ(first_frame, parent->FirstChild());
9981   EXPECT_EQ(nullptr, first_frame->PreviousSibling());
9982   EXPECT_EQ(second_frame, first_frame->NextSibling());
9983 
9984   EXPECT_EQ(first_frame, second_frame->PreviousSibling());
9985   EXPECT_EQ(third_frame, second_frame->NextSibling());
9986 
9987   EXPECT_EQ(second_frame, third_frame->PreviousSibling());
9988   EXPECT_EQ(fourth_frame, third_frame->NextSibling());
9989 
9990   EXPECT_EQ(third_frame, fourth_frame->PreviousSibling());
9991   EXPECT_EQ(nullptr, fourth_frame->NextSibling());
9992   EXPECT_EQ(fourth_frame, parent->LastChild());
9993 
9994   EXPECT_EQ(parent, first_frame->Parent());
9995   EXPECT_EQ(parent, second_frame->Parent());
9996   EXPECT_EQ(parent, third_frame->Parent());
9997   EXPECT_EQ(parent, fourth_frame->Parent());
9998 }
9999 
TEST_F(WebFrameTest,SendBeaconFromChildWithRemoteMainFrame)10000 TEST_F(WebFrameTest, SendBeaconFromChildWithRemoteMainFrame) {
10001   frame_test_helpers::WebViewHelper helper;
10002   helper.InitializeRemote();
10003 
10004   WebLocalFrame* local_frame =
10005       frame_test_helpers::CreateLocalChild(*helper.RemoteMainFrame());
10006 
10007   // Finally, make sure an embedder triggered load in the local frame swapped
10008   // back in works.
10009   RegisterMockedHttpURLLoad("send_beacon.html");
10010   RegisterMockedHttpURLLoad("reload_post.html");  // url param to sendBeacon()
10011   frame_test_helpers::LoadFrame(local_frame, base_url_ + "send_beacon.html");
10012   // Wait for the post.
10013   frame_test_helpers::PumpPendingRequestsForFrameToLoad(local_frame);
10014 }
10015 
TEST_F(WebFrameTest,SiteForCookiesFromChildWithRemoteMainFrame)10016 TEST_F(WebFrameTest, SiteForCookiesFromChildWithRemoteMainFrame) {
10017   frame_test_helpers::WebViewHelper helper;
10018   helper.InitializeRemote(nullptr,
10019                           SecurityOrigin::Create(ToKURL(not_base_url_)));
10020 
10021   WebLocalFrame* local_frame =
10022       frame_test_helpers::CreateLocalChild(*helper.RemoteMainFrame());
10023 
10024   RegisterMockedHttpURLLoad("foo.html");
10025   frame_test_helpers::LoadFrame(local_frame, base_url_ + "foo.html");
10026   EXPECT_TRUE(local_frame->GetDocument().SiteForCookies().IsNull());
10027 
10028   SchemeRegistry::RegisterURLSchemeAsFirstPartyWhenTopLevel("http");
10029   EXPECT_TRUE(net::SiteForCookies::FromUrl(ToKURL(not_base_url_))
10030                   .IsEquivalent(local_frame->GetDocument().SiteForCookies()));
10031   SchemeRegistry::RemoveURLSchemeAsFirstPartyWhenTopLevel("http");
10032 }
10033 
10034 // See https://crbug.com/525285.
TEST_F(WebFrameTest,RemoteToLocalSwapOnMainFrameInitializesCoreFrame)10035 TEST_F(WebFrameTest, RemoteToLocalSwapOnMainFrameInitializesCoreFrame) {
10036   frame_test_helpers::WebViewHelper helper;
10037   helper.InitializeRemote();
10038 
10039   frame_test_helpers::CreateLocalChild(*helper.RemoteMainFrame());
10040 
10041   // Do a remote-to-local swap of the top frame.
10042   WebLocalFrame* local_root =
10043       frame_test_helpers::CreateProvisional(*helper.RemoteMainFrame());
10044   helper.RemoteMainFrame()->Swap(local_root);
10045 
10046   // Load a page with a child frame in the new root to make sure this doesn't
10047   // crash when the child frame invokes setCoreFrame.
10048   RegisterMockedHttpURLLoad("single_iframe.html");
10049   RegisterMockedHttpURLLoad("visible_iframe.html");
10050   frame_test_helpers::LoadFrame(local_root, base_url_ + "single_iframe.html");
10051 }
10052 
10053 // See https://crbug.com/628942.
TEST_F(WebFrameTest,PausedPageLoadWithRemoteMainFrame)10054 TEST_F(WebFrameTest, PausedPageLoadWithRemoteMainFrame) {
10055   frame_test_helpers::WebViewHelper helper;
10056   helper.InitializeRemote();
10057   WebRemoteFrameImpl* remote_root = helper.RemoteMainFrame();
10058 
10059   // Check that ScopedPagePauser properly triggers deferred loading for
10060   // the current Page.
10061   Page* page = remote_root->GetFrame()->GetPage();
10062   EXPECT_FALSE(page->Paused());
10063   {
10064     ScopedPagePauser pauser;
10065     EXPECT_TRUE(page->Paused());
10066   }
10067   EXPECT_FALSE(page->Paused());
10068 
10069   // Repeat this for a page with a local child frame, and ensure that the
10070   // child frame's loads are also suspended.
10071   WebLocalFrameImpl* web_local_child =
10072       frame_test_helpers::CreateLocalChild(*remote_root);
10073   RegisterMockedHttpURLLoad("foo.html");
10074   frame_test_helpers::LoadFrame(web_local_child, base_url_ + "foo.html");
10075   LocalFrame* local_child = web_local_child->GetFrame();
10076   EXPECT_FALSE(page->Paused());
10077   EXPECT_FALSE(
10078       local_child->GetDocument()->Fetcher()->GetProperties().IsPaused());
10079   {
10080     ScopedPagePauser pauser;
10081     EXPECT_TRUE(page->Paused());
10082     EXPECT_TRUE(
10083         local_child->GetDocument()->Fetcher()->GetProperties().IsPaused());
10084   }
10085   EXPECT_FALSE(page->Paused());
10086   EXPECT_FALSE(
10087       local_child->GetDocument()->Fetcher()->GetProperties().IsPaused());
10088 }
10089 
10090 class OverscrollWidgetInputHandlerHost
10091     : public frame_test_helpers::TestWidgetInputHandlerHost {
10092  public:
10093   MOCK_METHOD5(DidOverscroll,
10094                void(const gfx::Vector2dF&,
10095                     const gfx::Vector2dF&,
10096                     const gfx::PointF&,
10097                     const gfx::Vector2dF&,
10098                     cc::OverscrollBehavior));
10099 
DidOverscroll(mojom::blink::DidOverscrollParamsPtr params)10100   void DidOverscroll(mojom::blink::DidOverscrollParamsPtr params) override {
10101     DidOverscroll(params->latest_overscroll_delta,
10102                   params->accumulated_overscroll,
10103                   params->causal_event_viewport_point,
10104                   params->current_fling_velocity, params->overscroll_behavior);
10105   }
10106 };
10107 
10108 class OverscrollWebWidgetClient
10109     : public frame_test_helpers::TestWebWidgetClient {
10110  public:
10111   OverscrollWebWidgetClient() = default;
10112 
GetInputHandlerHost()10113   frame_test_helpers::TestWidgetInputHandlerHost* GetInputHandlerHost()
10114       override {
10115     return &input_handler_host_;
10116   }
10117 
GetOverscrollWidgetInputHandlerHost()10118   OverscrollWidgetInputHandlerHost& GetOverscrollWidgetInputHandlerHost() {
10119     return input_handler_host_;
10120   }
10121 
10122  private:
10123   OverscrollWidgetInputHandlerHost input_handler_host_;
10124 };
10125 
10126 class WebFrameOverscrollTest
10127     : public WebFrameTest,
10128       public testing::WithParamInterface<WebGestureDevice> {
10129  public:
WebFrameOverscrollTest()10130   WebFrameOverscrollTest() {}
10131 
10132  protected:
GenerateEvent(WebInputEvent::Type type,float delta_x=0.0,float delta_y=0.0)10133   WebCoalescedInputEvent GenerateEvent(WebInputEvent::Type type,
10134                                        float delta_x = 0.0,
10135                                        float delta_y = 0.0) {
10136     WebGestureEvent event(type, WebInputEvent::kNoModifiers,
10137                           WebInputEvent::GetStaticTimeStampForTests(),
10138                           GetParam());
10139     // TODO(wjmaclean): Make sure that touchpad device is only ever used for
10140     // gesture scrolling event types.
10141     event.SetPositionInWidget(gfx::PointF(100, 100));
10142     if (type == WebInputEvent::Type::kGestureScrollUpdate) {
10143       event.data.scroll_update.delta_x = delta_x;
10144       event.data.scroll_update.delta_y = delta_y;
10145     } else if (type == WebInputEvent::Type::kGestureScrollBegin) {
10146       event.data.scroll_begin.delta_x_hint = delta_x;
10147       event.data.scroll_begin.delta_y_hint = delta_y;
10148     }
10149     return WebCoalescedInputEvent(event, ui::LatencyInfo());
10150   }
10151 
ScrollBegin(frame_test_helpers::WebViewHelper * web_view_helper,float delta_x_hint,float delta_y_hint)10152   void ScrollBegin(frame_test_helpers::WebViewHelper* web_view_helper,
10153                    float delta_x_hint,
10154                    float delta_y_hint) {
10155     web_view_helper->GetWebView()->MainFrameWidget()->HandleInputEvent(
10156         GenerateEvent(WebInputEvent::Type::kGestureScrollBegin, delta_x_hint,
10157                       delta_y_hint));
10158   }
10159 
ScrollUpdate(frame_test_helpers::WebViewHelper * web_view_helper,float delta_x,float delta_y)10160   void ScrollUpdate(frame_test_helpers::WebViewHelper* web_view_helper,
10161                     float delta_x,
10162                     float delta_y) {
10163     web_view_helper->GetWebView()->MainFrameWidget()->HandleInputEvent(
10164         GenerateEvent(WebInputEvent::Type::kGestureScrollUpdate, delta_x,
10165                       delta_y));
10166   }
10167 
ScrollEnd(frame_test_helpers::WebViewHelper * web_view_helper)10168   void ScrollEnd(frame_test_helpers::WebViewHelper* web_view_helper) {
10169     web_view_helper->GetWebView()->MainFrameWidget()->HandleInputEvent(
10170         GenerateEvent(WebInputEvent::Type::kGestureScrollEnd));
10171   }
10172 };
10173 
10174 INSTANTIATE_TEST_SUITE_P(All,
10175                          WebFrameOverscrollTest,
10176                          testing::Values(WebGestureDevice::kTouchpad,
10177                                          WebGestureDevice::kTouchscreen));
10178 
TEST_P(WebFrameOverscrollTest,AccumulatedRootOverscrollAndUnsedDeltaValuesOnOverscroll)10179 TEST_P(WebFrameOverscrollTest,
10180        AccumulatedRootOverscrollAndUnsedDeltaValuesOnOverscroll) {
10181   OverscrollWebWidgetClient client;
10182   RegisterMockedHttpURLLoad("overscroll/overscroll.html");
10183   frame_test_helpers::WebViewHelper web_view_helper;
10184 
10185   web_view_helper.InitializeAndLoad(base_url_ + "overscroll/overscroll.html",
10186                                     nullptr, nullptr, &client,
10187                                     ConfigureAndroid);
10188   web_view_helper.Resize(gfx::Size(200, 200));
10189 
10190   // Calculation of accumulatedRootOverscroll and unusedDelta on multiple
10191   // scrollUpdate.
10192   ScrollBegin(&web_view_helper, -300, -316);
10193   EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
10194               DidOverscroll(gfx::Vector2dF(8, 16), gfx::Vector2dF(8, 16),
10195                             gfx::PointF(100, 100), gfx::Vector2dF(),
10196                             kOverscrollBehaviorAuto));
10197   ScrollUpdate(&web_view_helper, -308, -316);
10198   base::RunLoop().RunUntilIdle();
10199   Mock::VerifyAndClearExpectations(
10200       &client.GetOverscrollWidgetInputHandlerHost());
10201 
10202   EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
10203               DidOverscroll(gfx::Vector2dF(0, 13), gfx::Vector2dF(8, 29),
10204                             gfx::PointF(100, 100), gfx::Vector2dF(),
10205                             kOverscrollBehaviorAuto));
10206   ScrollUpdate(&web_view_helper, 0, -13);
10207   base::RunLoop().RunUntilIdle();
10208   Mock::VerifyAndClearExpectations(
10209       &client.GetOverscrollWidgetInputHandlerHost());
10210 
10211   EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
10212               DidOverscroll(gfx::Vector2dF(20, 13), gfx::Vector2dF(28, 42),
10213                             gfx::PointF(100, 100), gfx::Vector2dF(),
10214                             kOverscrollBehaviorAuto));
10215   ScrollUpdate(&web_view_helper, -20, -13);
10216   base::RunLoop().RunUntilIdle();
10217   Mock::VerifyAndClearExpectations(
10218       &client.GetOverscrollWidgetInputHandlerHost());
10219 
10220   // Overscroll is not reported.
10221   EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
10222               DidOverscroll(_, _, _, _, _))
10223       .Times(0);
10224   ScrollUpdate(&web_view_helper, 0, 1);
10225   base::RunLoop().RunUntilIdle();
10226   Mock::VerifyAndClearExpectations(
10227       &client.GetOverscrollWidgetInputHandlerHost());
10228 
10229   EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
10230               DidOverscroll(_, _, _, _, _))
10231       .Times(0);
10232   ScrollUpdate(&web_view_helper, 1, 0);
10233   base::RunLoop().RunUntilIdle();
10234   Mock::VerifyAndClearExpectations(
10235       &client.GetOverscrollWidgetInputHandlerHost());
10236 
10237   // Overscroll is reported.
10238   EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
10239               DidOverscroll(gfx::Vector2dF(0, -701), gfx::Vector2dF(0, -701),
10240                             gfx::PointF(100, 100), gfx::Vector2dF(),
10241                             kOverscrollBehaviorAuto));
10242   ScrollUpdate(&web_view_helper, 0, 1000);
10243   base::RunLoop().RunUntilIdle();
10244   Mock::VerifyAndClearExpectations(
10245       &client.GetOverscrollWidgetInputHandlerHost());
10246 
10247   // Overscroll is not reported.
10248   EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
10249               DidOverscroll(_, _, _, _, _))
10250       .Times(0);
10251   ScrollEnd(&web_view_helper);
10252   base::RunLoop().RunUntilIdle();
10253   Mock::VerifyAndClearExpectations(
10254       &client.GetOverscrollWidgetInputHandlerHost());
10255 }
10256 
TEST_P(WebFrameOverscrollTest,AccumulatedOverscrollAndUnusedDeltaValuesOnDifferentAxesOverscroll)10257 TEST_P(WebFrameOverscrollTest,
10258        AccumulatedOverscrollAndUnusedDeltaValuesOnDifferentAxesOverscroll) {
10259   OverscrollWebWidgetClient client;
10260   RegisterMockedHttpURLLoad("overscroll/div-overscroll.html");
10261   frame_test_helpers::WebViewHelper web_view_helper;
10262 
10263   web_view_helper.InitializeAndLoad(
10264       base_url_ + "overscroll/div-overscroll.html", nullptr, nullptr, &client,
10265       ConfigureAndroid);
10266   web_view_helper.Resize(gfx::Size(200, 200));
10267 
10268   ScrollBegin(&web_view_helper, 0, -316);
10269 
10270   // Scroll the Div to the end.
10271   EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
10272               DidOverscroll(_, _, _, _, _))
10273       .Times(0);
10274   ScrollUpdate(&web_view_helper, 0, -316);
10275   base::RunLoop().RunUntilIdle();
10276   Mock::VerifyAndClearExpectations(
10277       &client.GetOverscrollWidgetInputHandlerHost());
10278 
10279   ScrollEnd(&web_view_helper);
10280   ScrollBegin(&web_view_helper, 0, -100);
10281 
10282   // Now On Scrolling DIV, scroll is bubbled and root layer is over-scrolled.
10283   EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
10284               DidOverscroll(gfx::Vector2dF(0, 100), gfx::Vector2dF(0, 100),
10285                             gfx::PointF(100, 100), gfx::Vector2dF(),
10286                             kOverscrollBehaviorAuto));
10287   ScrollUpdate(&web_view_helper, 0, -100);
10288   ScrollUpdate(&web_view_helper, 0, -100);
10289   base::RunLoop().RunUntilIdle();
10290   Mock::VerifyAndClearExpectations(
10291       &client.GetOverscrollWidgetInputHandlerHost());
10292 
10293   // TODO(bokan): This has never worked but by the accident that this test was
10294   // being run in a WebView without a size. This test should be fixed along with
10295   // the bug, crbug.com/589320.
10296   // Page scrolls vertically, but over-scrolls horizontally.
10297   // EXPECT_CALL(client, didOverscroll(gfx::Vector2dF(-100, 0),
10298   // gfx::Vector2dF(-100, 0), gfx::PointF(100, 100), gfx::Vector2dF()));
10299   // ScrollUpdate(&webViewHelper, 100, 50);
10300   // Mock::VerifyAndClearExpectations(&client);
10301 
10302   // Scrolling up, Overscroll is not reported.
10303   // EXPECT_CALL(client, didOverscroll(_, _, _, _)).Times(0);
10304   // ScrollUpdate(&webViewHelper, 0, -50);
10305   // Mock::VerifyAndClearExpectations(&client);
10306 
10307   // Page scrolls horizontally, but over-scrolls vertically.
10308   // EXPECT_CALL(client, didOverscroll(gfx::Vector2dF(0, 100), gfx::Vector2dF(0,
10309   // 100), gfx::PointF(100, 100), gfx::Vector2dF()));
10310   // ScrollUpdate(&webViewHelper, -100, -100);
10311   // Mock::VerifyAndClearExpectations(&client);
10312 }
10313 
TEST_P(WebFrameOverscrollTest,RootLayerOverscrolledOnInnerDivOverScroll)10314 TEST_P(WebFrameOverscrollTest, RootLayerOverscrolledOnInnerDivOverScroll) {
10315   OverscrollWebWidgetClient client;
10316   RegisterMockedHttpURLLoad("overscroll/div-overscroll.html");
10317   frame_test_helpers::WebViewHelper web_view_helper;
10318 
10319   web_view_helper.InitializeAndLoad(
10320       base_url_ + "overscroll/div-overscroll.html", nullptr, nullptr, &client,
10321       ConfigureAndroid);
10322   web_view_helper.Resize(gfx::Size(200, 200));
10323 
10324   ScrollBegin(&web_view_helper, 0, -316);
10325 
10326   // Scroll the Div to the end.
10327   EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
10328               DidOverscroll(_, _, _, _, _))
10329       .Times(0);
10330   ScrollUpdate(&web_view_helper, 0, -316);
10331   base::RunLoop().RunUntilIdle();
10332   Mock::VerifyAndClearExpectations(
10333       &client.GetOverscrollWidgetInputHandlerHost());
10334 
10335   ScrollEnd(&web_view_helper);
10336   ScrollBegin(&web_view_helper, 0, -150);
10337 
10338   // Now On Scrolling DIV, scroll is bubbled and root layer is over-scrolled.
10339   EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
10340               DidOverscroll(gfx::Vector2dF(0, 50), gfx::Vector2dF(0, 50),
10341                             gfx::PointF(100, 100), gfx::Vector2dF(),
10342                             kOverscrollBehaviorAuto));
10343   ScrollUpdate(&web_view_helper, 0, -150);
10344   base::RunLoop().RunUntilIdle();
10345   Mock::VerifyAndClearExpectations(
10346       &client.GetOverscrollWidgetInputHandlerHost());
10347 }
10348 
TEST_P(WebFrameOverscrollTest,RootLayerOverscrolledOnInnerIFrameOverScroll)10349 TEST_P(WebFrameOverscrollTest, RootLayerOverscrolledOnInnerIFrameOverScroll) {
10350   OverscrollWebWidgetClient client;
10351   RegisterMockedHttpURLLoad("overscroll/iframe-overscroll.html");
10352   RegisterMockedHttpURLLoad("overscroll/scrollable-iframe.html");
10353   frame_test_helpers::WebViewHelper web_view_helper;
10354 
10355   web_view_helper.InitializeAndLoad(
10356       base_url_ + "overscroll/iframe-overscroll.html", nullptr, nullptr,
10357       &client, ConfigureAndroid);
10358   web_view_helper.Resize(gfx::Size(200, 200));
10359 
10360   ScrollBegin(&web_view_helper, 0, -320);
10361   // Scroll the IFrame to the end.
10362   EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
10363               DidOverscroll(_, _, _, _, _))
10364       .Times(0);
10365 
10366   // This scroll will fully scroll the iframe but will be consumed before being
10367   // counted as overscroll.
10368   ScrollUpdate(&web_view_helper, 0, -320);
10369 
10370   // This scroll will again target the iframe but wont bubble further up. Make
10371   // sure that the unused scroll isn't handled as overscroll.
10372   ScrollUpdate(&web_view_helper, 0, -50);
10373   base::RunLoop().RunUntilIdle();
10374   Mock::VerifyAndClearExpectations(
10375       &client.GetOverscrollWidgetInputHandlerHost());
10376 
10377   ScrollEnd(&web_view_helper);
10378   ScrollBegin(&web_view_helper, 0, -150);
10379 
10380   // Now On Scrolling IFrame, scroll is bubbled and root layer is over-scrolled.
10381   EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
10382               DidOverscroll(gfx::Vector2dF(0, 50), gfx::Vector2dF(0, 50),
10383                             gfx::PointF(100, 100), gfx::Vector2dF(),
10384                             kOverscrollBehaviorAuto));
10385   ScrollUpdate(&web_view_helper, 0, -150);
10386   base::RunLoop().RunUntilIdle();
10387   Mock::VerifyAndClearExpectations(
10388       &client.GetOverscrollWidgetInputHandlerHost());
10389 
10390   ScrollEnd(&web_view_helper);
10391 }
10392 
TEST_P(WebFrameOverscrollTest,ScaledPageRootLayerOverscrolled)10393 TEST_P(WebFrameOverscrollTest, ScaledPageRootLayerOverscrolled) {
10394   OverscrollWebWidgetClient client;
10395   RegisterMockedHttpURLLoad("overscroll/overscroll.html");
10396   frame_test_helpers::WebViewHelper web_view_helper;
10397 
10398   WebViewImpl* web_view_impl = web_view_helper.InitializeAndLoad(
10399       base_url_ + "overscroll/overscroll.html", nullptr, nullptr, &client,
10400       ConfigureAndroid);
10401   web_view_helper.Resize(gfx::Size(200, 200));
10402   web_view_impl->SetPageScaleFactor(3.0);
10403 
10404   // Calculation of accumulatedRootOverscroll and unusedDelta on scaled page.
10405   // The point is (99, 99) because we clamp in the division by 3 to 33 so when
10406   // we go back to viewport coordinates it becomes (99, 99).
10407   ScrollBegin(&web_view_helper, 0, 30);
10408   EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
10409               DidOverscroll(gfx::Vector2dF(0, -30), gfx::Vector2dF(0, -30),
10410                             gfx::PointF(99, 99), gfx::Vector2dF(),
10411                             kOverscrollBehaviorAuto));
10412   ScrollUpdate(&web_view_helper, 0, 30);
10413   base::RunLoop().RunUntilIdle();
10414   Mock::VerifyAndClearExpectations(
10415       &client.GetOverscrollWidgetInputHandlerHost());
10416 
10417   EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
10418               DidOverscroll(gfx::Vector2dF(0, -30), gfx::Vector2dF(0, -60),
10419                             gfx::PointF(99, 99), gfx::Vector2dF(),
10420                             kOverscrollBehaviorAuto));
10421   ScrollUpdate(&web_view_helper, 0, 30);
10422   base::RunLoop().RunUntilIdle();
10423   Mock::VerifyAndClearExpectations(
10424       &client.GetOverscrollWidgetInputHandlerHost());
10425 
10426   EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
10427               DidOverscroll(gfx::Vector2dF(-30, -30), gfx::Vector2dF(-30, -90),
10428                             gfx::PointF(99, 99), gfx::Vector2dF(),
10429                             kOverscrollBehaviorAuto));
10430   ScrollUpdate(&web_view_helper, 30, 30);
10431   base::RunLoop().RunUntilIdle();
10432   Mock::VerifyAndClearExpectations(
10433       &client.GetOverscrollWidgetInputHandlerHost());
10434 
10435   EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
10436               DidOverscroll(gfx::Vector2dF(-30, 0), gfx::Vector2dF(-60, -90),
10437                             gfx::PointF(99, 99), gfx::Vector2dF(),
10438                             kOverscrollBehaviorAuto));
10439   ScrollUpdate(&web_view_helper, 30, 0);
10440   base::RunLoop().RunUntilIdle();
10441   Mock::VerifyAndClearExpectations(
10442       &client.GetOverscrollWidgetInputHandlerHost());
10443 
10444   // Overscroll is not reported.
10445   EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
10446               DidOverscroll(_, _, _, _, _))
10447       .Times(0);
10448   ScrollEnd(&web_view_helper);
10449   base::RunLoop().RunUntilIdle();
10450   Mock::VerifyAndClearExpectations(
10451       &client.GetOverscrollWidgetInputHandlerHost());
10452 }
10453 
TEST_P(WebFrameOverscrollTest,NoOverscrollForSmallvalues)10454 TEST_P(WebFrameOverscrollTest, NoOverscrollForSmallvalues) {
10455   OverscrollWebWidgetClient client;
10456   RegisterMockedHttpURLLoad("overscroll/overscroll.html");
10457   frame_test_helpers::WebViewHelper web_view_helper;
10458 
10459   web_view_helper.InitializeAndLoad(base_url_ + "overscroll/overscroll.html",
10460                                     nullptr, nullptr, &client,
10461                                     ConfigureAndroid);
10462   web_view_helper.Resize(gfx::Size(200, 200));
10463 
10464   ScrollBegin(&web_view_helper, 10, 10);
10465   EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
10466               DidOverscroll(gfx::Vector2dF(-10, -10), gfx::Vector2dF(-10, -10),
10467                             gfx::PointF(100, 100), gfx::Vector2dF(),
10468                             kOverscrollBehaviorAuto));
10469   ScrollUpdate(&web_view_helper, 10, 10);
10470   base::RunLoop().RunUntilIdle();
10471   Mock::VerifyAndClearExpectations(
10472       &client.GetOverscrollWidgetInputHandlerHost());
10473 
10474   EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
10475               DidOverscroll(gfx::Vector2dF(0, -0.10),
10476                             gfx::Vector2dF(-10, -10.10), gfx::PointF(100, 100),
10477                             gfx::Vector2dF(), kOverscrollBehaviorAuto));
10478   ScrollUpdate(&web_view_helper, 0, 0.10);
10479   base::RunLoop().RunUntilIdle();
10480   Mock::VerifyAndClearExpectations(
10481       &client.GetOverscrollWidgetInputHandlerHost());
10482 
10483   EXPECT_CALL(
10484       client.GetOverscrollWidgetInputHandlerHost(),
10485       DidOverscroll(gfx::Vector2dF(-0.10, 0), gfx::Vector2dF(-10.10, -10.10),
10486                     gfx::PointF(100, 100), gfx::Vector2dF(),
10487                     kOverscrollBehaviorAuto));
10488   ScrollUpdate(&web_view_helper, 0.10, 0);
10489   base::RunLoop().RunUntilIdle();
10490   Mock::VerifyAndClearExpectations(
10491       &client.GetOverscrollWidgetInputHandlerHost());
10492 
10493   // For residual values overscrollDelta should be reset and DidOverscroll
10494   // shouldn't be called.
10495   EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
10496               DidOverscroll(_, _, _, _, _))
10497       .Times(0);
10498   ScrollUpdate(&web_view_helper, 0, 0.09);
10499   base::RunLoop().RunUntilIdle();
10500   Mock::VerifyAndClearExpectations(
10501       &client.GetOverscrollWidgetInputHandlerHost());
10502 
10503   EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
10504               DidOverscroll(_, _, _, _, _))
10505       .Times(0);
10506   ScrollUpdate(&web_view_helper, 0.09, 0.09);
10507   base::RunLoop().RunUntilIdle();
10508   Mock::VerifyAndClearExpectations(
10509       &client.GetOverscrollWidgetInputHandlerHost());
10510 
10511   EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
10512               DidOverscroll(_, _, _, _, _))
10513       .Times(0);
10514   ScrollUpdate(&web_view_helper, 0.09, 0);
10515   base::RunLoop().RunUntilIdle();
10516   Mock::VerifyAndClearExpectations(
10517       &client.GetOverscrollWidgetInputHandlerHost());
10518 
10519   EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
10520               DidOverscroll(_, _, _, _, _))
10521       .Times(0);
10522   ScrollUpdate(&web_view_helper, 0, -0.09);
10523   base::RunLoop().RunUntilIdle();
10524   Mock::VerifyAndClearExpectations(
10525       &client.GetOverscrollWidgetInputHandlerHost());
10526 
10527   EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
10528               DidOverscroll(_, _, _, _, _))
10529       .Times(0);
10530   ScrollUpdate(&web_view_helper, -0.09, -0.09);
10531   base::RunLoop().RunUntilIdle();
10532   Mock::VerifyAndClearExpectations(
10533       &client.GetOverscrollWidgetInputHandlerHost());
10534 
10535   EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
10536               DidOverscroll(_, _, _, _, _))
10537       .Times(0);
10538   ScrollUpdate(&web_view_helper, -0.09, 0);
10539   base::RunLoop().RunUntilIdle();
10540   Mock::VerifyAndClearExpectations(
10541       &client.GetOverscrollWidgetInputHandlerHost());
10542 
10543   EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
10544               DidOverscroll(_, _, _, _, _))
10545       .Times(0);
10546   ScrollEnd(&web_view_helper);
10547   base::RunLoop().RunUntilIdle();
10548   Mock::VerifyAndClearExpectations(
10549       &client.GetOverscrollWidgetInputHandlerHost());
10550 }
10551 
TEST_P(WebFrameOverscrollTest,OverscrollBehaviorGoesToCompositor)10552 TEST_P(WebFrameOverscrollTest, OverscrollBehaviorGoesToCompositor) {
10553   OverscrollWebWidgetClient client;
10554   RegisterMockedHttpURLLoad("overscroll/overscroll.html");
10555   frame_test_helpers::WebViewHelper web_view_helper;
10556 
10557   web_view_helper.InitializeAndLoad(base_url_ + "overscroll/overscroll.html",
10558                                     nullptr, nullptr, &client,
10559                                     ConfigureAndroid);
10560   web_view_helper.Resize(gfx::Size(200, 200));
10561 
10562   WebLocalFrame* mainFrame =
10563       web_view_helper.GetWebView()->MainFrame()->ToWebLocalFrame();
10564   EXPECT_EQ(web_view_helper.GetLayerTreeHost()->overscroll_behavior(),
10565             kOverscrollBehaviorAuto);
10566   mainFrame->ExecuteScript(
10567       WebScriptSource(WebString("document.body.style="
10568                                 "'overscroll-behavior: auto;'")));
10569   ScrollBegin(&web_view_helper, 100, 116);
10570   EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
10571               DidOverscroll(gfx::Vector2dF(-100, -100),
10572                             gfx::Vector2dF(-100, -100), gfx::PointF(100, 100),
10573                             gfx::Vector2dF(), kOverscrollBehaviorAuto));
10574   ScrollUpdate(&web_view_helper, 100, 100);
10575   base::RunLoop().RunUntilIdle();
10576   Mock::VerifyAndClearExpectations(
10577       &client.GetOverscrollWidgetInputHandlerHost());
10578   EXPECT_EQ(web_view_helper.GetLayerTreeHost()->overscroll_behavior(),
10579             kOverscrollBehaviorAuto);
10580 
10581   mainFrame->ExecuteScript(
10582       WebScriptSource(WebString("document.body.style="
10583                                 "'overscroll-behavior: contain;'")));
10584   ScrollBegin(&web_view_helper, 100, 116);
10585   EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
10586               DidOverscroll(gfx::Vector2dF(-100, -100),
10587                             gfx::Vector2dF(-200, -200), gfx::PointF(100, 100),
10588                             gfx::Vector2dF(), kOverscrollBehaviorContain));
10589   ScrollUpdate(&web_view_helper, 100, 100);
10590   base::RunLoop().RunUntilIdle();
10591   Mock::VerifyAndClearExpectations(
10592       &client.GetOverscrollWidgetInputHandlerHost());
10593   EXPECT_EQ(web_view_helper.GetLayerTreeHost()->overscroll_behavior(),
10594             kOverscrollBehaviorContain);
10595 
10596   mainFrame->ExecuteScript(
10597       WebScriptSource(WebString("document.body.style="
10598                                 "'overscroll-behavior: none;'")));
10599   ScrollBegin(&web_view_helper, 100, 116);
10600   EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
10601               DidOverscroll(gfx::Vector2dF(-100, -100),
10602                             gfx::Vector2dF(-300, -300), gfx::PointF(100, 100),
10603                             gfx::Vector2dF(), kOverscrollBehaviorNone));
10604   ScrollUpdate(&web_view_helper, 100, 100);
10605   base::RunLoop().RunUntilIdle();
10606   Mock::VerifyAndClearExpectations(
10607       &client.GetOverscrollWidgetInputHandlerHost());
10608   EXPECT_EQ(web_view_helper.GetLayerTreeHost()->overscroll_behavior(),
10609             kOverscrollBehaviorNone);
10610 }
10611 
TEST_P(WebFrameOverscrollTest,OnlyMainFrameOverscrollBehaviorHasEffect)10612 TEST_P(WebFrameOverscrollTest, OnlyMainFrameOverscrollBehaviorHasEffect) {
10613   OverscrollWebWidgetClient client;
10614   RegisterMockedHttpURLLoad("overscroll/iframe-overscroll.html");
10615   RegisterMockedHttpURLLoad("overscroll/scrollable-iframe.html");
10616   frame_test_helpers::WebViewHelper web_view_helper;
10617 
10618   web_view_helper.InitializeAndLoad(
10619       base_url_ + "overscroll/iframe-overscroll.html", nullptr, nullptr,
10620       &client, ConfigureAndroid);
10621   web_view_helper.Resize(gfx::Size(200, 200));
10622 
10623   WebLocalFrame* mainFrame =
10624       web_view_helper.GetWebView()->MainFrame()->ToWebLocalFrame();
10625   mainFrame->ExecuteScript(
10626       WebScriptSource(WebString("document.body.style="
10627                                 "'overscroll-behavior: auto;'")));
10628   WebLocalFrame* subframe = web_view_helper.GetWebView()
10629                                 ->MainFrame()
10630                                 ->FirstChild()
10631                                 ->ToWebLocalFrame();
10632   subframe->ExecuteScript(
10633       WebScriptSource(WebString("document.body.style="
10634                                 "'overscroll-behavior: none;'")));
10635 
10636   ScrollBegin(&web_view_helper, 100, 116);
10637   EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
10638               DidOverscroll(gfx::Vector2dF(-100, -100),
10639                             gfx::Vector2dF(-100, -100), gfx::PointF(100, 100),
10640                             gfx::Vector2dF(), kOverscrollBehaviorAuto));
10641   ScrollUpdate(&web_view_helper, 100, 100);
10642   base::RunLoop().RunUntilIdle();
10643   Mock::VerifyAndClearExpectations(
10644       &client.GetOverscrollWidgetInputHandlerHost());
10645   EXPECT_EQ(web_view_helper.GetLayerTreeHost()->overscroll_behavior(),
10646             kOverscrollBehaviorAuto);
10647 
10648   mainFrame->ExecuteScript(
10649       WebScriptSource(WebString("document.body.style="
10650                                 "'overscroll-behavior: contain;'")));
10651   EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
10652               DidOverscroll(gfx::Vector2dF(-100, -100),
10653                             gfx::Vector2dF(-200, -200), gfx::PointF(100, 100),
10654                             gfx::Vector2dF(), kOverscrollBehaviorContain));
10655   ScrollUpdate(&web_view_helper, 100, 100);
10656   base::RunLoop().RunUntilIdle();
10657   Mock::VerifyAndClearExpectations(
10658       &client.GetOverscrollWidgetInputHandlerHost());
10659   EXPECT_EQ(web_view_helper.GetLayerTreeHost()->overscroll_behavior(),
10660             kOverscrollBehaviorContain);
10661 }
10662 
TEST_F(WebFrameTest,OrientationFrameDetach)10663 TEST_F(WebFrameTest, OrientationFrameDetach) {
10664   ScopedOrientationEventForTest orientation_event(true);
10665   RegisterMockedHttpURLLoad("orientation-frame-detach.html");
10666   frame_test_helpers::WebViewHelper web_view_helper;
10667   WebViewImpl* web_view_impl = web_view_helper.InitializeAndLoad(
10668       base_url_ + "orientation-frame-detach.html");
10669   web_view_impl->MainFrameImpl()->SendOrientationChangeEvent();
10670 }
10671 
TEST_F(WebFrameTest,MaxFrames)10672 TEST_F(WebFrameTest, MaxFrames) {
10673   frame_test_helpers::WebViewHelper web_view_helper;
10674   web_view_helper.InitializeRemote();
10675   Page* page = web_view_helper.GetWebView()->GetPage();
10676 
10677   WebLocalFrameImpl* frame =
10678       frame_test_helpers::CreateLocalChild(*web_view_helper.RemoteMainFrame());
10679   while (page->SubframeCount() < Page::MaxNumberOfFrames()) {
10680     frame_test_helpers::CreateRemoteChild(*web_view_helper.RemoteMainFrame());
10681   }
10682   auto* iframe = MakeGarbageCollected<HTMLIFrameElement>(
10683       *frame->GetFrame()->GetDocument());
10684   iframe->setAttribute(html_names::kSrcAttr, "");
10685   frame->GetFrame()->GetDocument()->body()->appendChild(iframe);
10686   EXPECT_FALSE(iframe->ContentFrame());
10687 }
10688 
10689 class TestViewportIntersection : public FakeRemoteFrameHost {
10690  public:
10691   TestViewportIntersection() = default;
10692   ~TestViewportIntersection() override = default;
10693 
GetIntersectionState() const10694   const mojom::blink::ViewportIntersectionStatePtr& GetIntersectionState()
10695       const {
10696     return intersection_state_;
10697   }
10698 
10699   // FakeRemoteFrameHost:
UpdateViewportIntersection(mojom::blink::ViewportIntersectionStatePtr intersection_state)10700   void UpdateViewportIntersection(
10701       mojom::blink::ViewportIntersectionStatePtr intersection_state) override {
10702     intersection_state_ = std::move(intersection_state);
10703   }
10704 
10705  private:
10706   mojom::blink::ViewportIntersectionStatePtr intersection_state_;
10707 };
10708 
TEST_F(WebFrameTest,RotatedIframeViewportIntersection)10709 TEST_F(WebFrameTest, RotatedIframeViewportIntersection) {
10710   frame_test_helpers::WebViewHelper web_view_helper;
10711   web_view_helper.Initialize();
10712   WebViewImpl* web_view = web_view_helper.GetWebView();
10713   web_view->Resize(gfx::Size(800, 600));
10714   InitializeWithHTML(*web_view->MainFrameImpl()->GetFrame(), R"HTML(
10715 <!DOCTYPE html>
10716 <style>
10717   iframe {
10718     position: absolute;
10719     top: 200px;
10720     left: 200px;
10721     transform: rotate(45deg);
10722   }
10723 </style>
10724 <iframe></iframe>
10725   )HTML");
10726   frame_test_helpers::TestWebRemoteFrameClient remote_frame_client;
10727   TestViewportIntersection remote_frame_host;
10728   remote_frame_host.Init(remote_frame_client.GetRemoteAssociatedInterfaces());
10729   WebRemoteFrameImpl* remote_frame =
10730       frame_test_helpers::CreateRemote(&remote_frame_client);
10731   web_view_helper.LocalMainFrame()->FirstChild()->Swap(remote_frame);
10732   web_view->MainFrameImpl()
10733       ->GetFrame()
10734       ->View()
10735       ->UpdateAllLifecyclePhasesForTest();
10736   base::RunLoop().RunUntilIdle();
10737   ASSERT_TRUE(!remote_frame_host.GetIntersectionState()
10738                    ->viewport_intersection.IsEmpty());
10739   EXPECT_TRUE(IntRect(IntPoint(), remote_frame->GetFrame()->View()->Size())
10740                   .Contains(IntRect(remote_frame_host.GetIntersectionState()
10741                                         ->viewport_intersection)));
10742   ASSERT_TRUE(!remote_frame_host.GetIntersectionState()
10743                    ->main_frame_intersection.IsEmpty());
10744   EXPECT_TRUE(IntRect(IntPoint(), remote_frame->GetFrame()->View()->Size())
10745                   .Contains(IntRect(remote_frame_host.GetIntersectionState()
10746                                         ->main_frame_intersection)));
10747   remote_frame->Detach();
10748 }
10749 
TEST_F(WebFrameTest,ImageDocumentLoadResponseEnd)10750 TEST_F(WebFrameTest, ImageDocumentLoadResponseEnd) {
10751   // Loading an image resource directly generates an ImageDocument with
10752   // the document loader feeding image data into the resource of a generated
10753   // img tag. We expect the load finish time to be the same for the document
10754   // and the image resource.
10755 
10756   RegisterMockedHttpURLLoadWithMimeType("white-1x1.png", "image/png");
10757   frame_test_helpers::WebViewHelper web_view_helper;
10758   web_view_helper.InitializeAndLoad(base_url_ + "white-1x1.png");
10759   WebViewImpl* web_view = web_view_helper.GetWebView();
10760   Document* document = web_view->MainFrameImpl()->GetFrame()->GetDocument();
10761 
10762   EXPECT_TRUE(document);
10763   EXPECT_TRUE(IsA<ImageDocument>(document));
10764 
10765   auto* img_document = To<ImageDocument>(document);
10766   ImageResourceContent* image_content = img_document->CachedImage();
10767 
10768   EXPECT_TRUE(image_content);
10769   EXPECT_NE(base::TimeTicks(), image_content->LoadResponseEnd());
10770 
10771   DocumentLoader* loader = document->Loader();
10772 
10773   EXPECT_TRUE(loader);
10774   EXPECT_EQ(loader->GetTiming().ResponseEnd(),
10775             image_content->LoadResponseEnd());
10776 }
10777 
TEST_F(WebFrameTest,CopyImageDocument)10778 TEST_F(WebFrameTest, CopyImageDocument) {
10779   // After loading an image document, we should be able to copy it directly.
10780 
10781   RegisterMockedHttpURLLoadWithMimeType("white-1x1.png", "image/png");
10782   frame_test_helpers::WebViewHelper web_view_helper;
10783   web_view_helper.InitializeAndLoad(base_url_ + "white-1x1.png");
10784   WebViewImpl* web_view = web_view_helper.GetWebView();
10785   WebLocalFrameImpl* web_frame = web_view->MainFrameImpl();
10786   Document* document = web_frame->GetFrame()->GetDocument();
10787 
10788   ASSERT_TRUE(document);
10789   EXPECT_TRUE(IsA<ImageDocument>(document));
10790 
10791   // Setup a mock clipboard host.
10792   PageTestBase::MockClipboardHostProvider mock_clipboard_host_provider(
10793       web_frame->GetFrame()->GetBrowserInterfaceBroker());
10794 
10795   SystemClipboard* system_clipboard =
10796       document->GetFrame()->GetSystemClipboard();
10797   ASSERT_TRUE(system_clipboard);
10798 
10799   EXPECT_TRUE(system_clipboard->ReadAvailableTypes().IsEmpty());
10800 
10801   bool result = web_frame->ExecuteCommand("Copy");
10802   test::RunPendingTasks();
10803 
10804   EXPECT_TRUE(result);
10805 
10806   Vector<String> types = system_clipboard->ReadAvailableTypes();
10807   EXPECT_EQ(2u, types.size());
10808   EXPECT_EQ("text/html", types[0]);
10809   EXPECT_EQ("image/png", types[1]);
10810 
10811   // Clear clipboard data
10812   system_clipboard->WritePlainText("");
10813   system_clipboard->CommitWrite();
10814 }
10815 
TEST_F(WebFrameTest,CopyTextInImageDocument)10816 TEST_F(WebFrameTest, CopyTextInImageDocument) {
10817   // If Javascript inserts other contents into an image document, we should be
10818   // able to copy those contents, not just the image itself.
10819 
10820   RegisterMockedHttpURLLoadWithMimeType("white-1x1.png", "image/png");
10821   frame_test_helpers::WebViewHelper web_view_helper;
10822   web_view_helper.InitializeAndLoad(base_url_ + "white-1x1.png");
10823   WebViewImpl* web_view = web_view_helper.GetWebView();
10824   WebLocalFrameImpl* web_frame = web_view->MainFrameImpl();
10825   Document* document = web_frame->GetFrame()->GetDocument();
10826 
10827   ASSERT_TRUE(document);
10828   EXPECT_TRUE(IsA<ImageDocument>(document));
10829 
10830   Node* text = document->createTextNode("copy me");
10831   document->body()->appendChild(text);
10832   document->GetFrame()->Selection().SetSelection(
10833       SelectionInDOMTree::Builder().SelectAllChildren(*text).Build(),
10834       SetSelectionOptions());
10835 
10836   // Setup a mock clipboard host.
10837   PageTestBase::MockClipboardHostProvider mock_clipboard_host_provider(
10838       web_frame->GetFrame()->GetBrowserInterfaceBroker());
10839 
10840   SystemClipboard* system_clipboard =
10841       document->GetFrame()->GetSystemClipboard();
10842   ASSERT_TRUE(system_clipboard);
10843 
10844   EXPECT_TRUE(system_clipboard->ReadAvailableTypes().IsEmpty());
10845 
10846   bool result = web_frame->ExecuteCommand("Copy");
10847   test::RunPendingTasks();
10848 
10849   EXPECT_TRUE(result);
10850 
10851   Vector<String> types = system_clipboard->ReadAvailableTypes();
10852   EXPECT_EQ(2u, types.size());
10853   EXPECT_EQ("text/plain", types[0]);
10854   EXPECT_EQ("text/html", types[1]);
10855 
10856   // Clear clipboard data
10857   system_clipboard->WritePlainText("");
10858   system_clipboard->CommitWrite();
10859 }
10860 
10861 class TestRemoteFrameHostForVisibility : public FakeRemoteFrameHost {
10862  public:
10863   TestRemoteFrameHostForVisibility() = default;
10864   ~TestRemoteFrameHostForVisibility() override = default;
10865 
10866   // FakeRemoteFrameHost:
VisibilityChanged(blink::mojom::FrameVisibility visibility)10867   void VisibilityChanged(blink::mojom::FrameVisibility visibility) override {
10868     visibility_ = visibility;
10869   }
10870 
visibility() const10871   blink::mojom::FrameVisibility visibility() const { return visibility_; }
10872 
10873  private:
10874   blink::mojom::FrameVisibility visibility_ =
10875       blink::mojom::FrameVisibility::kRenderedInViewport;
10876 };
10877 
10878 class WebRemoteFrameVisibilityChangeTest : public WebFrameTest {
10879  public:
WebRemoteFrameVisibilityChangeTest()10880   WebRemoteFrameVisibilityChangeTest() {
10881     RegisterMockedHttpURLLoad("visible_iframe.html");
10882     RegisterMockedHttpURLLoad("single_iframe.html");
10883     frame_ =
10884         web_view_helper_.InitializeAndLoad(base_url_ + "single_iframe.html")
10885             ->MainFrameImpl();
10886     web_view_helper_.Resize(gfx::Size(640, 480));
10887     remote_frame_host_.Init(
10888         remote_frame_client_.GetRemoteAssociatedInterfaces());
10889     web_remote_frame_ = frame_test_helpers::CreateRemote(&remote_frame_client_);
10890   }
10891 
10892   ~WebRemoteFrameVisibilityChangeTest() override = default;
10893 
ExecuteScriptOnMainFrame(const WebScriptSource & script)10894   void ExecuteScriptOnMainFrame(const WebScriptSource& script) {
10895     MainFrame()->ExecuteScript(script);
10896     web_view_helper_.GetWebView()
10897         ->MainFrameViewWidget()
10898         ->SynchronouslyCompositeForTesting(base::TimeTicks::Now());
10899     RunPendingTasks();
10900   }
10901 
SwapLocalFrameToRemoteFrame()10902   void SwapLocalFrameToRemoteFrame() {
10903     MainFrame()->LastChild()->Swap(RemoteFrame());
10904   }
10905 
MainFrame()10906   WebLocalFrame* MainFrame() { return frame_; }
RemoteFrame()10907   WebRemoteFrameImpl* RemoteFrame() { return web_remote_frame_; }
RemoteFrameHost()10908   TestRemoteFrameHostForVisibility* RemoteFrameHost() {
10909     return &remote_frame_host_;
10910   }
10911 
10912  private:
10913   TestRemoteFrameHostForVisibility remote_frame_host_;
10914   frame_test_helpers::TestWebRemoteFrameClient remote_frame_client_;
10915   frame_test_helpers::WebViewHelper web_view_helper_;
10916   WebLocalFrame* frame_;
10917   Persistent<WebRemoteFrameImpl> web_remote_frame_;
10918 };
10919 
TEST_F(WebRemoteFrameVisibilityChangeTest,FrameVisibilityChange)10920 TEST_F(WebRemoteFrameVisibilityChangeTest, FrameVisibilityChange) {
10921   SwapLocalFrameToRemoteFrame();
10922   ExecuteScriptOnMainFrame(WebScriptSource(
10923       "document.querySelector('iframe').style.display = 'none';"));
10924   EXPECT_EQ(blink::mojom::FrameVisibility::kNotRendered,
10925             RemoteFrameHost()->visibility());
10926 
10927   ExecuteScriptOnMainFrame(WebScriptSource(
10928       "document.querySelector('iframe').style.display = 'block';"));
10929   EXPECT_EQ(blink::mojom::FrameVisibility::kRenderedInViewport,
10930             RemoteFrameHost()->visibility());
10931 
10932   ExecuteScriptOnMainFrame(WebScriptSource(
10933       "var padding = document.createElement('div');"
10934       "padding.style = 'width: 400px; height: 800px;';"
10935       "document.body.insertBefore(padding, document.body.firstChild);"));
10936   EXPECT_EQ(blink::mojom::FrameVisibility::kRenderedOutOfViewport,
10937             RemoteFrameHost()->visibility());
10938 
10939   ExecuteScriptOnMainFrame(
10940       WebScriptSource("document.scrollingElement.scrollTop = 800;"));
10941   EXPECT_EQ(blink::mojom::FrameVisibility::kRenderedInViewport,
10942             RemoteFrameHost()->visibility());
10943 }
10944 
TEST_F(WebRemoteFrameVisibilityChangeTest,ParentVisibilityChange)10945 TEST_F(WebRemoteFrameVisibilityChangeTest, ParentVisibilityChange) {
10946   SwapLocalFrameToRemoteFrame();
10947   ExecuteScriptOnMainFrame(
10948       WebScriptSource("document.querySelector('iframe').parentElement.style."
10949                       "display = 'none';"));
10950   EXPECT_EQ(blink::mojom::FrameVisibility::kNotRendered,
10951             RemoteFrameHost()->visibility());
10952 }
10953 
10954 class TestLocalFrameHostForVisibility : public FakeLocalFrameHost {
10955  public:
10956   TestLocalFrameHostForVisibility() = default;
10957   ~TestLocalFrameHostForVisibility() override = default;
10958 
10959   // FakeLocalFrameHost:
VisibilityChanged(blink::mojom::FrameVisibility visibility)10960   void VisibilityChanged(blink::mojom::FrameVisibility visibility) override {
10961     visibility_ = visibility;
10962   }
10963 
visibility() const10964   blink::mojom::FrameVisibility visibility() const { return visibility_; }
10965 
10966  private:
10967   blink::mojom::FrameVisibility visibility_ =
10968       blink::mojom::FrameVisibility::kRenderedInViewport;
10969 };
10970 
10971 class WebLocalFrameVisibilityChangeTest
10972     : public WebFrameTest,
10973       public frame_test_helpers::TestWebFrameClient {
10974  public:
WebLocalFrameVisibilityChangeTest()10975   WebLocalFrameVisibilityChangeTest() {
10976     RegisterMockedHttpURLLoad("visible_iframe.html");
10977     RegisterMockedHttpURLLoad("single_iframe.html");
10978     child_host_.Init(child_client_.GetRemoteNavigationAssociatedInterfaces());
10979     frame_ = web_view_helper_
10980                  .InitializeAndLoad(base_url_ + "single_iframe.html", this)
10981                  ->MainFrameImpl();
10982     web_view_helper_.Resize(gfx::Size(640, 480));
10983   }
10984 
10985   ~WebLocalFrameVisibilityChangeTest() override = default;
10986 
ExecuteScriptOnMainFrame(const WebScriptSource & script)10987   void ExecuteScriptOnMainFrame(const WebScriptSource& script) {
10988     MainFrame()->ExecuteScript(script);
10989     web_view_helper_.GetWebView()
10990         ->MainFrameViewWidget()
10991         ->SynchronouslyCompositeForTesting(base::TimeTicks::Now());
10992     RunPendingTasks();
10993   }
10994 
MainFrame()10995   WebLocalFrame* MainFrame() { return frame_; }
10996 
10997   // frame_test_helpers::TestWebFrameClient:
CreateChildFrame(WebLocalFrame * parent,mojom::blink::TreeScopeType scope,const WebString & name,const WebString & fallback_name,const FramePolicy &,const WebFrameOwnerProperties &,mojom::blink::FrameOwnerElementType)10998   WebLocalFrame* CreateChildFrame(
10999       WebLocalFrame* parent,
11000       mojom::blink::TreeScopeType scope,
11001       const WebString& name,
11002       const WebString& fallback_name,
11003       const FramePolicy&,
11004       const WebFrameOwnerProperties&,
11005       mojom::blink::FrameOwnerElementType) override {
11006     return CreateLocalChild(*parent, scope, &child_client_);
11007   }
11008 
ChildHost()11009   TestLocalFrameHostForVisibility& ChildHost() { return child_host_; }
11010 
11011  private:
11012   TestLocalFrameHostForVisibility child_host_;
11013   frame_test_helpers::TestWebFrameClient child_client_;
11014   frame_test_helpers::WebViewHelper web_view_helper_;
11015   WebLocalFrame* frame_;
11016 };
11017 
TEST_F(WebLocalFrameVisibilityChangeTest,FrameVisibilityChange)11018 TEST_F(WebLocalFrameVisibilityChangeTest, FrameVisibilityChange) {
11019   ExecuteScriptOnMainFrame(WebScriptSource(
11020       "document.querySelector('iframe').style.display = 'none';"));
11021   EXPECT_EQ(blink::mojom::FrameVisibility::kNotRendered,
11022             ChildHost().visibility());
11023 
11024   ExecuteScriptOnMainFrame(WebScriptSource(
11025       "document.querySelector('iframe').style.display = 'block';"));
11026   EXPECT_EQ(blink::mojom::FrameVisibility::kRenderedInViewport,
11027             ChildHost().visibility());
11028 
11029   ExecuteScriptOnMainFrame(WebScriptSource(
11030       "var padding = document.createElement('div');"
11031       "padding.style = 'width: 400px; height: 800px;';"
11032       "document.body.insertBefore(padding, document.body.firstChild);"));
11033   EXPECT_EQ(blink::mojom::FrameVisibility::kRenderedOutOfViewport,
11034             ChildHost().visibility());
11035 
11036   ExecuteScriptOnMainFrame(
11037       WebScriptSource("document.scrollingElement.scrollTop = 800;"));
11038   EXPECT_EQ(blink::mojom::FrameVisibility::kRenderedInViewport,
11039             ChildHost().visibility());
11040 }
11041 
TEST_F(WebLocalFrameVisibilityChangeTest,ParentVisibilityChange)11042 TEST_F(WebLocalFrameVisibilityChangeTest, ParentVisibilityChange) {
11043   ExecuteScriptOnMainFrame(
11044       WebScriptSource("document.querySelector('iframe').parentElement.style."
11045                       "display = 'none';"));
11046   EXPECT_EQ(blink::mojom::FrameVisibility::kNotRendered,
11047             ChildHost().visibility());
11048 }
11049 
EnableGlobalReuseForUnownedMainFrames(WebSettings * settings)11050 static void EnableGlobalReuseForUnownedMainFrames(WebSettings* settings) {
11051   settings->SetShouldReuseGlobalForUnownedMainFrame(true);
11052 }
11053 
11054 // A main frame with no opener should have a unique security origin. Thus, the
11055 // global should never be reused on the initial navigation.
TEST(WebFrameGlobalReuseTest,MainFrameWithNoOpener)11056 TEST(WebFrameGlobalReuseTest, MainFrameWithNoOpener) {
11057   frame_test_helpers::WebViewHelper helper;
11058   helper.Initialize();
11059 
11060   WebLocalFrame* main_frame = helper.LocalMainFrame();
11061   v8::HandleScope scope(v8::Isolate::GetCurrent());
11062   main_frame->ExecuteScript(WebScriptSource("hello = 'world';"));
11063   frame_test_helpers::LoadFrame(main_frame, "data:text/html,new page");
11064   v8::Local<v8::Value> result =
11065       main_frame->ExecuteScriptAndReturnValue(WebScriptSource("hello"));
11066   EXPECT_TRUE(result.IsEmpty());
11067 }
11068 
11069 // Child frames should never reuse the global on a cross-origin navigation, even
11070 // if the setting is enabled. It's not safe to since the parent could have
11071 // injected script before the initial navigation.
TEST(WebFrameGlobalReuseTest,ChildFrame)11072 TEST(WebFrameGlobalReuseTest, ChildFrame) {
11073   frame_test_helpers::WebViewHelper helper;
11074   helper.Initialize(nullptr, nullptr, nullptr,
11075                     EnableGlobalReuseForUnownedMainFrames);
11076 
11077   WebLocalFrame* main_frame = helper.LocalMainFrame();
11078   frame_test_helpers::LoadFrame(main_frame, "data:text/html,<iframe></iframe>");
11079 
11080   WebLocalFrame* child_frame = main_frame->FirstChild()->ToWebLocalFrame();
11081   v8::HandleScope scope(v8::Isolate::GetCurrent());
11082   child_frame->ExecuteScript(WebScriptSource("hello = 'world';"));
11083   frame_test_helpers::LoadFrame(child_frame, "data:text/html,new page");
11084   v8::Local<v8::Value> result =
11085       child_frame->ExecuteScriptAndReturnValue(WebScriptSource("hello"));
11086   EXPECT_TRUE(result.IsEmpty());
11087 }
11088 
11089 // A main frame with an opener should never reuse the global on a cross-origin
11090 // navigation, even if the setting is enabled. It's not safe to since the opener
11091 // could have injected script.
TEST(WebFrameGlobalReuseTest,MainFrameWithOpener)11092 TEST(WebFrameGlobalReuseTest, MainFrameWithOpener) {
11093   frame_test_helpers::WebViewHelper opener_helper;
11094   opener_helper.Initialize();
11095   frame_test_helpers::WebViewHelper helper;
11096   helper.InitializeWithOpener(opener_helper.GetWebView()->MainFrame(), nullptr,
11097                               nullptr, nullptr,
11098                               EnableGlobalReuseForUnownedMainFrames);
11099 
11100   WebLocalFrame* main_frame = helper.LocalMainFrame();
11101   v8::HandleScope scope(v8::Isolate::GetCurrent());
11102   main_frame->ExecuteScript(WebScriptSource("hello = 'world';"));
11103   frame_test_helpers::LoadFrame(main_frame, "data:text/html,new page");
11104   v8::Local<v8::Value> result =
11105       main_frame->ExecuteScriptAndReturnValue(WebScriptSource("hello"));
11106   EXPECT_TRUE(result.IsEmpty());
11107 }
11108 
11109 // A main frame that is unrelated to any other frame /can/ reuse the global if
11110 // the setting is enabled. In this case, it's impossible for any other frames to
11111 // have touched the global. Only the embedder could have injected script, and
11112 // the embedder enabling this setting is a signal that the injected script needs
11113 // to persist on the first navigation away from the initial empty document.
TEST(WebFrameGlobalReuseTest,ReuseForMainFrameIfEnabled)11114 TEST(WebFrameGlobalReuseTest, ReuseForMainFrameIfEnabled) {
11115   frame_test_helpers::WebViewHelper helper;
11116   helper.Initialize(nullptr, nullptr, nullptr,
11117                     EnableGlobalReuseForUnownedMainFrames);
11118 
11119   WebLocalFrame* main_frame = helper.LocalMainFrame();
11120   v8::HandleScope scope(v8::Isolate::GetCurrent());
11121   main_frame->ExecuteScript(WebScriptSource("hello = 'world';"));
11122   frame_test_helpers::LoadFrame(main_frame, "data:text/html,new page");
11123   v8::Local<v8::Value> result =
11124       main_frame->ExecuteScriptAndReturnValue(WebScriptSource("hello"));
11125   ASSERT_TRUE(result->IsString());
11126   EXPECT_EQ("world",
11127             ToCoreString(result->ToString(main_frame->MainWorldScriptContext())
11128                              .ToLocalChecked()));
11129 }
11130 
11131 // This class intercepts the registration of Blob instances.
11132 //
11133 // Given that the content of the Blob is known (data URL)
11134 // it gets the data from the DataElement's BytesProvider, and creates
11135 // FakeBlob's accordingly.
11136 class BlobRegistryForSaveImageFromDataURL : public mojom::blink::BlobRegistry {
11137  public:
Register(mojo::PendingReceiver<mojom::blink::Blob> blob,const String & uuid,const String & content_type,const String & content_disposition,Vector<mojom::blink::DataElementPtr> elements,RegisterCallback callback)11138   void Register(mojo::PendingReceiver<mojom::blink::Blob> blob,
11139                 const String& uuid,
11140                 const String& content_type,
11141                 const String& content_disposition,
11142                 Vector<mojom::blink::DataElementPtr> elements,
11143                 RegisterCallback callback) override {
11144     DCHECK_EQ(elements.size(), 1u);
11145     DCHECK(elements[0]->is_bytes());
11146 
11147     auto& element0 = elements[0];
11148     const auto& bytes = element0->get_bytes();
11149     auto length = bytes->length;
11150     String body(reinterpret_cast<const char*>(bytes->embedded_data->data()),
11151                 static_cast<uint32_t>(length));
11152     mojo::MakeSelfOwnedReceiver(std::make_unique<FakeBlob>(uuid, body),
11153                                 std::move(blob));
11154     std::move(callback).Run();
11155   }
11156 
RegisterFromStream(const String & content_type,const String & content_disposition,uint64_t expected_length,mojo::ScopedDataPipeConsumerHandle,mojo::PendingAssociatedRemote<mojom::blink::ProgressClient>,RegisterFromStreamCallback)11157   void RegisterFromStream(
11158       const String& content_type,
11159       const String& content_disposition,
11160       uint64_t expected_length,
11161       mojo::ScopedDataPipeConsumerHandle,
11162       mojo::PendingAssociatedRemote<mojom::blink::ProgressClient>,
11163       RegisterFromStreamCallback) override {
11164     NOTREACHED();
11165   }
11166 
GetBlobFromUUID(mojo::PendingReceiver<mojom::blink::Blob>,const String & uuid,GetBlobFromUUIDCallback)11167   void GetBlobFromUUID(mojo::PendingReceiver<mojom::blink::Blob>,
11168                        const String& uuid,
11169                        GetBlobFromUUIDCallback) override {
11170     NOTREACHED();
11171   }
11172 
URLStoreForOrigin(const scoped_refptr<const SecurityOrigin> &,mojo::PendingAssociatedReceiver<mojom::blink::BlobURLStore>)11173   void URLStoreForOrigin(
11174       const scoped_refptr<const SecurityOrigin>&,
11175       mojo::PendingAssociatedReceiver<mojom::blink::BlobURLStore>) override {
11176     NOTREACHED();
11177   }
11178 };
11179 
11180 // blink::mojom::LocalFrameHost instance that intecepts DownloadURL() mojo
11181 // calls and reads the blob data URL sent by the renderer accordingly.
11182 class TestLocalFrameHostForSaveImageFromDataURL : public FakeLocalFrameHost {
11183  public:
TestLocalFrameHostForSaveImageFromDataURL()11184   TestLocalFrameHostForSaveImageFromDataURL()
11185       : blob_registry_receiver_(
11186             &blob_registry_,
11187             blob_registry_remote_.BindNewPipeAndPassReceiver()) {
11188     BlobDataHandle::SetBlobRegistryForTesting(blob_registry_remote_.get());
11189   }
~TestLocalFrameHostForSaveImageFromDataURL()11190   ~TestLocalFrameHostForSaveImageFromDataURL() override {
11191     BlobDataHandle::SetBlobRegistryForTesting(nullptr);
11192   }
11193 
11194   // FakeLocalFrameHost:
DownloadURL(mojom::blink::DownloadURLParamsPtr params)11195   void DownloadURL(mojom::blink::DownloadURLParamsPtr params) override {
11196     mojo::Remote<mojom::blink::Blob> blob(std::move(params->data_url_blob));
11197     mojo::ScopedDataPipeProducerHandle producer_handle;
11198     mojo::ScopedDataPipeConsumerHandle consumer_handle;
11199     auto result =
11200         mojo::CreateDataPipe(nullptr, &producer_handle, &consumer_handle);
11201     DCHECK(result == MOJO_RESULT_OK);
11202 
11203     blob->ReadAll(std::move(producer_handle), mojo::NullRemote());
11204 
11205     DataPipeDrainerClient client(&data_url_);
11206     auto data_pipe_drainer = std::make_unique<mojo::DataPipeDrainer>(
11207         &client, std::move(consumer_handle));
11208     client.Run();
11209   }
11210 
Result() const11211   const String& Result() const { return data_url_; }
Reset()11212   void Reset() { data_url_ = String(); }
11213 
11214  private:
11215   // Helper class to copy a blob to a string.
11216   class DataPipeDrainerClient : public mojo::DataPipeDrainer::Client {
11217    public:
DataPipeDrainerClient(String * output)11218     explicit DataPipeDrainerClient(String* output)
11219         : run_loop_(base::RunLoop::Type::kNestableTasksAllowed),
11220           output_(output) {}
Run()11221     void Run() { run_loop_.Run(); }
11222 
OnDataAvailable(const void * data,size_t num_bytes)11223     void OnDataAvailable(const void* data, size_t num_bytes) override {
11224       *output_ = String(reinterpret_cast<const char*>(data), num_bytes);
11225     }
OnDataComplete()11226     void OnDataComplete() override { run_loop_.Quit(); }
11227 
11228    private:
11229     base::RunLoop run_loop_;
11230     String* output_;
11231   };
11232 
11233   BlobRegistryForSaveImageFromDataURL blob_registry_;
11234   mojo::Remote<mojom::blink::BlobRegistry> blob_registry_remote_;
11235   mojo::Receiver<mojom::blink::BlobRegistry> blob_registry_receiver_;
11236 
11237   // Data URL retrieved from the blob.
11238   String data_url_;
11239 };
11240 
TEST_F(WebFrameTest,SaveImageAt)11241 TEST_F(WebFrameTest, SaveImageAt) {
11242   std::string url = base_url_ + "image-with-data-url.html";
11243   // TODO(crbug.com/751425): We should use the mock functionality
11244   // via the WebViewHelper instance in each test case.
11245   RegisterMockedURLLoadFromBase(base_url_, "image-with-data-url.html");
11246   url_test_helpers::RegisterMockedURLLoad(
11247       ToKURL("http://test"), test::CoreTestDataPath("white-1x1.png"));
11248 
11249   TestLocalFrameHostForSaveImageFromDataURL frame_host;
11250   frame_test_helpers::TestWebFrameClient web_frame_client;
11251   frame_host.Init(web_frame_client.GetRemoteNavigationAssociatedInterfaces());
11252   frame_test_helpers::WebViewHelper web_view_helper;
11253   RunPendingTasks();
11254 
11255   WebViewImpl* web_view =
11256       web_view_helper.InitializeAndLoad(url, &web_frame_client);
11257   web_view->MainFrameViewWidget()->Resize(gfx::Size(400, 400));
11258   UpdateAllLifecyclePhases(web_view);
11259 
11260   LocalFrame* local_frame = To<LocalFrame>(web_view->GetPage()->MainFrame());
11261 
11262   frame_host.Reset();
11263   local_frame->SaveImageAt(gfx::Point(1, 1));
11264   // Note that in this test does not use RunPendingTasks() since
11265   // TestLocalFrameHostForSaveImageFromDataURL trigger its own loops, so nesting
11266   // must be allowed.
11267   base::RunLoop(base::RunLoop::Type::kNestableTasksAllowed).RunUntilIdle();
11268 
11269   EXPECT_EQ(
11270       String::FromUTF8("data:image/gif;base64"
11271                        ",R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs="),
11272       frame_host.Result());
11273 
11274   frame_host.Reset();
11275 
11276   local_frame->SaveImageAt(gfx::Point(1, 2));
11277   base::RunLoop(base::RunLoop::Type::kNestableTasksAllowed).RunUntilIdle();
11278   EXPECT_EQ(String(), frame_host.Result());
11279 
11280   web_view->SetPageScaleFactor(4);
11281   web_view->SetVisualViewportOffset(gfx::PointF(1, 1));
11282 
11283   frame_host.Reset();
11284   local_frame->SaveImageAt(gfx::Point(3, 3));
11285   base::RunLoop(base::RunLoop::Type::kNestableTasksAllowed).RunUntilIdle();
11286   EXPECT_EQ(
11287       String::FromUTF8("data:image/gif;base64"
11288                        ",R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs="),
11289       frame_host.Result());
11290 
11291   // Explicitly reset to break dependency on locally scoped client.
11292   web_view_helper.Reset();
11293 }
11294 
TEST_F(WebFrameTest,SaveImageWithImageMap)11295 TEST_F(WebFrameTest, SaveImageWithImageMap) {
11296   std::string url = base_url_ + "image-map.html";
11297   // TODO(crbug.com/751425): We should use the mock functionality
11298   // via the WebViewHelper instance in each test case.
11299   RegisterMockedURLLoadFromBase(base_url_, "image-map.html");
11300 
11301   TestLocalFrameHostForSaveImageFromDataURL frame_host;
11302   frame_test_helpers::WebViewHelper helper;
11303   frame_test_helpers::TestWebFrameClient client;
11304   frame_host.Init(client.GetRemoteNavigationAssociatedInterfaces());
11305   WebViewImpl* web_view = helper.InitializeAndLoad(url, &client);
11306   web_view->MainFrameViewWidget()->Resize(gfx::Size(400, 400));
11307   RunPendingTasks();
11308 
11309   LocalFrame* local_frame = To<LocalFrame>(web_view->GetPage()->MainFrame());
11310 
11311   frame_host.Reset();
11312   local_frame->SaveImageAt(gfx::Point(25, 25));
11313   base::RunLoop(base::RunLoop::Type::kNestableTasksAllowed).RunUntilIdle();
11314   EXPECT_EQ(
11315       String::FromUTF8("data:image/gif;base64"
11316                        ",R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs="),
11317       frame_host.Result());
11318 
11319   frame_host.Reset();
11320   local_frame->SaveImageAt(gfx::Point(75, 25));
11321   base::RunLoop(base::RunLoop::Type::kNestableTasksAllowed).RunUntilIdle();
11322   EXPECT_EQ(
11323       String::FromUTF8("data:image/gif;base64"
11324                        ",R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs="),
11325       frame_host.Result());
11326 
11327   frame_host.Reset();
11328   local_frame->SaveImageAt(gfx::Point(125, 25));
11329   base::RunLoop(base::RunLoop::Type::kNestableTasksAllowed).RunUntilIdle();
11330   EXPECT_EQ(String(), frame_host.Result());
11331 
11332   // Explicitly reset to break dependency on locally scoped client.
11333   helper.Reset();
11334 }
11335 
TEST_F(WebFrameTest,CopyImageWithImageMap)11336 TEST_F(WebFrameTest, CopyImageWithImageMap) {
11337   std::string url = base_url_ + "image-map.html";
11338   // TODO(crbug.com/751425): We should use the mock functionality
11339   // via the WebViewHelper instance in each test case.
11340   RegisterMockedURLLoadFromBase(base_url_, "image-map.html");
11341 
11342   TestLocalFrameHostForSaveImageFromDataURL frame_host;
11343   frame_test_helpers::WebViewHelper helper;
11344   frame_test_helpers::TestWebFrameClient client;
11345   frame_host.Init(client.GetRemoteNavigationAssociatedInterfaces());
11346   WebViewImpl* web_view = helper.InitializeAndLoad(url, &client);
11347   web_view->MainFrameViewWidget()->Resize(gfx::Size(400, 400));
11348   RunPendingTasks();
11349 
11350   frame_host.Reset();
11351   LocalFrame* local_frame = To<LocalFrame>(web_view->GetPage()->MainFrame());
11352   local_frame->SaveImageAt(gfx::Point(25, 25));
11353   base::RunLoop(base::RunLoop::Type::kNestableTasksAllowed).RunUntilIdle();
11354   EXPECT_EQ(
11355       String::FromUTF8("data:image/gif;base64"
11356                        ",R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs="),
11357       frame_host.Result());
11358 
11359   frame_host.Reset();
11360   local_frame->SaveImageAt(gfx::Point(75, 25));
11361   base::RunLoop(base::RunLoop::Type::kNestableTasksAllowed).RunUntilIdle();
11362   EXPECT_EQ(
11363       String::FromUTF8("data:image/gif;base64"
11364                        ",R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs="),
11365       frame_host.Result());
11366 
11367   frame_host.Reset();
11368   local_frame->SaveImageAt(gfx::Point(125, 25));
11369   base::RunLoop(base::RunLoop::Type::kNestableTasksAllowed).RunUntilIdle();
11370   EXPECT_EQ(String(), frame_host.Result());
11371   // Explicitly reset to break dependency on locally scoped client.
11372   helper.Reset();
11373 }
11374 
TEST_F(WebFrameTest,LoadJavascriptURLInNewFrame)11375 TEST_F(WebFrameTest, LoadJavascriptURLInNewFrame) {
11376   frame_test_helpers::WebViewHelper helper;
11377   helper.Initialize();
11378 
11379   std::string redirect_url = base_url_ + "foo.html";
11380   KURL javascript_url = ToKURL("javascript:location='" + redirect_url + "'");
11381   url_test_helpers::RegisterMockedURLLoad(ToKURL(redirect_url),
11382                                           test::CoreTestDataPath("foo.html"));
11383   helper.LocalMainFrame()->LoadJavaScriptURL(javascript_url);
11384   RunPendingTasks();
11385 
11386   // The result of the JS url replaces the existing contents on the
11387   // Document, but the JS-triggered navigation should still occur.
11388   EXPECT_NE("", To<LocalFrame>(helper.GetWebView()->GetPage()->MainFrame())
11389                     ->GetDocument()
11390                     ->documentElement()
11391                     ->innerText());
11392   EXPECT_EQ(ToKURL(redirect_url),
11393             To<LocalFrame>(helper.GetWebView()->GetPage()->MainFrame())
11394                 ->GetDocument()
11395                 ->Url());
11396 }
11397 
TEST_F(WebFrameTest,EmptyJavascriptFrameUrl)11398 TEST_F(WebFrameTest, EmptyJavascriptFrameUrl) {
11399   std::string url = "data:text/html,<iframe src=\"javascript:''\"></iframe>";
11400   frame_test_helpers::WebViewHelper helper;
11401   helper.InitializeAndLoad(url);
11402   RunPendingTasks();
11403 
11404   LocalFrame* child = To<LocalFrame>(
11405       helper.GetWebView()->GetPage()->MainFrame()->Tree().FirstChild());
11406   EXPECT_EQ(BlankURL(), child->GetDocument()->Url());
11407   EXPECT_EQ(BlankURL(), child->Loader().GetDocumentLoader()->Url());
11408 }
11409 
11410 class TestResourcePriorityWebFrameClient
11411     : public frame_test_helpers::TestWebFrameClient {
11412  public:
11413   class ExpectedRequest {
11414    public:
ExpectedRequest(const KURL & url,WebURLRequest::Priority priority)11415     ExpectedRequest(const KURL& url, WebURLRequest::Priority priority)
11416         : url(url), priority(priority), seen(false) {}
11417 
11418     KURL url;
11419     WebURLRequest::Priority priority;
11420     bool seen;
11421   };
11422 
11423   TestResourcePriorityWebFrameClient() = default;
11424   ~TestResourcePriorityWebFrameClient() override = default;
11425 
11426   // frame_test_helpers::TestWebFrameClient:
WillSendRequest(WebURLRequest & request,ForRedirect for_redirect)11427   void WillSendRequest(WebURLRequest& request,
11428                        ForRedirect for_redirect) override {
11429     ExpectedRequest* expected_request = expected_requests_.at(request.Url());
11430     DCHECK(expected_request);
11431     EXPECT_EQ(expected_request->priority, request.GetPriority());
11432     expected_request->seen = true;
11433   }
11434 
AddExpectedRequest(const KURL & url,WebURLRequest::Priority priority)11435   void AddExpectedRequest(const KURL& url, WebURLRequest::Priority priority) {
11436     expected_requests_.insert(url,
11437                               std::make_unique<ExpectedRequest>(url, priority));
11438   }
11439 
VerifyAllRequests()11440   void VerifyAllRequests() {
11441     for (const auto& request : expected_requests_)
11442       EXPECT_TRUE(request.value->seen);
11443   }
11444 
11445  private:
11446   HashMap<KURL, std::unique_ptr<ExpectedRequest>> expected_requests_;
11447 };
11448 
TEST_F(WebFrameTest,ChangeResourcePriority)11449 TEST_F(WebFrameTest, ChangeResourcePriority) {
11450   TestResourcePriorityWebFrameClient client;
11451   RegisterMockedHttpURLLoad("promote_img_in_viewport_priority.html");
11452   RegisterMockedHttpURLLoad("image_slow.pl");
11453   RegisterMockedHttpURLLoad("image_slow_out_of_viewport.pl");
11454   client.AddExpectedRequest(ToKURL("http://internal.test/image_slow.pl"),
11455                             WebURLRequest::Priority::kLow);
11456   client.AddExpectedRequest(
11457       ToKURL("http://internal.test/image_slow_out_of_viewport.pl"),
11458       WebURLRequest::Priority::kLow);
11459 
11460   frame_test_helpers::WebViewHelper helper;
11461   helper.Initialize(&client);
11462   helper.Resize(gfx::Size(640, 480));
11463   frame_test_helpers::LoadFrame(
11464       helper.GetWebView()->MainFrameImpl(),
11465       base_url_ + "promote_img_in_viewport_priority.html");
11466 
11467   // Ensure the image in the viewport got promoted after the request was sent.
11468   Resource* image = To<WebLocalFrameImpl>(helper.GetWebView()->MainFrame())
11469                         ->GetFrame()
11470                         ->GetDocument()
11471                         ->Fetcher()
11472                         ->AllResources()
11473                         .at(ToKURL("http://internal.test/image_slow.pl"));
11474   DCHECK(image);
11475   EXPECT_EQ(ResourceLoadPriority::kHigh,
11476             image->GetResourceRequest().Priority());
11477 
11478   client.VerifyAllRequests();
11479 }
11480 
TEST_F(WebFrameTest,ScriptPriority)11481 TEST_F(WebFrameTest, ScriptPriority) {
11482   TestResourcePriorityWebFrameClient client;
11483   RegisterMockedHttpURLLoad("script_priority.html");
11484   RegisterMockedHttpURLLoad("priorities/defer.js");
11485   RegisterMockedHttpURLLoad("priorities/async.js");
11486   RegisterMockedHttpURLLoad("priorities/head.js");
11487   RegisterMockedHttpURLLoad("priorities/document-write.js");
11488   RegisterMockedHttpURLLoad("priorities/injected.js");
11489   RegisterMockedHttpURLLoad("priorities/injected-async.js");
11490   RegisterMockedHttpURLLoad("priorities/body.js");
11491   client.AddExpectedRequest(ToKURL("http://internal.test/priorities/defer.js"),
11492                             WebURLRequest::Priority::kLow);
11493   client.AddExpectedRequest(ToKURL("http://internal.test/priorities/async.js"),
11494                             WebURLRequest::Priority::kLow);
11495   client.AddExpectedRequest(ToKURL("http://internal.test/priorities/head.js"),
11496                             WebURLRequest::Priority::kHigh);
11497   client.AddExpectedRequest(
11498       ToKURL("http://internal.test/priorities/document-write.js"),
11499       WebURLRequest::Priority::kHigh);
11500   client.AddExpectedRequest(
11501       ToKURL("http://internal.test/priorities/injected.js"),
11502       WebURLRequest::Priority::kLow);
11503   client.AddExpectedRequest(
11504       ToKURL("http://internal.test/priorities/injected-async.js"),
11505       WebURLRequest::Priority::kLow);
11506   client.AddExpectedRequest(ToKURL("http://internal.test/priorities/body.js"),
11507                             WebURLRequest::Priority::kHigh);
11508 
11509   frame_test_helpers::WebViewHelper helper;
11510   helper.InitializeAndLoad(base_url_ + "script_priority.html", &client);
11511   client.VerifyAllRequests();
11512 }
11513 
11514 class MultipleDataChunkDelegate : public WebURLLoaderTestDelegate {
11515  public:
11516   MultipleDataChunkDelegate() = default;
11517   ~MultipleDataChunkDelegate() override = default;
11518 
11519   // WebURLLoaderTestDelegate:
DidReceiveData(WebURLLoaderClient * original_client,const char * data,int data_length)11520   void DidReceiveData(WebURLLoaderClient* original_client,
11521                       const char* data,
11522                       int data_length) override {
11523     EXPECT_GT(data_length, 16);
11524     original_client->DidReceiveData(data, 16);
11525     // This didReceiveData call shouldn't crash due to a failed assertion.
11526     original_client->DidReceiveData(data + 16, data_length - 16);
11527   }
11528 };
11529 
TEST_F(WebFrameTest,ImageDocumentDecodeError)11530 TEST_F(WebFrameTest, ImageDocumentDecodeError) {
11531   std::string url = base_url_ + "not_an_image.ico";
11532   url_test_helpers::RegisterMockedURLLoad(
11533       ToKURL(url), test::CoreTestDataPath("not_an_image.ico"), "image/x-icon");
11534   MultipleDataChunkDelegate delegate;
11535   url_test_helpers::SetLoaderDelegate(&delegate);
11536   frame_test_helpers::WebViewHelper helper;
11537   helper.InitializeAndLoad(url);
11538   url_test_helpers::SetLoaderDelegate(nullptr);
11539 
11540   Document* document =
11541       To<LocalFrame>(helper.GetWebView()->GetPage()->MainFrame())
11542           ->GetDocument();
11543   EXPECT_TRUE(IsA<ImageDocument>(document));
11544   EXPECT_EQ(ResourceStatus::kDecodeError,
11545             To<ImageDocument>(document)->CachedImage()->GetContentStatus());
11546 }
11547 
11548 // Ensure that the root layer -- whose size is ordinarily derived from the
11549 // content size -- maintains a minimum height matching the viewport in cases
11550 // where the content is smaller.
TEST_F(WebFrameTest,RootLayerMinimumHeight)11551 TEST_F(WebFrameTest, RootLayerMinimumHeight) {
11552   constexpr int kViewportWidth = 320;
11553   constexpr int kViewportHeight = 640;
11554   constexpr int kBrowserControlsHeight = 100;
11555 
11556   frame_test_helpers::WebViewHelper web_view_helper;
11557   web_view_helper.Initialize(nullptr, nullptr, nullptr, ConfigureAndroid);
11558   WebViewImpl* web_view = web_view_helper.GetWebView();
11559   web_view->ResizeWithBrowserControls(
11560       gfx::Size(kViewportWidth, kViewportHeight - kBrowserControlsHeight),
11561       kBrowserControlsHeight, 0, true);
11562 
11563   InitializeWithHTML(
11564       *web_view->MainFrameImpl()->GetFrame(),
11565       "<!DOCTYPE html>"
11566       "<meta name='viewport' content='width=device-width, initial-scale=1'>"
11567       "<style>"
11568       "  html, body {width:100%;height:540px;margin:0px}"
11569       "  #elem {"
11570       "    overflow: scroll;"
11571       "    width: 100px;"
11572       "    height: 10px;"
11573       "    position: fixed;"
11574       "    left: 0px;"
11575       "    bottom: 0px;"
11576       "  }"
11577       "</style>"
11578       "<div id='elem'></div>");
11579   UpdateAllLifecyclePhases(web_view);
11580 
11581   Document* document = web_view->MainFrameImpl()->GetFrame()->GetDocument();
11582   LocalFrameView* frame_view = web_view->MainFrameImpl()->GetFrameView();
11583   PaintLayerCompositor* compositor = frame_view->GetLayoutView()->Compositor();
11584 
11585   EXPECT_EQ(kViewportHeight - kBrowserControlsHeight,
11586             compositor->RootLayer()->BoundingBoxForCompositing().Height());
11587 
11588   document->View()->SetTracksRasterInvalidations(true);
11589 
11590   web_view->ResizeWithBrowserControls(
11591       gfx::Size(kViewportWidth, kViewportHeight), kBrowserControlsHeight, 0,
11592       false);
11593 
11594   EXPECT_EQ(kViewportHeight,
11595             compositor->RootLayer()->BoundingBoxForCompositing().Height());
11596   EXPECT_EQ(kViewportHeight, compositor->RootGraphicsLayer()->Size().height());
11597   EXPECT_EQ(kViewportHeight, compositor->RootGraphicsLayer()->Size().height());
11598 
11599   const RasterInvalidationTracking* invalidation_tracking =
11600       document->GetLayoutView()
11601           ->Layer()
11602           ->GetCompositedLayerMapping()
11603           ->MainGraphicsLayer()
11604           ->GetRasterInvalidationTracking();
11605   ASSERT_TRUE(invalidation_tracking);
11606   const auto& raster_invalidations = invalidation_tracking->Invalidations();
11607 
11608   // We don't issue raster invalidation, because the content paints into the
11609   // scrolling contents layer whose size hasn't changed.
11610   EXPECT_TRUE(raster_invalidations.IsEmpty());
11611 
11612   document->View()->SetTracksRasterInvalidations(false);
11613 }
11614 
11615 // Load a page with display:none set and try to scroll it. It shouldn't crash
11616 // due to lack of layoutObject. crbug.com/653327.
TEST_F(WebFrameTest,ScrollBeforeLayoutDoesntCrash)11617 TEST_F(WebFrameTest, ScrollBeforeLayoutDoesntCrash) {
11618   RegisterMockedHttpURLLoad("display-none.html");
11619   frame_test_helpers::WebViewHelper web_view_helper;
11620   web_view_helper.InitializeAndLoad(base_url_ + "display-none.html");
11621   WebViewImpl* web_view = web_view_helper.GetWebView();
11622   web_view_helper.Resize(gfx::Size(640, 480));
11623 
11624   Document* document = web_view->MainFrameImpl()->GetFrame()->GetDocument();
11625   document->documentElement()->SetLayoutObject(nullptr);
11626 
11627   WebGestureEvent begin_event(
11628       WebInputEvent::Type::kGestureScrollBegin, WebInputEvent::kNoModifiers,
11629       WebInputEvent::GetStaticTimeStampForTests(), WebGestureDevice::kTouchpad);
11630   WebGestureEvent update_event(
11631       WebInputEvent::Type::kGestureScrollUpdate, WebInputEvent::kNoModifiers,
11632       WebInputEvent::GetStaticTimeStampForTests(), WebGestureDevice::kTouchpad);
11633   WebGestureEvent end_event(
11634       WebInputEvent::Type::kGestureScrollEnd, WebInputEvent::kNoModifiers,
11635       WebInputEvent::GetStaticTimeStampForTests(), WebGestureDevice::kTouchpad);
11636 
11637   // Try GestureScrollEnd and GestureScrollUpdate first to make sure that not
11638   // seeing a Begin first doesn't break anything. (This currently happens).
11639   web_view_helper.GetWebView()->MainFrameWidget()->HandleInputEvent(
11640       WebCoalescedInputEvent(end_event, ui::LatencyInfo()));
11641   web_view_helper.GetWebView()->MainFrameWidget()->HandleInputEvent(
11642       WebCoalescedInputEvent(update_event, ui::LatencyInfo()));
11643 
11644   // Try a full Begin/Update/End cycle.
11645   web_view_helper.GetWebView()->MainFrameWidget()->HandleInputEvent(
11646       WebCoalescedInputEvent(begin_event, ui::LatencyInfo()));
11647   web_view_helper.GetWebView()->MainFrameWidget()->HandleInputEvent(
11648       WebCoalescedInputEvent(update_event, ui::LatencyInfo()));
11649   web_view_helper.GetWebView()->MainFrameWidget()->HandleInputEvent(
11650       WebCoalescedInputEvent(end_event, ui::LatencyInfo()));
11651 }
11652 
TEST_F(WebFrameTest,MouseOverDifferntNodeClearsTooltip)11653 TEST_F(WebFrameTest, MouseOverDifferntNodeClearsTooltip) {
11654   frame_test_helpers::WebViewHelper web_view_helper;
11655   web_view_helper.Initialize();
11656   web_view_helper.Resize(gfx::Size(200, 200));
11657   WebViewImpl* web_view = web_view_helper.GetWebView();
11658 
11659   InitializeWithHTML(
11660       *web_view->MainFrameImpl()->GetFrame(),
11661       "<head>"
11662       "  <style type='text/css'>"
11663       "   div"
11664       "    {"
11665       "      width: 200px;"
11666       "      height: 100px;"
11667       "      background-color: #eeeeff;"
11668       "    }"
11669       "    div:hover"
11670       "    {"
11671       "      background-color: #ddddff;"
11672       "    }"
11673       "  </style>"
11674       "</head>"
11675       "<body>"
11676       "  <div id='div1' title='Title Attribute Value'>Hover HERE</div>"
11677       "  <div id='div2' title='Title Attribute Value'>Then HERE</div>"
11678       "  <br><br><br>"
11679       "</body>");
11680   UpdateAllLifecyclePhases(web_view);
11681 
11682   Document* document = web_view->MainFrameImpl()->GetFrame()->GetDocument();
11683   Element* div1_tag = document->getElementById("div1");
11684 
11685   HitTestResult hit_test_result =
11686       web_view->MainFrameViewWidget()->CoreHitTestResultAt(
11687           gfx::PointF(div1_tag->OffsetLeft() + 5, div1_tag->OffsetTop() + 5));
11688 
11689   EXPECT_TRUE(hit_test_result.InnerElement());
11690 
11691   // Mouse over link. Mouse cursor should be hand.
11692   WebMouseEvent mouse_move_over_link_event(
11693       WebInputEvent::Type::kMouseMove,
11694       gfx::PointF(div1_tag->OffsetLeft() + 5, div1_tag->OffsetTop() + 5),
11695       gfx::PointF(div1_tag->OffsetLeft() + 5, div1_tag->OffsetTop() + 5),
11696       WebPointerProperties::Button::kNoButton, 0, WebInputEvent::kNoModifiers,
11697       base::TimeTicks::Now());
11698   mouse_move_over_link_event.SetFrameScale(1);
11699   document->GetFrame()->GetEventHandler().HandleMouseMoveEvent(
11700       mouse_move_over_link_event, Vector<WebMouseEvent>(),
11701       Vector<WebMouseEvent>());
11702 
11703   EXPECT_EQ(
11704       document->HoverElement(),
11705       document->GetFrame()->GetChromeClient().LastSetTooltipNodeForTesting());
11706   EXPECT_EQ(
11707       div1_tag,
11708       document->GetFrame()->GetChromeClient().LastSetTooltipNodeForTesting());
11709 
11710   Element* div2_tag = document->getElementById("div2");
11711 
11712   WebMouseEvent mouse_move_event(
11713       WebInputEvent::Type::kMouseMove,
11714       gfx::PointF(div2_tag->OffsetLeft() + 5, div2_tag->OffsetTop() + 5),
11715       gfx::PointF(div2_tag->OffsetLeft() + 5, div2_tag->OffsetTop() + 5),
11716       WebPointerProperties::Button::kNoButton, 0, WebInputEvent::kNoModifiers,
11717       base::TimeTicks::Now());
11718   mouse_move_event.SetFrameScale(1);
11719   document->GetFrame()->GetEventHandler().HandleMouseMoveEvent(
11720       mouse_move_event, Vector<WebMouseEvent>(), Vector<WebMouseEvent>());
11721 
11722   EXPECT_EQ(
11723       document->HoverElement(),
11724       document->GetFrame()->GetChromeClient().LastSetTooltipNodeForTesting());
11725   EXPECT_EQ(
11726       div2_tag,
11727       document->GetFrame()->GetChromeClient().LastSetTooltipNodeForTesting());
11728 }
11729 
11730 class WebFrameSimTest : public SimTest {
11731  public:
UseAndroidSettings()11732   void UseAndroidSettings() {
11733     WebView().GetPage()->GetSettings().SetViewportMetaEnabled(true);
11734     WebView().GetPage()->GetSettings().SetViewportEnabled(true);
11735     WebView().GetPage()->GetSettings().SetMainFrameResizesAreOrientationChanges(
11736         true);
11737     WebView().GetPage()->GetSettings().SetViewportStyle(
11738         mojom::blink::ViewportStyle::kMobile);
11739     WebView().GetSettings()->SetAutoZoomFocusedNodeToLegibleScale(true);
11740     WebView().GetSettings()->SetShrinksViewportContentToFit(true);
11741     WebView().SetDefaultPageScaleLimits(0.25f, 5);
11742   }
11743 };
11744 
TEST_F(WebFrameSimTest,HitTestWithIgnoreClippingAtNegativeOffset)11745 TEST_F(WebFrameSimTest, HitTestWithIgnoreClippingAtNegativeOffset) {
11746   WebView().MainFrameViewWidget()->Resize(gfx::Size(500, 300));
11747   WebView().GetPage()->GetSettings().SetTextAutosizingEnabled(false);
11748 
11749   SimRequest r("https://example.com/test.html", "text/html");
11750   LoadURL("https://example.com/test.html");
11751   r.Complete(R"HTML(
11752       <!DOCTYPE html>
11753       <style>
11754         body, html {
11755           width: 100%;
11756           height: 1000px;
11757           margin: 0;
11758         }
11759         #top {
11760           position: absolute;
11761           top: 500px;
11762           height: 100px;
11763           width: 100%;
11764 
11765         }
11766         #bottom {
11767           position: absolute;
11768           top: 600px;
11769           width: 100%;
11770           height: 500px;
11771         }
11772       </style>
11773       <div id="top"></div>
11774       <div id="bottom"></div>
11775   )HTML");
11776 
11777   Compositor().BeginFrame();
11778 
11779   auto* frame_view = To<LocalFrame>(WebView().GetPage()->MainFrame())->View();
11780 
11781   frame_view->GetScrollableArea()->SetScrollOffset(
11782       ScrollOffset(0, 600), mojom::blink::ScrollType::kProgrammatic);
11783   Compositor().BeginFrame();
11784 
11785   HitTestRequest request = HitTestRequest::kMove | HitTestRequest::kReadOnly |
11786                            HitTestRequest::kActive |
11787                            HitTestRequest::kIgnoreClipping;
11788   HitTestLocation location(
11789       frame_view->ConvertFromRootFrame(PhysicalOffset(100, -50)));
11790   HitTestResult result(request, location);
11791   frame_view->GetLayoutView()->HitTest(location, result);
11792 
11793   EXPECT_EQ(GetDocument().getElementById("top"), result.InnerNode());
11794 }
11795 
TEST_F(WebFrameSimTest,TickmarksDocumentRelative)11796 TEST_F(WebFrameSimTest, TickmarksDocumentRelative) {
11797   WebView().MainFrameViewWidget()->Resize(gfx::Size(500, 300));
11798   WebView().GetPage()->GetSettings().SetTextAutosizingEnabled(false);
11799 
11800   SimRequest request("https://example.com/test.html", "text/html");
11801   LoadURL("https://example.com/test.html");
11802   request.Complete(R"HTML(
11803       <!DOCTYPE html>
11804       <style>
11805         body, html {
11806           width: 4000px;
11807           height: 4000px;
11808           margin: 0;
11809         }
11810         div {
11811           position: absolute;
11812           left: 800px;
11813           top: 2000px;
11814         }
11815       </style>
11816       <div>test</div>
11817   )HTML");
11818 
11819   Compositor().BeginFrame();
11820 
11821   auto* frame = To<WebLocalFrameImpl>(WebView().MainFrame());
11822   auto* frame_view = To<LocalFrame>(WebView().GetPage()->MainFrame())->View();
11823 
11824   frame_view->GetScrollableArea()->SetScrollOffset(
11825       ScrollOffset(3000, 1000), mojom::blink::ScrollType::kProgrammatic);
11826   auto options = mojom::blink::FindOptions::New();
11827   options->run_synchronously_for_testing = true;
11828   WebString search_text = WebString::FromUTF8("test");
11829   const int kFindIdentifier = 12345;
11830   EXPECT_TRUE(frame->GetFindInPage()->FindInternal(kFindIdentifier, search_text,
11831                                                    *options, false));
11832 
11833   frame->EnsureTextFinder().ResetMatchCount();
11834   frame->EnsureTextFinder().StartScopingStringMatches(kFindIdentifier,
11835                                                       search_text, *options);
11836 
11837   // Get the tickmarks for the original find request.
11838   Vector<IntRect> original_tickmarks =
11839       frame_view->LayoutViewport()->GetTickmarks();
11840   EXPECT_EQ(1u, original_tickmarks.size());
11841 
11842   EXPECT_EQ(IntPoint(800, 2000), original_tickmarks[0].Location());
11843 }
11844 
TEST_F(WebFrameSimTest,FindInPageSelectNextMatch)11845 TEST_F(WebFrameSimTest, FindInPageSelectNextMatch) {
11846   WebView().MainFrameViewWidget()->Resize(gfx::Size(500, 300));
11847   WebView().GetPage()->GetSettings().SetTextAutosizingEnabled(false);
11848 
11849   SimRequest request("https://example.com/test.html", "text/html");
11850   LoadURL("https://example.com/test.html");
11851   request.Complete(R"HTML(
11852       <!DOCTYPE html>
11853       <style>
11854         body, html {
11855           width: 4000px;
11856           height: 4000px;
11857           margin: 0;
11858         }
11859         #box1 {
11860           position: absolute;
11861           left: 800px;
11862           top: 2000px;
11863         }
11864 
11865         #box2 {
11866           position: absolute;
11867           left: 1000px;
11868           top: 3000px;
11869         }
11870       </style>
11871       <div id="box1">test</div>
11872       <div id="box2">test</div>
11873   )HTML");
11874 
11875   Compositor().BeginFrame();
11876 
11877   auto* frame = To<WebLocalFrameImpl>(WebView().MainFrame());
11878   auto* local_frame = To<LocalFrame>(WebView().GetPage()->MainFrame());
11879   auto* frame_view = local_frame->View();
11880 
11881   Element* box1 = GetDocument().getElementById("box1");
11882   Element* box2 = GetDocument().getElementById("box2");
11883 
11884   IntRect box1_rect = box1->GetLayoutObject()->AbsoluteBoundingBoxRect();
11885   IntRect box2_rect = box2->GetLayoutObject()->AbsoluteBoundingBoxRect();
11886 
11887   frame_view->GetScrollableArea()->SetScrollOffset(
11888       ScrollOffset(3000, 1000), mojom::blink::ScrollType::kProgrammatic);
11889   auto options = mojom::blink::FindOptions::New();
11890   options->run_synchronously_for_testing = true;
11891   WebString search_text = WebString::FromUTF8("test");
11892   const int kFindIdentifier = 12345;
11893   EXPECT_TRUE(frame->GetFindInPage()->FindInternal(kFindIdentifier, search_text,
11894                                                    *options, false));
11895 
11896   frame->EnsureTextFinder().ResetMatchCount();
11897   frame->EnsureTextFinder().StartScopingStringMatches(kFindIdentifier,
11898                                                       search_text, *options);
11899 
11900   WebVector<gfx::RectF> web_match_rects =
11901       frame->EnsureTextFinder().FindMatchRects();
11902   ASSERT_EQ(2ul, web_match_rects.size());
11903 
11904   FloatRect result_rect = static_cast<FloatRect>(web_match_rects[0]);
11905   frame->EnsureTextFinder().SelectNearestFindMatch(result_rect.Center(),
11906                                                    nullptr);
11907 
11908   EXPECT_TRUE(frame_view->GetScrollableArea()->VisibleContentRect().Contains(
11909       box1_rect));
11910   result_rect = static_cast<FloatRect>(web_match_rects[1]);
11911   frame->EnsureTextFinder().SelectNearestFindMatch(result_rect.Center(),
11912                                                    nullptr);
11913 
11914   EXPECT_TRUE(
11915       frame_view->GetScrollableArea()->VisibleContentRect().Contains(box2_rect))
11916       << "Box [" << box2_rect.ToString() << "] is not visible in viewport ["
11917       << frame_view->GetScrollableArea()->VisibleContentRect().ToString()
11918       << "]";
11919 }
11920 
11921 // Test bubbling a document (End key) scroll from an inner iframe. This test
11922 // passes if it does not crash. https://crbug.com/904247.
TEST_F(WebFrameSimTest,ScrollToEndBubblingCrash)11923 TEST_F(WebFrameSimTest, ScrollToEndBubblingCrash) {
11924   WebView().MainFrameViewWidget()->Resize(gfx::Size(500, 300));
11925   WebView().GetPage()->GetSettings().SetScrollAnimatorEnabled(false);
11926 
11927   SimRequest request("https://example.com/test.html", "text/html");
11928   LoadURL("https://example.com/test.html");
11929   request.Complete(R"HTML(
11930       <!DOCTYPE html>
11931       <style>
11932         body, html {
11933           width: 100%;
11934           height: 100%;
11935           margin: 0;
11936         }
11937         #frame {
11938           width: 100%;
11939           height: 100%;
11940           border: 0;
11941         }
11942       </style>
11943       <iframe id="frame" srcdoc="
11944           <!DOCTYPE html>
11945           <style>html {height: 300%;}</style>
11946       "></iframe>
11947   )HTML");
11948 
11949   Compositor().BeginFrame();
11950   RunPendingTasks();
11951 
11952   // Focus the iframe.
11953   WebView().AdvanceFocus(false);
11954 
11955   WebKeyboardEvent key_event(WebInputEvent::Type::kRawKeyDown,
11956                              WebInputEvent::kNoModifiers,
11957                              WebInputEvent::GetStaticTimeStampForTests());
11958   key_event.windows_key_code = VKEY_END;
11959 
11960   // Scroll the iframe to the end.
11961   key_event.SetType(WebInputEvent::Type::kRawKeyDown);
11962   WebView().MainFrameWidget()->HandleInputEvent(
11963       WebCoalescedInputEvent(key_event, ui::LatencyInfo()));
11964   key_event.SetType(WebInputEvent::Type::kKeyUp);
11965   WebView().MainFrameWidget()->HandleInputEvent(
11966       WebCoalescedInputEvent(key_event, ui::LatencyInfo()));
11967 
11968   Compositor().BeginFrame();
11969 
11970   // End key should now bubble from the iframe up to the main viewport.
11971   key_event.SetType(WebInputEvent::Type::kRawKeyDown);
11972   WebView().MainFrameWidget()->HandleInputEvent(
11973       WebCoalescedInputEvent(key_event, ui::LatencyInfo()));
11974   key_event.SetType(WebInputEvent::Type::kKeyUp);
11975   WebView().MainFrameWidget()->HandleInputEvent(
11976       WebCoalescedInputEvent(key_event, ui::LatencyInfo()));
11977 }
11978 
TEST_F(WebFrameSimTest,TestScrollFocusedEditableElementIntoView)11979 TEST_F(WebFrameSimTest, TestScrollFocusedEditableElementIntoView) {
11980   WebView().MainFrameViewWidget()->Resize(gfx::Size(500, 300));
11981   WebView().SetDefaultPageScaleLimits(1.f, 4);
11982   WebView().EnableFakePageScaleAnimationForTesting(true);
11983   WebView().GetPage()->GetSettings().SetTextAutosizingEnabled(false);
11984   WebView().GetPage()->GetSettings().SetViewportEnabled(false);
11985   WebView().GetSettings()->SetAutoZoomFocusedNodeToLegibleScale(true);
11986 
11987   SimRequest request("https://example.com/test.html", "text/html");
11988   LoadURL("https://example.com/test.html");
11989   request.Complete(R"HTML(
11990       <!DOCTYPE html>
11991       <style>
11992         ::-webkit-scrollbar {
11993           width: 0px;
11994           height: 0px;
11995         }
11996         body {
11997           margin: 0px;
11998         }
11999         input {
12000           border: 0;
12001           padding: 0;
12002           position: absolute;
12003           left: 200px;
12004           top: 600px;
12005           width: 100px;
12006           height: 20px;
12007         }
12008         #content {
12009           background: silver;
12010           width: 500px;
12011           height: 600px;
12012         }
12013       </style>
12014       <div id="content">a</div>
12015       <input type="text">
12016   )HTML");
12017 
12018   Compositor().BeginFrame();
12019 
12020   WebView().AdvanceFocus(false);
12021 
12022   auto* frame = To<LocalFrame>(WebView().GetPage()->MainFrame());
12023   LocalFrameView* frame_view = frame->View();
12024   IntRect inputRect(200, 600, 100, 20);
12025 
12026   frame_view->GetScrollableArea()->SetScrollOffset(
12027       ScrollOffset(0, 0), mojom::blink::ScrollType::kProgrammatic);
12028 
12029   ASSERT_EQ(FloatPoint(),
12030             frame_view->GetScrollableArea()->VisibleContentRect().Location());
12031 
12032   WebView()
12033       .MainFrameImpl()
12034       ->FrameWidget()
12035       ->ScrollFocusedEditableElementIntoView();
12036 
12037   EXPECT_EQ(1, WebView().FakePageScaleAnimationPageScaleForTesting());
12038 
12039   frame_view->LayoutViewport()->SetScrollOffset(
12040       ToFloatSize(FloatPoint(
12041           WebView().FakePageScaleAnimationTargetPositionForTesting())),
12042       mojom::blink::ScrollType::kProgrammatic);
12043 
12044   EXPECT_TRUE(frame_view->GetScrollableArea()->VisibleContentRect().Contains(
12045       inputRect));
12046 
12047   // Reset the testing getters.
12048   WebView().EnableFakePageScaleAnimationForTesting(true);
12049 
12050   // This input is already in view, this shouldn't cause a scroll.
12051   WebView()
12052       .MainFrameImpl()
12053       ->FrameWidget()
12054       ->ScrollFocusedEditableElementIntoView();
12055 
12056   EXPECT_EQ(0, WebView().FakePageScaleAnimationPageScaleForTesting());
12057   EXPECT_EQ(IntPoint(),
12058             WebView().FakePageScaleAnimationTargetPositionForTesting());
12059 
12060   // Now resize the visual viewport so that the input box is no longer in view
12061   // (e.g. a keyboard is overlaid).
12062   WebView().ResizeVisualViewport(gfx::Size(200, 100));
12063   ASSERT_FALSE(frame_view->GetScrollableArea()->VisibleContentRect().Contains(
12064       inputRect));
12065 
12066   WebView()
12067       .MainFrameImpl()
12068       ->FrameWidget()
12069       ->ScrollFocusedEditableElementIntoView();
12070   frame_view->GetScrollableArea()->SetScrollOffset(
12071       ToFloatSize(FloatPoint(
12072           WebView().FakePageScaleAnimationTargetPositionForTesting())),
12073       mojom::blink::ScrollType::kProgrammatic);
12074 
12075   EXPECT_TRUE(frame_view->GetScrollableArea()->VisibleContentRect().Contains(
12076       inputRect));
12077   EXPECT_EQ(1, WebView().FakePageScaleAnimationPageScaleForTesting());
12078 }
12079 
12080 // Ensures scrolling a focused editable text into view that's located in the
12081 // root scroller works by scrolling the root scroller.
TEST_F(WebFrameSimTest,TestScrollFocusedEditableInRootScroller)12082 TEST_F(WebFrameSimTest, TestScrollFocusedEditableInRootScroller) {
12083   ScopedImplicitRootScrollerForTest implicit_root_scroller(true);
12084 
12085   WebView().MainFrameViewWidget()->Resize(gfx::Size(500, 300));
12086   WebView().SetDefaultPageScaleLimits(1.f, 4);
12087   WebView().EnableFakePageScaleAnimationForTesting(true);
12088   WebView().GetPage()->GetSettings().SetTextAutosizingEnabled(false);
12089   WebView().GetPage()->GetSettings().SetViewportEnabled(false);
12090   WebView().GetSettings()->SetAutoZoomFocusedNodeToLegibleScale(true);
12091 
12092   SimRequest request("https://example.com/test.html", "text/html");
12093   LoadURL("https://example.com/test.html");
12094   request.Complete(R"HTML(
12095       <!DOCTYPE html>
12096       <style>
12097         ::-webkit-scrollbar {
12098           width: 0px;
12099           height: 0px;
12100         }
12101         body,html {
12102           width: 100%;
12103           height: 100%;
12104           margin: 0px;
12105         }
12106         input {
12107           border: 0;
12108           padding: 0;
12109           margin-left: 200px;
12110           margin-top: 700px;
12111           width: 100px;
12112           height: 20px;
12113         }
12114         #scroller {
12115           background: silver;
12116           width: 100%;
12117           height: 100%;
12118           overflow: auto;
12119         }
12120       </style>
12121       <div id="scroller" tabindex="-1">
12122         <input type="text">
12123       </div>
12124   )HTML");
12125 
12126   Compositor().BeginFrame();
12127 
12128   TopDocumentRootScrollerController& rs_controller =
12129       GetDocument().GetPage()->GlobalRootScrollerController();
12130 
12131   Element* scroller = GetDocument().getElementById("scroller");
12132   ASSERT_EQ(scroller, rs_controller.GlobalRootScroller());
12133 
12134   auto* frame = To<LocalFrame>(WebView().GetPage()->MainFrame());
12135   VisualViewport& visual_viewport = frame->GetPage()->GetVisualViewport();
12136 
12137   WebView().AdvanceFocus(false);
12138 
12139   rs_controller.RootScrollerArea()->SetScrollOffset(
12140       ScrollOffset(0, 300), mojom::blink::ScrollType::kProgrammatic);
12141 
12142   LocalFrameView* frame_view = frame->View();
12143   IntRect inputRect(200, 700, 100, 20);
12144   ASSERT_EQ(1, visual_viewport.Scale());
12145   ASSERT_EQ(FloatPoint(0, 300),
12146             frame_view->GetScrollableArea()->VisibleContentRect().Location());
12147   ASSERT_FALSE(frame_view->GetScrollableArea()->VisibleContentRect().Contains(
12148       inputRect));
12149 
12150   WebView()
12151       .MainFrameImpl()
12152       ->FrameWidget()
12153       ->ScrollFocusedEditableElementIntoView();
12154 
12155   EXPECT_EQ(1, WebView().FakePageScaleAnimationPageScaleForTesting());
12156 
12157   ScrollOffset target_offset = ToFloatSize(
12158       FloatPoint(WebView().FakePageScaleAnimationTargetPositionForTesting()));
12159 
12160   rs_controller.RootScrollerArea()->SetScrollOffset(
12161       target_offset, mojom::blink::ScrollType::kProgrammatic);
12162 
12163   EXPECT_TRUE(frame_view->GetScrollableArea()->VisibleContentRect().Contains(
12164       inputRect));
12165 }
12166 
TEST_F(WebFrameSimTest,ScrollFocusedIntoViewClipped)12167 TEST_F(WebFrameSimTest, ScrollFocusedIntoViewClipped) {
12168   // The Android On-Screen Keyboard (OSK) resizes the Widget Blink is hosted
12169   // in. When the keyboard is shown, we scroll and zoom in on the currently
12170   // focused editable element. However, the scroll and zoom is a smoothly
12171   // animated "PageScaleAnimation" that's performed in CC only on the viewport
12172   // layers. There are some situations in which the widget resize causes the
12173   // focued input to be hidden by clipping parents that aren't the main frame.
12174   // In these cases, there's no way to scroll just the viewport to make the
12175   // input visible, we need to also scroll those clip/scroller elements  This
12176   // test ensures we do so. https://crbug.com/270018.
12177   UseAndroidSettings();
12178   WebView().MainFrameViewWidget()->Resize(gfx::Size(400, 600));
12179   WebView().EnableFakePageScaleAnimationForTesting(true);
12180   WebView().GetPage()->GetSettings().SetTextAutosizingEnabled(false);
12181 
12182   SimRequest request("https://example.com/test.html", "text/html");
12183   LoadURL("https://example.com/test.html");
12184   request.Complete(R"HTML(
12185       <!DOCTYPE html>
12186       <style>
12187         ::-webkit-scrollbar {
12188           width: 0px;
12189           height: 0px;
12190         }
12191         body, html {
12192           margin: 0px;
12193           width: 100%;
12194           height: 100%;
12195         }
12196         input {
12197           padding: 0;
12198           position: relative;
12199           top: 1400px;
12200           width: 100px;
12201           height: 20px;
12202         }
12203         #clip {
12204           width: 100%;
12205           height: 100%;
12206           overflow: hidden;
12207         }
12208         #container {
12209           width: 980px;
12210           height: 1470px;
12211         }
12212       </style>
12213       <div id="clip">
12214         <div id="container">
12215           <input type="text" id="target">
12216         </div>
12217       </div>
12218   )HTML");
12219 
12220   Compositor().BeginFrame();
12221   WebView().AdvanceFocus(false);
12222 
12223   auto* frame = To<LocalFrame>(WebView().GetPage()->MainFrame());
12224   LocalFrameView* frame_view = frame->View();
12225   VisualViewport& visual_viewport = frame->GetPage()->GetVisualViewport();
12226 
12227   ASSERT_EQ(FloatPoint(),
12228             frame_view->GetScrollableArea()->VisibleContentRect().Location());
12229 
12230   // Simulate the keyboard being shown and resizing the widget. Cause a scroll
12231   // into view after.
12232   WebView().MainFrameViewWidget()->Resize(gfx::Size(400, 300));
12233 
12234   float scale_before = visual_viewport.Scale();
12235   WebView()
12236       .MainFrameImpl()
12237       ->FrameWidget()
12238       ->ScrollFocusedEditableElementIntoView();
12239 
12240   Element* input = GetDocument().getElementById("target");
12241   IntRect input_rect(input->getBoundingClientRect()->top(),
12242                      input->getBoundingClientRect()->left(),
12243                      input->getBoundingClientRect()->width(),
12244                      input->getBoundingClientRect()->height());
12245 
12246   IntRect visible_content_rect(IntPoint(), frame_view->Size());
12247   EXPECT_TRUE(visible_content_rect.Contains(input_rect))
12248       << "Layout viewport [" << visible_content_rect.ToString()
12249       << "] does not contain input rect [" << input_rect.ToString()
12250       << "] after scroll into view.";
12251 
12252   EXPECT_TRUE(visual_viewport.VisibleRect().Contains(input_rect))
12253       << "Visual viewport [" << visual_viewport.VisibleRect().ToString()
12254       << "] does not contain input rect [" << input_rect.ToString()
12255       << "] after scroll into view.";
12256 
12257   // Make sure we also zoomed in on the input.
12258   EXPECT_GT(WebView().FakePageScaleAnimationPageScaleForTesting(),
12259             scale_before);
12260 
12261   // Additional gut-check that we actually scrolled the non-user-scrollable
12262   // clip element to make sure the input is in view.
12263   Element* clip = GetDocument().getElementById("clip");
12264   EXPECT_GT(clip->scrollTop(), 0);
12265 }
12266 
12267 //  This test ensures that we scroll to the correct scale when the focused
12268 //  element has a selection rather than a carret.
TEST_F(WebFrameSimTest,ScrollFocusedSelectionIntoView)12269 TEST_F(WebFrameSimTest, ScrollFocusedSelectionIntoView) {
12270   UseAndroidSettings();
12271   WebView().MainFrameViewWidget()->Resize(gfx::Size(400, 600));
12272   WebView().EnableFakePageScaleAnimationForTesting(true);
12273   WebView().GetPage()->GetSettings().SetTextAutosizingEnabled(false);
12274 
12275   SimRequest request("https://example.com/test.html", "text/html");
12276   LoadURL("https://example.com/test.html");
12277   request.Complete(R"HTML(
12278       <!DOCTYPE html>
12279       <style>
12280         ::-webkit-scrollbar {
12281           width: 0px;
12282           height: 0px;
12283         }
12284         body, html {
12285           margin: 0px;
12286           width: 100%;
12287           height: 100%;
12288         }
12289         input {
12290           padding: 0;
12291           width: 100px;
12292           height: 20px;
12293         }
12294       </style>
12295       <input type="text" id="target" value="test">
12296   )HTML");
12297 
12298   Compositor().BeginFrame();
12299   WebView().AdvanceFocus(false);
12300 
12301   auto* input = To<HTMLInputElement>(GetDocument().getElementById("target"));
12302   input->select();
12303 
12304   // Simulate the keyboard being shown and resizing the widget. Cause a scroll
12305   // into view after.
12306   ASSERT_EQ(WebView().FakePageScaleAnimationPageScaleForTesting(), 0.f);
12307   WebFrameWidget* widget = WebView().MainFrameImpl()->FrameWidgetImpl();
12308   widget->ScrollFocusedEditableElementIntoView();
12309 
12310   // Make sure zoomed in but only up to a legible scale. The bounds are
12311   // arbitrary and fuzzy since we don't specifically care to constrain the
12312   // amount of zooming (that should be tested elsewhere), we just care that it
12313   // zooms but not off to infinity.
12314   EXPECT_GT(WebView().FakePageScaleAnimationPageScaleForTesting(), .75f);
12315   EXPECT_LT(WebView().FakePageScaleAnimationPageScaleForTesting(), 2.f);
12316 }
12317 
TEST_F(WebFrameSimTest,DoubleTapZoomWhileScrolled)12318 TEST_F(WebFrameSimTest, DoubleTapZoomWhileScrolled) {
12319   UseAndroidSettings();
12320   WebView().MainFrameViewWidget()->Resize(gfx::Size(490, 500));
12321   WebView().EnableFakePageScaleAnimationForTesting(true);
12322   WebView().GetSettings()->SetTextAutosizingEnabled(false);
12323   WebView().SetDefaultPageScaleLimits(0.5f, 4);
12324 
12325   SimRequest request("https://example.com/test.html", "text/html");
12326   LoadURL("https://example.com/test.html");
12327   request.Complete(R"HTML(
12328       <!DOCTYPE html>
12329       <style>
12330         ::-webkit-scrollbar {
12331           width: 0px;
12332           height: 0px;
12333         }
12334         body {
12335           margin: 0px;
12336           width: 10000px;
12337           height: 10000px;
12338         }
12339         #target {
12340           position: absolute;
12341           left: 2000px;
12342           top: 3000px;
12343           width: 100px;
12344           height: 100px;
12345           background-color: blue;
12346         }
12347       </style>
12348       <div id="target"></div>
12349   )HTML");
12350 
12351   Compositor().BeginFrame();
12352 
12353   auto* frame = To<LocalFrame>(WebView().GetPage()->MainFrame());
12354   LocalFrameView* frame_view = frame->View();
12355   VisualViewport& visual_viewport = frame->GetPage()->GetVisualViewport();
12356   IntRect target_rect_in_document(2000, 3000, 100, 100);
12357 
12358   ASSERT_EQ(0.5f, visual_viewport.Scale());
12359 
12360   // Center the target in the screen.
12361   frame_view->GetScrollableArea()->SetScrollOffset(
12362       ScrollOffset(2000 - 440, 3000 - 450),
12363       mojom::blink::ScrollType::kProgrammatic);
12364   Element* target = GetDocument().QuerySelector("#target");
12365   DOMRect* rect = target->getBoundingClientRect();
12366   ASSERT_EQ(440, rect->left());
12367   ASSERT_EQ(450, rect->top());
12368 
12369   // Double-tap on the target. Expect that we zoom in and the target is
12370   // contained in the visual viewport.
12371   {
12372     gfx::Point point(445, 455);
12373     WebRect block_bounds = ComputeBlockBoundHelper(&WebView(), point, false);
12374     WebView().AnimateDoubleTapZoom(IntPoint(point), block_bounds);
12375     EXPECT_TRUE(WebView().FakeDoubleTapAnimationPendingForTesting());
12376     ScrollOffset new_offset = ToScrollOffset(
12377         FloatPoint(WebView().FakePageScaleAnimationTargetPositionForTesting()));
12378     float new_scale = WebView().FakePageScaleAnimationPageScaleForTesting();
12379     visual_viewport.SetScale(new_scale);
12380     frame_view->GetScrollableArea()->SetScrollOffset(
12381         new_offset, mojom::blink::ScrollType::kProgrammatic);
12382 
12383     EXPECT_FLOAT_EQ(1, visual_viewport.Scale());
12384     EXPECT_TRUE(frame_view->GetScrollableArea()->VisibleContentRect().Contains(
12385         target_rect_in_document));
12386   }
12387 
12388   // Reset the testing getters.
12389   WebView().EnableFakePageScaleAnimationForTesting(true);
12390 
12391   // Double-tap on the target again. We should zoom out and the target should
12392   // remain on screen.
12393   {
12394     gfx::Point point(445, 455);
12395     WebRect block_bounds = ComputeBlockBoundHelper(&WebView(), point, false);
12396     WebView().AnimateDoubleTapZoom(IntPoint(point), block_bounds);
12397     EXPECT_TRUE(WebView().FakeDoubleTapAnimationPendingForTesting());
12398     IntPoint target_offset(
12399         WebView().FakePageScaleAnimationTargetPositionForTesting());
12400     float new_scale = WebView().FakePageScaleAnimationPageScaleForTesting();
12401 
12402     EXPECT_FLOAT_EQ(0.5f, new_scale);
12403     EXPECT_TRUE(target_rect_in_document.Contains(target_offset));
12404   }
12405 }
12406 
TEST_F(WebFrameSimTest,ChangeBackgroundColor)12407 TEST_F(WebFrameSimTest, ChangeBackgroundColor) {
12408   SimRequest main_resource("https://example.com/test.html", "text/html");
12409 
12410   LoadURL("https://example.com/test.html");
12411   main_resource.Complete("<!DOCTYPE html><body></body>");
12412 
12413   Element* body = GetDocument().QuerySelector("body");
12414   EXPECT_TRUE(!!body);
12415 
12416   Compositor().BeginFrame();
12417   // White is the default background of a web page.
12418   EXPECT_EQ(SK_ColorWHITE, Compositor().background_color());
12419 
12420   // Setting the background of the body to red will cause the background
12421   // color of the WebView to switch to red.
12422   body->SetInlineStyleProperty(CSSPropertyID::kBackgroundColor, "red");
12423   Compositor().BeginFrame();
12424   EXPECT_EQ(SK_ColorRED, Compositor().background_color());
12425 }
12426 
12427 // Ensure we don't crash if we try to scroll into view the focused editable
12428 // element which doesn't have a LayoutObject.
TEST_F(WebFrameSimTest,ScrollFocusedEditableIntoViewNoLayoutObject)12429 TEST_F(WebFrameSimTest, ScrollFocusedEditableIntoViewNoLayoutObject) {
12430   WebView().MainFrameViewWidget()->Resize(gfx::Size(500, 600));
12431   WebView().GetPage()->GetSettings().SetTextAutosizingEnabled(false);
12432 
12433   SimRequest r("https://example.com/test.html", "text/html");
12434   LoadURL("https://example.com/test.html");
12435   r.Complete(R"HTML(
12436       <!DOCTYPE html>
12437       <style>
12438         input {
12439           position: absolute;
12440           top: 1000px;
12441           left: 800px;
12442         }
12443 
12444         @media (max-height: 500px) {
12445           input {
12446             display: none;
12447           }
12448         }
12449       </style>
12450       <input id="target" type="text"></input>
12451   )HTML");
12452 
12453   Compositor().BeginFrame();
12454 
12455   Element* input = GetDocument().getElementById("target");
12456   input->focus();
12457 
12458   ScrollableArea* area = GetDocument().View()->LayoutViewport();
12459   area->SetScrollOffset(ScrollOffset(0, 0),
12460                         mojom::blink::ScrollType::kProgrammatic);
12461 
12462   ASSERT_TRUE(input->GetLayoutObject());
12463   ASSERT_EQ(input, WebView().FocusedElement());
12464   ASSERT_EQ(ScrollOffset(0, 0), area->GetScrollOffset());
12465 
12466   // The resize should cause the focused element to lose its LayoutObject. If
12467   // this resize came from the Android on-screen keyboard, this would be
12468   // followed by a ScrollFocusedEditableElementIntoView. Ensure we don't crash.
12469   WebView().MainFrameViewWidget()->Resize(gfx::Size(500, 300));
12470 
12471   ASSERT_FALSE(input->GetLayoutObject());
12472   ASSERT_EQ(input, WebView().FocusedElement());
12473 
12474   WebFrameWidget* widget = WebView().MainFrameImpl()->FrameWidgetImpl();
12475   widget->ScrollFocusedEditableElementIntoView();
12476   Compositor().BeginFrame();
12477 
12478   // Shouldn't cause any scrolling either.
12479   EXPECT_EQ(ScrollOffset(0, 0), area->GetScrollOffset());
12480 }
12481 
TEST_F(WebFrameSimTest,DisplayNoneIFrameHasNoLayoutObjects)12482 TEST_F(WebFrameSimTest, DisplayNoneIFrameHasNoLayoutObjects) {
12483   SimRequest main_resource("https://example.com/test.html", "text/html");
12484   SimRequest frame_resource("https://example.com/frame.html", "text/html");
12485 
12486   LoadURL("https://example.com/test.html");
12487   main_resource.Complete(
12488       "<!DOCTYPE html>"
12489       "<iframe src=frame.html style='display: none'></iframe>");
12490   frame_resource.Complete(
12491       "<!DOCTYPE html>"
12492       "<html><body>This is a visible iframe.</body></html>");
12493 
12494   Element* element = GetDocument().QuerySelector("iframe");
12495   auto* frame_owner_element = To<HTMLFrameOwnerElement>(element);
12496   Document* iframe_doc = frame_owner_element->contentDocument();
12497   EXPECT_FALSE(iframe_doc->documentElement()->GetLayoutObject());
12498 
12499   // Changing the display from 'none' -> 'block' should cause layout objects to
12500   // appear.
12501   element->SetInlineStyleProperty(CSSPropertyID::kDisplay, CSSValueID::kBlock);
12502   Compositor().BeginFrame();
12503   EXPECT_TRUE(iframe_doc->documentElement()->GetLayoutObject());
12504 
12505   // Changing the display from 'block' -> 'none' should cause layout objects to
12506   // disappear.
12507   element->SetInlineStyleProperty(CSSPropertyID::kDisplay, CSSValueID::kNone);
12508 
12509   Compositor().BeginFrame();
12510   EXPECT_FALSE(iframe_doc->documentElement()->GetLayoutObject());
12511 }
12512 
12513 // Although it is not spec compliant, many websites intentionally call
12514 // Window.print() on display:none iframes. https://crbug.com/819327.
TEST_F(WebFrameSimTest,DisplayNoneIFramePrints)12515 TEST_F(WebFrameSimTest, DisplayNoneIFramePrints) {
12516   SimRequest main_resource("https://example.com/test.html", "text/html");
12517   SimRequest frame_resource("https://example.com/frame.html", "text/html");
12518 
12519   LoadURL("https://example.com/test.html");
12520   main_resource.Complete(
12521       "<!DOCTYPE html>"
12522       "<iframe src=frame.html style='display: none'></iframe>");
12523   frame_resource.Complete(
12524       "<!DOCTYPE html>"
12525       "<html><body>This is a visible iframe.</body></html>");
12526 
12527   Element* element = GetDocument().QuerySelector("iframe");
12528   auto* frame_owner_element = To<HTMLFrameOwnerElement>(element);
12529   Document* iframe_doc = frame_owner_element->contentDocument();
12530   EXPECT_FALSE(iframe_doc->documentElement()->GetLayoutObject());
12531 
12532   FloatSize page_size(400, 400);
12533   float maximum_shrink_ratio = 1.0;
12534   iframe_doc->GetFrame()->StartPrinting(page_size, page_size,
12535                                         maximum_shrink_ratio);
12536   EXPECT_TRUE(iframe_doc->documentElement()->GetLayoutObject());
12537 
12538   iframe_doc->GetFrame()->EndPrinting();
12539   EXPECT_FALSE(iframe_doc->documentElement()->GetLayoutObject());
12540 }
12541 
TEST_F(WebFrameSimTest,NormalIFrameHasLayoutObjects)12542 TEST_F(WebFrameSimTest, NormalIFrameHasLayoutObjects) {
12543   SimRequest main_resource("https://example.com/test.html", "text/html");
12544   SimRequest frame_resource("https://example.com/frame.html", "text/html");
12545 
12546   LoadURL("https://example.com/test.html");
12547   main_resource.Complete(
12548       "<!DOCTYPE html>"
12549       "<iframe src=frame.html style='display: block'></iframe>");
12550   frame_resource.Complete(
12551       "<!DOCTYPE html>"
12552       "<html><body>This is a visible iframe.</body></html>");
12553 
12554   Element* element = GetDocument().QuerySelector("iframe");
12555   auto* frame_owner_element = To<HTMLFrameOwnerElement>(element);
12556   Document* iframe_doc = frame_owner_element->contentDocument();
12557   EXPECT_TRUE(iframe_doc->documentElement()->GetLayoutObject());
12558 
12559   // Changing the display from 'block' -> 'none' should cause layout objects to
12560   // disappear.
12561   element->SetInlineStyleProperty(CSSPropertyID::kDisplay, CSSValueID::kNone);
12562   Compositor().BeginFrame();
12563   EXPECT_FALSE(iframe_doc->documentElement()->GetLayoutObject());
12564 }
12565 
TEST_F(WebFrameSimTest,RtlInitialScrollOffsetWithViewport)12566 TEST_F(WebFrameSimTest, RtlInitialScrollOffsetWithViewport) {
12567   UseAndroidSettings();
12568 
12569   WebView().MainFrameViewWidget()->Resize(gfx::Size(400, 400));
12570   WebView().SetDefaultPageScaleLimits(0.25f, 2);
12571 
12572   SimRequest main_resource("https://example.com/test.html", "text/html");
12573   LoadURL("https://example.com/test.html");
12574   main_resource.Complete(R"HTML(
12575     <meta name='viewport' content='width=device-width, minimum-scale=1'>
12576     <body dir='rtl'>
12577     <div style='width: 3000px; height: 20px'></div>
12578   )HTML");
12579 
12580   Compositor().BeginFrame();
12581   ScrollableArea* area = GetDocument().View()->LayoutViewport();
12582   ASSERT_EQ(ScrollOffset(0, 0), area->GetScrollOffset());
12583 }
12584 
TEST_F(WebFrameSimTest,LayoutViewportExceedsLayoutOverflow)12585 TEST_F(WebFrameSimTest, LayoutViewportExceedsLayoutOverflow) {
12586   UseAndroidSettings();
12587 
12588   WebView().ResizeWithBrowserControls(gfx::Size(400, 540), 60, 0, true);
12589   WebView().SetDefaultPageScaleLimits(0.25f, 2);
12590 
12591   SimRequest main_resource("https://example.com/test.html", "text/html");
12592   LoadURL("https://example.com/test.html");
12593   main_resource.Complete(R"HTML(
12594     <meta name='viewport' content='width=device-width, minimum-scale=1'>
12595     <body style='margin: 0; height: 95vh'>
12596   )HTML");
12597 
12598   Compositor().BeginFrame();
12599   ScrollableArea* area = GetDocument().View()->LayoutViewport();
12600   ASSERT_EQ(540, area->VisibleHeight());
12601   ASSERT_EQ(IntSize(400, 570), area->ContentsSize());
12602 
12603   // Hide browser controls, growing layout viewport without affecting ICB.
12604   WebView().ResizeWithBrowserControls(gfx::Size(400, 600), 60, 0, false);
12605   Compositor().BeginFrame();
12606 
12607   // ContentsSize() should grow to accommodate new visible size.
12608   ASSERT_EQ(600, area->VisibleHeight());
12609   ASSERT_EQ(IntSize(400, 600), area->ContentsSize());
12610 }
12611 
TEST_F(WebFrameSimTest,LayoutViewLocalVisualRect)12612 TEST_F(WebFrameSimTest, LayoutViewLocalVisualRect) {
12613   UseAndroidSettings();
12614 
12615   WebView().MainFrameViewWidget()->Resize(gfx::Size(600, 400));
12616   WebView().SetDefaultPageScaleLimits(0.5f, 2);
12617 
12618   SimRequest main_resource("https://example.com/test.html", "text/html");
12619   LoadURL("https://example.com/test.html");
12620   main_resource.Complete(R"HTML(
12621     <meta name='viewport' content='width=device-width, minimum-scale=0.5'>
12622     <body style='margin: 0; width: 1800px; height: 1200px'></div>
12623   )HTML");
12624 
12625   Compositor().BeginFrame();
12626   ASSERT_EQ(PhysicalRect(0, 0, 1200, 800),
12627             GetDocument().GetLayoutView()->LocalVisualRect());
12628 }
12629 
TEST_F(WebFrameSimTest,NamedLookupIgnoresEmptyNames)12630 TEST_F(WebFrameSimTest, NamedLookupIgnoresEmptyNames) {
12631   SimRequest main_resource("https://example.com/main.html", "text/html");
12632   LoadURL("https://example.com/main.html");
12633   main_resource.Complete(R"HTML(
12634     <body>
12635     <iframe name="" src="data:text/html,"></iframe>
12636     </body>)HTML");
12637 
12638   EXPECT_EQ(nullptr, MainFrame().GetFrame()->Tree().ScopedChild(""));
12639   EXPECT_EQ(nullptr,
12640             MainFrame().GetFrame()->Tree().ScopedChild(AtomicString()));
12641   EXPECT_EQ(nullptr, MainFrame().GetFrame()->Tree().ScopedChild(g_empty_atom));
12642 }
12643 
TEST_F(WebFrameTest,NoLoadingCompletionCallbacksInDetach)12644 TEST_F(WebFrameTest, NoLoadingCompletionCallbacksInDetach) {
12645   class LoadingObserverFrameClient
12646       : public frame_test_helpers::TestWebFrameClient {
12647    public:
12648     LoadingObserverFrameClient() = default;
12649     ~LoadingObserverFrameClient() override = default;
12650 
12651     // frame_test_helpers::TestWebFrameClient:
12652     void FrameDetached() override {
12653       did_call_frame_detached_ = true;
12654       TestWebFrameClient::FrameDetached();
12655     }
12656 
12657     void DidStopLoading() override {
12658       // TODO(dcheng): Investigate not calling this as well during frame detach.
12659       did_call_did_stop_loading_ = true;
12660       TestWebFrameClient::DidStopLoading();
12661     }
12662 
12663     void DidFinishDocumentLoad() override {
12664       // TODO(dcheng): Investigate not calling this as well during frame detach.
12665       did_call_did_finish_document_load_ = true;
12666     }
12667 
12668     void DidHandleOnloadEvents() override {
12669       // TODO(dcheng): Investigate not calling this as well during frame detach.
12670       did_call_did_handle_onload_events_ = true;
12671     }
12672 
12673     void DidFinishLoad() override {
12674       EXPECT_TRUE(false) << "didFinishLoad() should not have been called.";
12675     }
12676 
12677     bool DidCallFrameDetached() const { return did_call_frame_detached_; }
12678     bool DidCallDidStopLoading() const { return did_call_did_stop_loading_; }
12679     bool DidCallDidFinishDocumentLoad() const {
12680       return did_call_did_finish_document_load_;
12681     }
12682     bool DidCallDidHandleOnloadEvents() const {
12683       return did_call_did_handle_onload_events_;
12684     }
12685 
12686    private:
12687     bool did_call_frame_detached_ = false;
12688     bool did_call_did_stop_loading_ = false;
12689     bool did_call_did_finish_document_load_ = false;
12690     bool did_call_did_handle_onload_events_ = false;
12691   };
12692 
12693   class MainFrameClient : public frame_test_helpers::TestWebFrameClient {
12694    public:
12695     MainFrameClient() = default;
12696     ~MainFrameClient() override = default;
12697 
12698     // frame_test_helpers::TestWebFrameClient:
12699     WebLocalFrame* CreateChildFrame(
12700         WebLocalFrame* parent,
12701         mojom::blink::TreeScopeType scope,
12702         const WebString& name,
12703         const WebString& fallback_name,
12704         const FramePolicy&,
12705         const WebFrameOwnerProperties&,
12706         mojom::blink::FrameOwnerElementType) override {
12707       return CreateLocalChild(*parent, scope, &child_client_);
12708     }
12709 
12710     LoadingObserverFrameClient& ChildClient() { return child_client_; }
12711 
12712    private:
12713     LoadingObserverFrameClient child_client_;
12714   };
12715 
12716   RegisterMockedHttpURLLoad("single_iframe.html");
12717   url_test_helpers::RegisterMockedURLLoad(
12718       ToKURL(base_url_ + "visible_iframe.html"),
12719       test::CoreTestDataPath("frame_with_frame.html"));
12720   RegisterMockedHttpURLLoad("parent_detaching_frame.html");
12721 
12722   frame_test_helpers::WebViewHelper web_view_helper;
12723   MainFrameClient main_frame_client;
12724   web_view_helper.InitializeAndLoad(base_url_ + "single_iframe.html",
12725                                     &main_frame_client);
12726 
12727   EXPECT_TRUE(main_frame_client.ChildClient().DidCallFrameDetached());
12728   EXPECT_TRUE(main_frame_client.ChildClient().DidCallDidStopLoading());
12729   EXPECT_TRUE(main_frame_client.ChildClient().DidCallDidFinishDocumentLoad());
12730   EXPECT_TRUE(main_frame_client.ChildClient().DidCallDidHandleOnloadEvents());
12731 
12732   web_view_helper.Reset();
12733 }
12734 
TEST_F(WebFrameTest,ClearClosedOpener)12735 TEST_F(WebFrameTest, ClearClosedOpener) {
12736   frame_test_helpers::WebViewHelper opener_helper;
12737   opener_helper.Initialize();
12738   frame_test_helpers::WebViewHelper helper;
12739   helper.InitializeWithOpener(opener_helper.GetWebView()->MainFrame());
12740 
12741   opener_helper.Reset();
12742   EXPECT_EQ(nullptr, helper.LocalMainFrame()->Opener());
12743 }
12744 
12745 class ShowVirtualKeyboardObserverWidgetClient
12746     : public frame_test_helpers::TestWebWidgetClient {
12747  public:
12748   ShowVirtualKeyboardObserverWidgetClient() = default;
12749   ~ShowVirtualKeyboardObserverWidgetClient() override = default;
12750 
12751   // frame_test_helpers::TestWebWidgetClient:
TextInputStateChanged(ui::mojom::blink::TextInputStatePtr state)12752   void TextInputStateChanged(
12753       ui::mojom::blink::TextInputStatePtr state) override {
12754     did_show_virtual_keyboard_ |= state->show_ime_if_needed;
12755   }
12756 
DidShowVirtualKeyboard() const12757   bool DidShowVirtualKeyboard() const { return did_show_virtual_keyboard_; }
12758 
12759  private:
12760   bool did_show_virtual_keyboard_ = false;
12761 };
12762 
TEST_F(WebFrameTest,ShowVirtualKeyboardOnElementFocus)12763 TEST_F(WebFrameTest, ShowVirtualKeyboardOnElementFocus) {
12764   frame_test_helpers::WebViewHelper web_view_helper;
12765   web_view_helper.InitializeRemote();
12766 
12767   ShowVirtualKeyboardObserverWidgetClient web_widget_client;
12768   WebLocalFrameImpl* local_frame = frame_test_helpers::CreateLocalChild(
12769       *web_view_helper.RemoteMainFrame(), "child", WebFrameOwnerProperties(),
12770       nullptr, nullptr, &web_widget_client);
12771 
12772   RegisterMockedHttpURLLoad("input_field_default.html");
12773   frame_test_helpers::LoadFrame(local_frame,
12774                                 base_url_ + "input_field_default.html");
12775 
12776   // Simulate an input element focus leading to Element::focus() call with a
12777   // user gesture.
12778   LocalFrame::NotifyUserActivation(
12779       local_frame->GetFrame(), mojom::UserActivationNotificationType::kTest);
12780   local_frame->ExecuteScript(
12781       WebScriptSource("window.focus();"
12782                       "document.querySelector('input').focus();"));
12783 
12784   RunPendingTasks();
12785   // Verify that the right WebWidgetClient has been notified.
12786 #if BUILDFLAG(IS_ASH)
12787   EXPECT_FALSE(web_widget_client.DidShowVirtualKeyboard());
12788 #else
12789   EXPECT_TRUE(web_widget_client.DidShowVirtualKeyboard());
12790 #endif
12791   web_view_helper.Reset();
12792 }
12793 
12794 class ContextMenuWebFrameClient
12795     : public frame_test_helpers::TestWebFrameClient {
12796  public:
12797   ContextMenuWebFrameClient() = default;
12798   ~ContextMenuWebFrameClient() override = default;
12799 
12800   // WebLocalFrameClient:
ShowContextMenu(const WebContextMenuData & data,const base::Optional<gfx::Point> &)12801   void ShowContextMenu(const WebContextMenuData& data,
12802                        const base::Optional<gfx::Point>&) override {
12803     menu_data_ = data;
12804   }
12805 
GetMenuData()12806   WebContextMenuData GetMenuData() { return menu_data_; }
12807 
12808  private:
12809   WebContextMenuData menu_data_;
12810   DISALLOW_COPY_AND_ASSIGN(ContextMenuWebFrameClient);
12811 };
12812 
TestSelectAll(const std::string & html)12813 bool TestSelectAll(const std::string& html) {
12814   ContextMenuWebFrameClient frame;
12815   frame_test_helpers::WebViewHelper web_view_helper;
12816   WebViewImpl* web_view = web_view_helper.Initialize(&frame);
12817   frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(), html,
12818                                      ToKURL("about:blank"));
12819   web_view->MainFrameViewWidget()->Resize(gfx::Size(500, 300));
12820   web_view->MainFrameWidget()->UpdateAllLifecyclePhases(
12821       DocumentUpdateReason::kTest);
12822   RunPendingTasks();
12823   web_view->MainFrameImpl()->GetFrame()->SetInitialFocus(false);
12824   RunPendingTasks();
12825 
12826   WebMouseEvent mouse_event(WebInputEvent::Type::kMouseDown,
12827                             WebInputEvent::kNoModifiers,
12828                             WebInputEvent::GetStaticTimeStampForTests());
12829 
12830   mouse_event.button = WebMouseEvent::Button::kRight;
12831   mouse_event.SetPositionInWidget(8, 8);
12832   mouse_event.click_count = 1;
12833   web_view->MainFrameWidget()->HandleInputEvent(
12834       WebCoalescedInputEvent(mouse_event, ui::LatencyInfo()));
12835   RunPendingTasks();
12836   web_view_helper.Reset();
12837   return frame.GetMenuData().edit_flags &
12838          ContextMenuDataEditFlags::kCanSelectAll;
12839 }
12840 
TEST_F(WebFrameTest,ContextMenuDataSelectAll)12841 TEST_F(WebFrameTest, ContextMenuDataSelectAll) {
12842   EXPECT_FALSE(TestSelectAll("<textarea></textarea>"));
12843   EXPECT_TRUE(TestSelectAll("<textarea>nonempty</textarea>"));
12844   EXPECT_FALSE(TestSelectAll("<input>"));
12845   EXPECT_TRUE(TestSelectAll("<input value='nonempty'>"));
12846   EXPECT_FALSE(TestSelectAll("<div contenteditable></div>"));
12847   EXPECT_TRUE(TestSelectAll("<div contenteditable>nonempty</div>"));
12848   EXPECT_TRUE(TestSelectAll("<div contenteditable>\n</div>"));
12849 }
12850 
TEST_F(WebFrameTest,ContextMenuDataSelectedText)12851 TEST_F(WebFrameTest, ContextMenuDataSelectedText) {
12852   ContextMenuWebFrameClient frame;
12853   frame_test_helpers::WebViewHelper web_view_helper;
12854   WebViewImpl* web_view = web_view_helper.Initialize(&frame);
12855   const std::string& html = "<input value=' '>";
12856   frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(), html,
12857                                      ToKURL("about:blank"));
12858   web_view->MainFrameViewWidget()->Resize(gfx::Size(500, 300));
12859   UpdateAllLifecyclePhases(web_view);
12860   RunPendingTasks();
12861   web_view->MainFrameImpl()->GetFrame()->SetInitialFocus(false);
12862   RunPendingTasks();
12863 
12864   web_view->MainFrameImpl()->ExecuteCommand(WebString::FromUTF8("SelectAll"));
12865 
12866   WebMouseEvent mouse_event(WebInputEvent::Type::kMouseDown,
12867                             WebInputEvent::kNoModifiers,
12868                             WebInputEvent::GetStaticTimeStampForTests());
12869 
12870   mouse_event.button = WebMouseEvent::Button::kRight;
12871   mouse_event.SetPositionInWidget(8, 8);
12872   mouse_event.click_count = 1;
12873   web_view->MainFrameWidget()->HandleInputEvent(
12874       WebCoalescedInputEvent(mouse_event, ui::LatencyInfo()));
12875   RunPendingTasks();
12876   web_view_helper.Reset();
12877   EXPECT_EQ(frame.GetMenuData().selected_text, " ");
12878 }
12879 
TEST_F(WebFrameTest,ContextMenuDataPasswordSelectedText)12880 TEST_F(WebFrameTest, ContextMenuDataPasswordSelectedText) {
12881   ContextMenuWebFrameClient frame;
12882   frame_test_helpers::WebViewHelper web_view_helper;
12883   WebViewImpl* web_view = web_view_helper.Initialize(&frame);
12884   const std::string& html = "<input type='password' value='password'>";
12885   frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(), html,
12886                                      ToKURL("about:blank"));
12887   web_view->MainFrameViewWidget()->Resize(gfx::Size(500, 300));
12888   UpdateAllLifecyclePhases(web_view);
12889   RunPendingTasks();
12890   web_view->MainFrameImpl()->GetFrame()->SetInitialFocus(false);
12891   RunPendingTasks();
12892 
12893   web_view->MainFrameImpl()->ExecuteCommand(WebString::FromUTF8("SelectAll"));
12894 
12895   WebMouseEvent mouse_event(WebInputEvent::Type::kMouseDown,
12896                             WebInputEvent::kNoModifiers,
12897                             WebInputEvent::GetStaticTimeStampForTests());
12898 
12899   mouse_event.button = WebMouseEvent::Button::kRight;
12900   mouse_event.SetPositionInWidget(8, 8);
12901   mouse_event.click_count = 1;
12902   web_view->MainFrameWidget()->HandleInputEvent(
12903       WebCoalescedInputEvent(mouse_event, ui::LatencyInfo()));
12904 
12905   RunPendingTasks();
12906   web_view_helper.Reset();
12907   EXPECT_EQ(frame.GetMenuData().input_field_type,
12908             blink::ContextMenuDataInputFieldType::kPassword);
12909   EXPECT_FALSE(frame.GetMenuData().selected_text.IsEmpty());
12910 }
12911 
TEST_F(WebFrameTest,ContextMenuDataNonLocatedMenu)12912 TEST_F(WebFrameTest, ContextMenuDataNonLocatedMenu) {
12913   ContextMenuWebFrameClient frame;
12914   frame_test_helpers::WebViewHelper web_view_helper;
12915   WebViewImpl* web_view = web_view_helper.Initialize(&frame);
12916   const std::string& html =
12917       "<div style='font-size: 1000%; line-height: 0.7em'>Select me<br/>"
12918       "Next line</div>";
12919   frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(), html,
12920                                      ToKURL("about:blank"));
12921   web_view->MainFrameViewWidget()->Resize(gfx::Size(500, 300));
12922   UpdateAllLifecyclePhases(web_view);
12923   RunPendingTasks();
12924   web_view->MainFrameImpl()->GetFrame()->SetInitialFocus(false);
12925   RunPendingTasks();
12926 
12927   WebMouseEvent mouse_event(WebInputEvent::Type::kMouseDown,
12928                             WebInputEvent::kNoModifiers,
12929                             WebInputEvent::GetStaticTimeStampForTests());
12930 
12931   mouse_event.button = WebMouseEvent::Button::kLeft;
12932   mouse_event.SetPositionInWidget(0, 0);
12933   mouse_event.click_count = 2;
12934   web_view->MainFrameWidget()->HandleInputEvent(
12935       WebCoalescedInputEvent(mouse_event, ui::LatencyInfo()));
12936 
12937   web_view->MainFrameImpl()->LocalRootFrameWidget()->ShowContextMenu(
12938       ui::mojom::MenuSourceType::TOUCH,
12939       web_view->MainFrameImpl()->GetPositionInViewportForTesting());
12940 
12941   RunPendingTasks();
12942   web_view_helper.Reset();
12943   EXPECT_EQ(frame.GetMenuData().source_type, kMenuSourceTouch);
12944   EXPECT_FALSE(frame.GetMenuData().selected_text.IsEmpty());
12945 }
12946 
TEST_F(WebFrameTest,LocalFrameWithRemoteParentIsTransparent)12947 TEST_F(WebFrameTest, LocalFrameWithRemoteParentIsTransparent) {
12948   frame_test_helpers::WebViewHelper helper;
12949   helper.InitializeRemote();
12950 
12951   WebLocalFrameImpl* local_frame =
12952       frame_test_helpers::CreateLocalChild(*helper.RemoteMainFrame());
12953   frame_test_helpers::LoadFrame(local_frame, "data:text/html,some page");
12954 
12955   // Local frame with remote parent should have transparent baseBackgroundColor.
12956   Color color = local_frame->GetFrameView()->BaseBackgroundColor();
12957   EXPECT_EQ(Color::kTransparent, color);
12958 }
12959 
12960 class TestFallbackWebFrameClient
12961     : public frame_test_helpers::TestWebFrameClient {
12962  public:
TestFallbackWebFrameClient()12963   TestFallbackWebFrameClient() : child_client_(nullptr) {}
12964   ~TestFallbackWebFrameClient() override = default;
12965 
SetChildWebFrameClient(TestFallbackWebFrameClient * client)12966   void SetChildWebFrameClient(TestFallbackWebFrameClient* client) {
12967     child_client_ = client;
12968   }
12969 
12970   // frame_test_helpers::TestWebFrameClient:
CreateChildFrame(WebLocalFrame * parent,mojom::blink::TreeScopeType scope,const WebString &,const WebString &,const FramePolicy &,const WebFrameOwnerProperties & frameOwnerProperties,mojom::blink::FrameOwnerElementType)12971   WebLocalFrame* CreateChildFrame(
12972       WebLocalFrame* parent,
12973       mojom::blink::TreeScopeType scope,
12974       const WebString&,
12975       const WebString&,
12976       const FramePolicy&,
12977       const WebFrameOwnerProperties& frameOwnerProperties,
12978       mojom::blink::FrameOwnerElementType) override {
12979     DCHECK(child_client_);
12980     return CreateLocalChild(*parent, scope, child_client_);
12981   }
BeginNavigation(std::unique_ptr<WebNavigationInfo> info)12982   void BeginNavigation(std::unique_ptr<WebNavigationInfo> info) override {
12983     if (child_client_ || KURL(info->url_request.Url()) == BlankURL()) {
12984       TestWebFrameClient::BeginNavigation(std::move(info));
12985       return;
12986     }
12987     Frame()->WillStartNavigation(*info);
12988   }
12989 
12990  private:
12991   TestFallbackWebFrameClient* child_client_;
12992 };
12993 
TEST_F(WebFrameTest,FallbackForNonexistentProvisionalNavigation)12994 TEST_F(WebFrameTest, FallbackForNonexistentProvisionalNavigation) {
12995   RegisterMockedHttpURLLoad("fallback.html");
12996   TestFallbackWebFrameClient main_client;
12997   TestFallbackWebFrameClient child_client;
12998   main_client.SetChildWebFrameClient(&child_client);
12999 
13000   frame_test_helpers::WebViewHelper web_view_helper_;
13001   web_view_helper_.Initialize(&main_client);
13002 
13003   WebLocalFrameImpl* main_frame = web_view_helper_.LocalMainFrame();
13004   WebURLRequest request(ToKURL(base_url_ + "fallback.html"));
13005   main_frame->StartNavigation(request);
13006 
13007   // Because the child frame will have placeholder document loader, the main
13008   // frame will not finish loading, so
13009   // frame_test_helpers::PumpPendingRequestsForFrameToLoad doesn't work here.
13010   url_test_helpers::ServeAsynchronousRequests();
13011 
13012   // Overwrite the client-handled child frame navigation with about:blank.
13013   WebLocalFrame* child = main_frame->FirstChild()->ToWebLocalFrame();
13014   frame_test_helpers::LoadFrameDontWait(child, BlankURL());
13015 
13016   // Failing the original child frame navigation and trying to render fallback
13017   // content shouldn't crash. It should return NoLoadInProgress. This is so the
13018   // caller won't attempt to replace the correctly empty frame with an error
13019   // page.
13020   EXPECT_EQ(WebNavigationControl::NoLoadInProgress,
13021             To<WebLocalFrameImpl>(child)->MaybeRenderFallbackContent(
13022                 WebURLError(ResourceError::Failure(request.Url()))));
13023 }
13024 
TEST_F(WebFrameTest,AltTextOnAboutBlankPage)13025 TEST_F(WebFrameTest, AltTextOnAboutBlankPage) {
13026   frame_test_helpers::WebViewHelper web_view_helper;
13027   web_view_helper.InitializeAndLoad("about:blank");
13028   web_view_helper.Resize(gfx::Size(640, 480));
13029   WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
13030 
13031   const char kSource[] =
13032       "<img id='foo' src='foo' alt='foo alt' width='200' height='200'>";
13033   frame_test_helpers::LoadHTMLString(frame, kSource, ToKURL("about:blank"));
13034   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
13035   RunPendingTasks();
13036 
13037   // Check LayoutText with alt text "foo alt"
13038   LayoutObject* layout_object = frame->GetFrame()
13039                                     ->GetDocument()
13040                                     ->getElementById("foo")
13041                                     ->GetLayoutObject()
13042                                     ->SlowFirstChild();
13043   String text = "";
13044   for (LayoutObject* obj = layout_object; obj; obj = obj->NextInPreOrder()) {
13045     if (obj->IsText()) {
13046       text = To<LayoutText>(obj)->GetText();
13047       break;
13048     }
13049   }
13050   EXPECT_EQ("foo alt", text.Utf8());
13051 }
13052 
TEST_F(WebFrameTest,NavigatorPluginsClearedWhenPluginsDisabled)13053 TEST_F(WebFrameTest, NavigatorPluginsClearedWhenPluginsDisabled) {
13054   ScopedFakePluginRegistry fake_plugins;
13055   frame_test_helpers::WebViewHelper web_view_helper;
13056   web_view_helper.Initialize();
13057   v8::Isolate* isolate = v8::Isolate::GetCurrent();
13058   v8::Local<v8::Context> context = isolate->GetCurrentContext();
13059   v8::HandleScope scope(isolate);
13060   v8::Local<v8::Value> result =
13061       web_view_helper.LocalMainFrame()->ExecuteScriptAndReturnValue(
13062           WebScriptSource("navigator.plugins.length"));
13063   EXPECT_NE(0, result->Int32Value(context).ToChecked());
13064   web_view_helper.GetWebView()->GetPage()->GetSettings().SetPluginsEnabled(
13065       false);
13066   result = web_view_helper.LocalMainFrame()->ExecuteScriptAndReturnValue(
13067       WebScriptSource("navigator.plugins.length"));
13068   EXPECT_EQ(0, result->Int32Value(context).ToChecked());
13069 }
13070 
TEST_F(WebFrameTest,RecordSameDocumentNavigationToHistogram)13071 TEST_F(WebFrameTest, RecordSameDocumentNavigationToHistogram) {
13072   const char* histogramName =
13073       "RendererScheduler.UpdateForSameDocumentNavigationCount";
13074   frame_test_helpers::WebViewHelper web_view_helper;
13075   HistogramTester tester;
13076   web_view_helper.InitializeAndLoad("about:blank");
13077   auto* frame =
13078       To<LocalFrame>(web_view_helper.GetWebView()->GetPage()->MainFrame());
13079 
13080   DocumentLoader& document_loader = *web_view_helper.GetWebView()
13081                                          ->MainFrameImpl()
13082                                          ->GetFrame()
13083                                          ->GetDocument()
13084                                          ->Loader();
13085   scoped_refptr<SerializedScriptValue> message =
13086       SerializeString("message", ToScriptStateForMainWorld(frame));
13087   tester.ExpectTotalCount(histogramName, 0);
13088   document_loader.UpdateForSameDocumentNavigation(
13089       ToKURL("about:blank"), kSameDocumentNavigationHistoryApi, message,
13090       mojom::blink::ScrollRestorationType::kAuto,
13091       WebFrameLoadType::kReplaceCurrentItem, frame->GetDocument());
13092   // The bucket index corresponds to the definition of
13093   // |SinglePageAppNavigationType|.
13094   tester.ExpectBucketCount(histogramName,
13095                            kSPANavTypeHistoryPushStateOrReplaceState, 1);
13096   document_loader.UpdateForSameDocumentNavigation(
13097       ToKURL("about:blank"), kSameDocumentNavigationDefault, message,
13098       mojom::blink::ScrollRestorationType::kManual,
13099       WebFrameLoadType::kBackForward, frame->GetDocument());
13100   tester.ExpectBucketCount(histogramName,
13101                            kSPANavTypeSameDocumentBackwardOrForward, 1);
13102   document_loader.UpdateForSameDocumentNavigation(
13103       ToKURL("about:blank"), kSameDocumentNavigationDefault, message,
13104       mojom::blink::ScrollRestorationType::kManual,
13105       WebFrameLoadType::kReplaceCurrentItem, frame->GetDocument());
13106   tester.ExpectBucketCount(histogramName, kSPANavTypeOtherFragmentNavigation,
13107                            1);
13108   // kSameDocumentNavigationHistoryApi and WebFrameLoadType::kBackForward is an
13109   // illegal combination, which has been caught by DCHECK in
13110   // UpdateForSameDocumentNavigation().
13111 
13112   tester.ExpectTotalCount(histogramName, 3);
13113 }
13114 
TestFramePrinting(WebLocalFrameImpl * frame)13115 static void TestFramePrinting(WebLocalFrameImpl* frame) {
13116   WebPrintParams print_params;
13117   WebSize page_size(500, 500);
13118   print_params.print_content_area.width = page_size.width;
13119   print_params.print_content_area.height = page_size.height;
13120   EXPECT_EQ(1u, frame->PrintBegin(print_params, WebNode()));
13121   PaintRecorder recorder;
13122   frame->PrintPagesForTesting(recorder.beginRecording(IntRect()), page_size,
13123                               page_size);
13124   frame->PrintEnd();
13125 }
13126 
TEST_F(WebFrameTest,PrintDetachedIframe)13127 TEST_F(WebFrameTest, PrintDetachedIframe) {
13128   RegisterMockedHttpURLLoad("print-detached-iframe.html");
13129   frame_test_helpers::WebViewHelper web_view_helper;
13130   web_view_helper.InitializeAndLoad(base_url_ + "print-detached-iframe.html");
13131   TestFramePrinting(
13132       To<WebLocalFrameImpl>(web_view_helper.LocalMainFrame()->FirstChild()));
13133 }
13134 
TEST_F(WebFrameTest,PrintIframeUnderDetached)13135 TEST_F(WebFrameTest, PrintIframeUnderDetached) {
13136   RegisterMockedHttpURLLoad("print-detached-iframe.html");
13137   frame_test_helpers::WebViewHelper web_view_helper;
13138   web_view_helper.InitializeAndLoad(base_url_ + "print-detached-iframe.html");
13139   TestFramePrinting(To<WebLocalFrameImpl>(
13140       web_view_helper.LocalMainFrame()->FirstChild()->FirstChild()));
13141 }
13142 
13143 namespace {
13144 
13145 struct TextRunDOMNodeIdInfo {
13146   int glyph_len;
13147   DOMNodeId dom_node_id;
13148 };
13149 
13150 // Given a PaintRecord and a starting DOMNodeId, recursively iterate over all of
13151 // the (nested) paint ops, and populate |text_runs| with the number of glyphs
13152 // and the DOMNodeId of each text run.
RecursiveCollectTextRunDOMNodeIds(sk_sp<const PaintRecord> paint_record,DOMNodeId dom_node_id,std::vector<TextRunDOMNodeIdInfo> * text_runs)13153 void RecursiveCollectTextRunDOMNodeIds(
13154     sk_sp<const PaintRecord> paint_record,
13155     DOMNodeId dom_node_id,
13156     std::vector<TextRunDOMNodeIdInfo>* text_runs) {
13157   for (cc::PaintOpBuffer::Iterator it(paint_record.get()); it; ++it) {
13158     if ((*it)->GetType() == cc::PaintOpType::DrawRecord) {
13159       cc::DrawRecordOp* draw_record_op = static_cast<cc::DrawRecordOp*>(*it);
13160       RecursiveCollectTextRunDOMNodeIds(draw_record_op->record, dom_node_id,
13161                                         text_runs);
13162     } else if ((*it)->GetType() == cc::PaintOpType::SetNodeId) {
13163       cc::SetNodeIdOp* set_node_id_op = static_cast<cc::SetNodeIdOp*>(*it);
13164       dom_node_id = set_node_id_op->node_id;
13165     } else if ((*it)->GetType() == cc::PaintOpType::DrawTextBlob) {
13166       cc::DrawTextBlobOp* draw_text_op = static_cast<cc::DrawTextBlobOp*>(*it);
13167       SkTextBlob::Iter iter(*draw_text_op->blob);
13168       SkTextBlob::Iter::Run run;
13169       while (iter.next(&run)) {
13170         TextRunDOMNodeIdInfo text_run_info;
13171         text_run_info.glyph_len = run.fGlyphCount;
13172         text_run_info.dom_node_id = dom_node_id;
13173         text_runs->push_back(text_run_info);
13174       }
13175     }
13176   }
13177 }
13178 
13179 }  // namespace
13180 
TEST_F(WebFrameTest,FirstLetterHasDOMNodeIdWhenPrinting)13181 TEST_F(WebFrameTest, FirstLetterHasDOMNodeIdWhenPrinting) {
13182   // When printing, every DrawText painting op needs to have an associated
13183   // DOM Node ID. This test ensures that when the first-letter style is used,
13184   // the drawing op for the first letter is correctly associated with the same
13185   // DOM Node ID as the following text.
13186 
13187   // Load a web page with two elements containing the text
13188   // "Hello" and "World", where "World" has a first-letter style.
13189   RegisterMockedHttpURLLoad("first-letter.html");
13190   frame_test_helpers::WebViewHelper web_view_helper;
13191   web_view_helper.InitializeAndLoad(base_url_ + "first-letter.html");
13192 
13193   // Print the page and capture the PaintRecord.
13194   WebPrintParams print_params;
13195   WebSize page_size(500, 500);
13196   print_params.print_content_area.width = page_size.width;
13197   print_params.print_content_area.height = page_size.height;
13198   WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
13199   EXPECT_EQ(1u, frame->PrintBegin(print_params, WebNode()));
13200   PaintRecorder recorder;
13201   frame->PrintPagesForTesting(recorder.beginRecording(IntRect()), page_size,
13202                               page_size);
13203   frame->PrintEnd();
13204   sk_sp<PaintRecord> paint_record = recorder.finishRecordingAsPicture();
13205 
13206   // Unpack the paint record and collect info about the text runs.
13207   std::vector<TextRunDOMNodeIdInfo> text_runs;
13208   RecursiveCollectTextRunDOMNodeIds(paint_record, 0, &text_runs);
13209 
13210   // The first text run should be "Hello".
13211   ASSERT_EQ(3U, text_runs.size());
13212   EXPECT_EQ(5, text_runs[0].glyph_len);
13213   EXPECT_NE(kInvalidDOMNodeId, text_runs[0].dom_node_id);
13214 
13215   // The second text run should be "W", the first letter of "World".
13216   EXPECT_EQ(1, text_runs[1].glyph_len);
13217   EXPECT_NE(kInvalidDOMNodeId, text_runs[1].dom_node_id);
13218 
13219   // The last text run should be "orld", the rest of "World".
13220   EXPECT_EQ(4, text_runs[2].glyph_len);
13221   EXPECT_NE(kInvalidDOMNodeId, text_runs[2].dom_node_id);
13222 
13223   // The second and third text runs should have the same DOM Node ID.
13224   EXPECT_EQ(text_runs[1].dom_node_id, text_runs[2].dom_node_id);
13225 }
13226 
TEST_F(WebFrameTest,RightClickActivatesForExecuteCommand)13227 TEST_F(WebFrameTest, RightClickActivatesForExecuteCommand) {
13228   frame_test_helpers::WebViewHelper web_view_helper;
13229   WebViewImpl* web_view = web_view_helper.InitializeAndLoad("about:blank");
13230   WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
13231 
13232   // Setup a mock clipboard host.
13233   PageTestBase::MockClipboardHostProvider mock_clipboard_host_provider(
13234       frame->GetFrame()->GetBrowserInterfaceBroker());
13235 
13236   EXPECT_FALSE(frame->GetFrame()->HasStickyUserActivation());
13237   frame->ExecuteScript(
13238       WebScriptSource(WebString("document.execCommand('copy');")));
13239   EXPECT_FALSE(frame->GetFrame()->HasStickyUserActivation());
13240 
13241   // Right-click to activate the page.
13242   WebMouseEvent mouse_event(WebInputEvent::Type::kMouseDown,
13243                             WebInputEvent::kNoModifiers,
13244                             WebInputEvent::GetStaticTimeStampForTests());
13245   mouse_event.button = WebMouseEvent::Button::kRight;
13246   mouse_event.click_count = 1;
13247   web_view->MainFrameWidget()->HandleInputEvent(
13248       WebCoalescedInputEvent(mouse_event, ui::LatencyInfo()));
13249   RunPendingTasks();
13250 
13251   frame->ExecuteCommand(WebString::FromUTF8("Paste"));
13252   EXPECT_TRUE(frame->GetFrame()->HasStickyUserActivation());
13253 }
13254 
TEST_F(WebFrameTest,GetCanonicalUrlForSharingNone)13255 TEST_F(WebFrameTest, GetCanonicalUrlForSharingNone) {
13256   frame_test_helpers::WebViewHelper web_view_helper;
13257   web_view_helper.InitializeAndLoad("about:blank");
13258   WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
13259   EXPECT_TRUE(frame->GetDocument().CanonicalUrlForSharing().IsNull());
13260 }
13261 
TEST_F(WebFrameTest,GetCanonicalUrlForSharingNotInHead)13262 TEST_F(WebFrameTest, GetCanonicalUrlForSharingNotInHead) {
13263   frame_test_helpers::WebViewHelper web_view_helper;
13264   web_view_helper.Initialize();
13265   WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
13266   frame_test_helpers::LoadHTMLString(
13267       frame, R"(
13268     <body>
13269       <link rel="canonical" href="https://example.com/canonical.html">
13270     </body>)",
13271       ToKURL("https://example.com/test_page.html"));
13272   EXPECT_TRUE(frame->GetDocument().CanonicalUrlForSharing().IsNull());
13273 }
13274 
TEST_F(WebFrameTest,GetCanonicalUrlForSharing)13275 TEST_F(WebFrameTest, GetCanonicalUrlForSharing) {
13276   frame_test_helpers::WebViewHelper web_view_helper;
13277   web_view_helper.Initialize();
13278   WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
13279   frame_test_helpers::LoadHTMLString(
13280       frame, R"(
13281     <head>
13282       <link rel="canonical" href="https://example.com/canonical.html">
13283     </head>)",
13284       ToKURL("https://example.com/test_page.html"));
13285   EXPECT_EQ(WebURL(ToKURL("https://example.com/canonical.html")),
13286             frame->GetDocument().CanonicalUrlForSharing());
13287 }
13288 
TEST_F(WebFrameTest,GetCanonicalUrlForSharingMultiple)13289 TEST_F(WebFrameTest, GetCanonicalUrlForSharingMultiple) {
13290   frame_test_helpers::WebViewHelper web_view_helper;
13291   web_view_helper.Initialize();
13292   WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
13293   frame_test_helpers::LoadHTMLString(
13294       frame, R"(
13295     <head>
13296       <link rel="canonical" href="https://example.com/canonical1.html">
13297       <link rel="canonical" href="https://example.com/canonical2.html">
13298     </head>)",
13299       ToKURL("https://example.com/test_page.html"));
13300   EXPECT_EQ(WebURL(ToKURL("https://example.com/canonical1.html")),
13301             frame->GetDocument().CanonicalUrlForSharing());
13302 }
13303 
TEST_F(WebFrameTest,NavigationTimingInfo)13304 TEST_F(WebFrameTest, NavigationTimingInfo) {
13305   RegisterMockedHttpURLLoad("foo.html");
13306   frame_test_helpers::WebViewHelper web_view_helper;
13307   web_view_helper.InitializeAndLoad(base_url_ + "foo.html");
13308   ResourceTimingInfo* navigation_timing_info = web_view_helper.LocalMainFrame()
13309                                                    ->GetFrame()
13310                                                    ->Loader()
13311                                                    .GetDocumentLoader()
13312                                                    ->GetNavigationTimingInfo();
13313   EXPECT_EQ(navigation_timing_info->TransferSize(), static_cast<uint64_t>(34));
13314 }
13315 
TEST_F(WebFrameSimTest,EnterFullscreenResetScrollAndScaleState)13316 TEST_F(WebFrameSimTest, EnterFullscreenResetScrollAndScaleState) {
13317   UseAndroidSettings();
13318   WebView().MainFrameViewWidget()->Resize(gfx::Size(490, 500));
13319   WebView().EnableFakePageScaleAnimationForTesting(true);
13320   WebView().GetSettings()->SetTextAutosizingEnabled(false);
13321   WebView().SetDefaultPageScaleLimits(0.5f, 4);
13322 
13323   SimRequest request("https://example.com/test.html", "text/html");
13324   LoadURL("https://example.com/test.html");
13325   request.Complete(R"HTML(
13326       <!DOCTYPE html>
13327       <style>
13328         body {
13329           margin: 0px;
13330           width: 10000px;
13331           height: 10000px;
13332         }
13333       </style>
13334   )HTML");
13335 
13336   Compositor().BeginFrame();
13337 
13338   // Make the page scale and scroll with the given parameters.
13339   EXPECT_EQ(0.5f, WebView().PageScaleFactor());
13340   WebView().SetPageScaleFactor(2.0f);
13341   WebView().MainFrameImpl()->SetScrollOffset(WebSize(94, 111));
13342   WebView().SetVisualViewportOffset(gfx::PointF(12, 20));
13343   EXPECT_EQ(2.0f, WebView().PageScaleFactor());
13344   EXPECT_EQ(94, WebView().MainFrameImpl()->GetScrollOffset().width);
13345   EXPECT_EQ(111, WebView().MainFrameImpl()->GetScrollOffset().height);
13346   EXPECT_EQ(12, WebView().VisualViewportOffset().x());
13347   EXPECT_EQ(20, WebView().VisualViewportOffset().y());
13348 
13349   auto* frame = To<LocalFrame>(WebView().GetPage()->MainFrame());
13350   Element* element = frame->GetDocument()->body();
13351   LocalFrame::NotifyUserActivation(
13352       frame, mojom::UserActivationNotificationType::kTest);
13353   Fullscreen::RequestFullscreen(*element);
13354   WebView().DidEnterFullscreen();
13355 
13356   // Page scale factor must be 1.0 during fullscreen for elements to be sized
13357   // properly.
13358   EXPECT_EQ(1.0f, WebView().PageScaleFactor());
13359 
13360   // Confirm that exiting fullscreen restores back to default values.
13361   WebView().DidExitFullscreen();
13362   WebView().MainFrameWidget()->UpdateAllLifecyclePhases(
13363       DocumentUpdateReason::kTest);
13364 
13365   EXPECT_EQ(0.5f, WebView().PageScaleFactor());
13366   EXPECT_EQ(94, WebView().MainFrameImpl()->GetScrollOffset().width);
13367   EXPECT_EQ(111, WebView().MainFrameImpl()->GetScrollOffset().height);
13368   EXPECT_EQ(0, WebView().VisualViewportOffset().x());
13369   EXPECT_EQ(0, WebView().VisualViewportOffset().y());
13370 }
13371 
TEST_F(WebFrameSimTest,GetPageSizeType)13372 TEST_F(WebFrameSimTest, GetPageSizeType) {
13373   WebView().MainFrameViewWidget()->Resize(gfx::Size(500, 500));
13374 
13375   SimRequest request("https://example.com/test.html", "text/html");
13376   LoadURL("https://example.com/test.html");
13377   request.Complete(R"HTML(
13378       <!DOCTYPE html>
13379       <style>
13380         @page {}
13381       </style>
13382   )HTML");
13383 
13384   Compositor().BeginFrame();
13385   RunPendingTasks();
13386 
13387   const struct {
13388     const char* size;
13389     PageSizeType page_size_type;
13390   } test_cases[] = {
13391       {"auto", PageSizeType::kAuto},
13392       {"portrait", PageSizeType::kPortrait},
13393       {"landscape", PageSizeType::kLandscape},
13394       {"a4", PageSizeType::kFixed},
13395       {"letter", PageSizeType::kFixed},
13396       {"a4 portrait", PageSizeType::kFixed},
13397       {"letter landscape", PageSizeType::kFixed},
13398       {"10in", PageSizeType::kFixed},
13399       {"10in 12cm", PageSizeType::kFixed},
13400   };
13401 
13402   auto* main_frame = WebView().MainFrame()->ToWebLocalFrame();
13403   auto* doc = To<LocalFrame>(WebView().GetPage()->MainFrame())->GetDocument();
13404   auto* sheet = To<CSSStyleSheet>(doc->StyleSheets().item(0));
13405   CSSStyleDeclaration* style_decl =
13406       To<CSSPageRule>(sheet->cssRules(ASSERT_NO_EXCEPTION)->item(0))->style();
13407 
13408   // Initially empty @page rule.
13409   EXPECT_EQ(PageSizeType::kAuto, main_frame->GetPageSizeType(1));
13410 
13411   for (const auto& test : test_cases) {
13412     style_decl->setProperty(doc->GetExecutionContext(), "size", test.size, "",
13413                             ASSERT_NO_EXCEPTION);
13414     EXPECT_EQ(test.page_size_type, main_frame->GetPageSizeType(1));
13415   }
13416 }
13417 
TEST_F(WebFrameSimTest,PageOrientation)13418 TEST_F(WebFrameSimTest, PageOrientation) {
13419   ScopedNamedPagesForTest named_pages_enabler(true);
13420   gfx::Size page_size(500, 500);
13421   WebView().MainFrameWidget()->Resize(page_size);
13422 
13423   SimRequest request("https://example.com/test.html", "text/html");
13424   LoadURL("https://example.com/test.html");
13425   request.Complete(R"HTML(
13426       <!DOCTYPE html>
13427       <style>
13428         @page upright { page-orientation: upright; }
13429         @page clockwise { page-orientation: rotate-right; }
13430         @page counter-clockwise { page-orientation: rotate-left; }
13431         div { height: 10px; }
13432       </style>
13433       <!-- First page: -->
13434       <div style="page:upright;"></div>
13435       <!-- Second page: -->
13436       <div style="page:counter-clockwise;"></div>
13437       <!-- Third page: -->
13438       <div style="page:clockwise;"></div>
13439       <div style="page:clockwise;"></div>
13440       <!-- Fourth page: -->
13441       <div></div>
13442   )HTML");
13443 
13444   Compositor().BeginFrame();
13445   RunPendingTasks();
13446 
13447   auto* frame = WebView().MainFrame()->ToWebLocalFrame();
13448   WebPrintParams print_params;
13449   print_params.print_content_area.width = page_size.width();
13450   print_params.print_content_area.height = page_size.height();
13451   EXPECT_EQ(4u, frame->PrintBegin(print_params, WebNode()));
13452 
13453   WebPrintPageDescription description;
13454 
13455   frame->GetPageDescription(0, &description);
13456   EXPECT_EQ(description.orientation, PageOrientation::kUpright);
13457 
13458   frame->GetPageDescription(1, &description);
13459   EXPECT_EQ(description.orientation, PageOrientation::kRotateLeft);
13460 
13461   frame->GetPageDescription(2, &description);
13462   EXPECT_EQ(description.orientation, PageOrientation::kRotateRight);
13463 
13464   frame->GetPageDescription(3, &description);
13465   EXPECT_EQ(description.orientation, PageOrientation::kUpright);
13466 
13467   frame->PrintEnd();
13468 }
13469 
TEST_F(WebFrameSimTest,MainFrameTransformOffsetPixelSnapped)13470 TEST_F(WebFrameSimTest, MainFrameTransformOffsetPixelSnapped) {
13471   SimRequest request("https://example.com/test.html", "text/html");
13472   LoadURL("https://example.com/test.html");
13473   request.Complete(R"HTML(
13474       <!DOCTYPE html>
13475       <iframe id="iframe" style="position:absolute;top:7px;left:13.5px;border:none"></iframe>
13476   )HTML");
13477   frame_test_helpers::TestWebRemoteFrameClient remote_frame_client;
13478   TestViewportIntersection remote_frame_host;
13479   remote_frame_host.Init(remote_frame_client.GetRemoteAssociatedInterfaces());
13480   WebRemoteFrame* remote_frame =
13481       frame_test_helpers::CreateRemote(&remote_frame_client);
13482   MainFrame().FirstChild()->Swap(remote_frame);
13483   Compositor().BeginFrame();
13484   RunPendingTasks();
13485   EXPECT_TRUE(remote_frame_host.GetIntersectionState()
13486                   ->main_frame_transform.IsIdentityOrIntegerTranslation());
13487   EXPECT_EQ(remote_frame_host.GetIntersectionState()
13488                 ->main_frame_transform.matrix()
13489                 .get(0, 3),
13490             14.f);
13491   EXPECT_EQ(remote_frame_host.GetIntersectionState()
13492                 ->main_frame_transform.matrix()
13493                 .get(1, 3),
13494             7.f);
13495   MainFrame().FirstChild()->Detach();
13496 }
13497 
TEST_F(WebFrameTest,MediaQueriesInLocalFrameInsideRemote)13498 TEST_F(WebFrameTest, MediaQueriesInLocalFrameInsideRemote) {
13499   frame_test_helpers::WebViewHelper helper;
13500   helper.InitializeRemote();
13501 
13502   FixedLayoutTestWebWidgetClient client;
13503   client.screen_info_.is_monochrome = false;
13504   client.screen_info_.depth_per_component = 8;
13505 
13506   WebLocalFrameImpl* local_frame = frame_test_helpers::CreateLocalChild(
13507       *helper.RemoteMainFrame(), WebString(), WebFrameOwnerProperties(),
13508       nullptr, nullptr, &client);
13509 
13510   ASSERT_TRUE(local_frame->GetFrame());
13511   MediaValues* media_values =
13512       MediaValues::CreateDynamicIfFrameExists(local_frame->GetFrame());
13513   ASSERT_TRUE(media_values);
13514   EXPECT_EQ(0, media_values->MonochromeBitsPerComponent());
13515   EXPECT_EQ(8, media_values->ColorBitsPerComponent());
13516   // Need to explicitly reset helper to make sure local_frame is not deleted
13517   // first.
13518   helper.Reset();
13519 }
13520 
TEST_F(WebFrameTest,RemoteViewportAndMainframeIntersections)13521 TEST_F(WebFrameTest, RemoteViewportAndMainframeIntersections) {
13522   frame_test_helpers::WebViewHelper helper;
13523   helper.InitializeRemote();
13524   WebLocalFrameImpl* local_frame = frame_test_helpers::CreateLocalChild(
13525       *helper.RemoteMainFrame(), "frameName");
13526   frame_test_helpers::LoadHTMLString(local_frame, R"HTML(
13527       <!DOCTYPE html>
13528       <style>
13529       #target {
13530         position: absolute;
13531         top: 10px;
13532         left: 20px;
13533         width: 200px;
13534         height: 100px;
13535       }
13536       </style>
13537       <div id=target></div>
13538       )HTML",
13539                                      ToKURL("about:blank"));
13540 
13541   Element* target =
13542       local_frame->GetFrame()->GetDocument()->getElementById("target");
13543   ASSERT_TRUE(target);
13544   ASSERT_TRUE(target->GetLayoutObject());
13545 
13546   // Simulate the local child frame being positioned at (7, -11) in the parent's
13547   // viewport, indicating that the top 11px of the child's content is clipped
13548   // by the parent. Let the local child frame be at (7, 40) in the parent
13549   // element.
13550   WebFrameWidget* widget = local_frame->FrameWidget();
13551   ASSERT_TRUE(widget);
13552   gfx::Transform viewport_transform;
13553   viewport_transform.Translate(7, -11);
13554   gfx::Rect viewport_intersection(0, 11, 200, 89);
13555   gfx::Rect mainframe_intersection(0, 0, 200, 140);
13556   blink::mojom::FrameOcclusionState occlusion_state =
13557       blink::mojom::FrameOcclusionState::kUnknown;
13558 
13559   static_cast<WebFrameWidgetBase*>(widget)->SetRemoteViewportIntersection(
13560       {viewport_intersection, mainframe_intersection, viewport_intersection,
13561        occlusion_state, gfx::Size(), gfx::Point(), viewport_transform});
13562 
13563   // The viewport intersection should be applied by the layout geometry mapping
13564   // code when these flags are used.
13565   int viewport_intersection_flags =
13566       kTraverseDocumentBoundaries | kApplyRemoteMainFrameTransform;
13567 
13568   // Expectation is: (target location) + (viewport offset) = (20, 10) + (7, -11)
13569   PhysicalOffset offset = target->GetLayoutObject()->LocalToAbsolutePoint(
13570       PhysicalOffset(), viewport_intersection_flags);
13571   EXPECT_EQ(PhysicalOffset(27, -1), offset);
13572 
13573   PhysicalRect rect(0, 0, 25, 35);
13574   local_frame->GetFrame()
13575       ->GetDocument()
13576       ->GetLayoutView()
13577       ->MapToVisualRectInAncestorSpace(
13578           nullptr, rect, viewport_intersection_flags, kDefaultVisualRectFlags);
13579   EXPECT_EQ(PhysicalRect(7, 0, 25, 24), rect);
13580 
13581   // Without the main frame overflow clip the rect should not be clipped and the
13582   // coordinates returned are the rects coordinates in the viewport space.
13583   PhysicalRect mainframe_rect(0, 0, 25, 35);
13584   local_frame->GetFrame()
13585       ->GetDocument()
13586       ->GetLayoutView()
13587       ->MapToVisualRectInAncestorSpace(nullptr, mainframe_rect,
13588                                        viewport_intersection_flags,
13589                                        kDontApplyMainFrameOverflowClip);
13590   EXPECT_EQ(PhysicalRect(7, -11, 25, 35), mainframe_rect);
13591 }
13592 
13593 class TestUpdateFaviconURLLocalFrameHost : public FakeLocalFrameHost {
13594  public:
13595   TestUpdateFaviconURLLocalFrameHost() = default;
13596   ~TestUpdateFaviconURLLocalFrameHost() override = default;
13597 
13598   // FakeLocalFrameHost:
UpdateFaviconURL(WTF::Vector<blink::mojom::blink::FaviconURLPtr> favicon_urls)13599   void UpdateFaviconURL(
13600       WTF::Vector<blink::mojom::blink::FaviconURLPtr> favicon_urls) override {
13601     did_notify_ = true;
13602   }
13603 
13604   bool did_notify_ = false;
13605 };
13606 
13607 // Ensure the render view sends favicon url update events correctly.
TEST_F(WebFrameTest,FaviconURLUpdateEvent)13608 TEST_F(WebFrameTest, FaviconURLUpdateEvent) {
13609   TestUpdateFaviconURLLocalFrameHost frame_host;
13610   frame_test_helpers::TestWebFrameClient web_frame_client;
13611   frame_host.Init(web_frame_client.GetRemoteNavigationAssociatedInterfaces());
13612   frame_test_helpers::WebViewHelper web_view_helper;
13613   web_view_helper.Initialize(&web_frame_client);
13614   RunPendingTasks();
13615 
13616   WebViewImpl* web_view = web_view_helper.GetWebView();
13617   LocalFrame* frame = web_view->MainFrameImpl()->GetFrame();
13618 
13619   // An event should be sent when a favicon url exists.
13620   frame->GetDocument()->documentElement()->setInnerHTML(
13621       "<html>"
13622       "<head>"
13623       "<link rel='icon' href='http://www.google.com/favicon.ico'>"
13624       "</head>"
13625       "</html>");
13626   RunPendingTasks();
13627 
13628   EXPECT_TRUE(frame_host.did_notify_);
13629 
13630   frame_host.did_notify_ = false;
13631 
13632   // An event should not be sent if no favicon url exists. This is an assumption
13633   // made by some of Chrome's favicon handling.
13634   frame->GetDocument()->documentElement()->setInnerHTML(
13635       "<html>"
13636       "<head>"
13637       "</head>"
13638       "</html>");
13639   RunPendingTasks();
13640 
13641   EXPECT_FALSE(frame_host.did_notify_);
13642   web_view_helper.Reset();
13643 }
13644 
13645 class TestFocusedElementChangedLocalFrameHost : public FakeLocalFrameHost {
13646  public:
13647   TestFocusedElementChangedLocalFrameHost() = default;
13648   ~TestFocusedElementChangedLocalFrameHost() override = default;
13649 
13650   // FakeLocalFrameHost:
FocusedElementChanged(bool is_editable_element,const gfx::Rect & bounds_in_frame_widget,blink::mojom::FocusType focus_type)13651   void FocusedElementChanged(bool is_editable_element,
13652                              const gfx::Rect& bounds_in_frame_widget,
13653                              blink::mojom::FocusType focus_type) override {
13654     did_notify_ = true;
13655   }
13656 
13657   bool did_notify_ = false;
13658 };
13659 
TEST_F(WebFrameTest,FocusElementCallsFocusedElementChanged)13660 TEST_F(WebFrameTest, FocusElementCallsFocusedElementChanged) {
13661   TestFocusedElementChangedLocalFrameHost frame_host;
13662   frame_test_helpers::TestWebFrameClient web_frame_client;
13663   frame_host.Init(web_frame_client.GetRemoteNavigationAssociatedInterfaces());
13664   frame_test_helpers::WebViewHelper web_view_helper;
13665   web_view_helper.Initialize(&web_frame_client);
13666   RunPendingTasks();
13667   auto* main_frame = web_view_helper.GetWebView()->MainFrameImpl();
13668 
13669   main_frame->GetFrame()->GetDocument()->documentElement()->setInnerHTML(
13670       "<input id='test1' value='hello1'></input>"
13671       "<input id='test2' value='hello2'></input>");
13672   RunPendingTasks();
13673 
13674   EXPECT_FALSE(frame_host.did_notify_);
13675 
13676   main_frame->ExecuteScript(
13677       WebScriptSource(WebString("document.getElementById('test1').focus();")));
13678   RunPendingTasks();
13679   EXPECT_TRUE(frame_host.did_notify_);
13680   frame_host.did_notify_ = false;
13681 
13682   main_frame->ExecuteScript(
13683       WebScriptSource(WebString("document.getElementById('test2').focus();")));
13684   RunPendingTasks();
13685   EXPECT_TRUE(frame_host.did_notify_);
13686   frame_host.did_notify_ = false;
13687 
13688   main_frame->ExecuteScript(
13689       WebScriptSource(WebString("document.getElementById('test2').blur();")));
13690   RunPendingTasks();
13691   EXPECT_TRUE(frame_host.did_notify_);
13692 }
13693 
13694 // Tests that form.submit() cancels any navigations already sent to the browser
13695 // process.
TEST_F(WebFrameTest,FormSubmitCancelsNavigation)13696 TEST_F(WebFrameTest, FormSubmitCancelsNavigation) {
13697   frame_test_helpers::TestWebFrameClient web_frame_client;
13698   frame_test_helpers::WebViewHelper web_view_helper;
13699   web_view_helper.Initialize(&web_frame_client);
13700   RegisterMockedHttpURLLoad("foo.html");
13701   RegisterMockedHttpURLLoad("bar.html");
13702   auto* main_frame = web_view_helper.GetWebView()->MainFrameImpl();
13703   auto* local_frame = main_frame->GetFrame();
13704   auto* window = local_frame->DomWindow();
13705 
13706   window->document()->documentElement()->setInnerHTML(
13707       "<form id=formid action='http://internal.test/bar.html'></form>");
13708   ASSERT_FALSE(local_frame->Loader().HasProvisionalNavigation());
13709 
13710   FrameLoadRequest request(window,
13711                            ResourceRequest("http://internal.test/foo.html"));
13712   local_frame->Navigate(request, WebFrameLoadType::kStandard);
13713   ASSERT_TRUE(local_frame->Loader().HasProvisionalNavigation());
13714 
13715   main_frame->ExecuteScript(WebScriptSource(WebString("formid.submit()")));
13716   EXPECT_FALSE(local_frame->Loader().HasProvisionalNavigation());
13717 
13718   RunPendingTasks();
13719 }
13720 
13721 class TestLocalFrameHostForAnchorWithDownloadAttr : public FakeLocalFrameHost {
13722  public:
13723   TestLocalFrameHostForAnchorWithDownloadAttr() = default;
13724   ~TestLocalFrameHostForAnchorWithDownloadAttr() override = default;
13725 
13726   // FakeLocalFrameHost:
DownloadURL(mojom::blink::DownloadURLParamsPtr params)13727   void DownloadURL(mojom::blink::DownloadURLParamsPtr params) override {
13728     referrer_ = params->referrer ? params->referrer->url : KURL();
13729     referrer_policy_ = params->referrer
13730                            ? params->referrer->policy
13731                            : ReferrerUtils::MojoReferrerPolicyResolveDefault(
13732                                  network::mojom::ReferrerPolicy::kDefault);
13733   }
13734 
13735   KURL referrer_;
13736   network::mojom::ReferrerPolicy referrer_policy_;
13737 };
13738 
TEST_F(WebFrameTest,DownloadReferrerPolicy)13739 TEST_F(WebFrameTest, DownloadReferrerPolicy) {
13740   TestLocalFrameHostForAnchorWithDownloadAttr frame_host;
13741   frame_test_helpers::TestWebFrameClient web_frame_client;
13742   frame_host.Init(web_frame_client.GetRemoteNavigationAssociatedInterfaces());
13743   frame_test_helpers::WebViewHelper web_view_helper;
13744   web_view_helper.Initialize(&web_frame_client);
13745 
13746   WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
13747   KURL test_url = ToKURL("http://www.test.com/foo/index.html");
13748   // 1.<meta name='referrer' content='no-referrer'>
13749   frame_test_helpers::LoadHTMLString(
13750       frame, GetHTMLStringForReferrerPolicy("no-referrer", std::string()),
13751       test_url);
13752   EXPECT_TRUE(frame_host.referrer_.IsEmpty());
13753   EXPECT_EQ(frame_host.referrer_policy_,
13754             network::mojom::ReferrerPolicy::kNever);
13755 
13756   // 2.<meta name='referrer' content='origin'>
13757   frame_test_helpers::LoadHTMLString(
13758       frame, GetHTMLStringForReferrerPolicy("origin", std::string()), test_url);
13759   EXPECT_EQ(frame_host.referrer_, ToKURL("http://www.test.com/"));
13760   EXPECT_EQ(frame_host.referrer_policy_,
13761             network::mojom::ReferrerPolicy::kOrigin);
13762 
13763   // 3.Without any declared referrer-policy attribute
13764   frame_test_helpers::LoadHTMLString(
13765       frame, GetHTMLStringForReferrerPolicy(std::string(), std::string()),
13766       test_url);
13767   EXPECT_EQ(frame_host.referrer_, test_url);
13768   EXPECT_EQ(frame_host.referrer_policy_,
13769             ReferrerUtils::MojoReferrerPolicyResolveDefault(
13770                 network::mojom::ReferrerPolicy::kDefault));
13771 
13772   // 4.referrerpolicy='origin'
13773   frame_test_helpers::LoadHTMLString(
13774       frame, GetHTMLStringForReferrerPolicy(std::string(), "origin"), test_url);
13775   EXPECT_EQ(frame_host.referrer_, ToKURL("http://www.test.com/"));
13776   EXPECT_EQ(frame_host.referrer_policy_,
13777             network::mojom::ReferrerPolicy::kOrigin);
13778 
13779   // 5.referrerpolicy='same-origin'
13780   frame_test_helpers::LoadHTMLString(
13781       frame, GetHTMLStringForReferrerPolicy(std::string(), "same-origin"),
13782       test_url);
13783   EXPECT_EQ(frame_host.referrer_, test_url);
13784   EXPECT_EQ(frame_host.referrer_policy_,
13785             network::mojom::ReferrerPolicy::kSameOrigin);
13786 
13787   // 6.referrerpolicy='no-referrer'
13788   frame_test_helpers::LoadHTMLString(
13789       frame, GetHTMLStringForReferrerPolicy(std::string(), "no-referrer"),
13790       test_url);
13791   EXPECT_TRUE(frame_host.referrer_.IsEmpty());
13792   EXPECT_EQ(frame_host.referrer_policy_,
13793             network::mojom::ReferrerPolicy::kNever);
13794   web_view_helper.Reset();
13795 }
13796 
13797 }  // namespace blink
13798