Commit f76f7681 authored by Daniel Hosseinian's avatar Daniel Hosseinian Committed by Chromium LUCI CQ

Disable PDF content interaction in read-only mode

Since Presentation mode is read-only, ignore all input events to
disable form editing and tabbing across PDF contents.

When entering read-only mode:
- Unselect any selected text.
- Kill any form focus.
- Remove all form highlights, so they don't appear interactable.

Bug: 1157120
Change-Id: Idf0b5669b9d0f55ccd68198aa941fdeb1097910e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2596857
Commit-Queue: Daniel Hosseinian <dhoss@chromium.org>
Reviewed-by: default avatarK. Moon <kmoon@chromium.org>
Cr-Commit-Position: refs/heads/master@{#838492}
parent 3cc38f1d
......@@ -133,6 +133,7 @@ js_library("fullscreen_test") {
":test_util",
"../webui:test_util.m",
"//chrome/browser/resources/pdf:constants",
"//chrome/browser/resources/pdf:pdf_scripting_api",
"//chrome/browser/resources/pdf:pdf_viewer",
"//third_party/polymer/v3_0/components-chromium/iron-test-helpers:mock-interactions",
"//ui/webui/resources/js:cr.m",
......
......@@ -4,6 +4,7 @@
import {eventToPromise} from 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/_test_resources/webui/test_util.m.js';
import {FittingType} from 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/constants.js';
import {PDFScriptingAPI} from 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/pdf_scripting_api.js';
import {PDFViewerElement} from 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/pdf_viewer.js';
import {isMac} from 'chrome://resources/js/cr.m.js';
import {keyDownOn} from 'chrome://resources/polymer/v3_0/iron-test-helpers/mock-interactions.js';
......@@ -128,6 +129,17 @@ const tests = [
chrome.test.succeed();
},
async function testTextSelectionDisabled() {
await ensureFullscreen();
const client = new PDFScriptingAPI(window, window);
client.selectAll();
client.getSelectedText(selectedText => {
// No text should be selected.
chrome.test.assertEq(0, selectedText.length);
chrome.test.succeed();
});
},
];
chrome.test.runTests(tests);
......@@ -689,6 +689,12 @@ void OutOfProcessInstance::HandleMessage(const pp::Var& message) {
}
bool OutOfProcessInstance::HandleInputEvent(const pp::InputEvent& event) {
// Ignore user input in read-only mode.
// TODO(dhoss): Add a test for ignored input events. It is currently difficult
// to unit test certain `OutOfProcessInstance` methods.
if (engine()->IsReadOnly())
return false;
// To simplify things, convert the event into device coordinates.
pp::InputEvent event_device_res(event);
{
......
......@@ -976,7 +976,7 @@ void PDFiumEngine::KillFormFocus() {
void PDFiumEngine::UpdateFocus(bool has_focus) {
base::AutoReset<bool> updating_focus_guard(&updating_focus_, true);
if (has_focus) {
if (has_focus && !IsReadOnly()) {
UpdateFocusItemType(last_focused_item_type_);
if (focus_item_type_ == FocusElementType::kPage &&
PageIndexInBounds(last_focused_page_) &&
......@@ -2064,6 +2064,20 @@ bool PDFiumEngine::IsReadOnly() const {
void PDFiumEngine::SetReadOnly(bool enable) {
read_only_ = enable;
// Restore form highlights.
if (!read_only_) {
FPDF_SetFormFieldHighlightAlpha(form(), kFormHighlightAlpha);
return;
}
// Hide form highlights.
FPDF_SetFormFieldHighlightAlpha(form(), /*alpha=*/0);
KillFormFocus();
// Unselect text.
SelectionChangeInvalidator selection_invalidator(this);
selection_.clear();
}
void PDFiumEngine::SetTwoUpView(bool enable) {
......@@ -2222,7 +2236,7 @@ bool PDFiumEngine::HasPermission(DocumentPermission permission) const {
}
void PDFiumEngine::SelectAll() {
if (in_form_text_area_)
if (in_form_text_area_ || IsReadOnly())
return;
SelectionChangeInvalidator selection_invalidator(this);
......
......@@ -36,6 +36,7 @@ using ::testing::InSequence;
using ::testing::Invoke;
using ::testing::IsEmpty;
using ::testing::NiceMock;
using ::testing::Not;
using ::testing::Return;
using ::testing::StrictMock;
......@@ -1125,4 +1126,56 @@ TEST_F(PDFiumEngineTabbingTest, ScrollFocusedAnnotationIntoView) {
ScrollFocusedAnnotationIntoView(engine.get());
}
class ReadOnlyTestClient : public TestClient {
public:
ReadOnlyTestClient() = default;
~ReadOnlyTestClient() override = default;
ReadOnlyTestClient(const ReadOnlyTestClient&) = delete;
ReadOnlyTestClient& operator=(const ReadOnlyTestClient&) = delete;
// Mock PDFEngine::Client methods.
MOCK_METHOD(void, FormTextFieldFocusChange, (bool), (override));
MOCK_METHOD(void, SetSelectedText, (const std::string&), (override));
};
using PDFiumEngineReadOnlyTest = PDFiumTestBase;
TEST_F(PDFiumEngineReadOnlyTest, KillFormFocus) {
NiceMock<ReadOnlyTestClient> client;
std::unique_ptr<PDFiumEngine> engine = InitializeEngine(
&client, FILE_PATH_LITERAL("annotation_form_fields.pdf"));
ASSERT_TRUE(engine);
// Setting read-only mode should kill form focus.
EXPECT_FALSE(engine->IsReadOnly());
EXPECT_CALL(client, FormTextFieldFocusChange(false));
engine->SetReadOnly(true);
// Attempting to focus during read-only mode should once more trigger a
// killing of form focus.
EXPECT_TRUE(engine->IsReadOnly());
EXPECT_CALL(client, FormTextFieldFocusChange(false));
engine->UpdateFocus(true);
}
TEST_F(PDFiumEngineReadOnlyTest, UnselectText) {
NiceMock<ReadOnlyTestClient> client;
std::unique_ptr<PDFiumEngine> engine =
InitializeEngine(&client, FILE_PATH_LITERAL("hello_world2.pdf"));
ASSERT_TRUE(engine);
// Update the plugin size so that all the text is visible by
// `SelectionChangeInvalidator`.
engine->PluginSizeUpdated({500, 500});
// Select text before going into read-only mode.
EXPECT_FALSE(engine->IsReadOnly());
EXPECT_CALL(client, SetSelectedText(Not(IsEmpty())));
engine->SelectAll();
// Setting read-only mode should unselect the text.
EXPECT_CALL(client, SetSelectedText(IsEmpty()));
engine->SetReadOnly(true);
}
} // namespace chrome_pdf
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