chromium/pdf/pdf_view_web_plugin_unittest.cc

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "pdf/pdf_view_web_plugin.h"

#include <stdint.h>

#include <functional>
#include <memory>
#include <string>
#include <string_view>
#include <utility>
#include <vector>

#include "base/containers/span.h"
#include "base/location.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/values_test_util.h"
#include "base/time/time.h"
#include "base/values.h"
#include "cc/paint/paint_canvas.h"
#include "cc/test/pixel_comparator.h"
#include "cc/test/pixel_test_utils.h"
#include "mojo/public/cpp/bindings/associated_receiver.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "net/cookies/site_for_cookies.h"
#include "pdf/accessibility_structs.h"
#include "pdf/buildflags.h"
#include "pdf/content_restriction.h"
#include "pdf/document_layout.h"
#include "pdf/mojom/pdf.mojom.h"
#include "pdf/paint_ready_rect.h"
#include "pdf/pdf_accessibility_data_handler.h"
#include "pdf/pdf_accessibility_image_fetcher.h"
#include "pdf/pdf_features.h"
#include "pdf/test/mock_web_associated_url_loader.h"
#include "pdf/test/pdf_ink_test_helpers.h"
#include "pdf/test/test_helpers.h"
#include "pdf/test/test_pdfium_engine.h"
#include "printing/metafile_skia.h"
#include "services/network/public/mojom/referrer_policy.mojom-shared.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/input/web_coalesced_input_event.h"
#include "third_party/blink/public/common/input/web_input_event.h"
#include "third_party/blink/public/common/input/web_keyboard_event.h"
#include "third_party/blink/public/common/input/web_mouse_event.h"
#include "third_party/blink/public/common/loader/http_body_element_type.h"
#include "third_party/blink/public/platform/web_data.h"
#include "third_party/blink/public/platform/web_http_body.h"
#include "third_party/blink/public/platform/web_http_header_visitor.h"
#include "third_party/blink/public/platform/web_input_event_result.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_text_input_type.h"
#include "third_party/blink/public/platform/web_url.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/public/platform/web_url_response.h"
#include "third_party/blink/public/web/web_associated_url_loader.h"
#include "third_party/blink/public/web/web_associated_url_loader_client.h"
#include "third_party/blink/public/web/web_plugin_container.h"
#include "third_party/blink/public/web/web_plugin_params.h"
#include "third_party/blink/public/web/web_print_params.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "ui/base/cursor/cursor.h"
#include "ui/events/blink/blink_event_util.h"
#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/events/keycodes/dom/dom_key.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/geometry/skia_conversions.h"
#include "ui/gfx/geometry/vector2d_f.h"
#include "ui/gfx/range/range.h"
#include "ui/latency/latency_info.h"
#include "url/gurl.h"

