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. 4 5#include "chrome/browser/ui/autofill/popup_controller_common.h" 6 7#include <algorithm> 8#include <utility> 9 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/rect_conversions.h" 14#include "ui/gfx/screen.h" 15#include "ui/gfx/vector2d.h" 16 17namespace autofill { 18 19PopupControllerCommon::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) {} 27PopupControllerCommon::~PopupControllerCommon() {} 28 29void PopupControllerCommon::SetKeyPressCallback( 30 content::RenderWidgetHost::KeyPressEventCallback callback) { 31 DCHECK(key_press_event_callback_.is_null()); 32 key_press_event_callback_ = callback; 33} 34 35void 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_); 40 } 41} 42 43void 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_); 48 } 49 key_press_event_target_ = NULL; 50} 51 52gfx::Display PopupControllerCommon::GetDisplayNearestPoint( 53 const gfx::Point& point) const { 54 return gfx::Screen::GetScreenFor(container_view_)->GetDisplayNearestPoint( 55 point); 56} 57 58const gfx::Rect PopupControllerCommon::RoundedElementBounds() const { 59 return gfx::ToEnclosingRect(element_bounds_); 60} 61 62std::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(); 69 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())); 78 79 int right_available = rightmost_display_x - right_growth_start; 80 int left_available = left_growth_end - leftmost_display_x; 81 82 int popup_width = std::min(popup_required_width, 83 std::max(right_available, left_available)); 84 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); 89 else 90 return std::make_pair(left_growth_end - popup_width, popup_width); 91} 92 93std::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(); 100 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())); 109 110 int top_available = bottom_growth_start - topmost_display_y; 111 int bottom_available = bottommost_display_y - top_growth_end; 112 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); 118 } else { 119 // The popup must appear above the field. 120 return std::make_pair(top_growth_end - popup_required_height, 121 popup_required_height); 122 } 123} 124 125gfx::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 129 // popup go could). 130 gfx::Point top_left_corner_of_popup = RoundedElementBounds().origin() + 131 gfx::Vector2d(RoundedElementBounds().width() - desired_width, 132 -desired_height); 133 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); 140 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); 145 146 std::pair<int, int> popup_x_and_width = 147 CalculatePopupXAndWidth(top_left_display, 148 bottom_right_display, 149 desired_width); 150 std::pair<int, int> popup_y_and_height = 151 CalculatePopupYAndHeight(top_left_display, 152 bottom_right_display, 153 desired_height); 154 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); 159} 160 161} // namespace autofill 162