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