namespace chrome_pdf {

namespace {

AnyNumber;
ElementsAre;
ElementsAreArray;
Eq;
InSequence;
IsEmpty;
IsFalse;
IsTrue;
MockFunction;
NiceMock;
Pointwise;
Return;
SaveArg;
SizeIs;

// `kCanvasSize` needs to be big enough to hold plugin's snapshots during
// testing.
constexpr gfx::Size kCanvasSize(100, 100);

// Note: Make sure `kDefaultColor` is different from `kPaintColor` and the
// plugin's background color. This will help identify bitmap changes after
// painting.
constexpr SkColor kDefaultColor =;

constexpr SkColor kPaintColor =;

struct PaintParams {};

MATCHER(SearchStringResultEq, "") {}

MATCHER_P(IsExpectedImeKeyEvent, expected_text, "") {}

base::Value::Dict ParseMessage(std::string_view json) {}

// Generates the expected `SkBitmap` with `paint_color` filled in the expected
// clipped area and `kDefaultColor` as the background color.
SkBitmap GenerateExpectedBitmapForPaint(const gfx::Rect& expected_clipped_rect,
                                        SkColor paint_color) {}

class MockHeaderVisitor : public blink::WebHTTPHeaderVisitor {};

class MockPdfAccessibilityDataHandler : public PdfAccessibilityDataHandler {};

class FakePdfViewWebPluginClient : public PdfViewWebPlugin::Client {};

class FakePdfHost : public pdf::mojom::PdfHost {};

}  // namespace

class PdfViewWebPluginWithoutInitializeTest
    : public testing::TestWithParam<bool> {};

class PdfViewWebPluginTest : public PdfViewWebPluginWithoutInitializeTest {};

class PdfViewWebPluginFullFrameTest : public PdfViewWebPluginTest {};

TEST_F(PdfViewWebPluginWithoutInitializeTest, Initialize) {}

TEST_F(PdfViewWebPluginWithoutInitializeTest, InitializeWithEmptyUrl) {}

TEST_F(PdfViewWebPluginWithoutInitializeTest, InitializeForPrintPreview) {}

TEST_F(PdfViewWebPluginTest, CreateUrlLoader) {}

TEST_F(PdfViewWebPluginFullFrameTest, CreateUrlLoader) {}

TEST_F(PdfViewWebPluginFullFrameTest, CreateUrlLoaderMultipleTimes) {}

TEST_F(PdfViewWebPluginFullFrameTest, CreateUrlLoaderAfterDocumentLoadFailed) {}

TEST_F(PdfViewWebPluginTest, DocumentLoadComplete) {}

TEST_F(PdfViewWebPluginFullFrameTest, DocumentLoadComplete) {}

TEST_F(PdfViewWebPluginTest, DocumentLoadFailed) {}

TEST_F(PdfViewWebPluginFullFrameTest, DocumentLoadFailed) {}

TEST_F(PdfViewWebPluginTest, DocumentHasUnsupportedFeature) {}

TEST_F(PdfViewWebPluginTest, DocumentHasUnsupportedFeatureWithRepeatedFeature) {}

TEST_F(PdfViewWebPluginFullFrameTest, DocumentHasUnsupportedFeature) {}

TEST_F(PdfViewWebPluginFullFrameTest,
       DocumentHasUnsupportedFeatureWithRepeatedFeature) {}

TEST_F(PdfViewWebPluginTest, DocumentLoadProgress) {}

TEST_F(PdfViewWebPluginTest, DocumentLoadProgressIgnoreSmall) {}

TEST_F(PdfViewWebPluginTest, DocumentLoadProgressMultipleSmall) {}

TEST_F(PdfViewWebPluginTest, EnableAccessibilityBeforeDocumentLoadComplete) {}

TEST_F(PdfViewWebPluginTest,
       EnableAccessibilityBeforeDocumentLoadCompleteRepeated) {}

TEST_F(PdfViewWebPluginTest, EnableAccessibilityAfterDocumentLoadComplete) {}

TEST_F(PdfViewWebPluginTest,
       EnableAccessibilityAfterDocumentLoadCompleteRepeated) {}

TEST_F(PdfViewWebPluginTest,
       LoadOrReloadAccessibilityBeforeDocumentLoadComplete) {}

TEST_F(PdfViewWebPluginTest,
       LoadOrReloadAccessibilityBeforeDocumentLoadCompleteRepeated) {}

TEST_F(PdfViewWebPluginTest,
       LoadOrReloadAccessibilityAfterDocumentLoadComplete) {}

TEST_F(PdfViewWebPluginTest,
       LoadOrReloadAccessibilityAfterDocumentLoadCompleteRepeated) {}

TEST_F(PdfViewWebPluginTest,
       LoadOrReloadAccessibilityResetsAccessibilityPageIndex) {}

TEST_F(PdfViewWebPluginTest, GetContentRestrictionsWithNoPermissions) {}

TEST_F(PdfViewWebPluginTest, GetContentRestrictionsWithCopyAllowed) {}

TEST_F(PdfViewWebPluginTest, GetContentRestrictionsWithPrintLowQualityAllowed) {}

TEST_F(PdfViewWebPluginTest,
       GetContentRestrictionsWithCopyAndPrintLowQualityAllowed) {}

TEST_F(PdfViewWebPluginTest, GetContentRestrictionsWithPrintAllowed) {}

TEST_F(PdfViewWebPluginTest, GetContentRestrictionsWithCopyAndPrintAllowed) {}

TEST_F(PdfViewWebPluginTest, GetAccessibilityDocInfoWithNoPermissions) {}

TEST_F(PdfViewWebPluginTest, GetAccessibilityDocInfoWithCopyAllowed) {}

TEST_F(PdfViewWebPluginTest, GetAccessibilityDocInfoWithCopyAccessibleAllowed) {}

TEST_F(PdfViewWebPluginTest,
       GetAccessibilityDocInfoWithCopyAndCopyAccessibleAllowed) {}

TEST_F(PdfViewWebPluginTest, UpdateGeometrySetsPluginRect) {}

TEST_F(PdfViewWebPluginTest,
       UpdateGeometrySetsPluginRectOnVariousDeviceScales) {}

TEST_F(PdfViewWebPluginTest, UpdateGeometrySetsPluginRectWithEmptyWindow) {}

TEST_F(PdfViewWebPluginTest, UpdateGeometryScroll) {}

TEST_F(PdfViewWebPluginTest, UpdateGeometryScrollStopped) {}

TEST_F(PdfViewWebPluginTest, UpdateGeometryScrollUnderflow) {}

TEST_F(PdfViewWebPluginTest, UpdateGeometryScrollOverflow) {}

TEST_F(PdfViewWebPluginTest, UpdateGeometryScrollOverflowZoomed) {}

TEST_F(PdfViewWebPluginTest, UpdateGeometryScrollScaled) {}

TEST_F(PdfViewWebPluginTest, UpdateGeometryScrollOverflowScaled) {}

TEST_F(PdfViewWebPluginTest, SetCaretPosition) {}

TEST_F(PdfViewWebPluginTest, SetCaretPositionNegativeOrigin) {}

TEST_F(PdfViewWebPluginTest, SetCaretPositionFractional) {}

TEST_F(PdfViewWebPluginTest, SetCaretPositionScaled) {}

TEST_F(PdfViewWebPluginTest, PaintEmptySnapshots) {}

TEST_F(PdfViewWebPluginTest, PaintSnapshots) {}

TEST_F(PdfViewWebPluginTest, PaintSnapshotsWithVariousDeviceScales) {}

TEST_F(PdfViewWebPluginTest, PaintSnapshotsWithVariousRectPositions) {}

TEST_F(PdfViewWebPluginTest, OnPaintWithMultiplePaintRects) {}

TEST_F(PdfViewWebPluginTest, UpdateLayerTransformWithIdentity) {}

TEST_F(PdfViewWebPluginTest, UpdateLayerTransformWithScale) {}

TEST_F(PdfViewWebPluginTest, UpdateLayerTransformWithTranslate) {}

TEST_F(PdfViewWebPluginTest, UpdateLayerTransformWithScaleAndTranslate) {}

TEST_F(PdfViewWebPluginTest, HandleViewportMessageBeforeDocumentLoadComplete) {}

TEST_F(PdfViewWebPluginTest, HandleViewportMessageAfterDocumentLoadComplete) {}

TEST_F(PdfViewWebPluginTest, HandleViewportMessageSubsequently) {}

TEST_F(PdfViewWebPluginTest, HandleViewportMessageScroll) {}

TEST_F(PdfViewWebPluginTest, HandleViewportMessageScrollRightToLeft) {}

TEST_F(PdfViewWebPluginTest, HandleSetBackgroundColorMessage) {}

TEST_F(PdfViewWebPluginTest, HandleInputEvent) {}

class PdfViewWebPluginImeTest : public PdfViewWebPluginTest {};

TEST_F(PdfViewWebPluginImeTest, ImeSetCompositionAndFinishAscii) {}

TEST_F(PdfViewWebPluginImeTest, ImeSetCompositionAndFinishUnicode) {}

TEST_F(PdfViewWebPluginImeTest, ImeSetCompositionAndFinishEmpty) {}

TEST_F(PdfViewWebPluginImeTest, ImeCommitTextForPluginAscii) {}

TEST_F(PdfViewWebPluginImeTest, ImeCommitTextForPluginUnicode) {}

TEST_F(PdfViewWebPluginImeTest, ImeCommitTextForPluginEmpty) {}

TEST_F(PdfViewWebPluginTest, SelectionChanged) {}

TEST_F(PdfViewWebPluginTest, SelectionChangedNegativeOrigin) {}

TEST_F(PdfViewWebPluginTest, SelectionChangedScaled) {}

TEST_F(PdfViewWebPluginTest, ChangeTextSelection) {}

TEST_F(PdfViewWebPluginTest, SelectAll) {}

TEST_F(PdfViewWebPluginTest, FormTextFieldFocusChangeUpdatesTextInputType) {}

TEST_F(PdfViewWebPluginTest, SearchString) {}

TEST_F(PdfViewWebPluginTest, UpdateFocus) {}

TEST_F(PdfViewWebPluginTest, ShouldDispatchImeEventsToPlugin) {}

TEST_F(PdfViewWebPluginTest, CaretChange) {}

TEST_F(PdfViewWebPluginTest, EnteredEditMode) {}

TEST_F(PdfViewWebPluginTest, NotifyNumberOfFindResultsChanged) {}

TEST_F(PdfViewWebPluginTest, OnDocumentLoadComplete) {}

class PdfViewWebPluginWithDocInfoTest : public PdfViewWebPluginTest {};

TEST_P(PdfViewWebPluginWithDocInfoTest, OnDocumentLoadComplete) {}

INSTANTIATE_TEST_SUITE_P();

class PdfViewWebPluginSaveTest : public PdfViewWebPluginTest {};

#if BUILDFLAG(ENABLE_INK)
TEST_F(PdfViewWebPluginSaveTest, AnnotationInNonEditMode) {
  base::Value expected_response = base::test::ParseJson(R"({
    "type": "saveData",
    "token": "annotation-in-non-edit-mode",
    "fileName": "example.pdf",
    "editModeForTesting": false,
  })");
  AddDataToValue(base::make_span(TestPDFiumEngine::kLoadedData),
                 expected_response);

