| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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 "content/renderer/disambiguation_popup_helper.h" | |
| 6 | |
| 7 #include <stddef.h> | |
| 8 | |
| 9 #include "third_party/WebKit/public/platform/WebRect.h" | |
| 10 #include "ui/gfx/geometry/size_conversions.h" | |
| 11 | |
| 12 using blink::WebRect; | |
| 13 using blink::WebVector; | |
| 14 | |
| 15 namespace { | |
| 16 | |
| 17 // The amount of padding to add to the disambiguation popup to show | |
| 18 // content around the possible elements, adding some context. | |
| 19 const int kDisambiguationPopupPadding = 8; | |
| 20 | |
| 21 // Constants used for fitting the disambiguation popup inside the bounds of | |
| 22 // the view. Note that there are mirror constants in PopupZoomer.java. | |
| 23 const int kDisambiguationPopupBoundsMargin = 25; | |
| 24 | |
| 25 // The smallest allowable touch target used for disambiguation popup. | |
| 26 // This value is used to determine the minimum amount we need to scale to | |
| 27 // make all targets touchable. | |
| 28 const int kDisambiguationPopupMinimumTouchSize = 40; | |
| 29 const float kDisambiguationPopupMaxScale = 5.0; | |
| 30 const float kDisambiguationPopupMinScale = 2.0; | |
| 31 | |
| 32 // Compute the scaling factor to ensure the smallest touch candidate reaches | |
| 33 // a certain clickable size after zooming | |
| 34 float FindOptimalScaleFactor(const WebVector<WebRect>& target_rects, | |
| 35 float total_scale) { | |
| 36 using std::min; | |
| 37 using std::max; | |
| 38 if (!target_rects.size()) // shall never reach | |
| 39 return kDisambiguationPopupMinScale; | |
| 40 float smallest_target = min(target_rects[0].width * total_scale, | |
| 41 target_rects[0].height * total_scale); | |
| 42 for (size_t i = 1; i < target_rects.size(); i++) { | |
| 43 smallest_target = min(smallest_target, target_rects[i].width * total_scale); | |
| 44 smallest_target = min(smallest_target, | |
| 45 target_rects[i].height * total_scale); | |
| 46 } | |
| 47 smallest_target = max(smallest_target, 1.0f); | |
| 48 return min(kDisambiguationPopupMaxScale, max(kDisambiguationPopupMinScale, | |
| 49 kDisambiguationPopupMinimumTouchSize / smallest_target)) * total_scale; | |
| 50 } | |
| 51 | |
| 52 void TrimEdges(int *e1, int *e2, int max_combined) { | |
| 53 if (*e1 + *e2 <= max_combined) | |
| 54 return; | |
| 55 | |
| 56 if (std::min(*e1, *e2) * 2 >= max_combined) | |
| 57 *e1 = *e2 = max_combined / 2; | |
| 58 else if (*e1 > *e2) | |
| 59 *e1 = max_combined - *e2; | |
| 60 else | |
| 61 *e2 = max_combined - *e1; | |
| 62 } | |
| 63 | |
| 64 // Ensure the disambiguation popup fits inside the screen, | |
| 65 // clip the edges farthest to the touch point if needed. | |
| 66 gfx::Rect CropZoomArea(const gfx::Rect& zoom_rect, | |
| 67 const gfx::Size& viewport_size, | |
| 68 const gfx::Point& touch_point, | |
| 69 float scale) { | |
| 70 gfx::Size max_size = viewport_size; | |
| 71 max_size.Enlarge(-2 * kDisambiguationPopupBoundsMargin, | |
| 72 -2 * kDisambiguationPopupBoundsMargin); | |
| 73 max_size = gfx::ScaleToCeiledSize(max_size, 1.0 / scale); | |
| 74 | |
| 75 int left = touch_point.x() - zoom_rect.x(); | |
| 76 int right = zoom_rect.right() - touch_point.x(); | |
| 77 int top = touch_point.y() - zoom_rect.y(); | |
| 78 int bottom = zoom_rect.bottom() - touch_point.y(); | |
| 79 TrimEdges(&left, &right, max_size.width()); | |
| 80 TrimEdges(&top, &bottom, max_size.height()); | |
| 81 | |
| 82 return gfx::Rect(touch_point.x() - left, | |
| 83 touch_point.y() - top, | |
| 84 left + right, | |
| 85 top + bottom); | |
| 86 } | |
| 87 | |
| 88 } // namespace | |
| 89 | |
| 90 namespace content { | |
| 91 | |
| 92 float DisambiguationPopupHelper::ComputeZoomAreaAndScaleFactor( | |
| 93 const gfx::Rect& tap_rect, | |
| 94 const WebVector<WebRect>& target_rects, | |
| 95 const gfx::Size& screen_size, | |
| 96 const gfx::Size& visible_content_size, | |
| 97 float total_scale, | |
| 98 gfx::Rect* zoom_rect) { | |
| 99 *zoom_rect = tap_rect; | |
| 100 for (size_t i = 0; i < target_rects.size(); i++) | |
| 101 zoom_rect->Union(gfx::Rect(target_rects[i])); | |
| 102 zoom_rect->Inset(-kDisambiguationPopupPadding, -kDisambiguationPopupPadding); | |
| 103 | |
| 104 zoom_rect->Intersect(gfx::Rect(visible_content_size)); | |
| 105 | |
| 106 float new_total_scale = | |
| 107 FindOptimalScaleFactor(target_rects, total_scale); | |
| 108 *zoom_rect = CropZoomArea( | |
| 109 *zoom_rect, screen_size, tap_rect.CenterPoint(), new_total_scale); | |
| 110 | |
| 111 return new_total_scale; | |
| 112 } | |
| 113 | |
| 114 } // namespace content | |
| OLD | NEW |