summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
Diffstat (limited to 'content')
-rw-r--r--content/browser/renderer_host/render_widget_host_impl.cc15
-rw-r--r--content/browser/renderer_host/render_widget_host_impl.h4
-rw-r--r--content/common/view_messages.h12
-rw-r--r--content/content_renderer.gypi2
-rw-r--r--content/content_tests.gypi1
-rw-r--r--content/renderer/disambiguation_popup_helper.cc106
-rw-r--r--content/renderer/disambiguation_popup_helper.h34
-rw-r--r--content/renderer/disambiguation_popup_helper_unittest.cc81
-rw-r--r--content/renderer/render_view_impl.cc47
-rw-r--r--content/renderer/render_view_impl.h5
10 files changed, 307 insertions, 0 deletions
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 4fcdff0..ee008ca 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -316,6 +316,8 @@ bool RenderWidgetHostImpl::OnMessageReceived(const IPC::Message &msg) {
OnMsgDidActivateAcceleratedCompositing)
IPC_MESSAGE_HANDLER(ViewHostMsg_LockMouse, OnMsgLockMouse)
IPC_MESSAGE_HANDLER(ViewHostMsg_UnlockMouse, OnMsgUnlockMouse)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_ShowDisambiguationPopup,
+ OnMsgShowDisambiguationPopup)
#if defined(OS_POSIX) || defined(USE_AURA)
IPC_MESSAGE_HANDLER(ViewHostMsg_GetWindowRect, OnMsgGetWindowRect)
IPC_MESSAGE_HANDLER(ViewHostMsg_GetRootWindowRect, OnMsgGetRootWindowRect)
@@ -1825,6 +1827,19 @@ void RenderWidgetHostImpl::OnMsgUnlockMouse() {
RejectMouseLockOrUnlockIfNecessary();
}
+void RenderWidgetHostImpl::OnMsgShowDisambiguationPopup(
+ const gfx::Rect& rect,
+ const gfx::Size& size,
+ const TransportDIB::Id& id) {
+ TransportDIB* dib = process_->GetTransportDIB(id);
+
+ // TODO(trchen): implement the platform-specific disambiguation popup
+ NOTIMPLEMENTED();
+
+ Send(new ViewMsg_ReleaseDisambiguationPopupDIB(GetRoutingID(),
+ dib->handle()));
+}
+
#if defined(OS_POSIX) || defined(USE_AURA)
void RenderWidgetHostImpl::OnMsgGetWindowRect(gfx::NativeViewId window_id,
gfx::Rect* results) {
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index 223535b..673b485 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -574,6 +574,10 @@ class CONTENT_EXPORT RenderWidgetHostImpl : virtual public RenderWidgetHost,
bool privileged);
void OnMsgUnlockMouse();
+ void OnMsgShowDisambiguationPopup(const gfx::Rect& rect,
+ const gfx::Size& size,
+ const TransportDIB::Id& id);
+
#if defined(OS_POSIX) || defined(USE_AURA)
void OnMsgGetWindowRect(gfx::NativeViewId window_id, gfx::Rect* results);
void OnMsgGetRootWindowRect(gfx::NativeViewId window_id, gfx::Rect* results);
diff --git a/content/common/view_messages.h b/content/common/view_messages.h
index 1b77c74..261bda4 100644
--- a/content/common/view_messages.h
+++ b/content/common/view_messages.h
@@ -1431,6 +1431,11 @@ IPC_MESSAGE_ROUTED1(ViewMsg_SelectPopupMenuItem,
int /* selected index, -1 means no selection */)
#endif
+// An acknowledge to ViewHostMsg_MultipleTargetsTouched to notify the renderer
+// process to release the magnified image.
+IPC_MESSAGE_ROUTED1(ViewMsg_ReleaseDisambiguationPopupDIB,
+ TransportDIB::Handle /* DIB handle */)
+
// -----------------------------------------------------------------------------
// Messages sent from the renderer to the browser.
@@ -2395,3 +2400,10 @@ IPC_MESSAGE_ROUTED3(ViewHostMsg_FindMatchRects_Reply,
IPC_MESSAGE_ROUTED1(ViewHostMsg_StartContentIntent,
GURL /* content_url */)
#endif
+
+// Notifies that multiple touch targets may have been pressed, and to show
+// the disambiguation popup.
+IPC_MESSAGE_ROUTED3(ViewHostMsg_ShowDisambiguationPopup,
+ gfx::Rect, /* Border of touched targets */
+ gfx::Size, /* Size of zoomed image */
+ TransportDIB::Id /* DIB of zoomed image */)
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi
index 2a96e10..56d80d8 100644
--- a/content/content_renderer.gypi
+++ b/content/content_renderer.gypi
@@ -68,6 +68,8 @@
'renderer/devtools_agent_filter.h',
'renderer/devtools_client.cc',
'renderer/devtools_client.h',
+ 'renderer/disambiguation_popup_helper.cc',
+ 'renderer/disambiguation_popup_helper.h',
'renderer/do_not_track_bindings.cc',
'renderer/do_not_track_bindings.h',
'renderer/dom_automation_controller.cc',
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index 5473342..ad82ddb 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -352,6 +352,7 @@
'renderer/active_notification_tracker_unittest.cc',
'renderer/android/email_detector_unittest.cc',
'renderer/android/phone_number_detector_unittest.cc',
+ 'renderer/disambiguation_popup_helper_unittest.cc',
'renderer/gpu/input_event_filter_unittest.cc',
'renderer/hyphenator/hyphenator_unittest.cc',
'renderer/media/audio_message_filter_unittest.cc',
diff --git a/content/renderer/disambiguation_popup_helper.cc b/content/renderer/disambiguation_popup_helper.cc
new file mode 100644
index 0000000..1a55414
--- /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
diff --git a/content/renderer/disambiguation_popup_helper.h b/content/renderer/disambiguation_popup_helper.h
new file mode 100644
index 0000000..84ee049
--- /dev/null
+++ b/content/renderer/disambiguation_popup_helper.h
@@ -0,0 +1,34 @@
+// 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.
+
+#ifndef CONTENT_RENDERER_DISAMBIGUATION_POPUP_HELPER_H_
+#define CONTENT_RENDERER_DISAMBIGUATION_POPUP_HELPER_H_
+
+#include "content/common/content_export.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebVector.h"
+
+namespace gfx {
+class Rect;
+class Size;
+}
+
+namespace WebKit {
+struct WebRect;
+}
+
+namespace content {
+
+// Contains functions to calculate proper scaling factor and popup size
+class DisambiguationPopupHelper {
+ public:
+ CONTENT_EXPORT static float ComputeZoomAreaAndScaleFactor(
+ const gfx::Rect& tap_rect,
+ const WebKit::WebVector<WebKit::WebRect>& target_rects,
+ const gfx::Size& viewport_size,
+ gfx::Rect* zoom_rect);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_DISAMBIGUATION_POPUP_HELPER_H_
diff --git a/content/renderer/disambiguation_popup_helper_unittest.cc b/content/renderer/disambiguation_popup_helper_unittest.cc
new file mode 100644
index 0000000..2aaeb84
--- /dev/null
+++ b/content/renderer/disambiguation_popup_helper_unittest.cc
@@ -0,0 +1,81 @@
+// 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 "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebVector.h"
+#include "ui/gfx/rect.h"
+#include "ui/gfx/size.h"
+#include "ui/gfx/size_conversions.h"
+
+// these constants are copied from the implementation class
+namespace {
+const float kDisambiguationPopupMaxScale = 5.0;
+const float kDisambiguationPopupMinScale = 2.0;
+} // unnamed namespace
+
+namespace content {
+
+class DisambiguationPopupHelperUnittest : public testing::Test {
+ public:
+ DisambiguationPopupHelperUnittest()
+ : kViewportSize_(640, 480) { }
+ protected:
+ const gfx::Size kViewportSize_;
+};
+
+TEST_F(DisambiguationPopupHelperUnittest, ClipByViewport) {
+ gfx::Rect tap_rect(1000, 1000, 10, 10);
+ WebKit::WebVector<WebKit::WebRect> target_rects(static_cast<size_t>(1));
+ target_rects[0] = gfx::Rect(-20, -20, 10, 10);
+
+ gfx::Rect zoom_rect;
+ float scale = DisambiguationPopupHelper::ComputeZoomAreaAndScaleFactor(
+ tap_rect, target_rects, kViewportSize_, &zoom_rect);
+
+ EXPECT_TRUE(gfx::Rect(kViewportSize_).Contains(zoom_rect));
+ EXPECT_LE(kDisambiguationPopupMinScale, scale);
+
+ gfx::Size scaled_size = ToCeiledSize(zoom_rect.size().Scale(scale));
+ EXPECT_TRUE(gfx::Rect(kViewportSize_).Contains(gfx::Rect(scaled_size)));
+}
+
+TEST_F(DisambiguationPopupHelperUnittest, MiniTarget) {
+ gfx::Rect tap_rect(-5, -5, 20, 20);
+ WebKit::WebVector<WebKit::WebRect> target_rects(static_cast<size_t>(1));
+ target_rects[0] = gfx::Rect(10, 10, 1, 1);
+
+ gfx::Rect zoom_rect;
+ float scale = DisambiguationPopupHelper::ComputeZoomAreaAndScaleFactor(
+ tap_rect, target_rects, kViewportSize_, &zoom_rect);
+
+ EXPECT_TRUE(gfx::Rect(kViewportSize_).Contains(zoom_rect));
+ EXPECT_EQ(kDisambiguationPopupMaxScale, scale);
+ EXPECT_TRUE(zoom_rect.Contains(target_rects[0]));
+
+ gfx::Size scaled_size = ToCeiledSize(zoom_rect.size().Scale(scale));
+ EXPECT_TRUE(gfx::Rect(kViewportSize_).Contains(gfx::Rect(scaled_size)));
+}
+
+TEST_F(DisambiguationPopupHelperUnittest, LongLinks) {
+ gfx::Rect tap_rect(10, 10, 20, 20);
+ WebKit::WebVector<WebKit::WebRect> target_rects(static_cast<size_t>(2));
+ target_rects[0] = gfx::Rect(15, 15, 1000, 5);
+ target_rects[1] = gfx::Rect(15, 25, 1000, 5);
+
+ gfx::Rect zoom_rect;
+ float scale = DisambiguationPopupHelper::ComputeZoomAreaAndScaleFactor(
+ tap_rect, target_rects, kViewportSize_, &zoom_rect);
+
+ EXPECT_TRUE(gfx::Rect(kViewportSize_).Contains(zoom_rect));
+ EXPECT_EQ(kDisambiguationPopupMaxScale, scale);
+ EXPECT_TRUE(zoom_rect.Contains(tap_rect));
+
+ gfx::Size scaled_size = ToCeiledSize(zoom_rect.size().Scale(scale));
+ EXPECT_TRUE(gfx::Rect(kViewportSize_).Contains(gfx::Rect(scaled_size)));
+}
+
+} // namespace content
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index e8cf050..0d82ff6 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -68,6 +68,7 @@
#include "content/renderer/browser_plugin/old/guest_to_embedder_channel.h"
#include "content/renderer/device_orientation_dispatcher.h"
#include "content/renderer/devtools_agent.h"
+#include "content/renderer/disambiguation_popup_helper.h"
#include "content/renderer/dom_automation_controller.h"
#include "content/renderer/dom_storage/webstoragenamespace_impl.h"
#include "content/renderer/do_not_track_bindings.h"
@@ -180,6 +181,7 @@
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/point.h"
#include "ui/gfx/rect.h"
+#include "ui/gfx/size_conversions.h"
#include "v8/include/v8.h"
#include "webkit/appcache/web_application_cache_host_impl.h"
#include "webkit/dom_storage/dom_storage_types.h"
@@ -1059,6 +1061,8 @@ bool RenderViewImpl::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(ViewMsg_SetWindowVisibility, OnSetWindowVisibility)
IPC_MESSAGE_HANDLER(ViewMsg_WindowFrameChanged, OnWindowFrameChanged)
#endif
+ IPC_MESSAGE_HANDLER(ViewMsg_ReleaseDisambiguationPopupDIB,
+ OnReleaseDisambiguationPopupDIB)
// Have the super handle all other messages.
IPC_MESSAGE_UNHANDLED(handled = RenderWidget::OnMessageReceived(message))
@@ -6388,3 +6392,46 @@ void RenderViewImpl::OnUpdatedFrameTree(
updating_frame_tree_ = false;
}
+
+bool RenderViewImpl::didTapMultipleTargets(
+ const WebKit::WebGestureEvent& event,
+ const WebVector<WebRect>& target_rects) {
+ using content::DisambiguationPopupHelper;
+ gfx::Rect finger_rect(
+ event.x - event.data.tap.width / 2, event.y - event.data.tap.height / 2,
+ event.data.tap.width, event.data.tap.height);
+ gfx::Rect zoom_rect;
+ float scale = DisambiguationPopupHelper::ComputeZoomAreaAndScaleFactor(
+ finger_rect, target_rects, GetSize(), &zoom_rect);
+ if (!scale)
+ return false;
+
+ gfx::Size canvas_size = zoom_rect.size();
+ canvas_size = ToCeiledSize(canvas_size.Scale(scale));
+ TransportDIB* transport_dib = NULL;
+ {
+ scoped_ptr<skia::PlatformCanvas> canvas(
+ RenderProcess::current()->GetDrawingCanvas(&transport_dib,
+ gfx::Rect(canvas_size)));
+ if (!canvas.get())
+ return false;
+
+ canvas->scale(scale, scale);
+
+ canvas->translate(-zoom_rect.x(), -zoom_rect.y());
+ webwidget_->paint(webkit_glue::ToWebCanvas(canvas.get()), zoom_rect,
+ WebWidget::ForceSoftwareRenderingAndIgnoreGPUResidentContent);
+ }
+ Send(new ViewHostMsg_ShowDisambiguationPopup(routing_id_,
+ zoom_rect,
+ canvas_size,
+ transport_dib->id()));
+
+ return true;
+}
+
+void RenderViewImpl::OnReleaseDisambiguationPopupDIB(
+ TransportDIB::Handle dib_handle) {
+ TransportDIB* dib = TransportDIB::CreateWithHandle(dib_handle);
+ RenderProcess::current()->ReleaseTransportDIB(dib);
+}
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index 773c242..6ea0985 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -153,6 +153,7 @@ class WebDOMMessageEvent;
class WebDataSource;
class WebDragData;
class WebGeolocationClient;
+class WebGestureEvent;
#if defined(OS_ANDROID)
class WebHitTestResult;
#endif
@@ -495,6 +496,9 @@ class RenderViewImpl : public RenderWidget,
virtual void numberOfWheelEventHandlersChanged(unsigned num_handlers);
virtual void hasTouchEventHandlers(bool has_handlers);
virtual void didUpdateLayout();
+ virtual bool didTapMultipleTargets(
+ const WebKit::WebGestureEvent& event,
+ const WebKit::WebVector<WebKit::WebRect>& target_rects);
virtual void navigateBackForwardSoon(int offset);
virtual int historyBackListCount();
virtual int historyForwardListCount();
@@ -987,6 +991,7 @@ class RenderViewImpl : public RenderWidget,
void OnPasteAndMatchStyle();
void OnPostMessageEvent(const ViewMsg_PostMessage_Params& params);
void OnRedo();
+ void OnReleaseDisambiguationPopupDIB(TransportDIB::Handle dib_handle);
void OnReloadFrame();
void OnReplace(const string16& text);
CONTENT_EXPORT void OnReplaceAll(const string16& text);