  EXPECT_CALL(pdf_host_, SetPluginCanSave(true));
  ExpectUpdateTextInputState(blink::WebTextInputType::kWebTextInputTypeNone);
  EXPECT_CALL(*client_ptr_, PostMessage(base::test::IsJson(expected_response)));

  plugin_->OnMessage(ParseMessage(R"({
    "type": "save",
    "saveRequestType": 0,
    "token": "annotation-in-non-edit-mode",
  })"));

  pdf_receiver_.FlushForTesting();
}

TEST_F(PdfViewWebPluginSaveTest, AnnotationInEditMode) {
  plugin_->EnteredEditMode();
  pdf_receiver_.FlushForTesting();

  base::Value expected_response = base::test::ParseJson(R"({
    "type": "saveData",
    "token": "annotation-in-edit-mode",
    "fileName": "example.pdf",
    "editModeForTesting": true,
  })");
  AddDataToValue(base::make_span(TestPDFiumEngine::kSaveData),
                 expected_response);

  EXPECT_CALL(pdf_host_, SetPluginCanSave(true));
  ExpectUpdateTextInputState(blink::WebTextInputType::kWebTextInputTypeNone);
  EXPECT_CALL(*client_ptr_, PostMessage(base::test::IsJson(expected_response)));

  plugin_->OnMessage(ParseMessage(R"({
    "type": "save",
    "saveRequestType": 0,
    "token": "annotation-in-edit-mode",
  })"));

  pdf_receiver_.FlushForTesting();
}
#endif  // BUILDFLAG(ENABLE_INK)

