Chromium Code Reviews| 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..a521f3cdca582e5718382464e4a2b296d9ab42be |
| --- /dev/null |
| +++ b/content/renderer/disambiguation_popup_helper.cc |
| @@ -0,0 +1,102 @@ |
| +// 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" |
| + |
| +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 = 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 |
| + |
| +float DisambiguationPopupHelper::ComputeZoomAreaAndScaleFactor( |
|
darin (slow to review)
2012/10/08 21:03:46
There's enough code in here that I think you could
trchen
2012/10/11 23:54:05
Added 3 simple test cases. However all it does is
|
| + 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; |
| +} |
| + |