Index: content/renderer/disambiguation_popup_helper.cc |
diff --git a/content/renderer/disambiguation_popup_helper.cc b/content/renderer/disambiguation_popup_helper.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..1a55414c03f698fd3396539980d2e30a3c7a2b84 |
--- /dev/null |
+++ b/content/renderer/disambiguation_popup_helper.cc |
@@ -0,0 +1,106 @@ |
+// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "content/renderer/disambiguation_popup_helper.h" |
+ |
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h" |
+#include "ui/gfx/size_conversions.h" |
+ |
+using WebKit::WebRect; |
+using WebKit::WebVector; |
+ |
+namespace { |
+ |
+// The amount of padding to add to the disambiguation popup to show |
+// content around the possible elements, adding some context. |
+const int kDisambiguationPopupPadding = 8; |
+ |
+// Constants used for fitting the disambiguation popup inside the bounds of |
+// the view. Note that there are mirror constants in PopupZoomer.java. |
+const int kDisambiguationPopupBoundsMargin = 25; |
+ |
+// The smallest allowable touch target used for disambiguation popup. |
+// This value is used to determine the minimum amount we need to scale to |
+// make all targets touchable. |
+const int kDisambiguationPopupMinimumTouchSize = 40; |
+const float kDisambiguationPopupMaxScale = 5.0; |
+const float kDisambiguationPopupMinScale = 2.0; |
+ |
+// Compute the scaling factor to ensure the smallest touch candidate reaches |
+// a certain clickable size after zooming |
+float FindOptimalScaleFactor(const WebVector<WebRect>& target_rects) { |
+ using std::min; |
+ using std::max; |
+ if (!target_rects.size()) // shall never reach |
+ return kDisambiguationPopupMinScale; |
+ int smallest_target = min(target_rects[0].width, target_rects[0].height); |
+ for (size_t i = 1; i < target_rects.size(); i++) { |
+ smallest_target = min(smallest_target, target_rects[i].width); |
+ smallest_target = min(smallest_target, target_rects[i].height); |
+ } |
+ smallest_target = max(smallest_target, 1); |
+ return min(kDisambiguationPopupMaxScale, max(kDisambiguationPopupMinScale, |
+ static_cast<float>(kDisambiguationPopupMinimumTouchSize) |
+ / smallest_target)); |
+} |
+ |
+void TrimEdges(int *e1, int *e2, int max_combined) { |
+ if (*e1 + *e2 <= max_combined) |
+ return; |
+ |
+ if (std::min(*e1, *e2) * 2 >= max_combined) |
+ *e1 = *e2 = max_combined / 2; |
+ else if (*e1 > *e2) |
+ *e1 = max_combined - *e2; |
+ else |
+ *e2 = max_combined - *e1; |
+} |
+ |
+// Ensure the disambiguation popup fits inside the screen, |
+// clip the edges farthest to the touch point if needed. |
+gfx::Rect CropZoomArea(const gfx::Rect& zoom_rect, |
+ const gfx::Size& viewport_size, |
+ const gfx::Point& touch_point, |
+ float scale) { |
+ gfx::Size max_size = viewport_size; |
+ max_size.Enlarge(-2 * kDisambiguationPopupBoundsMargin, |
+ -2 * kDisambiguationPopupBoundsMargin); |
+ max_size = ToCeiledSize(max_size.Scale(1.0 / scale)); |
+ |
+ int left = touch_point.x() - zoom_rect.x(); |
+ int right = zoom_rect.right() - touch_point.x(); |
+ int top = touch_point.y() - zoom_rect.y(); |
+ int bottom = zoom_rect.bottom() - touch_point.y(); |
+ TrimEdges(&left, &right, max_size.width()); |
+ TrimEdges(&top, &bottom, max_size.height()); |
+ |
+ return gfx::Rect(touch_point.x() - left, |
+ touch_point.y() - top, |
+ left + right, |
+ top + bottom); |
+} |
+ |
+} // unnamed namespace |
+ |
+namespace content { |
+ |
+float DisambiguationPopupHelper::ComputeZoomAreaAndScaleFactor( |
+ const gfx::Rect& tap_rect, |
+ const WebVector<WebRect>& target_rects, |
+ const gfx::Size& viewport_size, |
+ gfx::Rect* zoom_rect) { |
+ *zoom_rect = tap_rect; |
+ for (size_t i = 0; i < target_rects.size(); i++) |
+ *zoom_rect = zoom_rect->Union(gfx::Rect(target_rects[i])); |
+ zoom_rect->Inset(-kDisambiguationPopupPadding, -kDisambiguationPopupPadding); |
+ *zoom_rect = zoom_rect->Intersect(gfx::Rect(viewport_size)); |
+ |
+ float scale = FindOptimalScaleFactor(target_rects); |
+ *zoom_rect = CropZoomArea( |
+ *zoom_rect, viewport_size, tap_rect.CenterPoint(), scale); |
+ |
+ return scale; |
+} |
+ |
+} // namespace content |