TEST_F(PdfViewWebPluginSaveTest, OriginalInNonEditMode) {}

TEST_F(PdfViewWebPluginSaveTest, OriginalInEditMode) {}

#if BUILDFLAG(ENABLE_INK)
TEST_F(PdfViewWebPluginSaveTest, EditedInNonEditMode) {
  base::Value expected_response = base::test::ParseJson(R"({
    "type": "saveData",
    "token": "edited-in-non-edit-mode",
    "fileName": "example.pdf",
    "editModeForTesting": false,
  })");
  AddDataToValue(base::make_span(TestPDFiumEngine::kLoadedData),
                 expected_response);

  ExpectUpdateTextInputState(blink::WebTextInputType::kWebTextInputTypeNone);
  EXPECT_CALL(*client_ptr_, PostMessage(base::test::IsJson(expected_response)));

  plugin_->OnMessage(ParseMessage(R"({
    "type": "save",
    "saveRequestType": 2,
    "token": "edited-in-non-edit-mode",
  })"));
}
#endif  // BUILDFLAG(ENABLE_INK)

TEST_F(PdfViewWebPluginSaveTest, EditedInEditMode) {}

class PdfViewWebPluginSubmitFormTest
    : public PdfViewWebPluginWithoutInitializeTest {};

TEST_F(PdfViewWebPluginSubmitFormTest, RequestMethod) {}

