Use the window coordinate for the autofill bounds.

Viewport and Window coordinates will differ when Zoom is used to implement DSF behavior.

BUG=485650
TEST=RenderViewImplScaleFactorTest.*, plus manually tested.

Review URL: https://codereview.chromium.org/1455143004

Cr-Commit-Position: refs/heads/master@{#363134}
diff --git a/components/autofill/content/renderer/autofill_agent.cc b/components/autofill/content/renderer/autofill_agent.cc
index a1ceea41..c81b661e3 100644
--- a/components/autofill/content/renderer/autofill_agent.cc
+++ b/components/autofill/content/renderer/autofill_agent.cc
@@ -731,9 +731,13 @@
                                        data_list_values,
                                        data_list_labels));
 
+  blink::WebRect bounding_box_in_window = element_.boundsInViewport();
+  render_frame()->GetRenderView()->convertViewportToWindow(
+      &bounding_box_in_window);
+
   Send(new AutofillHostMsg_QueryFormFieldAutofill(
       routing_id(), autofill_query_id_, form, field,
-      gfx::RectF(element_.boundsInViewport())));
+      gfx::RectF(bounding_box_in_window)));
 }
 
 void AutofillAgent::FillFieldWithValue(const base::string16& value,
diff --git a/components/autofill/content/renderer/password_autofill_agent.cc b/components/autofill/content/renderer/password_autofill_agent.cc
index a80fef1..4fe2a143 100644
--- a/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/components/autofill/content/renderer/password_autofill_agent.cc
@@ -1438,9 +1438,13 @@
       username.isNull() ? base::string16()
                         : static_cast<base::string16>(user_input.value()));
 
+  blink::WebRect bounding_box_in_window = selected_element.boundsInViewport();
+  render_frame()->GetRenderView()->convertViewportToWindow(
+      &bounding_box_in_window);
+
   Send(new AutofillHostMsg_ShowPasswordSuggestions(
       routing_id(), key_it->second, field.text_direction, username_string,
-      options, gfx::RectF(selected_element.boundsInViewport())));
+      options, gfx::RectF(bounding_box_in_window)));
   username_query_prefix_ = username_string;
   return CanShowSuggestion(fill_data, username_string, show_all);
 }
diff --git a/components/autofill/content/renderer/password_generation_agent.cc b/components/autofill/content/renderer/password_generation_agent.cc
index 4d1c8cc..6ad50b5 100644
--- a/components/autofill/content/renderer/password_generation_agent.cc
+++ b/components/autofill/content/renderer/password_generation_agent.cc
@@ -411,18 +411,26 @@
 }
 
 void PasswordGenerationAgent::ShowGenerationPopup() {
+  blink::WebRect bounding_box_in_window =
+      generation_element_.boundsInViewport();
+  render_frame()->GetRenderView()->convertViewportToWindow(
+      &bounding_box_in_window);
+
   Send(new AutofillHostMsg_ShowPasswordGenerationPopup(
-      routing_id(), gfx::RectF(generation_element_.boundsInViewport()),
+      routing_id(), gfx::RectF(bounding_box_in_window),
       generation_element_.maxLength(), *generation_form_data_->form));
 
   generation_popup_shown_ = true;
 }
 
 void PasswordGenerationAgent::ShowEditingPopup() {
+  blink::WebRect bounding_box_in_window =
+      generation_element_.boundsInViewport();
+  render_frame()->GetRenderView()->convertViewportToWindow(
+      &bounding_box_in_window);
   Send(new AutofillHostMsg_ShowPasswordEditingPopup(
-      routing_id(), gfx::RectF(generation_element_.boundsInViewport()),
+      routing_id(), gfx::RectF(bounding_box_in_window),
       *generation_form_data_->form));
-
   editing_popup_shown_ = true;
 }
 
diff --git a/content/public/renderer/render_view.h b/content/public/renderer/render_view.h
index dcf1de4..1f0a235 100644
--- a/content/public/renderer/render_view.h
+++ b/content/public/renderer/render_view.h
@@ -24,6 +24,7 @@
 class WebURLRequest;
 class WebView;
 struct WebContextMenuData;
+struct WebRect;
 }
 
 namespace gfx {
@@ -123,6 +124,13 @@
                                       bool animate) = 0;
 #endif
 
