diff options
author | trchen@chromium.org <trchen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-10-18 01:55:03 +0000 |
---|---|---|
committer | trchen@chromium.org <trchen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-10-18 01:55:03 +0000 |
commit | f9526d17e1eb2ae23c805c3dbe1ee5d489cc01f2 (patch) | |
tree | 09db5bb4f5c163cd2aca14a082ed7986496f9ec2 /content | |
parent | 5fcbd95d392220159dda31f9de049f792cbc20d5 (diff) | |
download | chromium_src-f9526d17e1eb2ae23c805c3dbe1ee5d489cc01f2.zip chromium_src-f9526d17e1eb2ae23c805c3dbe1ee5d489cc01f2.tar.gz chromium_src-f9526d17e1eb2ae23c805c3dbe1ee5d489cc01f2.tar.bz2 |
Implement disambiguation popup
This patch implements the renderer-process side of disambiguation popup.
Individual platforms shall provide its own browser-side handling.
Correspoding WebKit CL: https://bugs.webkit.org/show_bug.cgi?id=94182
BUG=100752
Review URL: https://chromiumcodereview.appspot.com/10885004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@162612 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
-rw-r--r-- | content/browser/renderer_host/render_widget_host_impl.cc | 15 | ||||
-rw-r--r-- | content/browser/renderer_host/render_widget_host_impl.h | 4 | ||||
-rw-r--r-- | content/common/view_messages.h | 12 | ||||
-rw-r--r-- | content/content_renderer.gypi | 2 | ||||
-rw-r--r-- | content/content_tests.gypi | 1 | ||||
-rw-r--r-- | content/renderer/disambiguation_popup_helper.cc | 106 | ||||
-rw-r--r-- | content/renderer/disambiguation_popup_helper.h | 34 | ||||
-rw-r--r-- | content/renderer/disambiguation_popup_helper_unittest.cc | 81 | ||||
-rw-r--r-- | content/renderer/render_view_impl.cc | 47 | ||||
-rw-r--r-- | content/renderer/render_view_impl.h | 5 |
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); |