TEST_F(PdfViewWebPluginSubmitFormTest, RequestBody) {}

TEST_F(PdfViewWebPluginSubmitFormTest, RelativeUrl) {}

TEST_F(PdfViewWebPluginSubmitFormTest, NoRelativeUrl) {}

TEST_F(PdfViewWebPluginSubmitFormTest, AbsoluteUrl) {}

TEST_F(PdfViewWebPluginSubmitFormTest, RelativeUrlInvalidDocumentUrl) {}

TEST_F(PdfViewWebPluginSubmitFormTest, AbsoluteUrlInvalidDocumentUrl) {}

class PdfViewWebPluginPrintTest : public PdfViewWebPluginTest {};

TEST_F(PdfViewWebPluginPrintTest, HighQuality) {}

TEST_F(PdfViewWebPluginPrintTest, HighQualityRasterized) {}

// Regression test for crbug.com/1307219.
TEST_F(PdfViewWebPluginPrintTest, LowQuality) {}

// Regression test for crbug.com/1307219.
TEST_F(PdfViewWebPluginPrintTest, LowQualityRasterized) {}

TEST_F(PdfViewWebPluginPrintTest, Disabled) {}

TEST_F(PdfViewWebPluginPrintTest, DisabledRasterized) {}

class PdfViewWebPluginPrintPreviewTest : public PdfViewWebPluginTest {};

TEST_F(PdfViewWebPluginPrintPreviewTest, HandleResetPrintPreviewModeMessage) {}

TEST_F(PdfViewWebPluginPrintPreviewTest,
       HandleResetPrintPreviewModeMessageForPdf) {}

TEST_F(PdfViewWebPluginPrintPreviewTest,
       HandleResetPrintPreviewModeMessageSetGrayscale) {}

TEST_F(PdfViewWebPluginPrintPreviewTest, DocumentLoadComplete) {}

TEST_F(PdfViewWebPluginPrintPreviewTest,
       DocumentLoadProgressResetByResetPrintPreviewModeMessage) {}

TEST_F(PdfViewWebPluginPrintPreviewTest,
       DocumentLoadProgressNotResetByLoadPreviewPageMessage) {}

TEST_F(PdfViewWebPluginPrintPreviewTest,
       HandleViewportMessageScrollRightToLeft) {}

#if BUILDFLAG(ENABLE_PDF_INK2)
class PdfViewWebPluginInkTest : public PdfViewWebPluginTest {};

TEST_F(PdfViewWebPluginInkTest, UpdateCursor) {}

TEST_F(PdfViewWebPluginInkTest, VisiblePageIndexFromPoint) {}
#endif  // BUILDFLAG(ENABLE_PDF_INK2)

}  // namespace chrome_pdf