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 = { ...@@ -699,12 +699,10 @@ PDFViewer.prototype = {
this.sendDocumentLoadedMessage_(); this.sendDocumentLoadedMessage_();
break; break;
case 'setScrollPosition': case 'setScrollPosition':
var position = this.viewport_.position; this.viewport_.scrollTo(/** @type {!PartialPoint} */ (message.data));
if (message.data.x !== undefined) break;
position.x = message.data.x; case 'scrollBy':
if (message.data.y !== undefined) this.viewport_.scrollBy(/** @type {!Point} */ (message.data));
position.y = message.data.y;
this.viewport_.position = position;
break; break;
case 'cancelStreamUrl': case 'cancelStreamUrl':
chrome.mimeHandlerPrivate.abortStream(); chrome.mimeHandlerPrivate.abortStream();
......
...@@ -2,6 +2,22 @@ ...@@ -2,6 +2,22 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // 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. * Returns the height of the intersection of two rectangles.
* @param {Object} rect1 the first rect * @param {Object} rect1 the first rect
...@@ -254,7 +270,7 @@ Viewport.prototype = { ...@@ -254,7 +270,7 @@ Viewport.prototype = {
/** /**
* Scroll the viewport to the specified position. * 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) { set position(position) {
this.window_.scrollTo(position.x, position.y + this.topToolbarHeight_); this.window_.scrollTo(position.x, position.y + this.topToolbarHeight_);
...@@ -906,5 +922,38 @@ Viewport.prototype = { ...@@ -906,5 +922,38 @@ Viewport.prototype = {
return ( return (
this.fittingType_ == FittingType.FIT_TO_PAGE || this.fittingType_ == FittingType.FIT_TO_PAGE ||
this.fittingType_ == FittingType.FIT_TO_HEIGHT); 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 = [ ...@@ -605,6 +605,110 @@ var tests = [
chrome.test.succeed(); 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() { function testGetPageScreenRect() {
var mockWindow = new MockWindow(100, 100); var mockWindow = new MockWindow(100, 100);
var mockSizer = new MockSizer(); var mockSizer = new MockSizer();
......
...@@ -112,6 +112,8 @@ const char kJSPreviewPageIndex[] = "index"; ...@@ -112,6 +112,8 @@ const char kJSPreviewPageIndex[] = "index";
const char kJSSetScrollPositionType[] = "setScrollPosition"; const char kJSSetScrollPositionType[] = "setScrollPosition";
const char kJSPositionX[] = "x"; const char kJSPositionX[] = "x";
const char kJSPositionY[] = "y"; const char kJSPositionY[] = "y";
// Scroll by (Plugin -> Page)
const char kJSScrollByType[] = "scrollBy";
// Cancel the stream URL request (Plugin -> Page) // Cancel the stream URL request (Plugin -> Page)
const char kJSCancelStreamUrlType[] = "cancelStreamUrl"; const char kJSCancelStreamUrlType[] = "cancelStreamUrl";
// Navigate to the given URL (Plugin -> Page) // Navigate to the given URL (Plugin -> Page)
...@@ -1242,6 +1244,14 @@ void OutOfProcessInstance::ScrollToY(int y_in_screen_coords, ...@@ -1242,6 +1244,14 @@ void OutOfProcessInstance::ScrollToY(int y_in_screen_coords,
PostMessage(position); 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) { void OutOfProcessInstance::ScrollToPage(int page) {
if (engine_->GetNumberOfPages() == 0) if (engine_->GetNumberOfPages() == 0)
return; return;
......
...@@ -101,6 +101,7 @@ class OutOfProcessInstance : public pp::Instance, ...@@ -101,6 +101,7 @@ class OutOfProcessInstance : public pp::Instance,
void DidScroll(const pp::Point& point) override; void DidScroll(const pp::Point& point) override;
void ScrollToX(int x_in_screen_coords) override; void ScrollToX(int x_in_screen_coords) override;
void ScrollToY(int y_in_screen_coords, bool compensate_for_toolbar) 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 ScrollToPage(int page) override;
void NavigateTo(const std::string& url, void NavigateTo(const std::string& url,
WindowOpenDisposition disposition) override; WindowOpenDisposition disposition) override;
......
...@@ -146,6 +146,9 @@ class PDFEngine { ...@@ -146,6 +146,9 @@ class PDFEngine {
virtual void ScrollToY(int y_in_screen_coords, virtual void ScrollToY(int y_in_screen_coords,
bool compensate_for_toolbar) = 0; 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|. // Scroll to zero-based |page|.
virtual void ScrollToPage(int page) = 0; virtual void ScrollToPage(int page) = 0;
......
...@@ -758,6 +758,7 @@ PDFiumEngine::PDFiumEngine(PDFEngine::Client* client) ...@@ -758,6 +758,7 @@ PDFiumEngine::PDFiumEngine(PDFEngine::Client* client)
in_form_text_area_(false), in_form_text_area_(false),
editable_form_text_area_(false), editable_form_text_area_(false),
mouse_left_button_down_(false), mouse_left_button_down_(false),
mouse_middle_button_down_(false),
permissions_(0), permissions_(0),
permissions_handler_revision_(-1), permissions_handler_revision_(-1),
fpdf_availability_(nullptr), fpdf_availability_(nullptr),
...@@ -1448,6 +1449,9 @@ bool PDFiumEngine::HandleEvent(const pp::InputEvent& event) { ...@@ -1448,6 +1449,9 @@ bool PDFiumEngine::HandleEvent(const pp::InputEvent& event) {
case PP_INPUTEVENT_TYPE_MOUSEMOVE: case PP_INPUTEVENT_TYPE_MOUSEMOVE:
rv = OnMouseMove(pp::MouseInputEvent(event)); rv = OnMouseMove(pp::MouseInputEvent(event));
break; break;
case PP_INPUTEVENT_TYPE_MOUSEENTER:
OnMouseEnter(pp::MouseInputEvent(event));
break;
case PP_INPUTEVENT_TYPE_KEYDOWN: case PP_INPUTEVENT_TYPE_KEYDOWN:
rv = OnKeyDown(pp::KeyboardInputEvent(event)); rv = OnKeyDown(pp::KeyboardInputEvent(event));
break; break;
...@@ -1947,6 +1951,8 @@ bool PDFiumEngine::OnLeftMouseDown(const pp::MouseInputEvent& event) { ...@@ -1947,6 +1951,8 @@ bool PDFiumEngine::OnLeftMouseDown(const pp::MouseInputEvent& event) {
bool PDFiumEngine::OnMiddleMouseDown(const pp::MouseInputEvent& event) { bool PDFiumEngine::OnMiddleMouseDown(const pp::MouseInputEvent& event) {
SetMouseLeftButtonDown(false); SetMouseLeftButtonDown(false);
mouse_middle_button_down_ = true;
mouse_middle_button_last_position_ = event.GetPosition();
SelectionChangeInvalidator selection_invalidator(this); SelectionChangeInvalidator selection_invalidator(this);
selection_.clear(); selection_.clear();
...@@ -2047,6 +2053,8 @@ bool PDFiumEngine::OnMouseUp(const pp::MouseInputEvent& event) { ...@@ -2047,6 +2053,8 @@ bool PDFiumEngine::OnMouseUp(const pp::MouseInputEvent& event) {
if (event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_LEFT) if (event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_LEFT)
SetMouseLeftButtonDown(false); SetMouseLeftButtonDown(false);
else if (event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_MIDDLE)
mouse_middle_button_down_ = false;
int page_index = -1; int page_index = -1;
int char_index = -1; int char_index = -1;
...@@ -2121,48 +2129,7 @@ bool PDFiumEngine::OnMouseMove(const pp::MouseInputEvent& event) { ...@@ -2121,48 +2129,7 @@ bool PDFiumEngine::OnMouseMove(const pp::MouseInputEvent& event) {
mouse_down_state_.Reset(); mouse_down_state_.Reset();
if (!selecting_) { if (!selecting_) {
PP_CursorType_Dev cursor; client_->UpdateCursor(DetermineCursorType(area, form_type));
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;
}
if (page_index != -1) { if (page_index != -1) {
double page_x; double page_x;
...@@ -2171,7 +2138,6 @@ bool PDFiumEngine::OnMouseMove(const pp::MouseInputEvent& event) { ...@@ -2171,7 +2138,6 @@ bool PDFiumEngine::OnMouseMove(const pp::MouseInputEvent& event) {
FORM_OnMouseMove(form_, pages_[page_index]->GetPage(), 0, page_x, page_y); FORM_OnMouseMove(form_, pages_[page_index]->GetPage(), 0, page_x, page_y);
} }
client_->UpdateCursor(cursor);
std::string url = GetLinkAtPosition(event.GetPosition()); std::string url = GetLinkAtPosition(event.GetPosition());
if (url != link_under_cursor_) { if (url != link_under_cursor_) {
link_under_cursor_ = url; link_under_cursor_ = url;
...@@ -2185,6 +2151,19 @@ bool PDFiumEngine::OnMouseMove(const pp::MouseInputEvent& event) { ...@@ -2185,6 +2151,19 @@ bool PDFiumEngine::OnMouseMove(const pp::MouseInputEvent& event) {
SetFormSelectedText(form_, pages_[last_page_mouse_down_]->GetPage()); 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 // No need to swallow the event, since this might interfere with the
// scrollbars if the user is dragging them. // scrollbars if the user is dragging them.
return false; return false;
...@@ -2199,6 +2178,60 @@ bool PDFiumEngine::OnMouseMove(const pp::MouseInputEvent& event) { ...@@ -2199,6 +2178,60 @@ bool PDFiumEngine::OnMouseMove(const pp::MouseInputEvent& event) {
return ExtendSelection(page_index, char_index); 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) { bool PDFiumEngine::ExtendSelection(int page_index, int char_index) {
// Check if the user has decreased their selection area and we need to remove // Check if the user has decreased their selection area and we need to remove
// pages from |selection_|. // pages from |selection_|.
......
...@@ -295,10 +295,15 @@ class PDFiumEngine : public PDFEngine, ...@@ -295,10 +295,15 @@ class PDFiumEngine : public PDFEngine,
bool OnMouseDown(const pp::MouseInputEvent& event); bool OnMouseDown(const pp::MouseInputEvent& event);
bool OnMouseUp(const pp::MouseInputEvent& event); bool OnMouseUp(const pp::MouseInputEvent& event);
bool OnMouseMove(const pp::MouseInputEvent& event); bool OnMouseMove(const pp::MouseInputEvent& event);
void OnMouseEnter(const pp::MouseInputEvent& event);
bool OnKeyDown(const pp::KeyboardInputEvent& event); bool OnKeyDown(const pp::KeyboardInputEvent& event);
bool OnKeyUp(const pp::KeyboardInputEvent& event); bool OnKeyUp(const pp::KeyboardInputEvent& event);
bool OnChar(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); bool ExtendSelection(int page_index, int char_index);
FPDF_DOCUMENT CreateSinglePageRasterPdf( FPDF_DOCUMENT CreateSinglePageRasterPdf(
...@@ -699,6 +704,12 @@ class PDFiumEngine : public PDFEngine, ...@@ -699,6 +704,12 @@ class PDFiumEngine : public PDFEngine,
// True if left mouse button is currently being held down. // True if left mouse button is currently being held down.
bool mouse_left_button_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. // The current text used for searching.
std::string current_find_text_; std::string current_find_text_;
// The results found. // The results found.
......
...@@ -31,6 +31,10 @@ void PreviewModeClient::ScrollToY(int y_in_screen_coords, ...@@ -31,6 +31,10 @@ void PreviewModeClient::ScrollToY(int y_in_screen_coords,
NOTREACHED(); NOTREACHED();
} }
void PreviewModeClient::ScrollBy(const pp::Point& point) {
NOTREACHED();
}
void PreviewModeClient::ScrollToPage(int page) { void PreviewModeClient::ScrollToPage(int page) {
NOTREACHED(); NOTREACHED();
} }
......
...@@ -32,6 +32,7 @@ class PreviewModeClient : public PDFEngine::Client { ...@@ -32,6 +32,7 @@ class PreviewModeClient : public PDFEngine::Client {
void DidScroll(const pp::Point& point) override; void DidScroll(const pp::Point& point) override;
void ScrollToX(int x_in_screen_coords) override; void ScrollToX(int x_in_screen_coords) override;
void ScrollToY(int y_in_screen_coords, bool compensate_for_toolbar) 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 ScrollToPage(int page) override;
void NavigateTo(const std::string& url, void NavigateTo(const std::string& url,
WindowOpenDisposition disposition) override; 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