Add ability to gather metrics to BubbleManager.
[chromium-blink-merge.git] / chrome / browser / ui / autofill / popup_controller_common.cc
blob87881ddc0dfe5d00246a30910be28e2c2f96f100
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/autofill/popup_controller_common.h"
7 #include <algorithm>
8 #include <utility>
10 #include "content/public/browser/render_view_host.h"
11 #include "content/public/browser/web_contents.h"
12 #include "ui/gfx/display.h"
13 #include "ui/gfx/geometry/rect_conversions.h"
14 #include "ui/gfx/geometry/vector2d.h"
15 #include "ui/gfx/screen.h"
17 namespace autofill {
19 PopupControllerCommon::PopupControllerCommon(
20 const gfx::RectF& element_bounds,
21 base::i18n::TextDirection text_direction,
22 const gfx::NativeView container_view,
23 content::WebContents* web_contents)
24 : element_bounds_(element_bounds),
25 text_direction_(text_direction),
26 container_view_(container_view),
27 web_contents_(web_contents),
28 key_press_event_target_(NULL) {
30 PopupControllerCommon::~PopupControllerCommon() {}
32 void PopupControllerCommon::SetKeyPressCallback(
33 content::RenderWidgetHost::KeyPressEventCallback callback) {
34 DCHECK(key_press_event_callback_.is_null());
35 key_press_event_callback_ = callback;
38 void PopupControllerCommon::RegisterKeyPressCallback() {
39 if (web_contents_ && !key_press_event_target_) {
40 key_press_event_target_ = web_contents_->GetRenderViewHost();
41 key_press_event_target_->AddKeyPressEventCallback(
42 key_press_event_callback_);
46 void PopupControllerCommon::RemoveKeyPressCallback() {
47 if (web_contents_ && (!web_contents_->IsBeingDestroyed()) &&
48 key_press_event_target_ == web_contents_->GetRenderViewHost()) {
49 web_contents_->GetRenderViewHost()->RemoveKeyPressEventCallback(
50 key_press_event_callback_);
52 key_press_event_target_ = NULL;
55 gfx::Display PopupControllerCommon::GetDisplayNearestPoint(
56 const gfx::Point& point) const {
57 return gfx::Screen::GetScreenFor(container_view_)->GetDisplayNearestPoint(
58 point);
61 const gfx::Rect PopupControllerCommon::RoundedElementBounds() const {
62 return gfx::ToEnclosingRect(element_bounds_);
65 std::pair<int, int> PopupControllerCommon::CalculatePopupXAndWidth(
66 const gfx::Display& left_display,
67 const gfx::Display& right_display,
68 int popup_required_width) const {
69 int leftmost_display_x = left_display.bounds().x();
70 int rightmost_display_x =
71 right_display.GetSizeInPixel().width() + right_display.bounds().x();
73 // Calculate the start coordinates for the popup if it is growing right or
74 // the end position if it is growing to the left, capped to screen space.
75 int right_growth_start = std::max(leftmost_display_x,
76 std::min(rightmost_display_x,
77 RoundedElementBounds().x()));
78 int left_growth_end = std::max(leftmost_display_x,
79 std::min(rightmost_display_x,
80 RoundedElementBounds().right()));
82 int right_available = rightmost_display_x - right_growth_start;
83 int left_available = left_growth_end - leftmost_display_x;
85 int popup_width = std::min(popup_required_width,
86 std::max(right_available, left_available));
88 std::pair<int, int> grow_right(right_growth_start, popup_width);
89 std::pair<int, int> grow_left(left_growth_end - popup_width, popup_width);
91 // Prefer to grow towards the end (right for LTR, left for RTL). But if there
92 // is not enough space available in the desired direction and more space in
93 // the other direction, reverse it.
94 if (is_rtl()) {
95 return left_available >= popup_width || left_available >= right_available
96 ? grow_left
97 : grow_right;
99 return right_available >= popup_width || right_available >= left_available
100 ? grow_right
101 : grow_left;
104 std::pair<int,int> PopupControllerCommon::CalculatePopupYAndHeight(
105 const gfx::Display& top_display,
106 const gfx::Display& bottom_display,
107 int popup_required_height) const {
108 int topmost_display_y = top_display.bounds().y();
109 int bottommost_display_y =
110 bottom_display.GetSizeInPixel().height() + bottom_display.bounds().y();
112 // Calculate the start coordinates for the popup if it is growing down or
113 // the end position if it is growing up, capped to screen space.
114 int top_growth_end = std::max(topmost_display_y,
115 std::min(bottommost_display_y,
116 RoundedElementBounds().y()));
117 int bottom_growth_start = std::max(topmost_display_y,
118 std::min(bottommost_display_y,
119 RoundedElementBounds().bottom()));
121 int top_available = bottom_growth_start - topmost_display_y;
122 int bottom_available = bottommost_display_y - top_growth_end;
124 // TODO(csharp): Restrict the popup height to what is available.
125 if (bottom_available >= popup_required_height ||
126 bottom_available >= top_available) {
127 // The popup can appear below the field.
128 return std::make_pair(bottom_growth_start, popup_required_height);
129 } else {
130 // The popup must appear above the field.
131 return std::make_pair(top_growth_end - popup_required_height,
132 popup_required_height);
136 gfx::Rect PopupControllerCommon::GetPopupBounds(int desired_width,
137 int desired_height) const {
138 // This is the top left point of the popup if the popup is above the element
139 // and grows to the left (since that is the highest and furthest left the
140 // popup go could).
141 gfx::Point top_left_corner_of_popup = RoundedElementBounds().origin() +
142 gfx::Vector2d(RoundedElementBounds().width() - desired_width,
143 -desired_height);
145 // This is the bottom right point of the popup if the popup is below the
146 // element and grows to the right (since the is the lowest and furthest right
147 // the popup could go).
148 gfx::Point bottom_right_corner_of_popup = RoundedElementBounds().origin() +
149 gfx::Vector2d(desired_width,
150 RoundedElementBounds().height() + desired_height);
152 gfx::Display top_left_display = GetDisplayNearestPoint(
153 top_left_corner_of_popup);
154 gfx::Display bottom_right_display = GetDisplayNearestPoint(
155 bottom_right_corner_of_popup);
157 std::pair<int, int> popup_x_and_width =
158 CalculatePopupXAndWidth(top_left_display,
159 bottom_right_display,
160 desired_width);
161 std::pair<int, int> popup_y_and_height =
162 CalculatePopupYAndHeight(top_left_display,
163 bottom_right_display,
164 desired_height);
166 return gfx::Rect(popup_x_and_width.first,
167 popup_y_and_height.first,
168 popup_x_and_width.second,
169 popup_y_and_height.second);
172 } // namespace autofill