Commit fa57a54a authored by Jinsong Fan's avatar Jinsong Fan Committed by Commit Bot

Fix the selection rect when it's clipped for showSelectionMenu

In the current implementation, always use the selection rect fully between
the handles to calculate the location of the context menu, but the selection
rect may be clipped, so in this case, the position of the context menu will
be far from the clipped selection rect.
The CL computes the clipped selection rect for showSelectionMenu.

Bug: 1015274
Change-Id: I7aaf27337c7009eb9fef78f3a1ee92e521de8cda
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1868575Reviewed-by: default avatarYoshifumi Inoue <yosin@chromium.org>
Reviewed-by: default avatarDavid Bokan <bokan@chromium.org>
Commit-Queue: Jinsong Fan <fanjinsong@sogou-inc.com>
Cr-Commit-Position: refs/heads/master@{#709465}
parent 557416cf
......@@ -188,6 +188,20 @@ static WebRect ComputeSelectionRect(LocalFrame* selected_frame) {
int right = std::max(focus.X() + focus.Width(), anchor.X() + anchor.Width());
int bottom =
std::max(focus.Y() + focus.Height(), anchor.Y() + anchor.Height());
// Intersect the selection rect and the visible bounds of the focused_element
// to ensure the selection rect is visible.
Document* doc = selected_frame->GetDocument();
if (doc) {
Element* focused_element = doc->FocusedElement();
if (focused_element) {
IntRect visible_bound = focused_element->VisibleBoundsInVisualViewport();
left = std::max(visible_bound.X(), left);
top = std::max(visible_bound.Y(), top);
right = std::min(visible_bound.MaxX(), right);
bottom = std::min(visible_bound.MaxY(), bottom);
}
}
return WebRect(left, top, right - left, bottom - top);
}
......
......@@ -8,6 +8,7 @@
#include "third_party/blink/public/platform/web_media_stream.h"
#include "third_party/blink/public/platform/web_media_stream_track.h"
#include "third_party/blink/public/platform/web_menu_source_type.h"
#include "third_party/blink/public/platform/web_rect.h"
#include "third_party/blink/public/web/web_context_menu_data.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h"
#include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
......@@ -16,6 +17,7 @@
#include "third_party/blink/renderer/core/html/media/html_video_element.h"
#include "third_party/blink/renderer/core/input/context_menu_allowed_scope.h"
#include "third_party/blink/renderer/core/page/context_menu_controller.h"
#include "third_party/blink/renderer/platform/geometry/int_rect.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/testing/empty_web_media_player.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
......@@ -588,4 +590,58 @@ TEST_F(ContextMenuControllerTest, ShowNonLocatedContextMenuEvent) {
EXPECT_EQ(context_menu_data.selected_text, "Sample Input Text");
}
TEST_F(ContextMenuControllerTest, SelectionRectClipped) {
GetDocument()->documentElement()->SetInnerHTMLFromString(
"<textarea id='text-area' cols=6 rows=2>Sample editable text</textarea>");
Document* document = GetDocument();
Element* editable_element = document->getElementById("text-area");
document->UpdateStyleAndLayout();
FrameSelection& selection = document->GetFrame()->Selection();
// Select the 'Sample' of |textarea|.
DOMRect* rect = editable_element->getBoundingClientRect();
WebGestureEvent gesture_event(
WebInputEvent::kGestureLongPress, WebInputEvent::kNoModifiers,
base::TimeTicks::Now(), WebGestureDevice::kTouchscreen);
gesture_event.SetPositionInWidget(WebFloatPoint(rect->left(), rect->top()));
GetWebView()->MainFrameWidget()->HandleInputEvent(
WebCoalescedInputEvent(gesture_event));
WebContextMenuData context_menu_data =
GetWebFrameClient().GetContextMenuData();
EXPECT_EQ(context_menu_data.selected_text, "Sample");
// The selection rect is not clipped.
IntRect anchor, focus;
selection.ComputeAbsoluteBounds(anchor, focus);
anchor = document->GetFrame()->View()->FrameToViewport(anchor);
focus = document->GetFrame()->View()->FrameToViewport(focus);
int left = std::min(focus.X(), anchor.X());
int top = std::min(focus.Y(), anchor.Y());
int right = std::max(focus.MaxX(), anchor.MaxX());
int bottom = std::max(focus.MaxY(), anchor.MaxY());
WebRect selection_rect(left, top, right - left, bottom - top);
EXPECT_EQ(context_menu_data.selection_rect, selection_rect);
// Select all the content of |textarea|.
selection.SelectAll();
EXPECT_TRUE(ShowContextMenuForElement(editable_element, kMenuSourceMouse));
context_menu_data = GetWebFrameClient().GetContextMenuData();
EXPECT_EQ(context_menu_data.selected_text, "Sample editable text");
// The selection rect is clipped by the editable box.
IntRect clip_bound = editable_element->VisibleBoundsInVisualViewport();
selection.ComputeAbsoluteBounds(anchor, focus);
anchor = document->GetFrame()->View()->FrameToViewport(anchor);
focus = document->GetFrame()->View()->FrameToViewport(focus);
left = std::max(clip_bound.X(), std::min(focus.X(), anchor.X()));
top = std::max(clip_bound.Y(), std::min(focus.Y(), anchor.Y()));
right = std::min(clip_bound.MaxX(), std::max(focus.MaxX(), anchor.MaxX()));
bottom = std::min(clip_bound.MaxY(), std::max(focus.MaxY(), anchor.MaxY()));
selection_rect = WebRect(left, top, right - left, bottom - top);
EXPECT_EQ(context_menu_data.selection_rect, selection_rect);
}
} // namespace blink
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment