[M108 Migration][HBBTV] Implement ewk_context_register_jsplugin_mime_types API
[platform/framework/web/chromium-efl.git] / pdf / pdf_view_web_plugin_unittest.cc
1 // Copyright 2021 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "pdf/pdf_view_web_plugin.h"
6
7 #include <stdint.h>
8
9 #include <functional>
10 #include <memory>
11 #include <string>
12 #include <utility>
13 #include <vector>
14
15 #include "base/containers/span.h"
16 #include "base/location.h"
17 #include "base/memory/raw_ptr.h"
18 #include "base/memory/weak_ptr.h"
19 #include "base/run_loop.h"
20 #include "base/strings/string_piece.h"
21 #include "base/test/bind.h"
22 #include "base/test/values_test_util.h"
23 #include "base/time/time.h"
24 #include "base/values.h"
25 #include "cc/paint/paint_canvas.h"
26 #include "cc/test/pixel_comparator.h"
27 #include "cc/test/pixel_test_utils.h"
28 #include "mojo/public/cpp/bindings/associated_receiver.h"
29 #include "mojo/public/cpp/bindings/associated_remote.h"
30 #include "net/cookies/site_for_cookies.h"
31 #include "pdf/accessibility_structs.h"
32 #include "pdf/buildflags.h"
33 #include "pdf/content_restriction.h"
34 #include "pdf/document_layout.h"
35 #include "pdf/mojom/pdf.mojom.h"
36 #include "pdf/paint_ready_rect.h"
37 #include "pdf/pdf_accessibility_data_handler.h"
38 #include "pdf/test/mock_web_associated_url_loader.h"
39 #include "pdf/test/test_helpers.h"
40 #include "pdf/test/test_pdfium_engine.h"
41 #include "printing/metafile_skia.h"
42 #include "services/network/public/mojom/referrer_policy.mojom-shared.h"
43 #include "testing/gmock/include/gmock/gmock.h"
44 #include "testing/gtest/include/gtest/gtest.h"
45 #include "third_party/blink/public/common/input/web_coalesced_input_event.h"
46 #include "third_party/blink/public/common/input/web_input_event.h"
47 #include "third_party/blink/public/common/input/web_keyboard_event.h"
48 #include "third_party/blink/public/common/input/web_mouse_event.h"
49 #include "third_party/blink/public/common/loader/http_body_element_type.h"
50 #include "third_party/blink/public/platform/web_data.h"
51 #include "third_party/blink/public/platform/web_http_body.h"
52 #include "third_party/blink/public/platform/web_http_header_visitor.h"
53 #include "third_party/blink/public/platform/web_input_event_result.h"
54 #include "third_party/blink/public/platform/web_string.h"
55 #include "third_party/blink/public/platform/web_text_input_type.h"
56 #include "third_party/blink/public/platform/web_url.h"
57 #include "third_party/blink/public/platform/web_url_request.h"
58 #include "third_party/blink/public/platform/web_url_response.h"
59 #include "third_party/blink/public/web/web_associated_url_loader.h"
60 #include "third_party/blink/public/web/web_associated_url_loader_client.h"
61 #include "third_party/blink/public/web/web_plugin_container.h"
62 #include "third_party/blink/public/web/web_plugin_params.h"
63 #include "third_party/blink/public/web/web_print_params.h"
64 #include "third_party/skia/include/core/SkBitmap.h"
65 #include "third_party/skia/include/core/SkCanvas.h"
66 #include "third_party/skia/include/core/SkColor.h"
67 #include "third_party/skia/include/core/SkRefCnt.h"
68 #include "third_party/skia/include/core/SkSurface.h"
69 #include "ui/base/cursor/cursor.h"
70 #include "ui/events/blink/blink_event_util.h"
71 #include "ui/events/keycodes/dom/dom_code.h"
72 #include "ui/events/keycodes/dom/dom_key.h"
73 #include "ui/gfx/canvas.h"
74 #include "ui/gfx/geometry/point.h"
75 #include "ui/gfx/geometry/point_f.h"
76 #include "ui/gfx/geometry/rect.h"
77 #include "ui/gfx/geometry/size.h"
78 #include "ui/gfx/geometry/skia_conversions.h"
79 #include "ui/gfx/geometry/vector2d_f.h"
80 #include "ui/gfx/range/range.h"
81 #include "ui/latency/latency_info.h"
82 #include "url/gurl.h"
83
84 namespace chrome_pdf {
85
86 namespace {
87
88 using ::testing::AnyNumber;
89 using ::testing::ElementsAre;
90 using ::testing::ElementsAreArray;
91 using ::testing::Eq;
92 using ::testing::InSequence;
93 using ::testing::Invoke;
94 using ::testing::IsEmpty;
95 using ::testing::IsFalse;
96 using ::testing::IsTrue;
97 using ::testing::MockFunction;
98 using ::testing::NiceMock;
99 using ::testing::Pointwise;
100 using ::testing::Return;
101 using ::testing::SaveArg;
102 using ::testing::SizeIs;
103
104 // `kCanvasSize` needs to be big enough to hold plugin's snapshots during
105 // testing.
106 constexpr gfx::Size kCanvasSize(100, 100);
107
108 // Note: Make sure `kDefaultColor` is different from `kPaintColor` and the
109 // plugin's background color. This will help identify bitmap changes after
110 // painting.
111 constexpr SkColor kDefaultColor = SK_ColorGREEN;
112
113 constexpr SkColor kPaintColor = SK_ColorRED;
114
115 struct PaintParams {
116   // The plugin container's device scale.
117   float device_scale;
118
119   // The window area in CSS pixels.
120   gfx::Rect window_rect;
121
122   // The target painting area on the canvas in CSS pixels.
123   gfx::Rect paint_rect;
124
125   // The expected clipped area to be filled with paint color. The clipped area
126   // should be the intersection of `paint_rect` and `window_rect`.
127   gfx::Rect expected_clipped_rect;
128 };
129
130 MATCHER(SearchStringResultEq, "") {
131   PDFEngine::Client::SearchStringResult l = std::get<0>(arg);
132   PDFEngine::Client::SearchStringResult r = std::get<1>(arg);
133   return l.start_index == r.start_index && l.length == r.length;
134 }
135
136 MATCHER_P(IsExpectedImeKeyEvent, expected_text, "") {
137   if (arg.GetType() != blink::WebInputEvent::Type::kChar)
138     return false;
139
140   const auto& event = static_cast<const blink::WebKeyboardEvent&>(arg);
141   return event.GetModifiers() == blink::WebInputEvent::kNoModifiers &&
142          event.windows_key_code == expected_text[0] &&
143          event.native_key_code == expected_text[0] &&
144          event.dom_code == static_cast<int>(ui::DomCode::NONE) &&
145          event.dom_key == ui::DomKey::NONE && !event.is_system_key &&
146          !event.is_browser_shortcut && event.text == expected_text &&
147          event.unmodified_text == expected_text;
148 }
149
150 base::Value::Dict ParseMessage(base::StringPiece json) {
151   return std::move(base::test::ParseJson(json).GetDict());
152 }
153
154 // Generates the expected `SkBitmap` with `paint_color` filled in the expected
155 // clipped area and `kDefaultColor` as the background color.
156 SkBitmap GenerateExpectedBitmapForPaint(const gfx::Rect& expected_clipped_rect,
157                                         SkColor paint_color) {
158   sk_sp<SkSurface> expected_surface =
159       CreateSkiaSurfaceForTesting(kCanvasSize, kDefaultColor);
160   expected_surface->getCanvas()->clipIRect(
161       gfx::RectToSkIRect(expected_clipped_rect));
162   expected_surface->getCanvas()->clear(paint_color);
163
164   SkBitmap expected_bitmap;
165   expected_surface->makeImageSnapshot()->asLegacyBitmap(&expected_bitmap);
166   return expected_bitmap;
167 }
168
169 class MockHeaderVisitor : public blink::WebHTTPHeaderVisitor {
170  public:
171   MOCK_METHOD(void,
172               VisitHeader,
173               (const blink::WebString&, const blink::WebString&),
174               (override));
175 };
176
177 class MockPdfAccessibilityDataHandler : public PdfAccessibilityDataHandler {
178  public:
179   // PdfAccessibilityDataHandler:
180   MOCK_METHOD(void,
181               SetAccessibilityViewportInfo,
182               (AccessibilityViewportInfo),
183               (override));
184   MOCK_METHOD(void,
185               SetAccessibilityDocInfo,
186               (AccessibilityDocInfo),
187               (override));
188   MOCK_METHOD(void,
189               SetAccessibilityPageInfo,
190               (AccessibilityPageInfo,
191                std::vector<AccessibilityTextRunInfo>,
192                std::vector<AccessibilityCharInfo>,
193                AccessibilityPageObjects),
194               (override));
195 };
196
197 class FakePdfViewWebPluginClient : public PdfViewWebPlugin::Client {
198  public:
199   FakePdfViewWebPluginClient() {
200     ON_CALL(*this, CreateAssociatedURLLoader).WillByDefault([]() {
201       auto associated_loader =
202           std::make_unique<NiceMock<MockWebAssociatedURLLoader>>();
203       ON_CALL(*associated_loader, LoadAsynchronously)
204           .WillByDefault([](const blink::WebURLRequest& /*request*/,
205                             blink::WebAssociatedURLLoaderClient* client) {
206             // TODO(crbug.com/1322928): Must trigger callback to free
207             // `UrlLoader`.
208             client->DidReceiveResponse(blink::WebURLResponse());
209             client->DidFinishLoading();
210           });
211       return associated_loader;
212     });
213     ON_CALL(*this, GetEmbedderOriginString)
214         .WillByDefault(
215             Return("chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/"));
216     ON_CALL(*this, HasFrame).WillByDefault(Return(true));
217   }
218
219   // PdfViewWebPlugin::Client:
220   MOCK_METHOD(std::unique_ptr<base::Value>,
221               FromV8Value,
222               (v8::Local<v8::Value>, v8::Local<v8::Context>),
223               (override));
224
225   MOCK_METHOD(base::WeakPtr<Client>, GetWeakPtr, (), (override));
226
227   MOCK_METHOD(std::unique_ptr<PDFiumEngine>,
228               CreateEngine,
229               (PDFEngine::Client*, PDFiumFormFiller::ScriptOption),
230               (override));
231
232   MOCK_METHOD(void,
233               SetPluginContainer,
234               (blink::WebPluginContainer*),
235               (override));
236   MOCK_METHOD(blink::WebPluginContainer*, PluginContainer, (), (override));
237
238   MOCK_METHOD(net::SiteForCookies, SiteForCookies, (), (const override));
239
240   MOCK_METHOD(blink::WebURL,
241               CompleteURL,
242               (const blink::WebString&),
243               (const override));
244
245   MOCK_METHOD(void, PostMessage, (base::Value::Dict), (override));
246
247   MOCK_METHOD(void, Invalidate, (), (override));
248
249   MOCK_METHOD(void,
250               RequestTouchEventType,
251               (blink::WebPluginContainer::TouchEventRequestType),
252               (override));
253
254   MOCK_METHOD(void, ReportFindInPageMatchCount, (int, int, bool), (override));
255
256   MOCK_METHOD(void, ReportFindInPageSelection, (int, int, bool), (override));
257
258   MOCK_METHOD(void,
259               ReportFindInPageTickmarks,
260               (const std::vector<gfx::Rect>&),
261               (override));
262
263   MOCK_METHOD(float, DeviceScaleFactor, (), (override));
264
265   MOCK_METHOD(gfx::PointF, GetScrollPosition, (), (override));
266
267   MOCK_METHOD(void, UsePluginAsFindHandler, (), (override));
268
269   MOCK_METHOD(void,
270               SetReferrerForRequest,
271               (blink::WebURLRequest&, const blink::WebURL&),
272               (override));
273
274   MOCK_METHOD(void, Alert, (const blink::WebString&), (override));
275
276   MOCK_METHOD(bool, Confirm, (const blink::WebString&), (override));
277
278   MOCK_METHOD(blink::WebString,
279               Prompt,
280               (const blink::WebString&, const blink::WebString&),
281               (override));
282
283   MOCK_METHOD(void,
284               TextSelectionChanged,
285               (const blink::WebString&, uint32_t, const gfx::Range&),
286               (override));
287
288   MOCK_METHOD(std::unique_ptr<blink::WebAssociatedURLLoader>,
289               CreateAssociatedURLLoader,
290               (const blink::WebAssociatedURLLoaderOptions&),
291               (override));
292
293   MOCK_METHOD(void, UpdateTextInputState, (), (override));
294
295   MOCK_METHOD(void, UpdateSelectionBounds, (), (override));
296
297   MOCK_METHOD(std::string, GetEmbedderOriginString, (), (override));
298
299   MOCK_METHOD(bool, HasFrame, (), (const override));
300
301   MOCK_METHOD(void, DidStartLoading, (), (override));
302   MOCK_METHOD(void, DidStopLoading, (), (override));
303
304   MOCK_METHOD(void, RecordComputedAction, (const std::string&), (override));
305
306   MOCK_METHOD(std::unique_ptr<PdfAccessibilityDataHandler>,
307               CreateAccessibilityDataHandler,
308               (PdfAccessibilityActionHandler*),
309               (override));
310 };
311
312 class FakePdfService : public pdf::mojom::PdfService {
313  public:
314   MOCK_METHOD(void,
315               SetListener,
316               (mojo::PendingRemote<pdf::mojom::PdfListener>),
317               (override));
318   MOCK_METHOD(void, UpdateContentRestrictions, (int32_t), (override));
319   MOCK_METHOD(void, HasUnsupportedFeature, (), (override));
320   MOCK_METHOD(void,
321               SaveUrlAs,
322               (const GURL&, network::mojom::ReferrerPolicy),
323               (override));
324   MOCK_METHOD(void,
325               SelectionChanged,
326               (const gfx::PointF&, int32_t, const gfx::PointF&, int32_t),
327               (override));
328   MOCK_METHOD(void, SetPluginCanSave, (bool), (override));
329 };
330
331 }  // namespace
332
333 class PdfViewWebPluginWithoutInitializeTest : public testing::Test {
334  protected:
335   // Custom deleter for `plugin_`. PdfViewWebPlugin must be destroyed by
336   // PdfViewWebPlugin::Destroy() instead of its destructor.
337   struct PluginDeleter {
338     void operator()(PdfViewWebPlugin* ptr) { ptr->Destroy(); }
339   };
340
341   static void AddToPluginParams(base::StringPiece name,
342                                 base::StringPiece value,
343                                 blink::WebPluginParams& params) {
344     params.attribute_names.push_back(
345         blink::WebString::FromUTF8(name.data(), name.size()));
346     params.attribute_values.push_back(
347         blink::WebString::FromUTF8(value.data(), value.size()));
348   }
349
350   void SetUpPlugin(base::StringPiece document_url,
351                    const blink::WebPluginParams& params) {
352     auto client = std::make_unique<NiceMock<FakePdfViewWebPluginClient>>();
353     client_ptr_ = client.get();
354
355     ON_CALL(*client_ptr_, CompleteURL)
356         .WillByDefault([parsed_document_url = GURL(document_url)](
357                            const blink::WebString& partial_url) {
358           return parsed_document_url.Resolve(partial_url.Utf8());
359         });
360     ON_CALL(*client_ptr_, CreateEngine)
361         .WillByDefault([this](
362                            PDFEngine::Client* client,
363                            PDFiumFormFiller::ScriptOption /*script_option*/) {
364           auto engine = std::make_unique<NiceMock<TestPDFiumEngine>>(client);
365           engine_ptr_ = engine.get();
366           return engine;
367         });
368     ON_CALL(*client_ptr_, CreateAccessibilityDataHandler)
369         .WillByDefault([this]() {
370           auto handler =
371               std::make_unique<NiceMock<MockPdfAccessibilityDataHandler>>();
372           accessibility_data_handler_ptr_ = handler.get();
373           return handler;
374         });
375     SetUpClient();
376
377     plugin_ =
378         std::unique_ptr<PdfViewWebPlugin, PluginDeleter>(new PdfViewWebPlugin(
379             std::move(client),
380             mojo::AssociatedRemote<pdf::mojom::PdfService>(
381                 pdf_receiver_.BindNewEndpointAndPassDedicatedRemote()),
382             params));
383   }
384
385   void SetUpPluginWithUrl(const std::string& url) {
386     blink::WebPluginParams params;
387     AddToPluginParams("src", url, params);
388     SetUpPluginParams(params);
389
390     SetUpPlugin(url, params);
391   }
392
393   // Allows derived classes to customize plugin parameters within
394   // `SetUpPluginWithUrl()`.
395   virtual void SetUpPluginParams(blink::WebPluginParams& params) {}
396
397   // Allows derived classes to customize `client_ptr_` within `SetUpPlugin()`.
398   virtual void SetUpClient() {}
399
400   void TearDown() override { plugin_.reset(); }
401
402   void ExpectUpdateTextInputState(
403       blink::WebTextInputType expected_text_input_type) {
404     EXPECT_CALL(*client_ptr_, UpdateTextInputState)
405         .WillOnce([this, expected_text_input_type]() {
406           EXPECT_EQ(expected_text_input_type,
407                     plugin_->GetPluginTextInputType());
408         });
409   }
410
411   NiceMock<FakePdfService> pdf_service_;
412   mojo::AssociatedReceiver<pdf::mojom::PdfService> pdf_receiver_{&pdf_service_};
413
414   raw_ptr<FakePdfViewWebPluginClient> client_ptr_;
415   std::unique_ptr<PdfViewWebPlugin, PluginDeleter> plugin_;
416   raw_ptr<TestPDFiumEngine> engine_ptr_;
417   raw_ptr<MockPdfAccessibilityDataHandler> accessibility_data_handler_ptr_;
418 };
419
420 class PdfViewWebPluginTest : public PdfViewWebPluginWithoutInitializeTest {
421  protected:
422   static constexpr char kPdfUrl[] = "http://localhost/example.pdf";
423
424   void SetUp() override {
425     SetUpPluginWithUrl(kPdfUrl);
426
427     EXPECT_TRUE(plugin_->InitializeForTesting());
428   }
429
430   void SetDocumentDimensions(const gfx::Size& dimensions) {
431     EXPECT_CALL(*engine_ptr_, ApplyDocumentLayout)
432         .WillRepeatedly(Return(dimensions));
433     SendViewportMessage(/*zoom=*/1.0);
434   }
435
436   void SendViewportMessage(double zoom) {
437     base::Value::Dict message = ParseMessage(R"({
438       "type": "viewport",
439       "userInitiated": false,
440       "zoom": 1,
441       "layoutOptions": {
442         "direction": 2,
443         "defaultPageOrientation": 0,
444         "twoUpViewEnabled": false,
445       },
446       "xOffset": 0,
447       "yOffset": 0,
448       "pinchPhase": 0,
449     })");
450     message.Set("zoom", zoom);
451     plugin_->OnMessage(message);
452   }
453
454   void UpdatePluginGeometry(float device_scale, const gfx::Rect& window_rect) {
455     UpdatePluginGeometryWithoutWaiting(device_scale, window_rect);
456
457     // Waits for main thread callback scheduled by `PaintManager`.
458     base::RunLoop run_loop;
459     base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
460                                                   run_loop.QuitClosure());
461     run_loop.Run();
462   }
463
464   void UpdatePluginGeometryWithoutWaiting(float device_scale,
465                                           const gfx::Rect& window_rect) {
466     // The plugin container's device scale must be set before calling
467     // UpdateGeometry().
468     EXPECT_CALL(*client_ptr_, DeviceScaleFactor)
469         .WillRepeatedly(Return(device_scale));
470     plugin_->UpdateGeometry(window_rect, window_rect, window_rect,
471                             /*is_visible=*/true);
472   }
473
474   void TestUpdateGeometrySetsPluginRect(float device_scale,
475                                         const gfx::Rect& window_rect,
476                                         float expected_device_scale,
477                                         const gfx::Rect& expected_plugin_rect) {
478     UpdatePluginGeometryWithoutWaiting(device_scale, window_rect);
479     EXPECT_EQ(expected_device_scale, plugin_->GetDeviceScaleForTesting())
480         << "Device scale comparison failure at device scale of "
481         << device_scale;
482     EXPECT_EQ(expected_plugin_rect, plugin_->GetPluginRectForTesting())
483         << "Plugin rect comparison failure at device scale of " << device_scale
484         << ", window rect of " << window_rect.ToString();
485   }
486
487   void TestPaintEmptySnapshots(float device_scale,
488                                const gfx::Rect& window_rect,
489                                const gfx::Rect& paint_rect,
490                                const gfx::Rect& expected_clipped_rect) {
491     UpdatePluginGeometryWithoutWaiting(device_scale, window_rect);
492     canvas_.DrawColor(kDefaultColor);
493
494     plugin_->Paint(canvas_.sk_canvas(), paint_rect);
495
496     // Expect the clipped area on canvas to be filled with plugin's background
497     // color.
498     SkBitmap expected_bitmap = GenerateExpectedBitmapForPaint(
499         expected_clipped_rect, plugin_->GetBackgroundColor());
500     EXPECT_TRUE(
501         cc::MatchesBitmap(canvas_.GetBitmap(), expected_bitmap,
502                           cc::ExactPixelComparator(/*discard_alpha=*/false)))
503         << "Failure at device scale of " << device_scale << ", window rect of "
504         << window_rect.ToString();
505   }
506
507   void TestPaintSnapshots(float device_scale,
508                           const gfx::Rect& window_rect,
509                           const gfx::Rect& paint_rect,
510                           const gfx::Rect& expected_clipped_rect) {
511     UpdatePluginGeometry(device_scale, window_rect);
512     canvas_.DrawColor(kDefaultColor);
513
514     // Paint the plugin with `kPaintColor`.
515     plugin_->UpdateSnapshot(CreateSkiaImageForTesting(
516         plugin_->GetPluginRectForTesting().size(), kPaintColor));
517     plugin_->Paint(canvas_.sk_canvas(), paint_rect);
518
519     // Expect the clipped area on canvas to be filled with `kPaintColor`.
520     SkBitmap expected_bitmap =
521         GenerateExpectedBitmapForPaint(expected_clipped_rect, kPaintColor);
522     EXPECT_TRUE(
523         cc::MatchesBitmap(canvas_.GetBitmap(), expected_bitmap,
524                           cc::ExactPixelComparator(/*discard_alpha=*/false)))
525         << "Failure at device scale of " << device_scale << ", window rect of "
526         << window_rect.ToString();
527   }
528
529   // Provides the cc::PaintCanvas for painting.
530   gfx::Canvas canvas_{kCanvasSize, /*image_scale=*/1.0f, /*is_opaque=*/true};
531 };
532
533 class PdfViewWebPluginFullFrameTest : public PdfViewWebPluginTest {
534  protected:
535   void SetUpPluginParams(blink::WebPluginParams& params) override {
536     AddToPluginParams("full-frame", "full-frame", params);
537   }
538 };
539
540 TEST_F(PdfViewWebPluginWithoutInitializeTest, Initialize) {
541   SetUpPluginWithUrl("http://localhost/example.pdf");
542
543   EXPECT_CALL(*client_ptr_, CreateAssociatedURLLoader)
544       .WillOnce([](const blink::WebAssociatedURLLoaderOptions& options) {
545         EXPECT_TRUE(options.grant_universal_access);
546
547         auto associated_loader =
548             std::make_unique<NiceMock<MockWebAssociatedURLLoader>>();
549         EXPECT_CALL(*associated_loader, LoadAsynchronously)
550             .WillOnce([](const blink::WebURLRequest& request,
551                          blink::WebAssociatedURLLoaderClient* client) {
552               EXPECT_EQ("http://localhost/example.pdf",
553                         request.Url().GetString().Utf8());
554               EXPECT_EQ("GET", request.HttpMethod().Utf8());
555               EXPECT_TRUE(request.HttpBody().IsNull());
556
557               NiceMock<MockHeaderVisitor> header_visitor;
558               EXPECT_CALL(header_visitor, VisitHeader).Times(0);
559               request.VisitHttpHeaderFields(&header_visitor);
560
561               EXPECT_FALSE(client->WillFollowRedirect(blink::WebURL(),
562                                                       blink::WebURLResponse()));
563               client->DidReceiveResponse(blink::WebURLResponse());
564               client->DidFinishLoading();
565             });
566         return associated_loader;
567       });
568   EXPECT_CALL(*client_ptr_, SetReferrerForRequest).Times(0);
569
570   EXPECT_TRUE(plugin_->InitializeForTesting());
571 }
572
573 TEST_F(PdfViewWebPluginWithoutInitializeTest, InitializeWithEmptyUrl) {
574   SetUpPluginWithUrl("");
575
576   EXPECT_CALL(*client_ptr_, CreateAssociatedURLLoader).Times(0);
577
578   EXPECT_FALSE(plugin_->InitializeForTesting());
579 }
580
581 TEST_F(PdfViewWebPluginWithoutInitializeTest, InitializeForPrintPreview) {
582   SetUpPluginWithUrl("about:blank");
583
584   EXPECT_CALL(*client_ptr_, GetEmbedderOriginString)
585       .WillRepeatedly(Return("chrome://print/"));
586   EXPECT_CALL(*client_ptr_, CreateAssociatedURLLoader).Times(0);
587
588   EXPECT_TRUE(plugin_->InitializeForTesting());
589 }
590
591 TEST_F(PdfViewWebPluginTest, CreateUrlLoader) {
592   EXPECT_CALL(*client_ptr_, DidStartLoading).Times(0);
593   EXPECT_CALL(pdf_service_, UpdateContentRestrictions).Times(0);
594   plugin_->CreateUrlLoader();
595
596   EXPECT_EQ(PdfViewWebPlugin::DocumentLoadState::kLoading,
597             plugin_->document_load_state_for_testing());
598   pdf_receiver_.FlushForTesting();
599 }
600
601 TEST_F(PdfViewWebPluginFullFrameTest, CreateUrlLoader) {
602   EXPECT_CALL(*client_ptr_, DidStartLoading);
603   EXPECT_CALL(pdf_service_,
604               UpdateContentRestrictions(kContentRestrictionSave |
605                                         kContentRestrictionPrint));
606   plugin_->CreateUrlLoader();
607
608   EXPECT_EQ(PdfViewWebPlugin::DocumentLoadState::kLoading,
609             plugin_->document_load_state_for_testing());
610   pdf_receiver_.FlushForTesting();
611 }
612
613 TEST_F(PdfViewWebPluginFullFrameTest, CreateUrlLoaderMultipleTimes) {
614   plugin_->CreateUrlLoader();
615
616   EXPECT_CALL(*client_ptr_, DidStartLoading).Times(0);
617   plugin_->CreateUrlLoader();
618 }
619
620 TEST_F(PdfViewWebPluginFullFrameTest, CreateUrlLoaderAfterDocumentLoadFailed) {
621   plugin_->CreateUrlLoader();
622   plugin_->DocumentLoadFailed();
623
624   EXPECT_CALL(*client_ptr_, DidStartLoading);
625   plugin_->CreateUrlLoader();
626 }
627
628 TEST_F(PdfViewWebPluginTest, DocumentLoadComplete) {
629   plugin_->CreateUrlLoader();
630
631   EXPECT_CALL(*client_ptr_, RecordComputedAction("PDF.LoadSuccess"));
632   EXPECT_CALL(*client_ptr_, PostMessage);
633   EXPECT_CALL(*client_ptr_, PostMessage(base::test::IsJson(R"({
634     "type": "formFocusChange",
635     "focused": false,
636   })")));
637   ExpectUpdateTextInputState(blink::WebTextInputType::kWebTextInputTypeNone);
638   EXPECT_CALL(*client_ptr_, PostMessage(base::test::IsJson(R"({
639     "type": "printPreviewLoaded",
640   })")))
641       .Times(0);
642   EXPECT_CALL(*accessibility_data_handler_ptr_, SetAccessibilityDocInfo)
643       .Times(0);
644   EXPECT_CALL(*client_ptr_, DidStopLoading).Times(0);
645   EXPECT_CALL(pdf_service_, UpdateContentRestrictions).Times(0);
646   plugin_->DocumentLoadComplete();
647
648   EXPECT_EQ(PdfViewWebPlugin::DocumentLoadState::kComplete,
649             plugin_->document_load_state_for_testing());
650   pdf_receiver_.FlushForTesting();
651 }
652
653 TEST_F(PdfViewWebPluginFullFrameTest, DocumentLoadComplete) {
654   // Must flush IPCs after `CreateUrlLoader()` in full-frame mode, otherwise
655   // there's an unexpected `UpdateContentRestrictions()` call (see the
656   // `PdfViewWebPluginFullFrameTest.CreateUrlLoader` test).
657   plugin_->CreateUrlLoader();
658   pdf_receiver_.FlushForTesting();
659
660   EXPECT_CALL(*client_ptr_, RecordComputedAction("PDF.LoadSuccess"));
661   EXPECT_CALL(*client_ptr_, PostMessage);
662   EXPECT_CALL(*client_ptr_, PostMessage(base::test::IsJson(R"({
663     "type": "formFocusChange",
664     "focused": false,
665   })")));
666   ExpectUpdateTextInputState(blink::WebTextInputType::kWebTextInputTypeNone);
667   EXPECT_CALL(*client_ptr_, PostMessage(base::test::IsJson(R"({
668     "type": "printPreviewLoaded",
669   })")))
670       .Times(0);
671   EXPECT_CALL(*accessibility_data_handler_ptr_, SetAccessibilityDocInfo)
672       .Times(0);
673   EXPECT_CALL(*client_ptr_, DidStopLoading);
674   EXPECT_CALL(pdf_service_, UpdateContentRestrictions(kContentRestrictionPrint |
675                                                       kContentRestrictionPaste |
676                                                       kContentRestrictionCut |
677                                                       kContentRestrictionCopy));
678   plugin_->DocumentLoadComplete();
679
680   EXPECT_EQ(PdfViewWebPlugin::DocumentLoadState::kComplete,
681             plugin_->document_load_state_for_testing());
682   pdf_receiver_.FlushForTesting();
683 }
684
685 TEST_F(PdfViewWebPluginTest, DocumentLoadFailed) {
686   plugin_->CreateUrlLoader();
687
688   EXPECT_CALL(*client_ptr_, RecordComputedAction("PDF.LoadFailure"));
689   EXPECT_CALL(*client_ptr_, DidStopLoading).Times(0);
690   plugin_->DocumentLoadFailed();
691
692   EXPECT_EQ(PdfViewWebPlugin::DocumentLoadState::kFailed,
693             plugin_->document_load_state_for_testing());
694 }
695
696 TEST_F(PdfViewWebPluginFullFrameTest, DocumentLoadFailed) {
697   plugin_->CreateUrlLoader();
698
699   EXPECT_CALL(*client_ptr_, RecordComputedAction("PDF.LoadFailure"));
700   EXPECT_CALL(*client_ptr_, DidStopLoading);
701   plugin_->DocumentLoadFailed();
702
703   EXPECT_EQ(PdfViewWebPlugin::DocumentLoadState::kFailed,
704             plugin_->document_load_state_for_testing());
705 }
706
707 TEST_F(PdfViewWebPluginTest, DocumentHasUnsupportedFeature) {
708   EXPECT_CALL(*client_ptr_, RecordComputedAction).Times(AnyNumber());
709   EXPECT_CALL(*client_ptr_, RecordComputedAction("PDF_Unsupported_feature1"));
710   EXPECT_CALL(*client_ptr_, RecordComputedAction("PDF_Unsupported_feature2"));
711
712   // `HasUnsupportedFeature()` is not called if the viewer is not full-frame.
713   EXPECT_CALL(pdf_service_, HasUnsupportedFeature).Times(0);
714
715   plugin_->DocumentHasUnsupportedFeature("feature1");
716   plugin_->DocumentHasUnsupportedFeature("feature2");
717
718   pdf_receiver_.FlushForTesting();
719 }
720
721 TEST_F(PdfViewWebPluginTest, DocumentHasUnsupportedFeatureWithRepeatedFeature) {
722   // Metrics should only be recorded once per feature.
723   EXPECT_CALL(*client_ptr_, RecordComputedAction).Times(AnyNumber());
724   EXPECT_CALL(*client_ptr_, RecordComputedAction("PDF_Unsupported_feature"));
725
726   // `HasUnsupportedFeature()` is not called if the viewer is not full-frame.
727   EXPECT_CALL(pdf_service_, HasUnsupportedFeature).Times(0);
728
729   plugin_->DocumentHasUnsupportedFeature("feature");
730   plugin_->DocumentHasUnsupportedFeature("feature");
731
732   pdf_receiver_.FlushForTesting();
733 }
734
735 TEST_F(PdfViewWebPluginFullFrameTest, DocumentHasUnsupportedFeature) {
736   EXPECT_CALL(*client_ptr_, RecordComputedAction).Times(AnyNumber());
737   EXPECT_CALL(*client_ptr_, RecordComputedAction("PDF_Unsupported_feature1"));
738   EXPECT_CALL(*client_ptr_, RecordComputedAction("PDF_Unsupported_feature2"));
739
740   // `HasUnsupportedFeature()` is called once for all features.
741   EXPECT_CALL(pdf_service_, HasUnsupportedFeature);
742
743   plugin_->DocumentHasUnsupportedFeature("feature1");
744   plugin_->DocumentHasUnsupportedFeature("feature2");
745
746   pdf_receiver_.FlushForTesting();
747 }
748
749 TEST_F(PdfViewWebPluginFullFrameTest,
750        DocumentHasUnsupportedFeatureWithRepeatedFeature) {
751   // Metrics should only be recorded once per feature.
752   EXPECT_CALL(*client_ptr_, RecordComputedAction).Times(AnyNumber());
753   EXPECT_CALL(*client_ptr_, RecordComputedAction("PDF_Unsupported_feature"));
754
755   // `HasUnsupportedFeature()` is called once for all features.
756   EXPECT_CALL(pdf_service_, HasUnsupportedFeature);
757
758   plugin_->DocumentHasUnsupportedFeature("feature");
759   plugin_->DocumentHasUnsupportedFeature("feature");
760
761   pdf_receiver_.FlushForTesting();
762 }
763
764 TEST_F(PdfViewWebPluginTest, DocumentLoadProgress) {
765   EXPECT_CALL(*client_ptr_, PostMessage(base::test::IsJson(R"({
766     "type": "loadProgress",
767     "progress": 5.0,
768   })")));
769   plugin_->DocumentLoadProgress(10, 200);
770 }
771
772 TEST_F(PdfViewWebPluginTest, DocumentLoadProgressIgnoreSmall) {
773   plugin_->DocumentLoadProgress(2, 100);
774
775   EXPECT_CALL(*client_ptr_, PostMessage).Times(0);
776   plugin_->DocumentLoadProgress(3, 100);
777 }
778
779 TEST_F(PdfViewWebPluginTest, DocumentLoadProgressMultipleSmall) {
780   plugin_->DocumentLoadProgress(2, 100);
781
782   EXPECT_CALL(*client_ptr_, PostMessage(base::test::IsJson(R"({
783     "type": "loadProgress",
784     "progress": 4.0,
785   })")));
786   plugin_->DocumentLoadProgress(3, 100);
787   plugin_->DocumentLoadProgress(4, 100);
788 }
789
790 TEST_F(PdfViewWebPluginTest, EnableAccessibilityBeforeDocumentLoadComplete) {
791   EXPECT_CALL(*accessibility_data_handler_ptr_, SetAccessibilityDocInfo)
792       .Times(0);
793   plugin_->EnableAccessibility();
794
795   EXPECT_CALL(*accessibility_data_handler_ptr_, SetAccessibilityDocInfo);
796   plugin_->CreateUrlLoader();
797   plugin_->DocumentLoadComplete();
798 }
799
800 TEST_F(PdfViewWebPluginTest,
801        EnableAccessibilityBeforeDocumentLoadCompleteRepeated) {
802   EXPECT_CALL(*accessibility_data_handler_ptr_, SetAccessibilityDocInfo)
803       .Times(0);
804   plugin_->EnableAccessibility();
805   plugin_->EnableAccessibility();
806
807   EXPECT_CALL(*accessibility_data_handler_ptr_, SetAccessibilityDocInfo);
808   plugin_->CreateUrlLoader();
809   plugin_->DocumentLoadComplete();
810 }
811
812 TEST_F(PdfViewWebPluginTest, EnableAccessibilityAfterDocumentLoadComplete) {
813   EXPECT_CALL(*accessibility_data_handler_ptr_, SetAccessibilityDocInfo)
814       .Times(0);
815   plugin_->CreateUrlLoader();
816   plugin_->DocumentLoadComplete();
817
818   EXPECT_CALL(*accessibility_data_handler_ptr_, SetAccessibilityDocInfo);
819   plugin_->EnableAccessibility();
820 }
821
822 TEST_F(PdfViewWebPluginTest,
823        EnableAccessibilityAfterDocumentLoadCompleteRepeated) {
824   plugin_->CreateUrlLoader();
825   plugin_->DocumentLoadComplete();
826   plugin_->EnableAccessibility();
827
828   EXPECT_CALL(*accessibility_data_handler_ptr_, SetAccessibilityDocInfo)
829       .Times(0);
830   plugin_->EnableAccessibility();
831 }
832
833 TEST_F(PdfViewWebPluginTest, GetContentRestrictionsWithNoPermissions) {
834   EXPECT_EQ(kContentRestrictionCopy | kContentRestrictionCut |
835                 kContentRestrictionPaste | kContentRestrictionPrint,
836             plugin_->GetContentRestrictionsForTesting());
837   EXPECT_FALSE(plugin_->CanCopy());
838 }
839
840 TEST_F(PdfViewWebPluginTest, GetContentRestrictionsWithCopyAllowed) {
841   EXPECT_CALL(*engine_ptr_, HasPermission).WillRepeatedly(Return(false));
842   EXPECT_CALL(*engine_ptr_, HasPermission(DocumentPermission::kCopy))
843       .WillRepeatedly(Return(true));
844
845   EXPECT_EQ(kContentRestrictionCut | kContentRestrictionPaste |
846                 kContentRestrictionPrint,
847             plugin_->GetContentRestrictionsForTesting());
848   EXPECT_TRUE(plugin_->CanCopy());
849 }
850
851 TEST_F(PdfViewWebPluginTest, GetContentRestrictionsWithPrintLowQualityAllowed) {
852   EXPECT_CALL(*engine_ptr_, HasPermission).WillRepeatedly(Return(false));
853   EXPECT_CALL(*engine_ptr_, HasPermission(DocumentPermission::kPrintLowQuality))
854       .WillRepeatedly(Return(true));
855
856   EXPECT_EQ(kContentRestrictionCopy | kContentRestrictionCut |
857                 kContentRestrictionPaste,
858             plugin_->GetContentRestrictionsForTesting());
859 }
860
861 TEST_F(PdfViewWebPluginTest,
862        GetContentRestrictionsWithCopyAndPrintLowQualityAllowed) {
863   EXPECT_CALL(*engine_ptr_, HasPermission).WillRepeatedly(Return(false));
864   EXPECT_CALL(*engine_ptr_, HasPermission(DocumentPermission::kCopy))
865       .WillRepeatedly(Return(true));
866   EXPECT_CALL(*engine_ptr_, HasPermission(DocumentPermission::kPrintLowQuality))
867       .WillRepeatedly(Return(true));
868
869   EXPECT_EQ(kContentRestrictionCut | kContentRestrictionPaste,
870             plugin_->GetContentRestrictionsForTesting());
871 }
872
873 TEST_F(PdfViewWebPluginTest, GetContentRestrictionsWithPrintAllowed) {
874   EXPECT_CALL(*engine_ptr_, HasPermission).WillRepeatedly(Return(false));
875   EXPECT_CALL(*engine_ptr_,
876               HasPermission(DocumentPermission::kPrintHighQuality))
877       .WillRepeatedly(Return(true));
878   EXPECT_CALL(*engine_ptr_, HasPermission(DocumentPermission::kPrintLowQuality))
879       .WillRepeatedly(Return(true));
880
881   EXPECT_EQ(kContentRestrictionCopy | kContentRestrictionCut |
882                 kContentRestrictionPaste,
883             plugin_->GetContentRestrictionsForTesting());
884 }
885
886 TEST_F(PdfViewWebPluginTest, GetContentRestrictionsWithCopyAndPrintAllowed) {
887   EXPECT_CALL(*engine_ptr_, HasPermission).WillRepeatedly(Return(false));
888   EXPECT_CALL(*engine_ptr_, HasPermission(DocumentPermission::kCopy))
889       .WillRepeatedly(Return(true));
890   EXPECT_CALL(*engine_ptr_,
891               HasPermission(DocumentPermission::kPrintHighQuality))
892       .WillRepeatedly(Return(true));
893   EXPECT_CALL(*engine_ptr_, HasPermission(DocumentPermission::kPrintLowQuality))
894       .WillRepeatedly(Return(true));
895
896   EXPECT_EQ(kContentRestrictionCut | kContentRestrictionPaste,
897             plugin_->GetContentRestrictionsForTesting());
898 }
899
900 TEST_F(PdfViewWebPluginTest, GetAccessibilityDocInfoWithNoPermissions) {
901   AccessibilityDocInfo doc_info = plugin_->GetAccessibilityDocInfoForTesting();
902
903   EXPECT_EQ(TestPDFiumEngine::kPageNumber, doc_info.page_count);
904   EXPECT_FALSE(doc_info.text_accessible);
905   EXPECT_FALSE(doc_info.text_copyable);
906 }
907
908 TEST_F(PdfViewWebPluginTest, GetAccessibilityDocInfoWithCopyAllowed) {
909   EXPECT_CALL(*engine_ptr_, HasPermission).WillRepeatedly(Return(false));
910   EXPECT_CALL(*engine_ptr_, HasPermission(DocumentPermission::kCopy))
911       .WillRepeatedly(Return(true));
912
913   AccessibilityDocInfo doc_info = plugin_->GetAccessibilityDocInfoForTesting();
914
915   EXPECT_EQ(TestPDFiumEngine::kPageNumber, doc_info.page_count);
916   EXPECT_FALSE(doc_info.text_accessible);
917   EXPECT_TRUE(doc_info.text_copyable);
918 }
919
920 TEST_F(PdfViewWebPluginTest, GetAccessibilityDocInfoWithCopyAccessibleAllowed) {
921   EXPECT_CALL(*engine_ptr_, HasPermission).WillRepeatedly(Return(false));
922   EXPECT_CALL(*engine_ptr_, HasPermission(DocumentPermission::kCopyAccessible))
923       .WillRepeatedly(Return(true));
924
925   AccessibilityDocInfo doc_info = plugin_->GetAccessibilityDocInfoForTesting();
926
927   EXPECT_EQ(TestPDFiumEngine::kPageNumber, doc_info.page_count);
928   EXPECT_TRUE(doc_info.text_accessible);
929   EXPECT_FALSE(doc_info.text_copyable);
930 }
931
932 TEST_F(PdfViewWebPluginTest,
933        GetAccessibilityDocInfoWithCopyAndCopyAccessibleAllowed) {
934   EXPECT_CALL(*engine_ptr_, HasPermission).WillRepeatedly(Return(false));
935   EXPECT_CALL(*engine_ptr_, HasPermission(DocumentPermission::kCopy))
936       .WillRepeatedly(Return(true));
937   EXPECT_CALL(*engine_ptr_, HasPermission(DocumentPermission::kCopyAccessible))
938       .WillRepeatedly(Return(true));
939
940   AccessibilityDocInfo doc_info = plugin_->GetAccessibilityDocInfoForTesting();
941
942   EXPECT_EQ(TestPDFiumEngine::kPageNumber, doc_info.page_count);
943   EXPECT_TRUE(doc_info.text_accessible);
944   EXPECT_TRUE(doc_info.text_copyable);
945 }
946
947 TEST_F(PdfViewWebPluginTest, UpdateGeometrySetsPluginRect) {
948   EXPECT_CALL(*engine_ptr_, ZoomUpdated(2.0f));
949   TestUpdateGeometrySetsPluginRect(
950       /*device_scale=*/2.0f, /*window_rect=*/gfx::Rect(4, 4, 12, 12),
951       /*expected_device_scale=*/2.0f,
952       /*expected_plugin_rect=*/gfx::Rect(4, 4, 12, 12));
953 }
954
955 TEST_F(PdfViewWebPluginTest,
956        UpdateGeometrySetsPluginRectOnVariousDeviceScales) {
957   struct UpdateGeometryParams {
958     // The plugin container's device scale.
959     float device_scale;
960
961     //  The window rect in CSS pixels.
962     gfx::Rect window_rect;
963
964     // The expected plugin device scale.
965     float expected_device_scale;
966
967     // The expected plugin rect in device pixels.
968     gfx::Rect expected_plugin_rect;
969   };
970
971   static constexpr UpdateGeometryParams kUpdateGeometryParams[] = {
972       {1.0f, gfx::Rect(3, 4, 5, 6), 1.0f, gfx::Rect(3, 4, 5, 6)},
973       {2.0f, gfx::Rect(3, 4, 5, 6), 2.0f, gfx::Rect(3, 4, 5, 6)},
974   };
975
976   for (const auto& params : kUpdateGeometryParams) {
977     TestUpdateGeometrySetsPluginRect(params.device_scale, params.window_rect,
978                                      params.expected_device_scale,
979                                      params.expected_plugin_rect);
980   }
981 }
982
983 TEST_F(PdfViewWebPluginTest, UpdateGeometrySetsPluginRectWithEmptyWindow) {
984   EXPECT_CALL(*engine_ptr_, ZoomUpdated).Times(0);
985   TestUpdateGeometrySetsPluginRect(
986       /*device_scale=*/2.0f, /*window_rect=*/gfx::Rect(2, 2, 0, 0),
987       /*expected_device_scale=*/1.0f, /*expected_plugin_rect=*/gfx::Rect());
988 }
989
990 TEST_F(PdfViewWebPluginTest, UpdateGeometryScroll) {
991   SetDocumentDimensions({100, 200});
992
993   EXPECT_CALL(*client_ptr_, GetScrollPosition)
994       .WillRepeatedly(Return(gfx::PointF(4.0f, 6.0f)));
995   EXPECT_CALL(*engine_ptr_, ScrolledToXPosition(4));
996   EXPECT_CALL(*engine_ptr_, ScrolledToYPosition(6));
997   UpdatePluginGeometryWithoutWaiting(1.0f, gfx::Rect(3, 4, 5, 6));
998 }
999
1000 TEST_F(PdfViewWebPluginTest, UpdateGeometryScrollStopped) {
1001   SetDocumentDimensions({100, 200});
1002
1003   plugin_->OnMessage(ParseMessage(R"({
1004     "type": "stopScrolling",
1005   })"));
1006
1007   EXPECT_CALL(*client_ptr_, GetScrollPosition)
1008       .WillRepeatedly(Return(gfx::PointF(4.0f, 6.0f)));
1009   EXPECT_CALL(*engine_ptr_, ScrolledToXPosition).Times(0);
1010   EXPECT_CALL(*engine_ptr_, ScrolledToYPosition).Times(0);
1011   UpdatePluginGeometryWithoutWaiting(1.0f, gfx::Rect(3, 4, 5, 6));
1012 }
1013
1014 TEST_F(PdfViewWebPluginTest, UpdateGeometryScrollUnderflow) {
1015   SetDocumentDimensions({100, 200});
1016
1017   EXPECT_CALL(*client_ptr_, GetScrollPosition)
1018       .WillRepeatedly(Return(gfx::PointF(-1.0f, -1.0f)));
1019   EXPECT_CALL(*engine_ptr_, ScrolledToXPosition(0));
1020   EXPECT_CALL(*engine_ptr_, ScrolledToYPosition(0));
1021   UpdatePluginGeometryWithoutWaiting(1.0f, gfx::Rect(3, 4, 5, 6));
1022 }
1023
1024 TEST_F(PdfViewWebPluginTest, UpdateGeometryScrollOverflow) {
1025   SetDocumentDimensions({100, 200});
1026
1027   EXPECT_CALL(*client_ptr_, GetScrollPosition)
1028       .WillRepeatedly(Return(gfx::PointF(96.0f, 195.0f)));
1029   EXPECT_CALL(*engine_ptr_, ScrolledToXPosition(95));
1030   EXPECT_CALL(*engine_ptr_, ScrolledToYPosition(194));
1031   UpdatePluginGeometryWithoutWaiting(1.0f, gfx::Rect(3, 4, 5, 6));
1032 }
1033
1034 TEST_F(PdfViewWebPluginTest, UpdateGeometryScrollOverflowZoomed) {
1035   SetDocumentDimensions({100, 200});
1036   SendViewportMessage(/*zoom=*/2.0);
1037
1038   EXPECT_CALL(*client_ptr_, GetScrollPosition)
1039       .WillRepeatedly(Return(gfx::PointF(196.0f, 395.0f)));
1040   EXPECT_CALL(*engine_ptr_, ScrolledToXPosition(195));
1041   EXPECT_CALL(*engine_ptr_, ScrolledToYPosition(394));
1042   UpdatePluginGeometryWithoutWaiting(1.0f, gfx::Rect(3, 4, 5, 6));
1043 }
1044
1045 TEST_F(PdfViewWebPluginTest, UpdateGeometryScrollScaled) {
1046   SetDocumentDimensions({100, 200});
1047
1048   EXPECT_CALL(*client_ptr_, GetScrollPosition)
1049       .WillRepeatedly(Return(gfx::PointF(4.0f, 6.0f)));
1050   EXPECT_CALL(*engine_ptr_, ScrolledToXPosition(4));
1051   EXPECT_CALL(*engine_ptr_, ScrolledToYPosition(6));
1052   UpdatePluginGeometryWithoutWaiting(2.0f, gfx::Rect(3, 4, 5, 6));
1053 }
1054
1055 TEST_F(PdfViewWebPluginTest, UpdateGeometryScrollOverflowScaled) {
1056   SetDocumentDimensions({100, 200});
1057
1058   EXPECT_CALL(*client_ptr_, GetScrollPosition)
1059       .WillRepeatedly(Return(gfx::PointF(195.0f, 395.0f)));
1060   EXPECT_CALL(*engine_ptr_, ScrolledToXPosition(194));
1061   EXPECT_CALL(*engine_ptr_, ScrolledToYPosition(394));
1062   UpdatePluginGeometryWithoutWaiting(2.0f, gfx::Rect(3, 4, 5, 6));
1063 }
1064
1065 TEST_F(PdfViewWebPluginTest, SetCaretPosition) {
1066   SetDocumentDimensions({16, 9});
1067   UpdatePluginGeometryWithoutWaiting(1.0f, {10, 20, 20, 5});
1068
1069   EXPECT_CALL(*engine_ptr_, SetCaretPosition(gfx::Point(2, 3)));
1070   plugin_->SetCaretPosition({4.0f, 3.0f});
1071 }
1072
1073 TEST_F(PdfViewWebPluginTest, SetCaretPositionNegativeOrigin) {
1074   SetDocumentDimensions({16, 9});
1075   UpdatePluginGeometryWithoutWaiting(1.0f, {-10, -20, 20, 5});
1076
1077   EXPECT_CALL(*engine_ptr_, SetCaretPosition(gfx::Point(2, 3)));
1078   plugin_->SetCaretPosition({4.0f, 3.0f});
1079 }
1080
1081 TEST_F(PdfViewWebPluginTest, SetCaretPositionFractional) {
1082   SetDocumentDimensions({16, 9});
1083   UpdatePluginGeometryWithoutWaiting(1.0f, {10, 20, 20, 5});
1084
1085   EXPECT_CALL(*engine_ptr_, SetCaretPosition(gfx::Point(1, 2)));
1086   plugin_->SetCaretPosition({3.9f, 2.9f});
1087 }
1088
1089 TEST_F(PdfViewWebPluginTest, SetCaretPositionScaled) {
1090   SetDocumentDimensions({16, 9});
1091   UpdatePluginGeometryWithoutWaiting(2.0f, {20, 40, 40, 10});
1092
1093   EXPECT_CALL(*engine_ptr_, SetCaretPosition(gfx::Point(4, 6)));
1094   plugin_->SetCaretPosition({4.0f, 3.0f});
1095 }
1096
1097 TEST_F(PdfViewWebPluginTest, PaintEmptySnapshots) {
1098   TestPaintEmptySnapshots(/*device_scale=*/4.0f,
1099                           /*window_rect=*/gfx::Rect(10, 10, 20, 20),
1100                           /*paint_rect=*/gfx::Rect(5, 5, 15, 15),
1101                           /*expected_clipped_rect=*/gfx::Rect(10, 10, 10, 10));
1102 }
1103
1104 TEST_F(PdfViewWebPluginTest, PaintSnapshots) {
1105   TestPaintSnapshots(/*device_scale=*/4.0f,
1106                      /*window_rect=*/gfx::Rect(10, 10, 20, 20),
1107                      /*paint_rect=*/gfx::Rect(5, 5, 15, 15),
1108                      /*expected_clipped_rect=*/gfx::Rect(10, 10, 10, 10));
1109 }
1110
1111 TEST_F(PdfViewWebPluginTest, PaintSnapshotsWithVariousDeviceScales) {
1112   static constexpr PaintParams kPaintWithVariousScalesParams[] = {
1113       {0.4f, gfx::Rect(8, 8, 30, 30), gfx::Rect(10, 10, 30, 30),
1114        gfx::Rect(10, 10, 28, 28)},
1115       {1.0f, gfx::Rect(8, 8, 30, 30), gfx::Rect(10, 10, 30, 30),
1116        gfx::Rect(10, 10, 28, 28)},
1117       {4.0f, gfx::Rect(8, 8, 30, 30), gfx::Rect(10, 10, 30, 30),
1118        gfx::Rect(10, 10, 28, 28)},
1119   };
1120
1121   for (const auto& params : kPaintWithVariousScalesParams) {
1122     TestPaintSnapshots(params.device_scale, params.window_rect,
1123                        params.paint_rect, params.expected_clipped_rect);
1124   }
1125 }
1126
1127 TEST_F(PdfViewWebPluginTest, PaintSnapshotsWithVariousRectPositions) {
1128   static constexpr PaintParams kPaintWithVariousPositionsParams[] = {
1129       // The window origin falls outside the `paint_rect` area.
1130       {4.0f, gfx::Rect(10, 10, 20, 20), gfx::Rect(5, 5, 15, 15),
1131        gfx::Rect(10, 10, 10, 10)},
1132       // The window origin falls within the `paint_rect` area.
1133       {4.0f, gfx::Rect(4, 4, 20, 20), gfx::Rect(8, 8, 15, 15),
1134        gfx::Rect(8, 8, 15, 15)},
1135   };
1136
1137   for (const auto& params : kPaintWithVariousPositionsParams) {
1138     TestPaintSnapshots(params.device_scale, params.window_rect,
1139                        params.paint_rect, params.expected_clipped_rect);
1140   }
1141 }
1142
1143 TEST_F(PdfViewWebPluginTest, OnPaintWithMultiplePaintRects) {
1144   SetDocumentDimensions({100, 200});
1145   UpdatePluginGeometryWithoutWaiting(/*device_scale=*/1.0f,
1146                                      gfx::Rect(0, 0, 40, 40));
1147
1148   EXPECT_CALL(*engine_ptr_, Paint)
1149       .WillRepeatedly(
1150           [](const gfx::Rect& rect, SkBitmap& /*image_data*/,
1151              std::vector<gfx::Rect>& ready,
1152              std::vector<gfx::Rect>& /*pending*/) { ready.push_back(rect); });
1153   std::vector<PaintReadyRect> ready;
1154   std::vector<gfx::Rect> pending;
1155   plugin_->OnPaint(
1156       /*paint_rects=*/{gfx::Rect(5, 5, 10, 10), gfx::Rect(20, 20, 10, 10)},
1157       ready, pending);
1158
1159   // Expect three paints: an initial background-clearing paint, and one for each
1160   // requested paint rectangle.
1161   ASSERT_THAT(ready, SizeIs(3));
1162   EXPECT_THAT(pending, IsEmpty());
1163
1164   EXPECT_EQ(gfx::Rect(0, 0, 90, 90), ready[0].rect());
1165   EXPECT_TRUE(ready[0].flush_now());
1166
1167   EXPECT_EQ(gfx::Rect(5, 5, 10, 10), ready[1].rect());
1168   EXPECT_FALSE(ready[1].flush_now());
1169
1170   EXPECT_EQ(gfx::Rect(20, 20, 10, 10), ready[2].rect());
1171   EXPECT_FALSE(ready[2].flush_now());
1172
1173   // All the requested paints should share the same `SkImage`.
1174   EXPECT_NE(&ready[0].image(), &ready[1].image());
1175   EXPECT_EQ(&ready[1].image(), &ready[2].image());
1176 }
1177
1178 TEST_F(PdfViewWebPluginTest, UpdateLayerTransformWithIdentity) {
1179   plugin_->UpdateLayerTransform(1.0f, gfx::Vector2dF());
1180   TestPaintSnapshots(/*device_scale=*/4.0f,
1181                      /*window_rect=*/gfx::Rect(10, 10, 20, 20),
1182                      /*paint_rect=*/gfx::Rect(10, 10, 20, 20),
1183                      /*expected_clipped_rect=*/gfx::Rect(10, 10, 20, 20));
1184 }
1185
1186 TEST_F(PdfViewWebPluginTest, UpdateLayerTransformWithScale) {
1187   plugin_->UpdateLayerTransform(0.5f, gfx::Vector2dF());
1188   TestPaintSnapshots(/*device_scale=*/4.0f,
1189                      /*window_rect=*/gfx::Rect(10, 10, 20, 20),
1190                      /*paint_rect=*/gfx::Rect(10, 10, 20, 20),
1191                      /*expected_clipped_rect=*/gfx::Rect(10, 10, 10, 10));
1192 }
1193
1194 TEST_F(PdfViewWebPluginTest, UpdateLayerTransformWithTranslate) {
1195   plugin_->UpdateLayerTransform(1.0f, gfx::Vector2dF(-1.25, 1.25));
1196   TestPaintSnapshots(/*device_scale=*/4.0f,
1197                      /*window_rect=*/gfx::Rect(10, 10, 20, 20),
1198                      /*paint_rect=*/gfx::Rect(10, 10, 20, 20),
1199                      /*expected_clipped_rect=*/gfx::Rect(10, 15, 15, 15));
1200 }
1201
1202 TEST_F(PdfViewWebPluginTest, UpdateLayerTransformWithScaleAndTranslate) {
1203   plugin_->UpdateLayerTransform(0.5f, gfx::Vector2dF(-1.25, 1.25));
1204   TestPaintSnapshots(/*device_scale=*/4.0f,
1205                      /*window_rect=*/gfx::Rect(10, 10, 20, 20),
1206                      /*paint_rect=*/gfx::Rect(10, 10, 20, 20),
1207                      /*expected_clipped_rect=*/gfx::Rect(10, 15, 5, 10));
1208 }
1209
1210 TEST_F(PdfViewWebPluginTest, HandleViewportMessageBeforeDocumentLoadComplete) {
1211   EXPECT_CALL(*engine_ptr_, ApplyDocumentLayout(DocumentLayout::Options()));
1212   EXPECT_CALL(*client_ptr_, PostMessage).Times(0);
1213
1214   plugin_->OnMessage(ParseMessage(R"({
1215     "type": "viewport",
1216     "userInitiated": false,
1217     "zoom": 1,
1218     "layoutOptions": {
1219       "direction": 0,
1220       "defaultPageOrientation": 0,
1221       "twoUpViewEnabled": false,
1222     },
1223     "xOffset": 0,
1224     "yOffset": 0,
1225     "pinchPhase": 0,
1226   })"));
1227 }
1228
1229 TEST_F(PdfViewWebPluginTest, HandleViewportMessageAfterDocumentLoadComplete) {
1230   plugin_->DocumentLoadComplete();
1231
1232   EXPECT_CALL(*engine_ptr_, ApplyDocumentLayout(DocumentLayout::Options()));
1233   EXPECT_CALL(*client_ptr_, PostMessage(base::test::IsJson(R"({
1234     "type": "loadProgress",
1235     "progress": 100.0,
1236   })")));
1237
1238   plugin_->OnMessage(ParseMessage(R"({
1239     "type": "viewport",
1240     "userInitiated": false,
1241     "zoom": 1,
1242     "layoutOptions": {
1243       "direction": 0,
1244       "defaultPageOrientation": 0,
1245       "twoUpViewEnabled": false,
1246     },
1247     "xOffset": 0,
1248     "yOffset": 0,
1249     "pinchPhase": 0,
1250   })"));
1251 }
1252
1253 TEST_F(PdfViewWebPluginTest, HandleViewportMessageSubsequently) {
1254   plugin_->OnMessage(ParseMessage(R"({
1255     "type": "viewport",
1256     "userInitiated": false,
1257     "zoom": 1,
1258     "layoutOptions": {
1259       "direction": 0,
1260       "defaultPageOrientation": 0,
1261       "twoUpViewEnabled": false,
1262     },
1263     "xOffset": 0,
1264     "yOffset": 0,
1265     "pinchPhase": 0,
1266   })"));
1267
1268   DocumentLayout::Options two_up_options;
1269   two_up_options.set_page_spread(DocumentLayout::PageSpread::kTwoUpOdd);
1270   EXPECT_CALL(*engine_ptr_, ApplyDocumentLayout(two_up_options));
1271   EXPECT_CALL(*client_ptr_, PostMessage).Times(0);
1272
1273   plugin_->OnMessage(ParseMessage(R"({
1274     "type": "viewport",
1275     "userInitiated": false,
1276     "zoom": 1,
1277     "layoutOptions": {
1278       "direction": 0,
1279       "defaultPageOrientation": 0,
1280       "twoUpViewEnabled": true,
1281     },
1282     "xOffset": 0,
1283     "yOffset": 0,
1284     "pinchPhase": 0,
1285   })"));
1286 }
1287
1288 TEST_F(PdfViewWebPluginTest, HandleViewportMessageScroll) {
1289   EXPECT_CALL(*engine_ptr_, ApplyDocumentLayout)
1290       .WillRepeatedly(Return(gfx::Size(16, 9)));
1291   EXPECT_CALL(*engine_ptr_, ScrolledToXPosition(2));
1292   EXPECT_CALL(*engine_ptr_, ScrolledToYPosition(3));
1293
1294   plugin_->OnMessage(ParseMessage(R"({
1295     "type": "viewport",
1296     "userInitiated": false,
1297     "zoom": 1,
1298     "layoutOptions": {
1299       "direction": 2,
1300       "defaultPageOrientation": 0,
1301       "twoUpViewEnabled": false,
1302     },
1303     "xOffset": 2,
1304     "yOffset": 3,
1305     "pinchPhase": 0,
1306   })"));
1307 }
1308
1309 TEST_F(PdfViewWebPluginTest, HandleViewportMessageScrollRightToLeft) {
1310   EXPECT_CALL(*engine_ptr_, ApplyDocumentLayout)
1311       .WillRepeatedly(Return(gfx::Size(16, 9)));
1312   EXPECT_CALL(*engine_ptr_, ScrolledToXPosition(2));
1313   EXPECT_CALL(*engine_ptr_, ScrolledToYPosition(3));
1314
1315   plugin_->OnMessage(ParseMessage(R"({
1316     "type": "viewport",
1317     "userInitiated": false,
1318     "zoom": 1,
1319     "layoutOptions": {
1320       "direction": 1,
1321       "defaultPageOrientation": 0,
1322       "twoUpViewEnabled": false,
1323     },
1324     "xOffset": 2,
1325     "yOffset": 3,
1326     "pinchPhase": 0,
1327   })"));
1328 }
1329
1330 TEST_F(PdfViewWebPluginTest, HandleSetBackgroundColorMessage) {
1331   ASSERT_NE(SK_ColorGREEN, plugin_->GetBackgroundColor());
1332
1333   base::Value::Dict message;
1334   message.Set("type", "setBackgroundColor");
1335   message.Set("color", static_cast<double>(SK_ColorGREEN));
1336   plugin_->OnMessage(message);
1337
1338   EXPECT_EQ(SK_ColorGREEN, plugin_->GetBackgroundColor());
1339 }
1340
1341 TEST_F(PdfViewWebPluginTest, HandleInputEvent) {
1342   UpdatePluginGeometryWithoutWaiting(2.0f, {0, 0, 20, 20});
1343
1344   EXPECT_CALL(*engine_ptr_, HandleInputEvent)
1345       .WillRepeatedly([](const blink::WebInputEvent& event) {
1346         if (!blink::WebInputEvent::IsMouseEventType(event.GetType())) {
1347           ADD_FAILURE() << "Unexpected event type: " << event.GetType();
1348           return false;
1349         }
1350
1351         const auto& mouse_event =
1352             static_cast<const blink::WebMouseEvent&>(event);
1353         EXPECT_EQ(blink::WebInputEvent::Type::kMouseDown,
1354                   mouse_event.GetType());
1355         EXPECT_EQ(gfx::PointF(10.0f, 40.0f), mouse_event.PositionInWidget());
1356         return true;
1357       });
1358
1359   blink::WebMouseEvent mouse_event;
1360   mouse_event.SetType(blink::WebInputEvent::Type::kMouseDown);
1361   mouse_event.SetPositionInWidget(10.0f, 20.0f);
1362
1363   ui::Cursor dummy_cursor;
1364   EXPECT_EQ(blink::WebInputEventResult::kHandledApplication,
1365             plugin_->HandleInputEvent(
1366                 blink::WebCoalescedInputEvent(mouse_event, ui::LatencyInfo()),
1367                 &dummy_cursor));
1368 }
1369
1370 class PdfViewWebPluginImeTest : public PdfViewWebPluginTest {
1371  public:
1372   void TestImeSetCompositionForPlugin(const blink::WebString& text) {
1373     EXPECT_CALL(*engine_ptr_, HandleInputEvent).Times(0);
1374     plugin_->ImeSetCompositionForPlugin(text, std::vector<ui::ImeTextSpan>(),
1375                                         gfx::Range(),
1376                                         /*selection_start=*/0,
1377                                         /*selection_end=*/0);
1378   }
1379
1380   void TestImeFinishComposingTextForPlugin(
1381       const blink::WebString& expected_text) {
1382     InSequence sequence;
1383     std::u16string expected_text16 = expected_text.Utf16();
1384     if (expected_text16.size()) {
1385       for (const auto& c : expected_text16) {
1386         base::StringPiece16 expected_key(&c, 1);
1387         EXPECT_CALL(*engine_ptr_,
1388                     HandleInputEvent(IsExpectedImeKeyEvent(expected_key)))
1389             .WillOnce(Return(true));
1390       }
1391     } else {
1392       EXPECT_CALL(*engine_ptr_, HandleInputEvent).Times(0);
1393     }
1394     plugin_->ImeFinishComposingTextForPlugin(false);
1395   }
1396
1397   void TestImeCommitTextForPlugin(const blink::WebString& text) {
1398     InSequence sequence;
1399     std::u16string expected_text16 = text.Utf16();
1400     if (expected_text16.size()) {
1401       for (const auto& c : expected_text16) {
1402         base::StringPiece16 event(&c, 1);
1403         EXPECT_CALL(*engine_ptr_,
1404                     HandleInputEvent(IsExpectedImeKeyEvent(event)))
1405             .WillOnce(Return(true));
1406       }
1407     } else {
1408       EXPECT_CALL(*engine_ptr_, HandleInputEvent).Times(0);
1409     }
1410     plugin_->ImeCommitTextForPlugin(text, std::vector<ui::ImeTextSpan>(),
1411                                     gfx::Range(),
1412                                     /*relative_cursor_pos=*/0);
1413   }
1414 };
1415
1416 TEST_F(PdfViewWebPluginImeTest, ImeSetCompositionAndFinishAscii) {
1417   const blink::WebString text = blink::WebString::FromASCII("input");
1418   TestImeSetCompositionForPlugin(text);
1419   TestImeFinishComposingTextForPlugin(text);
1420 }
1421
1422 TEST_F(PdfViewWebPluginImeTest, ImeSetCompositionAndFinishUnicode) {
1423   const blink::WebString text = blink::WebString::FromUTF16(u"你好");
1424   TestImeSetCompositionForPlugin(text);
1425   TestImeFinishComposingTextForPlugin(text);
1426   // Calling ImeFinishComposingTextForPlugin() again is a no-op.
1427   TestImeFinishComposingTextForPlugin("");
1428 }
1429
1430 TEST_F(PdfViewWebPluginImeTest, ImeSetCompositionAndFinishEmpty) {
1431   const blink::WebString text;
1432   TestImeSetCompositionForPlugin(text);
1433   TestImeFinishComposingTextForPlugin(text);
1434 }
1435
1436 TEST_F(PdfViewWebPluginImeTest, ImeCommitTextForPluginAscii) {
1437   const blink::WebString text = blink::WebString::FromASCII("a b");
1438   TestImeCommitTextForPlugin(text);
1439 }
1440
1441 TEST_F(PdfViewWebPluginImeTest, ImeCommitTextForPluginUnicode) {
1442   const blink::WebString text = blink::WebString::FromUTF16(u"さようなら");
1443   TestImeCommitTextForPlugin(text);
1444 }
1445
1446 TEST_F(PdfViewWebPluginImeTest, ImeCommitTextForPluginEmpty) {
1447   const blink::WebString text;
1448   TestImeCommitTextForPlugin(text);
1449 }
1450
1451 TEST_F(PdfViewWebPluginTest, SelectionChanged) {
1452   plugin_->EnableAccessibility();
1453   plugin_->DocumentLoadComplete();
1454   UpdatePluginGeometryWithoutWaiting(1.0f, {300, 56, 20, 5});
1455   SetDocumentDimensions({16, 9});
1456
1457   AccessibilityViewportInfo viewport_info;
1458   EXPECT_CALL(pdf_service_, SelectionChanged(gfx::PointF(-8.0f, -20.0f), 40,
1459                                              gfx::PointF(52.0f, 60.0f), 80));
1460   EXPECT_CALL(*accessibility_data_handler_ptr_, SetAccessibilityViewportInfo)
1461       .WillOnce(SaveArg<0>(&viewport_info));
1462   plugin_->SelectionChanged({-10, -20, 30, 40}, {50, 60, 70, 80});
1463
1464   EXPECT_EQ(gfx::Point(), viewport_info.scroll);
1465   pdf_receiver_.FlushForTesting();
1466 }
1467
1468 TEST_F(PdfViewWebPluginTest, SelectionChangedNegativeOrigin) {
1469   plugin_->EnableAccessibility();
1470   plugin_->DocumentLoadComplete();
1471   UpdatePluginGeometryWithoutWaiting(1.0f, {-300, -56, 20, 5});
1472   SetDocumentDimensions({16, 9});
1473
1474   AccessibilityViewportInfo viewport_info;
1475   EXPECT_CALL(pdf_service_, SelectionChanged(gfx::PointF(-8.0f, -20.0f), 40,
1476                                              gfx::PointF(52.0f, 60.0f), 80));
1477   EXPECT_CALL(*accessibility_data_handler_ptr_, SetAccessibilityViewportInfo)
1478       .WillOnce(SaveArg<0>(&viewport_info));
1479   plugin_->SelectionChanged({-10, -20, 30, 40}, {50, 60, 70, 80});
1480
1481   EXPECT_EQ(gfx::Point(), viewport_info.scroll);
1482   pdf_receiver_.FlushForTesting();
1483 }
1484
1485 TEST_F(PdfViewWebPluginTest, SelectionChangedScaled) {
1486   plugin_->EnableAccessibility();
1487   plugin_->DocumentLoadComplete();
1488   UpdatePluginGeometryWithoutWaiting(2.0f, {600, 112, 40, 10});
1489   SetDocumentDimensions({16, 9});
1490
1491   AccessibilityViewportInfo viewport_info;
1492   EXPECT_CALL(pdf_service_, SelectionChanged(gfx::PointF(-8.0f, -20.0f), 40,
1493                                              gfx::PointF(52.0f, 60.0f), 80));
1494   EXPECT_CALL(*accessibility_data_handler_ptr_, SetAccessibilityViewportInfo)
1495       .WillOnce(SaveArg<0>(&viewport_info));
1496   plugin_->SelectionChanged({-20, -40, 60, 80}, {100, 120, 140, 160});
1497
1498   EXPECT_EQ(gfx::Point(), viewport_info.scroll);
1499   pdf_receiver_.FlushForTesting();
1500 }
1501
1502 TEST_F(PdfViewWebPluginTest, ChangeTextSelection) {
1503   ASSERT_FALSE(plugin_->HasSelection());
1504   ASSERT_TRUE(plugin_->SelectionAsText().IsEmpty());
1505   ASSERT_TRUE(plugin_->SelectionAsMarkup().IsEmpty());
1506
1507   static constexpr char kSelectedText[] = "1234";
1508   EXPECT_CALL(*client_ptr_,
1509               TextSelectionChanged(blink::WebString::FromUTF8(kSelectedText), 0,
1510                                    gfx::Range(0, 4)));
1511
1512   plugin_->SetSelectedText(kSelectedText);
1513   EXPECT_TRUE(plugin_->HasSelection());
1514   EXPECT_EQ(kSelectedText, plugin_->SelectionAsText().Utf8());
1515   EXPECT_EQ(kSelectedText, plugin_->SelectionAsMarkup().Utf8());
1516
1517   static constexpr char kEmptyText[] = "";
1518   EXPECT_CALL(*client_ptr_,
1519               TextSelectionChanged(blink::WebString::FromUTF8(kEmptyText), 0,
1520                                    gfx::Range(0, 0)));
1521   plugin_->SetSelectedText(kEmptyText);
1522   EXPECT_FALSE(plugin_->HasSelection());
1523   EXPECT_TRUE(plugin_->SelectionAsText().IsEmpty());
1524   EXPECT_TRUE(plugin_->SelectionAsMarkup().IsEmpty());
1525 }
1526
1527 TEST_F(PdfViewWebPluginTest, FormTextFieldFocusChangeUpdatesTextInputType) {
1528   ASSERT_EQ(blink::WebTextInputType::kWebTextInputTypeNone,
1529             plugin_->GetPluginTextInputType());
1530
1531   ExpectUpdateTextInputState(blink::WebTextInputType::kWebTextInputTypeText);
1532   plugin_->FormFieldFocusChange(PDFEngine::FocusFieldType::kText);
1533
1534   ExpectUpdateTextInputState(blink::WebTextInputType::kWebTextInputTypeNone);
1535   plugin_->FormFieldFocusChange(PDFEngine::FocusFieldType::kNoFocus);
1536
1537   ExpectUpdateTextInputState(blink::WebTextInputType::kWebTextInputTypeText);
1538   plugin_->FormFieldFocusChange(PDFEngine::FocusFieldType::kText);
1539
1540   ExpectUpdateTextInputState(blink::WebTextInputType::kWebTextInputTypeNone);
1541   plugin_->FormFieldFocusChange(PDFEngine::FocusFieldType::kNonText);
1542 }
1543
1544 TEST_F(PdfViewWebPluginTest, SearchString) {
1545   static constexpr char16_t kPattern[] = u"fox";
1546   static constexpr char16_t kTarget[] =
1547       u"The quick brown fox jumped over the lazy Fox";
1548
1549   {
1550     static constexpr PDFEngine::Client::SearchStringResult kExpectation[] = {
1551         {16, 3}};
1552     EXPECT_THAT(
1553         plugin_->SearchString(kTarget, kPattern, /*case_sensitive=*/true),
1554         Pointwise(SearchStringResultEq(), kExpectation));
1555   }
1556   {
1557     static constexpr PDFEngine::Client::SearchStringResult kExpectation[] = {
1558         {16, 3}, {41, 3}};
1559     EXPECT_THAT(
1560         plugin_->SearchString(kTarget, kPattern, /*case_sensitive=*/false),
1561         Pointwise(SearchStringResultEq(), kExpectation));
1562   }
1563 }
1564
1565 TEST_F(PdfViewWebPluginTest, UpdateFocus) {
1566   MockFunction<void(int checkpoint_num)> checkpoint;
1567
1568   {
1569     InSequence sequence;
1570
1571     // Focus false -> true: Triggers updates.
1572     EXPECT_CALL(*client_ptr_, UpdateTextInputState);
1573     EXPECT_CALL(*client_ptr_, UpdateSelectionBounds);
1574     EXPECT_CALL(checkpoint, Call(1));
1575
1576     // Focus true -> true: No updates.
1577     EXPECT_CALL(checkpoint, Call(2));
1578
1579     // Focus true -> false: Triggers updates. `UpdateTextInputState` is called
1580     // twice because it also gets called due to
1581     // `PDFiumEngine::UpdateFocus(false)`.
1582     EXPECT_CALL(*client_ptr_, UpdateTextInputState).Times(2);
1583     EXPECT_CALL(*client_ptr_, UpdateSelectionBounds);
1584     EXPECT_CALL(checkpoint, Call(3));
1585
1586     // Focus false -> false: No updates.
1587     EXPECT_CALL(checkpoint, Call(4));
1588
1589     // Focus false -> true: Triggers updates.
1590     EXPECT_CALL(*client_ptr_, UpdateTextInputState);
1591     EXPECT_CALL(*client_ptr_, UpdateSelectionBounds);
1592   }
1593
1594   // The focus type does not matter in this test.
1595   plugin_->UpdateFocus(/*focused=*/true, blink::mojom::FocusType::kNone);
1596   checkpoint.Call(1);
1597   plugin_->UpdateFocus(/*focused=*/true, blink::mojom::FocusType::kNone);
1598   checkpoint.Call(2);
1599   plugin_->UpdateFocus(/*focused=*/false, blink::mojom::FocusType::kNone);
1600   checkpoint.Call(3);
1601   plugin_->UpdateFocus(/*focused=*/false, blink::mojom::FocusType::kNone);
1602   checkpoint.Call(4);
1603   plugin_->UpdateFocus(/*focused=*/true, blink::mojom::FocusType::kNone);
1604 }
1605
1606 TEST_F(PdfViewWebPluginTest, ShouldDispatchImeEventsToPlugin) {
1607   ASSERT_TRUE(plugin_->ShouldDispatchImeEventsToPlugin());
1608 }
1609
1610 TEST_F(PdfViewWebPluginTest, CaretChange) {
1611   EXPECT_CALL(*engine_ptr_, ZoomUpdated(2.0f));
1612   UpdatePluginGeometry(
1613       /*device_scale=*/2.0f, /*window_rect=*/gfx::Rect(12, 24, 36, 48));
1614   plugin_->CaretChanged(gfx::Rect(10, 20, 30, 40));
1615   EXPECT_EQ(gfx::Rect(28, 20, 30, 40), plugin_->GetPluginCaretBounds());
1616 }
1617
1618 TEST_F(PdfViewWebPluginTest, EnteredEditMode) {
1619   EXPECT_CALL(pdf_service_, SetPluginCanSave(true));
1620   EXPECT_CALL(*client_ptr_, PostMessage).Times(AnyNumber());
1621   EXPECT_CALL(*client_ptr_, PostMessage(base::test::IsJson(R"({
1622     "type": "setIsEditing",
1623   })")));
1624   plugin_->EnteredEditMode();
1625
1626   pdf_receiver_.FlushForTesting();
1627 }
1628
1629 TEST_F(PdfViewWebPluginTest, NotifyNumberOfFindResultsChanged) {
1630   plugin_->StartFind("x", /*case_sensitive=*/false, /*identifier=*/123);
1631
1632   const std::vector<gfx::Rect> tickmarks = {gfx::Rect(1, 2), gfx::Rect(3, 4)};
1633   plugin_->UpdateTickMarks(tickmarks);
1634
1635   EXPECT_CALL(*client_ptr_, ReportFindInPageTickmarks(tickmarks));
1636   EXPECT_CALL(*client_ptr_, ReportFindInPageMatchCount(123, 5, true));
1637   plugin_->NotifyNumberOfFindResultsChanged(/*total=*/5, /*final_result=*/true);
1638 }
1639
1640 TEST_F(PdfViewWebPluginTest, OnDocumentLoadComplete) {
1641   base::Value::Dict metadata;
1642   metadata.Set("fileSize", "0 B");
1643   metadata.Set("linearized", false);
1644   metadata.Set("pageSize", "Varies");
1645   metadata.Set("canSerializeDocument", true);
1646
1647   base::Value::Dict message;
1648   message.Set("type", "metadata");
1649   message.Set("metadataData", std::move(metadata));
1650
1651   EXPECT_CALL(*client_ptr_, PostMessage);
1652   EXPECT_CALL(*client_ptr_, PostMessage(Eq(std::ref(message))));
1653   plugin_->DocumentLoadComplete();
1654 }
1655
1656 class PdfViewWebPluginWithDocInfoTest : public PdfViewWebPluginTest {
1657  protected:
1658   class TestPDFiumEngineWithDocInfo : public TestPDFiumEngine {
1659    public:
1660     explicit TestPDFiumEngineWithDocInfo(PDFEngine::Client* client)
1661         : TestPDFiumEngine(client) {
1662       InitializeDocumentAttachments();
1663       InitializeDocumentMetadata();
1664     }
1665
1666     base::Value::List GetBookmarks() override {
1667       // Create `bookmark1` which navigates to an in-doc position. This bookmark
1668       // will be in the top-level bookmark list.
1669       base::Value::Dict bookmark1;
1670       bookmark1.Set("title", "Bookmark 1");
1671       bookmark1.Set("page", 2);
1672       bookmark1.Set("x", 10);
1673       bookmark1.Set("y", 20);
1674       bookmark1.Set("zoom", 2.0);
1675
1676       // Create `bookmark2` which navigates to a web page. This bookmark will be
1677       // a child of `bookmark1`.
1678       base::Value::Dict bookmark2;
1679       bookmark2.Set("title", "Bookmark 2");
1680       bookmark2.Set("uri", "test.com");
1681
1682       base::Value::List children_of_bookmark1;
1683       children_of_bookmark1.Append(std::move(bookmark2));
1684       bookmark1.Set("children", std::move(children_of_bookmark1));
1685
1686       // Create the top-level bookmark list.
1687       base::Value::List bookmarks;
1688       bookmarks.Append(std::move(bookmark1));
1689       return bookmarks;
1690     }
1691
1692     absl::optional<gfx::Size> GetUniformPageSizePoints() override {
1693       return gfx::Size(1000, 1200);
1694     }
1695
1696    private:
1697     void InitializeDocumentAttachments() {
1698       doc_attachment_info_list().resize(3);
1699
1700       // A regular attachment.
1701       doc_attachment_info_list()[0].name = u"attachment1.txt";
1702       doc_attachment_info_list()[0].creation_date = u"D:20170712214438-07'00'";
1703       doc_attachment_info_list()[0].modified_date = u"D:20160115091400";
1704       doc_attachment_info_list()[0].is_readable = true;
1705       doc_attachment_info_list()[0].size_bytes = 13u;
1706
1707       // An unreadable attachment.
1708       doc_attachment_info_list()[1].name = u"attachment2.pdf";
1709       doc_attachment_info_list()[1].is_readable = false;
1710
1711       // A readable attachment that exceeds download size limit.
1712       doc_attachment_info_list()[2].name = u"attachment3.mov";
1713       doc_attachment_info_list()[2].is_readable = true;
1714       doc_attachment_info_list()[2].size_bytes =
1715           PdfViewWebPlugin::kMaximumSavedFileSize + 1;
1716     }
1717
1718     void InitializeDocumentMetadata() {
1719       metadata().version = PdfVersion::k1_7;
1720       metadata().size_bytes = 13u;
1721       metadata().page_count = 13u;
1722       metadata().linearized = true;
1723       metadata().has_attachments = true;
1724       metadata().form_type = FormType::kAcroForm;
1725       metadata().title = "Title";
1726       metadata().author = "Author";
1727       metadata().subject = "Subject";
1728       metadata().keywords = "Keywords";
1729       metadata().creator = "Creator";
1730       metadata().producer = "Producer";
1731       ASSERT_TRUE(base::Time::FromUTCString("2021-05-04 11:12:13",
1732                                             &metadata().creation_date));
1733       ASSERT_TRUE(base::Time::FromUTCString("2021-06-04 15:16:17",
1734                                             &metadata().mod_date));
1735     }
1736   };
1737
1738   static base::Value::Dict CreateExpectedAttachmentsResponse() {
1739     base::Value::List attachments;
1740     {
1741       base::Value::Dict attachment;
1742       attachment.Set("name", "attachment1.txt");
1743       attachment.Set("size", 13);
1744       attachment.Set("readable", true);
1745       attachments.Append(std::move(attachment));
1746     }
1747     {
1748       base::Value::Dict attachment;
1749       attachment.Set("name", "attachment2.pdf");
1750       attachment.Set("size", 0);
1751       attachment.Set("readable", false);
1752       attachments.Append(std::move(attachment));
1753     }
1754     {
1755       base::Value::Dict attachment;
1756       attachment.Set("name", "attachment3.mov");
1757       attachment.Set("size", -1);
1758       attachment.Set("readable", true);
1759       attachments.Append(std::move(attachment));
1760     }
1761
1762     base::Value::Dict message;
1763     message.Set("type", "attachments");
1764     message.Set("attachmentsData", std::move(attachments));
1765     return message;
1766   }
1767
1768   static base::Value::Dict CreateExpectedBookmarksResponse(
1769       base::Value::List bookmarks) {
1770     base::Value::Dict message;
1771     message.Set("type", "bookmarks");
1772     message.Set("bookmarksData", std::move(bookmarks));
1773     return message;
1774   }
1775
1776   static base::Value::Dict CreateExpectedMetadataResponse() {
1777     base::Value::Dict metadata;
1778     metadata.Set("version", "1.7");
1779     metadata.Set("fileSize", "13 B");
1780     metadata.Set("linearized", true);
1781
1782     metadata.Set("title", "Title");
1783     metadata.Set("author", "Author");
1784     metadata.Set("subject", "Subject");
1785     metadata.Set("keywords", "Keywords");
1786     metadata.Set("creator", "Creator");
1787     metadata.Set("producer", "Producer");
1788     metadata.Set("creationDate", "5/4/21, 4:12:13 AM");
1789     metadata.Set("modDate", "6/4/21, 8:16:17 AM");
1790     metadata.Set("pageSize", "13.89 × 16.67 in (portrait)");
1791     metadata.Set("canSerializeDocument", true);
1792
1793     base::Value::Dict message;
1794     message.Set("type", "metadata");
1795     message.Set("metadataData", std::move(metadata));
1796     return message;
1797   }
1798
1799   void SetUpClient() override {
1800     EXPECT_CALL(*client_ptr_, CreateEngine).WillOnce([this]() {
1801       auto engine = std::make_unique<NiceMock<TestPDFiumEngineWithDocInfo>>(
1802           plugin_.get());
1803       engine_ptr_ = engine.get();
1804       return engine;
1805     });
1806   }
1807 };
1808
1809 TEST_F(PdfViewWebPluginWithDocInfoTest, OnDocumentLoadComplete) {
1810   const base::Value::Dict expect_attachments =
1811       CreateExpectedAttachmentsResponse();
1812   const base::Value::Dict expect_bookmarks =
1813       CreateExpectedBookmarksResponse(engine_ptr_->GetBookmarks());
1814   const base::Value::Dict expect_metadata = CreateExpectedMetadataResponse();
1815   EXPECT_CALL(*client_ptr_, PostMessage);
1816   EXPECT_CALL(*client_ptr_, PostMessage(Eq(std::ref(expect_attachments))));
1817   EXPECT_CALL(*client_ptr_, PostMessage(Eq(std::ref(expect_bookmarks))));
1818   EXPECT_CALL(*client_ptr_, PostMessage(Eq(std::ref(expect_metadata))));
1819   plugin_->DocumentLoadComplete();
1820 }
1821
1822 class PdfViewWebPluginSaveTest : public PdfViewWebPluginTest {
1823  protected:
1824   static void AddDataToValue(base::span<const uint8_t> data,
1825                              base::Value& value) {
1826     value.GetDict().Set("dataToSave", base::Value(data));
1827   }
1828
1829   void SetUpClient() override {
1830     // Ignore non-"saveData" `PdfViewWebPlugin::Client::PostMessage()` calls.
1831     EXPECT_CALL(*client_ptr_, PostMessage)
1832         .WillRepeatedly([](const base::Value::Dict& message) {
1833           EXPECT_NE("saveData", *message.FindString("type"));
1834         });
1835   }
1836 };
1837
1838 #if BUILDFLAG(ENABLE_INK)
1839 TEST_F(PdfViewWebPluginSaveTest, AnnotationInNonEditMode) {
1840   base::Value expected_response = base::test::ParseJson(R"({
1841     "type": "saveData",
1842     "token": "annotation-in-non-edit-mode",
1843     "fileName": "example.pdf",
1844     "editModeForTesting": false,
1845   })");
1846   AddDataToValue(base::make_span(TestPDFiumEngine::kLoadedData),
1847                  expected_response);
1848
1849   EXPECT_CALL(pdf_service_, SetPluginCanSave(true));
1850   ExpectUpdateTextInputState(blink::WebTextInputType::kWebTextInputTypeNone);
1851   EXPECT_CALL(*client_ptr_, PostMessage(base::test::IsJson(expected_response)));
1852
1853   plugin_->OnMessage(ParseMessage(R"({
1854     "type": "save",
1855     "saveRequestType": 0,
1856     "token": "annotation-in-non-edit-mode",
1857   })"));
1858
1859   pdf_receiver_.FlushForTesting();
1860 }
1861
1862 TEST_F(PdfViewWebPluginSaveTest, AnnotationInEditMode) {
1863   plugin_->EnteredEditMode();
1864   pdf_receiver_.FlushForTesting();
1865
1866   base::Value expected_response = base::test::ParseJson(R"({
1867     "type": "saveData",
1868     "token": "annotation-in-edit-mode",
1869     "fileName": "example.pdf",
1870     "editModeForTesting": true,
1871   })");
1872   AddDataToValue(base::make_span(TestPDFiumEngine::kSaveData),
1873                  expected_response);
1874
1875   EXPECT_CALL(pdf_service_, SetPluginCanSave(true));
1876   ExpectUpdateTextInputState(blink::WebTextInputType::kWebTextInputTypeNone);
1877   EXPECT_CALL(*client_ptr_, PostMessage(base::test::IsJson(expected_response)));
1878
1879   plugin_->OnMessage(ParseMessage(R"({
1880     "type": "save",
1881     "saveRequestType": 0,
1882     "token": "annotation-in-edit-mode",
1883   })"));
1884
1885   pdf_receiver_.FlushForTesting();
1886 }
1887 #endif  // BUILDFLAG(ENABLE_INK)
1888
1889 TEST_F(PdfViewWebPluginSaveTest, OriginalInNonEditMode) {
1890   {
1891     InSequence pdf_service_sequence;
1892
1893     EXPECT_CALL(pdf_service_, SetPluginCanSave(false));
1894     EXPECT_CALL(
1895         pdf_service_,
1896         SaveUrlAs(GURL(kPdfUrl), network::mojom::ReferrerPolicy::kDefault));
1897     EXPECT_CALL(pdf_service_, SetPluginCanSave(false));
1898   }
1899
1900   ExpectUpdateTextInputState(blink::WebTextInputType::kWebTextInputTypeNone);
1901   EXPECT_CALL(*client_ptr_, PostMessage(base::test::IsJson(R"({
1902     "type": "consumeSaveToken",
1903     "token": "original-in-non-edit-mode",
1904   })")));
1905
1906   plugin_->OnMessage(ParseMessage(R"({
1907     "type": "save",
1908     "saveRequestType": 1,
1909     "token": "original-in-non-edit-mode",
1910   })"));
1911
1912   pdf_receiver_.FlushForTesting();
1913 }
1914
1915 TEST_F(PdfViewWebPluginSaveTest, OriginalInEditMode) {
1916   plugin_->EnteredEditMode();
1917   pdf_receiver_.FlushForTesting();
1918
1919   {
1920     InSequence pdf_service_sequence;
1921
1922     EXPECT_CALL(pdf_service_, SetPluginCanSave(false));
1923     EXPECT_CALL(
1924         pdf_service_,
1925         SaveUrlAs(GURL(kPdfUrl), network::mojom::ReferrerPolicy::kDefault));
1926     EXPECT_CALL(pdf_service_, SetPluginCanSave(true));
1927   }
1928
1929   ExpectUpdateTextInputState(blink::WebTextInputType::kWebTextInputTypeNone);
1930   EXPECT_CALL(*client_ptr_, PostMessage(base::test::IsJson(R"({
1931     "type": "consumeSaveToken",
1932     "token": "original-in-edit-mode",
1933   })")));
1934
1935   plugin_->OnMessage(ParseMessage(R"({
1936     "type": "save",
1937     "saveRequestType": 1,
1938     "token": "original-in-edit-mode",
1939   })"));
1940
1941   pdf_receiver_.FlushForTesting();
1942 }
1943
1944 #if BUILDFLAG(ENABLE_INK)
1945 TEST_F(PdfViewWebPluginSaveTest, EditedInNonEditMode) {
1946   base::Value expected_response = base::test::ParseJson(R"({
1947     "type": "saveData",
1948     "token": "edited-in-non-edit-mode",
1949     "fileName": "example.pdf",
1950     "editModeForTesting": false,
1951   })");
1952   AddDataToValue(base::make_span(TestPDFiumEngine::kLoadedData),
1953                  expected_response);
1954
1955   ExpectUpdateTextInputState(blink::WebTextInputType::kWebTextInputTypeNone);
1956   EXPECT_CALL(*client_ptr_, PostMessage(base::test::IsJson(expected_response)));
1957
1958   plugin_->OnMessage(ParseMessage(R"({
1959     "type": "save",
1960     "saveRequestType": 2,
1961     "token": "edited-in-non-edit-mode",
1962   })"));
1963 }
1964 #endif  // BUILDFLAG(ENABLE_INK)
1965
1966 TEST_F(PdfViewWebPluginSaveTest, EditedInEditMode) {
1967   plugin_->EnteredEditMode();
1968
1969   base::Value expected_response = base::test::ParseJson(R"({
1970     "type": "saveData",
1971     "token": "edited-in-edit-mode",
1972     "fileName": "example.pdf",
1973     "editModeForTesting": true,
1974   })");
1975   AddDataToValue(base::make_span(TestPDFiumEngine::kSaveData),
1976                  expected_response);
1977
1978   ExpectUpdateTextInputState(blink::WebTextInputType::kWebTextInputTypeNone);
1979   EXPECT_CALL(*client_ptr_, PostMessage(base::test::IsJson(expected_response)));
1980
1981   plugin_->OnMessage(ParseMessage(R"({
1982     "type": "save",
1983     "saveRequestType": 2,
1984     "token": "edited-in-edit-mode",
1985   })"));
1986 }
1987
1988 class PdfViewWebPluginSubmitFormTest
1989     : public PdfViewWebPluginWithoutInitializeTest {
1990  protected:
1991   void SubmitForm(const std::string& url,
1992                   base::StringPiece form_data = "data") {
1993     EXPECT_TRUE(plugin_->InitializeForTesting());
1994
1995     EXPECT_CALL(*client_ptr_, CreateAssociatedURLLoader).WillOnce([this]() {
1996       auto associated_loader =
1997           std::make_unique<NiceMock<MockWebAssociatedURLLoader>>();
1998       EXPECT_CALL(*associated_loader, LoadAsynchronously)
1999           .WillOnce([this](const blink::WebURLRequest& request,
2000                            blink::WebAssociatedURLLoaderClient* /*client*/) {
2001             // TODO(crbug.com/1322928): The `UrlLoader` created by `LoadUrl()`
2002             // and `SubmitForm()` shouldn't use different ownership semantics.
2003             // The loader created by `SubmitForm()` is owned by the plugin, and
2004             // cannot leak past the destruction of the plugin.
2005             request_.CopyFrom(request);
2006           });
2007       return associated_loader;
2008     });
2009
2010     plugin_->SubmitForm(url, form_data.data(), form_data.size());
2011   }
2012
2013   void SubmitFailingForm(const std::string& url) {
2014     EXPECT_TRUE(plugin_->InitializeForTesting());
2015
2016     EXPECT_CALL(*client_ptr_, CreateAssociatedURLLoader).Times(0);
2017
2018     constexpr base::StringPiece kFormData = "form data";
2019     plugin_->SubmitForm(url, kFormData.data(), kFormData.size());
2020   }
2021
2022   blink::WebURLRequest request_;
2023 };
2024
2025 TEST_F(PdfViewWebPluginSubmitFormTest, RequestMethod) {
2026   SetUpPluginWithUrl("https://www.example.com/path/to/the.pdf");
2027
2028   SubmitForm(/*url=*/"");
2029
2030   EXPECT_EQ(request_.HttpMethod().Utf8(), "POST");
2031 }
2032
2033 TEST_F(PdfViewWebPluginSubmitFormTest, RequestBody) {
2034   SetUpPluginWithUrl("https://www.example.com/path/to/the.pdf");
2035
2036   constexpr base::StringPiece kFormData = "form data";
2037   SubmitForm(/*url=*/"", kFormData);
2038
2039   blink::WebHTTPBody::Element element;
2040   EXPECT_EQ(request_.HttpBody().ElementCount(), 1u);
2041   ASSERT_TRUE(request_.HttpBody().ElementAt(0, element));
2042   ASSERT_EQ(element.type, blink::HTTPBodyElementType::kTypeData);
2043   EXPECT_THAT(element.data.Copy(), testing::ElementsAreArray(kFormData));
2044 }
2045
2046 TEST_F(PdfViewWebPluginSubmitFormTest, RelativeUrl) {
2047   SetUpPluginWithUrl("https://www.example.com/path/to/the.pdf");
2048
2049   SubmitForm("relative_endpoint");
2050
2051   EXPECT_EQ(request_.Url().GetString().Utf8(),
2052             "https://www.example.com/path/to/relative_endpoint");
2053 }
2054
2055 TEST_F(PdfViewWebPluginSubmitFormTest, NoRelativeUrl) {
2056   SetUpPluginWithUrl("https://www.example.com/path/to/the.pdf");
2057
2058   SubmitForm("");
2059
2060   EXPECT_EQ(request_.Url().GetString().Utf8(),
2061             "https://www.example.com/path/to/the.pdf");
2062 }
2063
2064 TEST_F(PdfViewWebPluginSubmitFormTest, AbsoluteUrl) {
2065   SetUpPluginWithUrl("https://a.example.com/path/to/the.pdf");
2066
2067   SubmitForm("https://b.example.com/relative_endpoint");
2068
2069   EXPECT_EQ(request_.Url().GetString().Utf8(),
2070             "https://b.example.com/relative_endpoint");
2071 }
2072
2073 TEST_F(PdfViewWebPluginSubmitFormTest, RelativeUrlInvalidDocumentUrl) {
2074   SetUpPluginWithUrl("https://www.%B%Ad.com/path/to/the.pdf");
2075
2076   SubmitFailingForm("relative_endpoint");
2077 }
2078
2079 TEST_F(PdfViewWebPluginSubmitFormTest, AbsoluteUrlInvalidDocumentUrl) {
2080   SetUpPluginWithUrl("https://www.%B%Ad.com/path/to/the.pdf");
2081
2082   SubmitFailingForm("https://wwww.example.com");
2083 }
2084
2085 class PdfViewWebPluginPrintTest : public PdfViewWebPluginTest {
2086  protected:
2087   void SetUp() override {
2088     PdfViewWebPluginTest::SetUp();
2089
2090     // Size must be at least 1 for conversion to `SkMemoryStream`.
2091     ON_CALL(*engine_ptr_, PrintPages)
2092         .WillByDefault(Return(std::vector<uint8_t>(1)));
2093
2094     canvas_.sk_canvas()->SetPrintingMetafile(&metafile_);
2095   }
2096
2097   printing::MetafileSkia metafile_;
2098 };
2099
2100 TEST_F(PdfViewWebPluginPrintTest, HighQuality) {
2101   EXPECT_CALL(*engine_ptr_,
2102               HasPermission(DocumentPermission::kPrintHighQuality))
2103       .WillRepeatedly(Return(true));
2104   EXPECT_CALL(*engine_ptr_, HasPermission(DocumentPermission::kPrintLowQuality))
2105       .WillRepeatedly(Return(true));
2106   ASSERT_EQ(static_cast<int>(TestPDFiumEngine::kPageNumber),
2107             plugin_->PrintBegin(blink::WebPrintParams()));
2108
2109   EXPECT_CALL(
2110       *engine_ptr_,
2111       PrintPages(ElementsAre(0),
2112                  Field(&blink::WebPrintParams::rasterize_pdf, IsFalse())));
2113   plugin_->PrintPage(0, canvas_.sk_canvas());
2114   plugin_->PrintEnd();
2115 }
2116
2117 TEST_F(PdfViewWebPluginPrintTest, HighQualityRasterized) {
2118   EXPECT_CALL(*engine_ptr_,
2119               HasPermission(DocumentPermission::kPrintHighQuality))
2120       .WillRepeatedly(Return(true));
2121   EXPECT_CALL(*engine_ptr_, HasPermission(DocumentPermission::kPrintLowQuality))
2122       .WillRepeatedly(Return(true));
2123
2124   blink::WebPrintParams params;
2125   params.rasterize_pdf = true;
2126   ASSERT_EQ(static_cast<int>(TestPDFiumEngine::kPageNumber),
2127             plugin_->PrintBegin(params));
2128
2129   EXPECT_CALL(
2130       *engine_ptr_,
2131       PrintPages(ElementsAre(0),
2132                  Field(&blink::WebPrintParams::rasterize_pdf, IsTrue())));
2133   plugin_->PrintPage(0, canvas_.sk_canvas());
2134   plugin_->PrintEnd();
2135 }
2136
2137 // Regression test for crbug.com/1307219.
2138 TEST_F(PdfViewWebPluginPrintTest, LowQuality) {
2139   EXPECT_CALL(*engine_ptr_,
2140               HasPermission(DocumentPermission::kPrintHighQuality))
2141       .WillRepeatedly(Return(false));
2142   EXPECT_CALL(*engine_ptr_, HasPermission(DocumentPermission::kPrintLowQuality))
2143       .WillRepeatedly(Return(true));
2144   ASSERT_EQ(static_cast<int>(TestPDFiumEngine::kPageNumber),
2145             plugin_->PrintBegin(blink::WebPrintParams()));
2146
2147   EXPECT_CALL(
2148       *engine_ptr_,
2149       PrintPages(ElementsAre(0),
2150                  Field(&blink::WebPrintParams::rasterize_pdf, IsTrue())));
2151   plugin_->PrintPage(0, canvas_.sk_canvas());
2152   plugin_->PrintEnd();
2153 }
2154
2155 // Regression test for crbug.com/1307219.
2156 TEST_F(PdfViewWebPluginPrintTest, LowQualityRasterized) {
2157   EXPECT_CALL(*engine_ptr_,
2158               HasPermission(DocumentPermission::kPrintHighQuality))
2159       .WillRepeatedly(Return(false));
2160   EXPECT_CALL(*engine_ptr_, HasPermission(DocumentPermission::kPrintLowQuality))
2161       .WillRepeatedly(Return(true));
2162
2163   blink::WebPrintParams params;
2164   params.rasterize_pdf = true;
2165   ASSERT_EQ(static_cast<int>(TestPDFiumEngine::kPageNumber),
2166             plugin_->PrintBegin(params));
2167
2168   EXPECT_CALL(
2169       *engine_ptr_,
2170       PrintPages(ElementsAre(0),
2171                  Field(&blink::WebPrintParams::rasterize_pdf, IsTrue())));
2172   plugin_->PrintPage(0, canvas_.sk_canvas());
2173   plugin_->PrintEnd();
2174 }
2175
2176 TEST_F(PdfViewWebPluginPrintTest, Disabled) {
2177   EXPECT_EQ(0, plugin_->PrintBegin(blink::WebPrintParams()));
2178 }
2179
2180 TEST_F(PdfViewWebPluginPrintTest, DisabledRasterized) {
2181   blink::WebPrintParams params;
2182   params.rasterize_pdf = true;
2183   EXPECT_EQ(0, plugin_->PrintBegin(params));
2184 }
2185
2186 class PdfViewWebPluginPrintPreviewTest : public PdfViewWebPluginTest {
2187  protected:
2188   void SetUpClient() override {
2189     EXPECT_CALL(*client_ptr_, GetEmbedderOriginString)
2190         .WillRepeatedly(Return("chrome://print/"));
2191   }
2192 };
2193
2194 TEST_F(PdfViewWebPluginPrintPreviewTest, HandleResetPrintPreviewModeMessage) {
2195   EXPECT_CALL(*client_ptr_, CreateEngine)
2196       .WillOnce([](PDFEngine::Client* client,
2197                    PDFiumFormFiller::ScriptOption script_option) {
2198         EXPECT_EQ(PDFiumFormFiller::ScriptOption::kNoJavaScript, script_option);
2199
2200         auto engine = std::make_unique<NiceMock<TestPDFiumEngine>>(client);
2201         EXPECT_CALL(*engine, ZoomUpdated);
2202         EXPECT_CALL(*engine, PageOffsetUpdated);
2203         EXPECT_CALL(*engine, PluginSizeUpdated);
2204         EXPECT_CALL(*engine, SetGrayscale(false));
2205         return engine;
2206       });
2207
2208   plugin_->OnMessage(ParseMessage(R"({
2209     "type": "resetPrintPreviewMode",
2210     "url": "chrome-untrusted://print/0/0/print.pdf",
2211     "grayscale": false,
2212     "pageCount": 1,
2213   })"));
2214 }
2215
2216 TEST_F(PdfViewWebPluginPrintPreviewTest,
2217        HandleResetPrintPreviewModeMessageSetGrayscale) {
2218   EXPECT_CALL(*client_ptr_, CreateEngine)
2219       .WillOnce([](PDFEngine::Client* client,
2220                    PDFiumFormFiller::ScriptOption /*script_option*/) {
2221         auto engine = std::make_unique<NiceMock<TestPDFiumEngine>>(client);
2222         EXPECT_CALL(*engine, SetGrayscale(true));
2223         return engine;
2224       });
2225
2226   plugin_->OnMessage(ParseMessage(R"({
2227     "type": "resetPrintPreviewMode",
2228     "url": "chrome-untrusted://print/0/0/print.pdf",
2229     "grayscale": true,
2230     "pageCount": 1,
2231   })"));
2232 }
2233
2234 TEST_F(PdfViewWebPluginPrintPreviewTest, DocumentLoadComplete) {
2235   plugin_->OnMessage(ParseMessage(R"({
2236     "type": "resetPrintPreviewMode",
2237     "url": "chrome-untrusted://print/0/0/print.pdf",
2238     "grayscale": false,
2239     "pageCount": 1,
2240   })"));
2241
2242   EXPECT_CALL(*client_ptr_, RecordComputedAction("PDF.LoadSuccess"));
2243   EXPECT_CALL(*client_ptr_, PostMessage);
2244   EXPECT_CALL(*client_ptr_, PostMessage(base::test::IsJson(R"({
2245     "type": "formFocusChange",
2246     "focused": false,
2247   })")));
2248   ExpectUpdateTextInputState(blink::WebTextInputType::kWebTextInputTypeNone);
2249   EXPECT_CALL(*client_ptr_, PostMessage(base::test::IsJson(R"({
2250     "type": "printPreviewLoaded",
2251   })")));
2252   EXPECT_CALL(*accessibility_data_handler_ptr_, SetAccessibilityDocInfo)
2253       .Times(0);
2254   EXPECT_CALL(*client_ptr_, DidStopLoading).Times(0);
2255   EXPECT_CALL(pdf_service_, UpdateContentRestrictions).Times(0);
2256   plugin_->DocumentLoadComplete();
2257
2258   EXPECT_EQ(PdfViewWebPlugin::DocumentLoadState::kComplete,
2259             plugin_->document_load_state_for_testing());
2260   pdf_receiver_.FlushForTesting();
2261 }
2262
2263 TEST_F(PdfViewWebPluginPrintPreviewTest,
2264        DocumentLoadProgressResetByResetPrintPreviewModeMessage) {
2265   plugin_->DocumentLoadProgress(2, 100);
2266
2267   plugin_->OnMessage(ParseMessage(R"({
2268     "type": "resetPrintPreviewMode",
2269     "url": "chrome-untrusted://print/123/0/print.pdf",
2270     "grayscale": false,
2271     "pageCount": 2,
2272   })"));
2273
2274   EXPECT_CALL(*client_ptr_, PostMessage(base::test::IsJson(R"({
2275     "type": "loadProgress",
2276     "progress": 3.0,
2277   })")));
2278   plugin_->DocumentLoadProgress(3, 100);
2279 }
2280
2281 TEST_F(PdfViewWebPluginPrintPreviewTest,
2282        DocumentLoadProgressNotResetByLoadPreviewPageMessage) {
2283   plugin_->OnMessage(ParseMessage(R"({
2284     "type": "resetPrintPreviewMode",
2285     "url": "chrome-untrusted://print/123/0/print.pdf",
2286     "grayscale": false,
2287     "pageCount": 2,
2288   })"));
2289
2290   plugin_->DocumentLoadProgress(2, 100);
2291
2292   plugin_->OnMessage(ParseMessage(R"({
2293     "type": "loadPreviewPage",
2294     "url": "chrome-untrusted://print/123/1/print.pdf",
2295     "index": 1,
2296   })"));
2297
2298   EXPECT_CALL(*client_ptr_, PostMessage).Times(0);
2299   plugin_->DocumentLoadProgress(3, 100);
2300 }
2301
2302 TEST_F(PdfViewWebPluginPrintPreviewTest,
2303        HandleViewportMessageScrollRightToLeft) {
2304   EXPECT_CALL(*engine_ptr_, ApplyDocumentLayout)
2305       .WillRepeatedly(Return(gfx::Size(16, 9)));
2306   EXPECT_CALL(*engine_ptr_, ScrolledToXPosition(14));
2307   EXPECT_CALL(*engine_ptr_, ScrolledToYPosition(3));
2308
2309   plugin_->OnMessage(ParseMessage(R"({
2310     "type": "viewport",
2311     "userInitiated": false,
2312     "zoom": 1,
2313     "layoutOptions": {
2314       "direction": 1,
2315       "defaultPageOrientation": 0,
2316       "twoUpViewEnabled": false,
2317     },
2318     "xOffset": -2,
2319     "yOffset": 3,
2320     "pinchPhase": 0,
2321   })"));
2322 }
2323
2324 }  // namespace chrome_pdf