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"
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"
19 PopupControllerCommon::PopupControllerCommon(
20 const gfx::RectF
& element_bounds
,
21 const gfx::NativeView container_view
,
22 content::WebContents
* web_contents
)
23 : element_bounds_(element_bounds
),
24 container_view_(container_view
),
25 web_contents_(web_contents
),
26 key_press_event_target_(NULL
) {}
27 PopupControllerCommon::~PopupControllerCommon() {}
29 void PopupControllerCommon::SetKeyPressCallback(
30 content::RenderWidgetHost::KeyPressEventCallback callback
) {
31 DCHECK(key_press_event_callback_
.is_null());
32 key_press_event_callback_
= callback
;
35 void PopupControllerCommon::RegisterKeyPressCallback() {
36 if (web_contents_
&& !key_press_event_target_
) {
37 key_press_event_target_
= web_contents_
->GetRenderViewHost();
38 key_press_event_target_
->AddKeyPressEventCallback(
39 key_press_event_callback_
);
43 void PopupControllerCommon::RemoveKeyPressCallback() {
44 if (web_contents_
&& (!web_contents_
->IsBeingDestroyed()) &&
45 key_press_event_target_
== web_contents_
->GetRenderViewHost()) {
46 web_contents_
->GetRenderViewHost()->RemoveKeyPressEventCallback(
47 key_press_event_callback_
);
49 key_press_event_target_
= NULL
;
52 gfx::Display
PopupControllerCommon::GetDisplayNearestPoint(
53 const gfx::Point
& point
) const {
54 return gfx::Screen::GetScreenFor(container_view_
)->GetDisplayNearestPoint(
58 const gfx::Rect
PopupControllerCommon::RoundedElementBounds() const {
59 return gfx::ToEnclosingRect(element_bounds_
);
62 std::pair
<int, int> PopupControllerCommon::CalculatePopupXAndWidth(
63 const gfx::Display
& left_display
,
64 const gfx::Display
& right_display
,
65 int popup_required_width
) const {
66 int leftmost_display_x
= left_display
.bounds().x();
67 int rightmost_display_x
=
68 right_display
.GetSizeInPixel().width() + right_display
.bounds().x();
70 // Calculate the start coordinates for the popup if it is growing right or
71 // the end position if it is growing to the left, capped to screen space.
72 int right_growth_start
= std::max(leftmost_display_x
,
73 std::min(rightmost_display_x
,
74 RoundedElementBounds().x()));
75 int left_growth_end
= std::max(leftmost_display_x
,
76 std::min(rightmost_display_x
,
77 RoundedElementBounds().right()));
79 int right_available
= rightmost_display_x
- right_growth_start
;
80 int left_available
= left_growth_end
- leftmost_display_x
;
82 int popup_width
= std::min(popup_required_width
,
83 std::max(right_available
, left_available
));
85 // If there is enough space for the popup on the right, show it there,
86 // otherwise choose the larger size.
87 if (right_available
>= popup_width
|| right_available
>= left_available
)
88 return std::make_pair(right_growth_start
, popup_width
);
90 return std::make_pair(left_growth_end
- popup_width
, popup_width
);
93 std::pair
<int,int> PopupControllerCommon::CalculatePopupYAndHeight(
94 const gfx::Display
& top_display
,
95 const gfx::Display
& bottom_display
,
96 int popup_required_height
) const {
97 int topmost_display_y
= top_display
.bounds().y();
98 int bottommost_display_y
=
99 bottom_display
.GetSizeInPixel().height() + bottom_display
.bounds().y();
101 // Calculate the start coordinates for the popup if it is growing down or
102 // the end position if it is growing up, capped to screen space.
103 int top_growth_end
= std::max(topmost_display_y
,
104 std::min(bottommost_display_y
,
105 RoundedElementBounds().y()));
106 int bottom_growth_start
= std::max(topmost_display_y
,
107 std::min(bottommost_display_y
,
108 RoundedElementBounds().bottom()));
110 int top_available
= bottom_growth_start
- topmost_display_y
;
111 int bottom_available
= bottommost_display_y
- top_growth_end
;
113 // TODO(csharp): Restrict the popup height to what is available.
114 if (bottom_available
>= popup_required_height
||
115 bottom_available
>= top_available
) {
116 // The popup can appear below the field.
117 return std::make_pair(bottom_growth_start
, popup_required_height
);
119 // The popup must appear above the field.
120 return std::make_pair(top_growth_end
- popup_required_height
,
121 popup_required_height
);
125 gfx::Rect
PopupControllerCommon::GetPopupBounds(int desired_width
,
126 int desired_height
) const {
127 // This is the top left point of the popup if the popup is above the element
128 // and grows to the left (since that is the highest and furthest left the
130 gfx::Point top_left_corner_of_popup
= RoundedElementBounds().origin() +
131 gfx::Vector2d(RoundedElementBounds().width() - desired_width
,
134 // This is the bottom right point of the popup if the popup is below the
135 // element and grows to the right (since the is the lowest and furthest right
136 // the popup could go).
137 gfx::Point bottom_right_corner_of_popup
= RoundedElementBounds().origin() +
138 gfx::Vector2d(desired_width
,
139 RoundedElementBounds().height() + desired_height
);
141 gfx::Display top_left_display
= GetDisplayNearestPoint(
142 top_left_corner_of_popup
);
143 gfx::Display bottom_right_display
= GetDisplayNearestPoint(
144 bottom_right_corner_of_popup
);
146 std::pair
<int, int> popup_x_and_width
=
147 CalculatePopupXAndWidth(top_left_display
,
148 bottom_right_display
,
150 std::pair
<int, int> popup_y_and_height
=
151 CalculatePopupYAndHeight(top_left_display
,
152 bottom_right_display
,
155 return gfx::Rect(popup_x_and_width
.first
,
156 popup_y_and_height
.first
,
157 popup_x_and_width
.second
,
158 popup_y_and_height
.second
);
161 } // namespace autofill