Commit 585c7af0 authored by Henrique Nakashima's avatar Henrique Nakashima Committed by Commit Bot

Pan around PDF with middle mouse drag.

Bug: 234933
Cq-Include-Trybots: master.tryserver.chromium.linux:closure_compilation
Change-Id: I4a42336006cf553bf52d30be4656f953d8341323
Reviewed-on: https://chromium-review.googlesource.com/974447Reviewed-by: default avatardsinclair <dsinclair@chromium.org>
Reviewed-by: default avatarDemetrios Papadopoulos <dpapad@chromium.org>
Reviewed-by: default avatarLei Zhang <thestig@chromium.org>
Commit-Queue: Henrique Nakashima <hnakashima@chromium.org>
Cr-Commit-Position: refs/heads/master@{#546017}
parent ffc960a3
......@@ -699,12 +699,10 @@ PDFViewer.prototype = {
this.sendDocumentLoadedMessage_();
break;
case 'setScrollPosition':
var position = this.viewport_.position;
if (message.data.x !== undefined)
position.x = message.data.x;
if (message.data.y !== undefined)
position.y = message.data.y;
this.viewport_.position = position;
this.viewport_.scrollTo(/** @type {!PartialPoint} */ (message.data));
break;
case 'scrollBy':
this.viewport_.scrollBy(/** @type {!Point} */ (message.data));
break;
case 'cancelStreamUrl':
chrome.mimeHandlerPrivate.abortStream();
......
......@@ -2,6 +2,22 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @typedef {{
* x: number,
* y: number
* }}
*/
let Point;
/**
* @typedef {{
* x: number | undefined,
* y: number | undefined
* }}
*/
let PartialPoint;
/**
* Returns the height of the intersection of two rectangles.
* @param {Object} rect1 the first rect
......@@ -254,7 +270,7 @@ Viewport.prototype = {
/**
* Scroll the viewport to the specified position.
* @type {Object} position the position to scroll to.
* @type {Object} position The position to scroll to.
*/
set position(position) {
this.window_.scrollTo(position.x, position.y + this.topToolbarHeight_);
......@@ -906,5 +922,38 @@ Viewport.prototype = {
return (
this.fittingType_ == FittingType.FIT_TO_PAGE ||
this.fittingType_ == FittingType.FIT_TO_HEIGHT);
},
/**
* Scroll the viewport to the specified position.
*
* @param {!PartialPoint} point The position to which to move the viewport.
*/
scrollTo: function(point) {
let changed = false;
const newPosition = this.position;
if (point.x !== undefined && point.x != newPosition.x) {
newPosition.x = point.x;
changed = true;
}
if (point.y !== undefined && point.y != newPosition.y) {
newPosition.y = point.y;
changed = true;
}
if (changed)
this.position = newPosition;
},
/**
* Scroll the viewport by the specified delta.
*
* @param {!Point} delta The delta by which to move the viewport.
*/
scrollBy: function(delta) {
const newPosition = this.position;
newPosition.x += delta.x;
newPosition.y += delta.y;
this.scrollTo(newPosition);
}
};
......@@ -605,6 +605,110 @@ var tests = [
chrome.test.succeed();
},
function testScrollTo() {
var mockWindow = new MockWindow(100, 100);
var mockSizer = new MockSizer();
var mockCallback = new MockViewportChangedCallback();
var viewport = new Viewport(mockWindow, mockSizer, mockCallback.callback,
function() {}, function() {}, function() {},
0, 1, 0);
var documentDimensions = new MockDocumentDimensions();
documentDimensions.addPage(200, 200);
viewport.setDocumentDimensions(documentDimensions);
viewport.setZoom(1);
chrome.test.assertEq(0, viewport.position.x);
chrome.test.assertEq(0, viewport.position.y);
mockCallback.reset();
viewport.scrollTo({x: 0, y: 0});
chrome.test.assertFalse(mockCallback.wasCalled);
chrome.test.assertEq(0, viewport.position.x);
chrome.test.assertEq(0, viewport.position.y);
mockCallback.reset();
viewport.scrollTo({x: 10, y: 20});
chrome.test.assertTrue(mockCallback.wasCalled);
chrome.test.assertEq(10, viewport.position.x);
chrome.test.assertEq(20, viewport.position.y);
mockCallback.reset();
viewport.scrollTo({y: 30});
chrome.test.assertTrue(mockCallback.wasCalled);
chrome.test.assertEq(10, viewport.position.x);
chrome.test.assertEq(30, viewport.position.y);
mockCallback.reset();
viewport.scrollTo({y: 30});
chrome.test.assertFalse(mockCallback.wasCalled);
chrome.test.assertEq(10, viewport.position.x);
chrome.test.assertEq(30, viewport.position.y);
mockCallback.reset();
viewport.scrollTo({x: 40});
chrome.test.assertTrue(mockCallback.wasCalled);
chrome.test.assertEq(40, viewport.position.x);
chrome.test.assertEq(30, viewport.position.y);
mockCallback.reset();
viewport.scrollTo({});
chrome.test.assertFalse(mockCallback.wasCalled);
chrome.test.assertEq(40, viewport.position.x);
chrome.test.assertEq(30, viewport.position.y);
chrome.test.succeed();
},
function testScrollBy() {
var mockWindow = new MockWindow(100, 100);
var mockSizer = new MockSizer();
var mockCallback = new MockViewportChangedCallback();
var viewport = new Viewport(mockWindow, mockSizer, mockCallback.callback,
function() {}, function() {}, function() {},
0, 1, 0);
var documentDimensions = new MockDocumentDimensions();
documentDimensions.addPage(200, 200);
viewport.setDocumentDimensions(documentDimensions);
viewport.setZoom(1);
chrome.test.assertEq(0, viewport.position.x);
chrome.test.assertEq(0, viewport.position.y);
mockCallback.reset();
viewport.scrollBy({x: 10, y: 20});
chrome.test.assertTrue(mockCallback.wasCalled);
chrome.test.assertEq(10, viewport.position.x);
chrome.test.assertEq(20, viewport.position.y);
mockCallback.reset();
viewport.scrollBy({x: 10, y: 20});
chrome.test.assertTrue(mockCallback.wasCalled);
chrome.test.assertEq(20, viewport.position.x);
chrome.test.assertEq(40, viewport.position.y);
mockCallback.reset();
viewport.scrollBy({x: -5, y: 0});
chrome.test.assertTrue(mockCallback.wasCalled);
chrome.test.assertEq(15, viewport.position.x);
chrome.test.assertEq(40, viewport.position.y);
mockCallback.reset();
viewport.scrollBy({x: 0, y: 60});
chrome.test.assertTrue(mockCallback.wasCalled);
chrome.test.assertEq(15, viewport.position.x);
chrome.test.assertEq(100, viewport.position.y);
mockCallback.reset();
viewport.scrollBy({x: 0, y: 0});
chrome.test.assertFalse(mockCallback.wasCalled);
chrome.test.assertEq(15, viewport.position.x);
chrome.test.assertEq(100, viewport.position.y);
chrome.test.succeed();
},
function testGetPageScreenRect() {
var mockWindow = new MockWindow(100, 100);
var mockSizer = new MockSizer();
......
......@@ -112,6 +112,8 @@ const char kJSPreviewPageIndex[] = "index";
const char kJSSetScrollPositionType[] = "setScrollPosition";
const char kJSPositionX[] = "x";
const char kJSPositionY[] = "y";
// Scroll by (Plugin -> Page)
const char kJSScrollByType[] = "scrollBy";
// Cancel the stream URL request (Plugin -> Page)
const char kJSCancelStreamUrlType[] = "cancelStreamUrl";
// Navigate to the given URL (Plugin -> Page)
......@@ -1242,6 +1244,14 @@ void OutOfProcessInstance::ScrollToY(int y_in_screen_coords,
PostMessage(position);
}
void OutOfProcessInstance::ScrollBy(const pp::Point& point) {
pp::VarDictionary position;
position.Set(kType, kJSScrollByType);
position.Set(kJSPositionX, pp::Var(point.x() / device_scale_));
position.Set(kJSPositionY, pp::Var(point.y() / device_scale_));
PostMessage(position);
}
void OutOfProcessInstance::ScrollToPage(int page) {
if (engine_->GetNumberOfPages() == 0)
return;
......
......@@ -101,6 +101,7 @@ class OutOfProcessInstance : public pp::Instance,
void DidScroll(const pp::Point& point) override;
void ScrollToX(int x_in_screen_coords) override;
void ScrollToY(int y_in_screen_coords, bool compensate_for_toolbar) override;
void ScrollBy(const pp::Point& point) override;
void ScrollToPage(int page) override;
void NavigateTo(const std::string& url,
WindowOpenDisposition disposition) override;
......
......@@ -146,6 +146,9 @@ class PDFEngine {
virtual void ScrollToY(int y_in_screen_coords,
bool compensate_for_toolbar) = 0;
// Scroll by a given delta relative to the current position.
virtual void ScrollBy(const pp::Point& point) = 0;
// Scroll to zero-based |page|.
virtual void ScrollToPage(int page) = 0;
......
......@@ -758,6 +758,7 @@ PDFiumEngine::PDFiumEngine(PDFEngine::Client* client)
in_form_text_area_(false),
editable_form_text_area_(false),
mouse_left_button_down_(false),
mouse_middle_button_down_(false),
permissions_(0),
permissions_handler_revision_(-1),
fpdf_availability_(nullptr),
......@@ -1448,6 +1449,9 @@ bool PDFiumEngine::HandleEvent(const pp::InputEvent& event) {
case PP_INPUTEVENT_TYPE_MOUSEMOVE:
rv = OnMouseMove(pp::MouseInputEvent(event));
break;
case PP_INPUTEVENT_TYPE_MOUSEENTER:
OnMouseEnter(pp::MouseInputEvent(event));
break;
case PP_INPUTEVENT_TYPE_KEYDOWN:
rv = OnKeyDown(pp::KeyboardInputEvent(event));
break;
......@@ -1947,6 +1951,8 @@ bool PDFiumEngine::OnLeftMouseDown(const pp::MouseInputEvent& event) {
bool PDFiumEngine::OnMiddleMouseDown(const pp::MouseInputEvent& event) {
SetMouseLeftButtonDown(false);
mouse_middle_button_down_ = true;
mouse_middle_button_last_position_ = event.GetPosition();
SelectionChangeInvalidator selection_invalidator(this);
selection_.clear();
......@@ -2047,6 +2053,8 @@ bool PDFiumEngine::OnMouseUp(const pp::MouseInputEvent& event) {
if (event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_LEFT)
SetMouseLeftButtonDown(false);
else if (event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_MIDDLE)
mouse_middle_button_down_ = false;
int page_index = -1;
int char_index = -1;
......@@ -2121,48 +2129,7 @@ bool PDFiumEngine::OnMouseMove(const pp::MouseInputEvent& event) {
mouse_down_state_.Reset();
if (!selecting_) {
PP_CursorType_Dev cursor;
switch (area) {
case PDFiumPage::TEXT_AREA:
cursor = PP_CURSORTYPE_IBEAM;
break;
case PDFiumPage::WEBLINK_AREA:
case PDFiumPage::DOCLINK_AREA:
cursor = PP_CURSORTYPE_HAND;
break;
case PDFiumPage::NONSELECTABLE_AREA:
case PDFiumPage::FORM_TEXT_AREA:
default:
switch (form_type) {
case FPDF_FORMFIELD_PUSHBUTTON:
case FPDF_FORMFIELD_CHECKBOX:
case FPDF_FORMFIELD_RADIOBUTTON:
case FPDF_FORMFIELD_COMBOBOX:
case FPDF_FORMFIELD_LISTBOX:
cursor = PP_CURSORTYPE_HAND;
break;
case FPDF_FORMFIELD_TEXTFIELD:
cursor = PP_CURSORTYPE_IBEAM;
break;
#if defined(PDF_ENABLE_XFA)
case FPDF_FORMFIELD_XFA_CHECKBOX:
case FPDF_FORMFIELD_XFA_COMBOBOX:
case FPDF_FORMFIELD_XFA_IMAGEFIELD:
case FPDF_FORMFIELD_XFA_LISTBOX:
case FPDF_FORMFIELD_XFA_PUSHBUTTON:
case FPDF_FORMFIELD_XFA_SIGNATURE:
cursor = PP_CURSORTYPE_HAND;
break;
case FPDF_FORMFIELD_XFA_TEXTFIELD:
cursor = PP_CURSORTYPE_IBEAM;
break;
#endif
default:
cursor = PP_CURSORTYPE_POINTER;
break;
}
break;
}
client_->UpdateCursor(DetermineCursorType(area, form_type));
if (page_index != -1) {
double page_x;
......@@ -2171,7 +2138,6 @@ bool PDFiumEngine::OnMouseMove(const pp::MouseInputEvent& event) {
FORM_OnMouseMove(form_, pages_[page_index]->GetPage(), 0, page_x, page_y);
}
client_->UpdateCursor(cursor);
std::string url = GetLinkAtPosition(event.GetPosition());
if (url != link_under_cursor_) {
link_under_cursor_ = url;
......@@ -2185,6 +2151,19 @@ bool PDFiumEngine::OnMouseMove(const pp::MouseInputEvent& event) {
SetFormSelectedText(form_, pages_[last_page_mouse_down_]->GetPage());
}
if (mouse_middle_button_down_) {
// Subtract (origin - destination) so delta is already the delta for
// moving the page, rather than the delta the mouse moved.
// GetMovement() does not work here, as small mouse movements are
// considered zero.
pp::Point page_position_delta =
mouse_middle_button_last_position_ - event.GetPosition();
if (page_position_delta.x() != 0 || page_position_delta.y() != 0) {
client_->ScrollBy(page_position_delta);
mouse_middle_button_last_position_ = event.GetPosition();
}
}
// No need to swallow the event, since this might interfere with the
// scrollbars if the user is dragging them.
return false;
......@@ -2199,6 +2178,60 @@ bool PDFiumEngine::OnMouseMove(const pp::MouseInputEvent& event) {
return ExtendSelection(page_index, char_index);
}
PP_CursorType_Dev PDFiumEngine::DetermineCursorType(PDFiumPage::Area area,
int form_type) const {
if (mouse_middle_button_down_) {
return PP_CURSORTYPE_HAND;
}
switch (area) {
case PDFiumPage::TEXT_AREA:
return PP_CURSORTYPE_IBEAM;
case PDFiumPage::WEBLINK_AREA:
case PDFiumPage::DOCLINK_AREA:
return PP_CURSORTYPE_HAND;
case PDFiumPage::NONSELECTABLE_AREA:
case PDFiumPage::FORM_TEXT_AREA:
default:
switch (form_type) {
case FPDF_FORMFIELD_PUSHBUTTON:
case FPDF_FORMFIELD_CHECKBOX:
case FPDF_FORMFIELD_RADIOBUTTON:
case FPDF_FORMFIELD_COMBOBOX:
case FPDF_FORMFIELD_LISTBOX:
return PP_CURSORTYPE_HAND;
case FPDF_FORMFIELD_TEXTFIELD:
return PP_CURSORTYPE_IBEAM;
#if defined(PDF_ENABLE_XFA)
case FPDF_FORMFIELD_XFA_CHECKBOX:
case FPDF_FORMFIELD_XFA_COMBOBOX:
case FPDF_FORMFIELD_XFA_IMAGEFIELD:
case FPDF_FORMFIELD_XFA_LISTBOX:
case FPDF_FORMFIELD_XFA_PUSHBUTTON:
case FPDF_FORMFIELD_XFA_SIGNATURE:
return PP_CURSORTYPE_HAND;
case FPDF_FORMFIELD_XFA_TEXTFIELD:
return PP_CURSORTYPE_IBEAM;
#endif
default:
return PP_CURSORTYPE_POINTER;
}
}
}
void PDFiumEngine::OnMouseEnter(const pp::MouseInputEvent& event) {
if (event.GetModifiers() & PP_INPUTEVENT_MODIFIER_MIDDLEBUTTONDOWN) {
if (!mouse_middle_button_down_) {
mouse_middle_button_down_ = true;
mouse_middle_button_last_position_ = event.GetPosition();
}
} else {
if (mouse_middle_button_down_) {
mouse_middle_button_down_ = false;
}
}
}
bool PDFiumEngine::ExtendSelection(int page_index, int char_index) {
// Check if the user has decreased their selection area and we need to remove
// pages from |selection_|.
......
......@@ -295,10 +295,15 @@ class PDFiumEngine : public PDFEngine,
bool OnMouseDown(const pp::MouseInputEvent& event);
bool OnMouseUp(const pp::MouseInputEvent& event);
bool OnMouseMove(const pp::MouseInputEvent& event);
void OnMouseEnter(const pp::MouseInputEvent& event);
bool OnKeyDown(const pp::KeyboardInputEvent& event);
bool OnKeyUp(const pp::KeyboardInputEvent& event);
bool OnChar(const pp::KeyboardInputEvent& event);
// Decide what cursor should be displayed.
PP_CursorType_Dev DetermineCursorType(PDFiumPage::Area area,
int form_type) const;
bool ExtendSelection(int page_index, int char_index);
FPDF_DOCUMENT CreateSinglePageRasterPdf(
......@@ -699,6 +704,12 @@ class PDFiumEngine : public PDFEngine,
// True if left mouse button is currently being held down.
bool mouse_left_button_down_;
// True if middle mouse button is currently being held down.
bool mouse_middle_button_down_;
// Last known position while performing middle mouse button pan.
pp::Point mouse_middle_button_last_position_;
// The current text used for searching.
std::string current_find_text_;
// The results found.
......
......@@ -31,6 +31,10 @@ void PreviewModeClient::ScrollToY(int y_in_screen_coords,
NOTREACHED();
}
void PreviewModeClient::ScrollBy(const pp::Point& point) {
NOTREACHED();
}
void PreviewModeClient::ScrollToPage(int page) {
NOTREACHED();
}
......
......@@ -32,6 +32,7 @@ class PreviewModeClient : public PDFEngine::Client {
void DidScroll(const pp::Point& point) override;
void ScrollToX(int x_in_screen_coords) override;
void ScrollToY(int y_in_screen_coords, bool compensate_for_toolbar) override;
void ScrollBy(const pp::Point& point) override;
void ScrollToPage(int page) override;
void NavigateTo(const std::string& url,
WindowOpenDisposition disposition) override;
......
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