| 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
|
|
|