+  // Converts the |rect| from Blink's Viewport coordinates to the
+  // coordinates in the native window used to display the content, in
+  // DIP.  They're identical in tradional world, but will differ when
+  // use-zoom-for-dsf feature is eanbled, and Viewport coordinates
+  // becomes DSF times larger than window coordinates.
+  virtual void convertViewportToWindow(blink::WebRect* rect) = 0;
+
  protected:
   ~RenderView() override {}
 
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc
index bcdc6afd..a06e8d4 100644
--- a/content/renderer/render_view_browsertest.cc
+++ b/content/renderer/render_view_browsertest.cc
@@ -366,7 +366,7 @@
 
 class RenderViewImplBlinkSettingsTest : public RenderViewImplTest {
  public:
-  void DoSetUp() {
+  virtual void DoSetUp() {
     RenderViewImplTest::SetUp();
   }
 
@@ -384,6 +384,22 @@
   void SetUp() override {}
 };
 
+class RenderViewImplScaleFactorTest : public RenderViewImplBlinkSettingsTest {
+ public:
+  void DoSetUp() override {
+    RenderViewImplBlinkSettingsTest::DoSetUp();
+
+    ViewMsg_Resize_Params params;
+    params.screen_info.deviceScaleFactor = 2.f;
+    params.new_size = gfx::Size(100, 100);
+    params.physical_backing_size = gfx::Size(200, 200);
+    params.visible_viewport_size = params.new_size;
+    params.needs_resize_ack = false;
+    view()->OnResize(params);
+    ASSERT_EQ(2.f, view()->device_scale_factor_);
+  }
+};
+
 // Ensure that the main RenderFrame is deleted and cleared from the RenderView
 // after closing it.
 TEST_F(RenderViewImplTest, RenderFrameClearedAfterClose) {
@@ -2471,6 +2487,29 @@
   EXPECT_TRUE(settings()->viewportEnabled());
 }
 
+TEST_F(RenderViewImplScaleFactorTest, ConverViewportToWindowWithoutZoomForDSF) {
+  DoSetUp();
+  blink::WebRect rect(20, 10, 200, 100);
+  view()->convertViewportToWindow(&rect);
+  EXPECT_EQ(20, rect.x);
+  EXPECT_EQ(10, rect.y);
+  EXPECT_EQ(200, rect.width);
+  EXPECT_EQ(100, rect.height);
+}
+
+TEST_F(RenderViewImplScaleFactorTest, ConverViewportToWindowWithZoomForDSF) {
+  base::CommandLine::ForCurrentProcess()->AppendSwitch(
+      switches::kEnableUseZoomForDSF);
+  DoSetUp();
+
+  blink::WebRect rect(20, 10, 200, 100);
+  view()->convertViewportToWindow(&rect);
+  EXPECT_EQ(10, rect.x);
+  EXPECT_EQ(5, rect.y);
+  EXPECT_EQ(100, rect.width);
+  EXPECT_EQ(50, rect.height);
+}
+
 TEST_F(DevToolsAgentTest, DevToolsResumeOnClose) {
   Attach();
   EXPECT_FALSE(IsPaused());
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index e71d180..03fa09cb 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -1941,7 +1941,9 @@
   bool is_editable = false;
   if (!toNode.isNull() && toNode.isElementNode()) {
     WebElement element = const_cast<WebNode&>(toNode).to<WebElement>();
-    node_bounds = gfx::Rect(element.boundsInViewport());
+    blink::WebRect rect = element.boundsInViewport();
+    convertViewportToWindow(&rect);
+    node_bounds = gfx::Rect(rect);
     is_editable = element.isEditable();
   }
   Send(new ViewHostMsg_FocusedNodeChanged(routing_id_, is_editable,
@@ -2136,6 +2138,20 @@
   return renderer_preferences_.accept_languages;
 }
 
+void RenderViewImpl::convertViewportToWindow(blink::WebRect* rect) {
+  if (IsUseZoomForDSFEnabled()) {
+    float reverse = 1 / device_scale_factor_;
+    // TODO(oshima): We may wait to allow pixel precision here as the the
+    // anchor element can be placed at half pixel.
+    gfx::Rect window_rect =
+        gfx::ScaleToEnclosedRect(gfx::Rect(*rect), reverse);
+    rect->x = window_rect.x();
+    rect->y = window_rect.y();
+    rect->width = window_rect.width();
+    rect->height = window_rect.height();
+  }
+}
+
 void RenderViewImpl::didChangeIcon(WebLocalFrame* frame,
                                    WebIconURL::Type icon_type) {
   if (frame->parent())
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index 9ab5603..9a9d986 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -450,6 +450,8 @@
                               TopControlsState current,
                               bool animate) override;
 #endif
+  void convertViewportToWindow(blink::WebRect* rect) override;
+
   bool uses_temporary_zoom_level() const { return uses_temporary_zoom_level_; }
 
   // Please do not add your stuff randomly to the end here. If there is an
@@ -510,6 +512,7 @@
  private:
   // For unit tests.
   friend class DevToolsAgentTest;
+  friend class RenderViewImplScaleFactorTest;
   friend class RenderViewImplTest;
   friend class RenderViewTest;
   friend class RendererAccessibilityTest;
@@ -559,6 +562,8 @@
   FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, SendCandidateWindowEvents);
   FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, RenderFrameClearedAfterClose);
   FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, PaintAfterSwapOut);
+  FRIEND_TEST_ALL_PREFIXES(RenderViewImplScaleFactorTest,
+                           ConverViewportToScreenWithZoomForDSF);
 
   typedef std::map<GURL, double> HostZoomLevels;