OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 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_view_common.h" |
| 6 |
| 7 #include <algorithm> |
| 8 #include <utility> |
| 9 |
| 10 #include "ui/gfx/display.h" |
| 11 #include "ui/gfx/geometry/point.h" |
| 12 #include "ui/gfx/geometry/rect.h" |
| 13 #include "ui/gfx/geometry/vector2d.h" |
| 14 #include "ui/gfx/screen.h" |
| 15 |
| 16 namespace autofill { |
| 17 |
| 18 namespace { |
| 19 |
| 20 std::pair<int, int> CalculatePopupXAndWidth(const gfx::Display& left_display, |
| 21 const gfx::Display& right_display, |
| 22 int popup_required_width, |
| 23 const gfx::Rect element_bounds, |
| 24 bool is_rtl) { |
| 25 int leftmost_display_x = left_display.bounds().x(); |
| 26 int rightmost_display_x = |
| 27 right_display.GetSizeInPixel().width() + right_display.bounds().x(); |
| 28 |
| 29 // Calculate the start coordinates for the popup if it is growing right or |
| 30 // the end position if it is growing to the left, capped to screen space. |
| 31 int right_growth_start = std::max( |
| 32 leftmost_display_x, std::min(rightmost_display_x, element_bounds.x())); |
| 33 int left_growth_end = |
| 34 std::max(leftmost_display_x, |
| 35 std::min(rightmost_display_x, element_bounds.right())); |
| 36 |
| 37 int right_available = rightmost_display_x - right_growth_start; |
| 38 int left_available = left_growth_end - leftmost_display_x; |
| 39 |
| 40 int popup_width = |
| 41 std::min(popup_required_width, std::max(right_available, left_available)); |
| 42 |
| 43 std::pair<int, int> grow_right(right_growth_start, popup_width); |
| 44 std::pair<int, int> grow_left(left_growth_end - popup_width, popup_width); |
| 45 |
| 46 // Prefer to grow towards the end (right for LTR, left for RTL). But if there |
| 47 // is not enough space available in the desired direction and more space in |
| 48 // the other direction, reverse it. |
| 49 if (is_rtl) { |
| 50 return left_available >= popup_width || left_available >= right_available |
| 51 ? grow_left |
| 52 : grow_right; |
| 53 } |
| 54 return right_available >= popup_width || right_available >= left_available |
| 55 ? grow_right |
| 56 : grow_left; |
| 57 } |
| 58 |
| 59 // Calculates the height of the popup and the y position of it. These values |
| 60 // will stay on the screen. |
| 61 std::pair<int, int> CalculatePopupYAndHeight(const gfx::Display& top_display, |
| 62 const gfx::Display& bottom_display, |
| 63 int popup_required_height, |
| 64 const gfx::Rect element_bounds) { |
| 65 int topmost_display_y = top_display.bounds().y(); |
| 66 int bottommost_display_y = |
| 67 bottom_display.GetSizeInPixel().height() + bottom_display.bounds().y(); |
| 68 |
| 69 // Calculate the start coordinates for the popup if it is growing down or |
| 70 // the end position if it is growing up, capped to screen space. |
| 71 int top_growth_end = std::max( |
| 72 topmost_display_y, std::min(bottommost_display_y, element_bounds.y())); |
| 73 int bottom_growth_start = |
| 74 std::max(topmost_display_y, |
| 75 std::min(bottommost_display_y, element_bounds.bottom())); |
| 76 |
| 77 int top_available = bottom_growth_start - topmost_display_y; |
| 78 int bottom_available = bottommost_display_y - top_growth_end; |
| 79 |
| 80 // TODO(csharp): Restrict the popup height to what is available. |
| 81 if (bottom_available >= popup_required_height || |
| 82 bottom_available >= top_available) { |
| 83 // The popup can appear below the field. |
| 84 return std::make_pair(bottom_growth_start, popup_required_height); |
| 85 } else { |
| 86 // The popup must appear above the field. |
| 87 return std::make_pair(top_growth_end - popup_required_height, |
| 88 popup_required_height); |
| 89 } |
| 90 } |
| 91 |
| 92 } // namespace |
| 93 |
| 94 gfx::Rect PopupViewCommon::CalculatePopupBounds(int desired_width, |
| 95 int desired_height, |
| 96 const gfx::Rect& element_bounds, |
| 97 gfx::NativeView container_view, |
| 98 bool is_rtl) { |
| 99 // This is the top left point of the popup if the popup is above the element |
| 100 // and grows to the left (since that is the highest and furthest left the |
| 101 // popup go could). |
| 102 gfx::Point top_left_corner_of_popup = |
| 103 element_bounds.origin() + |
| 104 gfx::Vector2d(element_bounds.width() - desired_width, -desired_height); |
| 105 |
| 106 // This is the bottom right point of the popup if the popup is below the |
| 107 // element and grows to the right (since the is the lowest and furthest right |
| 108 // the popup could go). |
| 109 gfx::Point bottom_right_corner_of_popup = |
| 110 element_bounds.origin() + |
| 111 gfx::Vector2d(desired_width, element_bounds.height() + desired_height); |
| 112 |
| 113 gfx::Display top_left_display = |
| 114 GetDisplayNearestPoint(top_left_corner_of_popup, container_view); |
| 115 gfx::Display bottom_right_display = |
| 116 GetDisplayNearestPoint(bottom_right_corner_of_popup, container_view); |
| 117 |
| 118 std::pair<int, int> popup_x_and_width = |
| 119 CalculatePopupXAndWidth(top_left_display, bottom_right_display, |
| 120 desired_width, element_bounds, is_rtl); |
| 121 std::pair<int, int> popup_y_and_height = CalculatePopupYAndHeight( |
| 122 top_left_display, bottom_right_display, desired_height, element_bounds); |
| 123 |
| 124 return gfx::Rect(popup_x_and_width.first, popup_y_and_height.first, |
| 125 popup_x_and_width.second, popup_y_and_height.second); |
| 126 } |
| 127 |
| 128 gfx::Display PopupViewCommon::GetDisplayNearestPoint( |
| 129 const gfx::Point& point, |
| 130 gfx::NativeView container_view) { |
| 131 return gfx::Screen::GetScreenFor(container_view) |
| 132 ->GetDisplayNearestPoint(point); |
| 133 } |
| 134 |
| 135 } // namespace autofill |
OLD | NEW |