| // Copyright 2025 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_caret.h" |
| |
| #include <stdint.h> |
| |
| #include "base/compiler_specific.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "base/test/task_environment.h" |
| #include "base/time/time.h" |
| #include "pdf/accessibility_structs.h" |
| #include "pdf/page_character_index.h" |
| #include "pdf/page_orientation.h" |
| #include "pdf/pdf_caret_client.h" |
| #include "pdf/region_data.h" |
| #include "pdf/test/mock_pdf_caret_client.h" |
| #include "pdf/test/test_helpers.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/blink/public/common/input/web_keyboard_event.h" |
| #include "third_party/skia/include/core/SkBitmap.h" |
| #include "third_party/skia/include/core/SkImageInfo.h" |
| #include "third_party/skia/include/core/SkSurface.h" |
| #include "ui/events/keycodes/keyboard_codes.h" |
| #include "ui/gfx/geometry/rect.h" |
| |
| namespace chrome_pdf { |
| |
| namespace { |
| |
| using ::testing::_; |
| using ::testing::AnyNumber; |
| using ::testing::InSequence; |
| using ::testing::Mock; |
| using ::testing::Return; |
| using ::testing::StrictMock; |
| |
| constexpr char kCaretFirstVisibleHistogram[] = "PDF.Caret.FirstVisible"; |
| |
| constexpr base::TimeDelta kOneMs = base::Milliseconds(1); |
| |
| constexpr gfx::Size kCanvasSize(100, 100); |
| constexpr SkColor kDefaultColor = SK_ColorGREEN; |
| |
| constexpr PageCharacterIndex kTestChar0{0, 0}; |
| constexpr PageCharacterIndex kTestChar1{0, 1}; |
| constexpr PageCharacterIndex kTestChar2{0, 2}; |
| constexpr PageCharacterIndex kTestChar3{0, 3}; |
| constexpr PageCharacterIndex kTestChar4{0, 4}; |
| constexpr PageCharacterIndex kTestChar5{0, 5}; |
| constexpr PageCharacterIndex kTestPage1Char0{1, 0}; |
| constexpr PageCharacterIndex kTestPage1Char1{1, 1}; |
| constexpr PageCharacterIndex kTestPage2Char0{2, 0}; |
| constexpr PageCharacterIndex kTestPage3Char0{3, 0}; |
| |
| constexpr gfx::Rect kDefaultScreenRect{10, 10, 12, 12}; |
| constexpr gfx::Rect kDefaultCaret{10, 10, 1, 12}; |
| constexpr gfx::Rect kTestChar0ScreenRect{10, 10, 12, 14}; |
| constexpr gfx::Rect kTestChar1ScreenRect{22, 10, 12, 14}; |
| constexpr gfx::Rect kTestChar3ScreenRect{46, 10, 12, 14}; |
| constexpr gfx::Rect kTestChar4ScreenRect{58, 10, 12, 14}; |
| constexpr gfx::Rect kTestChar0Caret{10, 10, 1, 14}; |
| constexpr gfx::Rect kTestChar0EndCaret{22, 10, 1, 14}; |
| constexpr gfx::Rect kTestChar1Caret = kTestChar0EndCaret; |
| constexpr gfx::Rect kTestChar1EndCaret{34, 10, 1, 14}; |
| constexpr gfx::Rect kTestChar2Caret = kTestChar1EndCaret; |
| constexpr gfx::Rect kTestChar0ZoomedCaret{20, 20, 1, 28}; |
| constexpr gfx::Rect kTestChar3Caret{46, 10, 1, 14}; |
| |
| constexpr gfx::Rect kTestChar0TopCaret{10, 10, 12, 1}; |
| constexpr gfx::Rect kTestChar0BottomCaret{10, 24, 12, 1}; |
| |
| constexpr gfx::Rect kTestMultiPage1Char0ScreenRect{15, 15, 8, 4}; |
| constexpr gfx::Rect kTestMultiPage1Char1ScreenRect{23, 15, 8, 4}; |
| constexpr gfx::Rect kTestMultiPage2Char0ScreenRect{40, 40, 15, 20}; |
| constexpr gfx::Rect kTestMultiPage2NonTextScreenRect{40, 40, 1, 12}; |
| constexpr gfx::Rect kTestMultiPage3Char0ScreenRect{50, 50, 16, 20}; |
| constexpr gfx::Rect kTestMultiPage1Char0Caret{15, 15, 1, 4}; |
| constexpr gfx::Rect kTestMultiPage1Char0EndCaret{23, 15, 1, 4}; |
| constexpr gfx::Rect kTestMultiPage1Char1Caret = kTestMultiPage1Char0EndCaret; |
| constexpr gfx::Rect kTestMultiPage1Char1EndCaret{31, 15, 1, 4}; |
| constexpr gfx::Rect kTestMultiPage2Char0Caret{40, 40, 1, 20}; |
| constexpr gfx::Rect kTestMultiPage3Char0Caret{50, 50, 1, 20}; |
| constexpr gfx::Rect kTestMultiPage3Char0EndCaret{66, 50, 1, 20}; |
| |
| AccessibilityTextRunInfo GenerateTestTextRunInfo( |
| AccessibilityTextDirection direction) { |
| // `PdfCaret` only uses the direction of the text run. |
| AccessibilityTextRunInfo text_run; |
| text_run.direction = direction; |
| return text_run; |
| } |
| |
| class PdfCaretTest : public testing::Test { |
| public: |
| PdfCaretTest() = default; |
| PdfCaretTest(const PdfCaretTest&) = delete; |
| PdfCaretTest& operator=(const PdfCaretTest&) = delete; |
| ~PdfCaretTest() override = default; |
| |
| MockPdfCaretClient& client() { return client_; } |
| |
| PdfCaret& caret() { return *caret_; } |
| |
| void SetUp() override { |
| ResetBitmap(); |
| EXPECT_CALL(client(), GetCurrentOrientation()) |
| .WillRepeatedly(Return(PageOrientation::kOriginal)); |
| EXPECT_CALL(client(), GetTextRunInfoAt(_)) |
| .WillRepeatedly(Return( |
| GenerateTestTextRunInfo(AccessibilityTextDirection::kLeftToRight))); |
| EXPECT_CALL(client(), IsSelecting()).WillRepeatedly(Return(false)); |
| EXPECT_CALL(client(), ScrollToChar(_)).Times(AnyNumber()); |
| } |
| |
| void InitializeCaretAtChar(const PageCharacterIndex& index) { |
| caret_ = std::make_unique<PdfCaret>(&client_); |
| caret_->SetChar(index); |
| } |
| |
| void InitializeVisibleCaretAtChar(const PageCharacterIndex& index) { |
| InitializeCaretAtChar(index); |
| caret_->SetEnabled(true); |
| caret_->SetVisible(true); |
| } |
| |
| RegionData GetRegionData(const gfx::Point& location) { |
| uint8_t* buffer = static_cast<uint8_t*>(bitmap_.getPixels()); |
| CHECK(buffer); |
| |
| size_t stride = bitmap_.rowBytes(); |
| size_t offset = location.y() * stride + location.x() * 4; |
| // SAFETY: Skia guarantees bitmap_.height() * bitmap_.rowBytes() is the |
| // exact size of the allocated pixel buffer, including row padding. However, |
| // Skia does not have a span-based API for this. |
| // TODO(crbug.com/357905831): Switch to SkSpan when possible. |
| UNSAFE_BUFFERS( |
| base::span<uint8_t> buffer_span(buffer, bitmap_.height() * stride)); |
| return RegionData(buffer_span.subspan(offset), stride); |
| } |
| |
| void TestDrawCaret(const gfx::Rect& expected_caret) { |
| EXPECT_EQ(expected_caret, client().invalidated_rect()); |
| EXPECT_TRUE(caret().MaybeDrawCaret(GetRegionData(expected_caret.origin()), |
| expected_caret)); |
| EXPECT_TRUE(VerifyCaretRendering(expected_caret)); |
| |
| // Reset for future calls. |
| ResetBitmap(); |
| } |
| |
| void TestDrawCaretFails(const gfx::Rect& expected_caret) { |
| EXPECT_FALSE(caret().MaybeDrawCaret(GetRegionData(expected_caret.origin()), |
| expected_caret)); |
| EXPECT_TRUE(VerifyBlankRendering()); |
| |
| // Reset for future calls. |
| ResetBitmap(); |
| } |
| |
| bool VerifyCaretRendering(const gfx::Rect& expected_caret) { |
| int width = bitmap_.width(); |
| int height = bitmap_.height(); |
| |
| for (int y = 0; y < height; ++y) { |
| for (int x = 0; x < width; ++x) { |
| if (expected_caret.Contains(x, y) == |
| (bitmap_.getColor(x, y) == kDefaultColor)) { |
| return false; |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| bool VerifyBlankRendering() { |
| int width = bitmap_.width(); |
| int height = bitmap_.height(); |
| |
| for (int y = 0; y < height; ++y) { |
| for (int x = 0; x < width; ++x) { |
| if (bitmap_.getColor(x, y) != kDefaultColor) { |
| return false; |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| void ResetBitmap() { |
| bitmap_.reset(); |
| |
| sk_sp<SkSurface> surface = |
| CreateSkiaSurfaceForTesting(kCanvasSize, kDefaultColor); |
| SkImageInfo image_info = |
| SkImageInfo::MakeN32Premul(kCanvasSize.width(), kCanvasSize.height()); |
| CHECK(bitmap_.tryAllocPixels(image_info)); |
| sk_sp<SkImage> image = surface->makeImageSnapshot(); |
| CHECK(image); |
| CHECK(image->readPixels(bitmap_.info(), bitmap_.getPixels(), |
| bitmap_.rowBytes(), 0, 0)); |
| } |
| |
| void SetUpChar(const PageCharacterIndex& index, |
| std::vector<gfx::Rect> rects) { |
| EXPECT_CALL(client_, GetScreenRectsForCaret(index)) |
| .WillRepeatedly(Return(std::move(rects))); |
| } |
| |
| void SetUpPagesWithCharCounts(const std::vector<uint32_t>& char_counts) { |
| EXPECT_CALL(client(), PageIndexInBounds(_)).WillRepeatedly(Return(false)); |
| for (size_t i = 0; i < char_counts.size(); ++i) { |
| EXPECT_CALL(client(), PageIndexInBounds(i)).WillRepeatedly(Return(true)); |
| EXPECT_CALL(client(), GetCharCount(i)) |
| .WillRepeatedly(Return(char_counts[i])); |
| } |
| } |
| |
| void SetUpSingleCharLineTest() { |
| SetUpPagesWithCharCounts({1}); |
| SetUpChar(kTestChar0, {kTestChar0ScreenRect}); |
| } |
| |
| void SetUpTwoCharLineTest() { |
| SetUpPagesWithCharCounts({2}); |
| SetUpChar(kTestChar0, {kTestChar0ScreenRect}); |
| SetUpChar(kTestChar1, {kTestChar1ScreenRect}); |
| } |
| |
| void SetUpNoTextPageTest() { |
| SetUpPagesWithCharCounts({0}); |
| SetUpChar(kTestChar0, {kDefaultScreenRect}); |
| } |
| |
| void SetUpMultiPageTest() { |
| SetUpPagesWithCharCounts({1, 2, 0, 1}); |
| // Page 0: "ab". |
| // Page 1: "c". |
| // Page 2: No text. |
| // Page 3: "d". |
| SetUpChar(kTestChar0, {kTestChar0ScreenRect}); |
| SetUpChar(kTestPage1Char0, {kTestMultiPage1Char0ScreenRect}); |
| SetUpChar(kTestPage1Char1, {kTestMultiPage1Char1ScreenRect}); |
| SetUpChar(kTestPage2Char0, {kTestMultiPage2NonTextScreenRect}); |
| SetUpChar(kTestPage3Char0, {kTestMultiPage3Char0ScreenRect}); |
| } |
| |
| blink::WebKeyboardEvent GenerateKeyboardEvent(ui::KeyboardCode key) { |
| blink::WebKeyboardEvent event( |
| blink::WebInputEvent::Type::kRawKeyDown, 0, |
| blink::WebInputEvent::GetStaticTimeStampForTests()); |
| event.windows_key_code = key; |
| return event; |
| } |
| |
| private: |
| StrictMock<MockPdfCaretClient> client_; |
| std::unique_ptr<PdfCaret> caret_; |
| SkBitmap bitmap_; |
| }; |
| |
| TEST_F(PdfCaretTest, NoTextPage) { |
| base::HistogramTester histograms; |
| SetUpNoTextPageTest(); |
| InitializeVisibleCaretAtChar(kTestChar0); |
| |
| TestDrawCaret(kDefaultCaret); |
| histograms.ExpectUniqueSample(kCaretFirstVisibleHistogram, true, 1); |
| } |
| |
| TEST_F(PdfCaretTest, SetEnabled) { |
| base::HistogramTester histograms; |
| SetUpSingleCharLineTest(); |
| InitializeCaretAtChar(kTestChar0); |
| |
| caret().SetVisible(true); |
| |
| // Default disabled. |
| TestDrawCaretFails(kTestChar0Caret); |
| histograms.ExpectTotalCount(kCaretFirstVisibleHistogram, 0); |
| |
| caret().SetEnabled(true); |
| |
| TestDrawCaret(kTestChar0Caret); |
| histograms.ExpectUniqueSample(kCaretFirstVisibleHistogram, true, 1); |
| |
| caret().SetEnabled(false); |
| |
| TestDrawCaretFails(kTestChar0Caret); |
| histograms.ExpectUniqueSample(kCaretFirstVisibleHistogram, true, 1); |
| |
| GetPdfTestTaskEnvironment().FastForwardBy(PdfCaret::kDefaultBlinkInterval); |
| |
| TestDrawCaretFails(kTestChar0Caret); |
| histograms.ExpectUniqueSample(kCaretFirstVisibleHistogram, true, 1); |
| |
| caret().SetEnabled(true); |
| |
| TestDrawCaret(kTestChar0Caret); |
| histograms.ExpectUniqueSample(kCaretFirstVisibleHistogram, true, 1); |
| } |
| |
| TEST_F(PdfCaretTest, SetVisible) { |
| base::HistogramTester histograms; |
| SetUpSingleCharLineTest(); |
| InitializeCaretAtChar(kTestChar0); |
| |
| caret().SetEnabled(true); |
| |
| // Default not visible. |
| TestDrawCaretFails(kTestChar0Caret); |
| histograms.ExpectTotalCount(kCaretFirstVisibleHistogram, 0); |
| |
| caret().SetVisible(true); |
| |
| TestDrawCaret(kTestChar0Caret); |
| |
| caret().SetVisible(false); |
| |
| TestDrawCaretFails(kTestChar0Caret); |
| histograms.ExpectUniqueSample(kCaretFirstVisibleHistogram, true, 1); |
| |
| GetPdfTestTaskEnvironment().FastForwardBy(PdfCaret::kDefaultBlinkInterval); |
| |
| TestDrawCaretFails(kTestChar0Caret); |
| histograms.ExpectUniqueSample(kCaretFirstVisibleHistogram, true, 1); |
| |
| caret().SetVisible(true); |
| |
| TestDrawCaret(kTestChar0Caret); |
| histograms.ExpectUniqueSample(kCaretFirstVisibleHistogram, true, 1); |
| } |
| |
| TEST_F(PdfCaretTest, SetBlinkIntervalWhileNotVisible) { |
| SetUpSingleCharLineTest(); |
| InitializeCaretAtChar(kTestChar0); |
| |
| TestDrawCaretFails(kTestChar0Caret); |
| |
| // Blinks by default, but not visible. |
| GetPdfTestTaskEnvironment().FastForwardBy(PdfCaret::kDefaultBlinkInterval); |
| TestDrawCaretFails(kTestChar0Caret); |
| |
| // Turn off blinking. Still not visible. |
| caret().SetBlinkInterval(base::TimeDelta()); |
| |
| TestDrawCaretFails(kTestChar0Caret); |
| |
| GetPdfTestTaskEnvironment().FastForwardBy(PdfCaret::kDefaultBlinkInterval); |
| TestDrawCaretFails(kTestChar0Caret); |
| |
| // Turn on blinking. Still not visible. |
| constexpr base::TimeDelta kBlinkInterval = base::Milliseconds(200); |
| caret().SetBlinkInterval(kBlinkInterval); |
| |
| TestDrawCaretFails(kTestChar0Caret); |
| |
| GetPdfTestTaskEnvironment().FastForwardBy(kBlinkInterval); |
| TestDrawCaretFails(kTestChar0Caret); |
| } |
| |
| TEST_F(PdfCaretTest, SetBlinkIntervalWhileVisible) { |
| SetUpSingleCharLineTest(); |
| InitializeVisibleCaretAtChar(kTestChar0); |
| |
| TestDrawCaret(kTestChar0Caret); |
| |
| // Blinks by default. |
| GetPdfTestTaskEnvironment().FastForwardBy(PdfCaret::kDefaultBlinkInterval); |
| TestDrawCaretFails(kTestChar0Caret); |
| |
| // Turn off blinking. Caret should always be visible. |
| caret().SetBlinkInterval(base::TimeDelta()); |
| |
| TestDrawCaret(kTestChar0Caret); |
| |
| GetPdfTestTaskEnvironment().FastForwardBy(PdfCaret::kDefaultBlinkInterval); |
| TestDrawCaret(kTestChar0Caret); |
| |
| // Turn on blinking. |
| constexpr base::TimeDelta kBlinkInterval = base::Milliseconds(300); |
| caret().SetBlinkInterval(kBlinkInterval); |
| |
| TestDrawCaret(kTestChar0Caret); |
| |
| GetPdfTestTaskEnvironment().FastForwardBy(kBlinkInterval); |
| TestDrawCaretFails(kTestChar0Caret); |
| |
| GetPdfTestTaskEnvironment().FastForwardBy(kBlinkInterval - kOneMs); |
| TestDrawCaretFails(kTestChar0Caret); |
| |
| // Set to the same blink interval. Should not reset the blink timer. |
| caret().SetBlinkInterval(kBlinkInterval); |
| |
| TestDrawCaretFails(kTestChar0Caret); |
| |
| GetPdfTestTaskEnvironment().FastForwardBy(kOneMs); |
| TestDrawCaret(kTestChar0Caret); |
| } |
| |
| TEST_F(PdfCaretTest, SetBlinkIntervalNegative) { |
| SetUpSingleCharLineTest(); |
| InitializeVisibleCaretAtChar(kTestChar0); |
| |
| // Setting blink interval to negative does nothing. |
| caret().SetBlinkInterval(base::Milliseconds(-100)); |
| |
| TestDrawCaret(kTestChar0Caret); |
| |
| GetPdfTestTaskEnvironment().FastForwardBy(PdfCaret::kDefaultBlinkInterval); |
| TestDrawCaretFails(kTestChar0Caret); |
| |
| GetPdfTestTaskEnvironment().FastForwardBy(base::Milliseconds(100)); |
| TestDrawCaretFails(kTestChar0Caret); |
| } |
| |
| TEST_F(PdfCaretTest, MaybeDrawCaret) { |
| base::HistogramTester histograms; |
| SetUpSingleCharLineTest(); |
| InitializeCaretAtChar(kTestChar0); |
| |
| // Not yet visible. |
| EXPECT_FALSE(caret().MaybeDrawCaret(GetRegionData(kTestChar0Caret.origin()), |
| kTestChar0Caret)); |
| histograms.ExpectTotalCount(kCaretFirstVisibleHistogram, 0); |
| |
| caret().SetEnabled(true); |
| caret().SetVisible(true); |
| |
| // Not dirty in screen. |
| EXPECT_FALSE(caret().MaybeDrawCaret(GetRegionData(gfx::Point(70, 70)), |
| gfx::Rect(70, 70, 20, 30))); |
| histograms.ExpectTotalCount(kCaretFirstVisibleHistogram, 0); |
| |
| // Partially dirty in screen. For testing purposes, origin is bottom left |
| // instead of top right. |
| EXPECT_TRUE(caret().MaybeDrawCaret(GetRegionData(gfx::Point(5, 5)), |
| gfx::Rect(5, 5, 20, 30))); |
| VerifyCaretRendering(gfx::Rect(5, 5, 1, 9)); |
| histograms.ExpectUniqueSample(kCaretFirstVisibleHistogram, true, 1); |
| ResetBitmap(); |
| |
| // Fully dirty in screen. |
| EXPECT_TRUE(caret().MaybeDrawCaret(GetRegionData(kTestChar0Caret.origin()), |
| kTestChar0Caret)); |
| VerifyCaretRendering(kTestChar0Caret); |
| histograms.ExpectUniqueSample(kCaretFirstVisibleHistogram, true, 1); |
| } |
| |
| TEST_F(PdfCaretTest, Blink) { |
| SetUpTwoCharLineTest(); |
| InitializeVisibleCaretAtChar(kTestChar0); |
| |
| TestDrawCaret(kTestChar0Caret); |
| |
| GetPdfTestTaskEnvironment().FastForwardBy(PdfCaret::kDefaultBlinkInterval - |
| kOneMs); |
| TestDrawCaret(kTestChar0Caret); |
| |
| GetPdfTestTaskEnvironment().FastForwardBy(kOneMs); |
| TestDrawCaretFails(kTestChar0Caret); |
| |
| GetPdfTestTaskEnvironment().FastForwardBy(PdfCaret::kDefaultBlinkInterval - |
| kOneMs); |
| TestDrawCaretFails(kTestChar0Caret); |
| |
| GetPdfTestTaskEnvironment().FastForwardBy(kOneMs); |
| TestDrawCaret(kTestChar0Caret); |
| |
| // Moving to another char should reset the blink duration. |
| GetPdfTestTaskEnvironment().FastForwardBy(kOneMs); |
| |
| caret().SetCharAndDraw(kTestChar1); |
| TestDrawCaret(kTestChar1Caret); |
| |
| GetPdfTestTaskEnvironment().FastForwardBy(PdfCaret::kDefaultBlinkInterval - |
| kOneMs); |
| TestDrawCaret(kTestChar1Caret); |
| |
| GetPdfTestTaskEnvironment().FastForwardBy(kOneMs); |
| TestDrawCaretFails(kTestChar1Caret); |
| |
| // Moving to another char should make the caret reappear immediately. |
| caret().SetCharAndDraw(kTestChar0); |
| TestDrawCaret(kTestChar0Caret); |
| } |
| |
| TEST_F(PdfCaretTest, OnGeometryChanged) { |
| SetUpSingleCharLineTest(); |
| InitializeVisibleCaretAtChar(kTestChar0); |
| |
| EXPECT_EQ(kTestChar0Caret, client().invalidated_rect()); |
| |
| caret().OnGeometryChanged(); |
| |
| EXPECT_EQ(kTestChar0Caret, client().invalidated_rect()); |
| |
| // Simulate a 200% zoom geometry change. |
| SetUpChar(kTestChar0, {kTestChar0ZoomedCaret}); |
| caret().OnGeometryChanged(); |
| |
| EXPECT_EQ(kTestChar0ZoomedCaret, client().invalidated_rect()); |
| EXPECT_TRUE(caret().MaybeDrawCaret(GetRegionData(gfx::Point()), |
| gfx::Rect(kCanvasSize))); |
| EXPECT_TRUE(VerifyCaretRendering(kTestChar0ZoomedCaret)); |
| |
| ResetBitmap(); |
| |
| // Simulate a scroll geometry change. |
| constexpr gfx::Rect kTestChar0ZoomedScrolledCaret{40, 60, 1, 28}; |
| SetUpChar(kTestChar0, {kTestChar0ZoomedScrolledCaret}); |
| caret().OnGeometryChanged(); |
| |
| EXPECT_EQ(kTestChar0ZoomedScrolledCaret, client().invalidated_rect()); |
| EXPECT_TRUE(caret().MaybeDrawCaret(GetRegionData(gfx::Point()), |
| gfx::Rect(kCanvasSize))); |
| EXPECT_TRUE(VerifyCaretRendering(kTestChar0ZoomedScrolledCaret)); |
| |
| ResetBitmap(); |
| |
| // Simulate a scroll geometry change such that the caret is off-screen. |
| constexpr gfx::Rect kOffScreenCaret{140, 160, 1, 28}; |
| SetUpChar(kTestChar0, {kOffScreenCaret}); |
| caret().OnGeometryChanged(); |
| |
| EXPECT_EQ(kOffScreenCaret, client().invalidated_rect()); |
| EXPECT_FALSE(caret().MaybeDrawCaret(GetRegionData(gfx::Point()), |
| gfx::Rect(kCanvasSize))); |
| EXPECT_TRUE(VerifyBlankRendering()); |
| } |
| |
| TEST_F(PdfCaretTest, OnGeometryChangedToggleEnabled) { |
| SetUpSingleCharLineTest(); |
| InitializeVisibleCaretAtChar(kTestChar0); |
| |
| EXPECT_EQ(kTestChar0Caret, client().invalidated_rect()); |
| |
| caret().SetEnabled(false); |
| |
| // Call `OnGeometryChanged()` while the caret is disabled. |
| SetUpChar(kTestChar0, {kTestChar0ZoomedCaret}); |
| caret().OnGeometryChanged(); |
| |
| EXPECT_EQ(kTestChar0Caret, client().invalidated_rect()); |
| |
| caret().SetEnabled(true); |
| |
| EXPECT_EQ(kTestChar0ZoomedCaret, client().invalidated_rect()); |
| EXPECT_TRUE(caret().MaybeDrawCaret(GetRegionData(gfx::Point()), |
| gfx::Rect(kCanvasSize))); |
| EXPECT_TRUE(VerifyCaretRendering(kTestChar0ZoomedCaret)); |
| } |
| |
| TEST_F(PdfCaretTest, OnGeometryChangedToggleVisible) { |
| SetUpSingleCharLineTest(); |
| InitializeVisibleCaretAtChar(kTestChar0); |
| |
| EXPECT_EQ(kTestChar0Caret, client().invalidated_rect()); |
| |
| caret().SetVisible(false); |
| |
| // Call `OnGeometryChanged()` while the caret is not visible. |
| SetUpChar(kTestChar0, {kTestChar0ZoomedCaret}); |
| caret().OnGeometryChanged(); |
| |
| EXPECT_EQ(kTestChar0Caret, client().invalidated_rect()); |
| |
| caret().SetVisible(true); |
| |
| EXPECT_EQ(kTestChar0ZoomedCaret, client().invalidated_rect()); |
| EXPECT_TRUE(caret().MaybeDrawCaret(GetRegionData(gfx::Point()), |
| gfx::Rect(kCanvasSize))); |
| EXPECT_TRUE(VerifyCaretRendering(kTestChar0ZoomedCaret)); |
| } |
| |
| TEST_F(PdfCaretTest, SetChar) { |
| SetUpSingleCharLineTest(); |
| InitializeVisibleCaretAtChar(kTestChar0); |
| |
| EXPECT_EQ(kTestChar0Caret, client().invalidated_rect()); |
| |
| caret().SetChar(kTestChar1); |
| |
| // New caret position should not be invalidated. |
| EXPECT_EQ(kTestChar0Caret, client().invalidated_rect()); |
| |
| caret().SetChar(kTestChar0); |
| |
| // Old caret position should be invalidated. |
| EXPECT_EQ(kTestChar0EndCaret, client().invalidated_rect()); |
| } |
| |
| TEST_F(PdfCaretTest, SetCharAndDraw) { |
| SetUpPagesWithCharCounts({2}); |
| // "ab". |
| SetUpChar(kTestChar0, {kTestChar0ScreenRect}); |
| // Set up second char two pixels to the right of the first char. |
| SetUpChar(kTestChar1, {gfx::Rect(24, 10, 12, 14)}); |
| InitializeVisibleCaretAtChar(kTestChar0); |
| |
| caret().SetCharAndDraw(kTestChar0); |
| TestDrawCaret(kTestChar0Caret); |
| |
| caret().SetCharAndDraw(kTestChar1); |
| TestDrawCaret(gfx::Rect(24, 10, 1, 14)); |
| |
| constexpr gfx::Rect kSecondCharEndCaret{36, 10, 1, 14}; |
| caret().SetCharAndDraw(kTestChar2); |
| TestDrawCaret(kSecondCharEndCaret); |
| |
| // Setting the position should still work, even when not visible. The effects |
| // will only appear when the caret is set to visible again. |
| caret().SetEnabled(false); |
| caret().SetCharAndDraw(kTestChar0); |
| EXPECT_EQ(kSecondCharEndCaret, client().invalidated_rect()); |
| |
| caret().SetEnabled(true); |
| TestDrawCaret(kTestChar0Caret); |
| } |
| |
| TEST_F(PdfCaretTest, SetCharAndDrawSpecialChars) { |
| SetUpPagesWithCharCounts({4}); |
| // "a \n" |
| // "b". |
| SetUpChar(kTestChar0, {kTestChar0ScreenRect}); |
| SetUpChar(kTestChar1, {}); |
| SetUpChar(kTestChar2, {}); |
| SetUpChar(kTestChar3, {gfx::Rect(10, 26, 10, 8)}); |
| InitializeVisibleCaretAtChar(kTestChar0); |
| |
| caret().SetCharAndDraw(kTestChar0); |
| TestDrawCaret(kTestChar0Caret); |
| |
| // Synthetic whitespaces and newlines added by PDFium do not have screen |
| // rects. Caret should be directly to the right of the first char's rect. |
| caret().SetCharAndDraw(kTestChar1); |
| TestDrawCaret(kTestChar1Caret); |
| |
| // Consecutive chars with empty screen rects should still use the right of the |
| // previous char's rect. |
| caret().SetCharAndDraw(kTestChar2); |
| TestDrawCaret(kTestChar1Caret); |
| |
| // Char with different width and height after newline. |
| caret().SetCharAndDraw(kTestChar3); |
| TestDrawCaret(gfx::Rect{10, 26, 1, 8}); |
| } |
| |
| TEST_F(PdfCaretTest, SetCharAndDrawMultiPage) { |
| SetUpMultiPageTest(); |
| InitializeVisibleCaretAtChar(kTestChar0); |
| |
| caret().SetCharAndDraw(kTestChar0); |
| TestDrawCaret(kTestChar0Caret); |
| |
| caret().SetCharAndDraw(kTestPage3Char0); |
| TestDrawCaret(kTestMultiPage3Char0Caret); |
| |
| caret().SetCharAndDraw({3, 1}); |
| TestDrawCaret(kTestMultiPage3Char0EndCaret); |
| |
| caret().SetCharAndDraw(kTestPage1Char1); |
| TestDrawCaret(kTestMultiPage1Char1Caret); |
| |
| caret().SetCharAndDraw(kTestPage1Char0); |
| TestDrawCaret(kTestMultiPage1Char0Caret); |
| } |
| |
| class PdfCaretTextDirectionTest : public PdfCaretTest { |
| public: |
| void SetUpTextDirectionTest(const PageCharacterIndex& start_index, |
| AccessibilityTextDirection direction) { |
| SetUpPagesWithCharCounts({2}); |
| // "a\n". |
| SetUpChar(kTestChar0, {kTestChar0ScreenRect}); |
| SetUpChar(kTestChar1, {}); |
| EXPECT_CALL(client(), GetTextRunInfoAt(_)) |
| .WillRepeatedly(Return(GenerateTestTextRunInfo(direction))); |
| InitializeVisibleCaretAtChar(start_index); |
| } |
| |
| void TestLeftToRight() { |
| InSequence sequence; |
| TestOrientation(PageOrientation::kOriginal, kTestChar0Caret); |
| TestOrientation(PageOrientation::kClockwise90, kTestChar0TopCaret); |
| TestOrientation(PageOrientation::kClockwise180, kTestChar0EndCaret); |
| TestOrientation(PageOrientation::kClockwise270, kTestChar0BottomCaret); |
| } |
| |
| void TestRightToLeft() { |
| InSequence sequence; |
| TestOrientation(PageOrientation::kOriginal, kTestChar0EndCaret); |
| TestOrientation(PageOrientation::kClockwise90, kTestChar0BottomCaret); |
| TestOrientation(PageOrientation::kClockwise180, kTestChar0Caret); |
| TestOrientation(PageOrientation::kClockwise270, kTestChar0TopCaret); |
| } |
| |
| void TestTopToBottom() { |
| InSequence sequence; |
| TestOrientation(PageOrientation::kOriginal, kTestChar0TopCaret); |
| TestOrientation(PageOrientation::kClockwise90, kTestChar0EndCaret); |
| TestOrientation(PageOrientation::kClockwise180, kTestChar0BottomCaret); |
| TestOrientation(PageOrientation::kClockwise270, kTestChar0Caret); |
| } |
| |
| void TestBottomToTop() { |
| InSequence sequence; |
| TestOrientation(PageOrientation::kOriginal, kTestChar0BottomCaret); |
| TestOrientation(PageOrientation::kClockwise90, kTestChar0Caret); |
| TestOrientation(PageOrientation::kClockwise180, kTestChar0TopCaret); |
| TestOrientation(PageOrientation::kClockwise270, kTestChar0EndCaret); |
| } |
| |
| void TestOrientation(PageOrientation orientation, gfx::Rect expected_caret) { |
| EXPECT_CALL(client(), GetCurrentOrientation()) |
| .WillOnce(Return(orientation)); |
| caret().OnGeometryChanged(); |
| TestDrawCaret(expected_caret); |
| } |
| }; |
| |
| TEST_F(PdfCaretTextDirectionTest, NoTextPage) { |
| SetUpNoTextPageTest(); |
| EXPECT_CALL(client(), GetTextRunInfoAt(_)) |
| .WillRepeatedly(Return(std::nullopt)); |
| InitializeVisibleCaretAtChar(kTestChar0); |
| |
| InSequence sequence; |
| TestOrientation(PageOrientation::kOriginal, kDefaultCaret); |
| TestOrientation(PageOrientation::kClockwise90, kTestChar0TopCaret); |
| TestOrientation(PageOrientation::kClockwise180, gfx::Rect(22, 10, 1, 12)); |
| TestOrientation(PageOrientation::kClockwise270, gfx::Rect(10, 22, 12, 1)); |
| } |
| |
| TEST_F(PdfCaretTextDirectionTest, LeftToRight) { |
| SetUpTextDirectionTest(kTestChar0, AccessibilityTextDirection::kLeftToRight); |
| TestLeftToRight(); |
| } |
| |
| TEST_F(PdfCaretTextDirectionTest, RightToLeft) { |
| SetUpTextDirectionTest(kTestChar0, AccessibilityTextDirection::kRightToLeft); |
| TestRightToLeft(); |
| } |
| |
| TEST_F(PdfCaretTextDirectionTest, TopToBottom) { |
| SetUpTextDirectionTest(kTestChar0, AccessibilityTextDirection::kTopToBottom); |
| TestTopToBottom(); |
| } |
| |
| TEST_F(PdfCaretTextDirectionTest, BottomToTop) { |
| SetUpTextDirectionTest(kTestChar0, AccessibilityTextDirection::kBottomToTop); |
| TestBottomToTop(); |
| } |
| |
| TEST_F(PdfCaretTextDirectionTest, LeftToRightEmptyScreenRect) { |
| SetUpTextDirectionTest(kTestChar1, AccessibilityTextDirection::kLeftToRight); |
| // When on a character with an empty screen rect, the previous character's |
| // screen rect is used, but flipped. |
| TestRightToLeft(); |
| } |
| |
| TEST_F(PdfCaretTextDirectionTest, RightToLeftEmptyScreenRect) { |
| SetUpTextDirectionTest(kTestChar1, AccessibilityTextDirection::kRightToLeft); |
| // When on a character with an empty screen rect, the previous character's |
| // screen rect is used, but flipped. |
| TestLeftToRight(); |
| } |
| |
| TEST_F(PdfCaretTextDirectionTest, TopToBottomEmptyScreenRect) { |
| SetUpTextDirectionTest(kTestChar1, AccessibilityTextDirection::kTopToBottom); |
| // When on a character with an empty screen rect, the previous character's |
| // screen rect is used, but flipped. |
| TestBottomToTop(); |
| } |
| |
| TEST_F(PdfCaretTextDirectionTest, BottomToTopEmptyScreenRect) { |
| SetUpTextDirectionTest(kTestChar1, AccessibilityTextDirection::kBottomToTop); |
| // When on a character with an empty screen rect, the previous character's |
| // screen rect is used, but flipped. |
| TestTopToBottom(); |
| } |
| |
| class PdfCaretMoveTest : public PdfCaretTest { |
| public: |
| void SetUp() override { |
| PdfCaretTest::SetUp(); |
| EXPECT_CALL(client(), IsSynthesizedNewline(_)) |
| .WillRepeatedly(Return(false)); |
| EXPECT_CALL(client(), ClearTextSelection()).Times(AnyNumber()); |
| } |
| |
| void SetUpPagesWithSynthesizedChars( |
| const std::vector<std::vector<uint32_t>>& synthesized_chars) { |
| for (size_t page_index = 0; page_index < synthesized_chars.size(); |
| ++page_index) { |
| for (uint32_t synthesized_char : synthesized_chars[page_index]) { |
| PageCharacterIndex index{static_cast<uint32_t>(page_index), |
| synthesized_char}; |
| EXPECT_CALL(client(), IsSynthesizedNewline(index)) |
| .WillRepeatedly(Return(true)); |
| } |
| } |
| } |
| |
| void SetUpMultiLineTest() { |
| SetUpPagesWithCharCounts({10}); |
| SetUpPagesWithSynthesizedChars({{2, 3, 6, 7}}); |
| // "ab\r\n" |
| // "cd\r\n" |
| // "ef". |
| SetUpChar(kTestChar0, {kTestChar0ScreenRect}); |
| SetUpChar(kTestChar1, {kTestChar1ScreenRect}); |
| SetUpChar(kTestChar2, {}); |
| SetUpChar(kTestChar3, {}); |
| SetUpChar(kTestChar4, {gfx::Rect(11, 26, 10, 12)}); |
| SetUpChar(kTestChar5, {gfx::Rect(21, 26, 10, 12)}); |
| SetUpChar({0, 6}, {}); |
| SetUpChar({0, 7}, {}); |
| SetUpChar({0, 8}, {gfx::Rect(10, 50, 14, 16)}); |
| SetUpChar({0, 9}, {gfx::Rect(24, 50, 14, 16)}); |
| } |
| |
| void SetUpTwoWordWithUnicodeTest() { |
| SetUpPagesWithCharCounts({5}); |
| SetUpCharWithUnicode(kTestChar0, 'a', {kTestChar0ScreenRect}); |
| SetUpCharWithUnicode(kTestChar1, 'b', {kTestChar1ScreenRect}); |
| SetUpCharWithUnicode(kTestChar2, ' ', {}); |
| SetUpCharWithUnicode(kTestChar3, 'c', {kTestChar3ScreenRect}); |
| SetUpCharWithUnicode(kTestChar4, 'd', {kTestChar4ScreenRect}); |
| } |
| |
| void SetUpCharWithUnicode(const PageCharacterIndex& index, |
| uint32_t unicode_char, |
| std::vector<gfx::Rect> rects) { |
| SetUpChar(index, rects); |
| EXPECT_CALL(client(), GetCharUnicode(index)) |
| .WillRepeatedly(Return(unicode_char)); |
| } |
| |
| blink::WebKeyboardEvent GenerateControlKeyboardEvent(ui::KeyboardCode key) { |
| blink::WebKeyboardEvent event = GenerateKeyboardEvent(key); |
| #if BUILDFLAG(IS_MAC) |
| event.SetModifiers(blink::WebInputEvent::Modifiers::kAltKey); |
| #else |
| event.SetModifiers(blink::WebInputEvent::Modifiers::kControlKey); |
| #endif // BUILDFLAG(IS_MAC) |
| return event; |
| } |
| |
| bool MoveLeftByWordWithKeyboard() { |
| return caret().OnKeyDown( |
| GenerateControlKeyboardEvent(ui::KeyboardCode::VKEY_LEFT)); |
| } |
| |
| bool MoveRightByWordWithKeyboard() { |
| return caret().OnKeyDown( |
| GenerateControlKeyboardEvent(ui::KeyboardCode::VKEY_RIGHT)); |
| } |
| }; |
| |
| TEST_F(PdfCaretMoveTest, OnKeyDownNotEnabledNotVisible) { |
| SetUpSingleCharLineTest(); |
| InitializeCaretAtChar(kTestChar0); |
| |
| EXPECT_FALSE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_0))); |
| EXPECT_FALSE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_LEFT))); |
| EXPECT_FALSE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_RIGHT))); |
| EXPECT_FALSE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_UP))); |
| EXPECT_FALSE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_DOWN))); |
| } |
| |
| TEST_F(PdfCaretMoveTest, OnKeyDownNotEnabledVisible) { |
| SetUpSingleCharLineTest(); |
| InitializeCaretAtChar(kTestChar0); |
| |
| caret().SetVisible(true); |
| |
| EXPECT_FALSE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_0))); |
| EXPECT_FALSE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_LEFT))); |
| EXPECT_FALSE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_RIGHT))); |
| EXPECT_FALSE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_UP))); |
| EXPECT_FALSE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_DOWN))); |
| } |
| |
| TEST_F(PdfCaretMoveTest, OnKeyDownEnabledNotVisible) { |
| SetUpSingleCharLineTest(); |
| InitializeCaretAtChar(kTestChar0); |
| |
| caret().SetEnabled(true); |
| |
| EXPECT_FALSE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_0))); |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_LEFT))); |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_RIGHT))); |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_UP))); |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_DOWN))); |
| } |
| |
| TEST_F(PdfCaretMoveTest, OnKeyDownEnabledVisible) { |
| SetUpSingleCharLineTest(); |
| InitializeVisibleCaretAtChar(kTestChar0); |
| |
| EXPECT_FALSE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_0))); |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_LEFT))); |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_RIGHT))); |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_UP))); |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_DOWN))); |
| } |
| |
| TEST_F(PdfCaretMoveTest, MoveCharLeftRight) { |
| SetUpTwoCharLineTest(); |
| |
| // Start at left of char 0. |
| InitializeVisibleCaretAtChar(kTestChar0); |
| |
| // Left of char 1. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_RIGHT))); |
| TestDrawCaret(kTestChar1Caret); |
| |
| // Right of char 1. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_RIGHT))); |
| TestDrawCaret(kTestChar1EndCaret); |
| |
| // Right of char 1. |
| EXPECT_CALL(client(), IsSynthesizedNewline(kTestChar2)).Times(0); |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_RIGHT))); |
| TestDrawCaret(kTestChar1EndCaret); |
| |
| // Left of char 1. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_LEFT))); |
| TestDrawCaret(kTestChar1Caret); |
| |
| // Left of char 0. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_LEFT))); |
| TestDrawCaret(kTestChar0Caret); |
| |
| // Left of char 0. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_LEFT))); |
| TestDrawCaret(kTestChar0Caret); |
| } |
| |
| TEST_F(PdfCaretMoveTest, MoveCharLeftRightMultiPage) { |
| SetUpMultiPageTest(); |
| |
| // Start at left of page 1, char 0. |
| InitializeVisibleCaretAtChar(kTestPage1Char0); |
| |
| // Right of page 0, char 0. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_LEFT))); |
| TestDrawCaret(kTestChar0EndCaret); |
| |
| // Left of page 1, char 0. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_RIGHT))); |
| TestDrawCaret(kTestMultiPage1Char0Caret); |
| |
| // Left of page 1, char 1. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_RIGHT))); |
| TestDrawCaret(kTestMultiPage1Char1Caret); |
| |
| // Right of page 1, char 1. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_RIGHT))); |
| TestDrawCaret(kTestMultiPage1Char1EndCaret); |
| |
| // Top-left of page 2. Page 2 does not have any chars. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_RIGHT))); |
| TestDrawCaret(kTestMultiPage2NonTextScreenRect); |
| |
| // Left of page 3, char 0. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_RIGHT))); |
| TestDrawCaret(kTestMultiPage3Char0Caret); |
| |
| // Top-left of page 2. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_LEFT))); |
| TestDrawCaret(kTestMultiPage2NonTextScreenRect); |
| |
| // Right of page 1, char 1. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_LEFT))); |
| TestDrawCaret(kTestMultiPage1Char1EndCaret); |
| } |
| |
| TEST_F(PdfCaretMoveTest, MoveCharLeftRightSkipNewlines) { |
| SetUpPagesWithCharCounts({4}); |
| SetUpPagesWithSynthesizedChars({{1, 2}}); |
| // "a\r\n" |
| // "b". |
| SetUpChar(kTestChar0, {kTestChar0ScreenRect}); |
| SetUpChar(kTestChar1, {}); |
| SetUpChar(kTestChar2, {}); |
| SetUpChar(kTestChar3, {gfx::Rect(10, 26, 12, 14)}); |
| |
| // Start at left of page 0, char 0. |
| InitializeVisibleCaretAtChar(kTestChar0); |
| |
| // Right of page 0, char 0. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_RIGHT))); |
| TestDrawCaret(kTestChar0EndCaret); |
| |
| // Left of page 0, char 3 'b', skipping one newline. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_RIGHT))); |
| TestDrawCaret(gfx::Rect(10, 26, 1, 14)); |
| |
| // Right of page 0, char 0, skipping one newline. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_LEFT))); |
| TestDrawCaret(kTestChar0EndCaret); |
| } |
| |
| TEST_F(PdfCaretMoveTest, MoveCharLeftRightStartEndNewlines) { |
| SetUpPagesWithCharCounts({2}); |
| // "\n" |
| // "\n". |
| SetUpChar(kTestChar0, {kTestChar0ScreenRect}); |
| SetUpChar(kTestChar1, {kTestChar1ScreenRect}); |
| |
| // Start at left of page 0, char 0. |
| InitializeVisibleCaretAtChar(kTestChar0); |
| |
| // Left of page 0, char 1. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_RIGHT))); |
| TestDrawCaret(kTestChar1Caret); |
| |
| // Right of page 0, char 1. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_RIGHT))); |
| TestDrawCaret(kTestChar1EndCaret); |
| |
| // Left of page 0, char 1. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_LEFT))); |
| TestDrawCaret(kTestChar1Caret); |
| |
| // Left of page 0, char 0. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_LEFT))); |
| TestDrawCaret(kTestChar0Caret); |
| } |
| |
| TEST_F(PdfCaretMoveTest, MoveCharLeftRightConsecutiveNewlines) { |
| SetUpPagesWithCharCounts({5}); |
| SetUpPagesWithSynthesizedChars({{1, 2}}); |
| // "a\r\n" |
| // "\n" |
| // "b". |
| SetUpChar(kTestChar0, {kTestChar0ScreenRect}); |
| SetUpChar(kTestChar1, {}); |
| SetUpChar(kTestChar2, {}); |
| SetUpChar(kTestChar3, {gfx::Rect(10, 26, 12, 14)}); |
| SetUpChar(kTestChar4, {gfx::Rect(22, 26, 12, 14)}); |
| |
| // Start at left of page 0, char 1. |
| InitializeVisibleCaretAtChar(kTestChar1); |
| |
| // Left of page 0, char 3 '\n', skipping one newline. |
| constexpr gfx::Rect kTestChar3NewlineCaret{10, 26, 1, 14}; |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_RIGHT))); |
| TestDrawCaret(kTestChar3NewlineCaret); |
| |
| // Left of page 0, char 4 'b'. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_RIGHT))); |
| TestDrawCaret(gfx::Rect(22, 26, 1, 14)); |
| |
| // Left of page 0, char 3. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_LEFT))); |
| TestDrawCaret(kTestChar3NewlineCaret); |
| |
| // Right of page 0, char 0, skipping one newline. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_LEFT))); |
| TestDrawCaret(kTestChar0EndCaret); |
| } |
| |
| TEST_F(PdfCaretMoveTest, MoveCharLeftRightSingleSyntheticNewline) { |
| SetUpPagesWithCharCounts({3}); |
| SetUpPagesWithSynthesizedChars({{1}}); |
| // "a\n" |
| // "b". |
| SetUpChar(kTestChar0, {kTestChar0ScreenRect}); |
| SetUpChar(kTestChar1, {}); |
| SetUpChar(kTestChar2, {gfx::Rect(10, 26, 12, 14)}); |
| |
| // Start at left of page 0, char 0. |
| InitializeVisibleCaretAtChar(kTestChar0); |
| |
| // Right of page 0, char 1. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_RIGHT))); |
| TestDrawCaret(kTestChar0EndCaret); |
| |
| // Left of page 0, char 2 'b'. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_RIGHT))); |
| TestDrawCaret(gfx::Rect(10, 26, 1, 14)); |
| |
| // Right of page 0, char 1. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_LEFT))); |
| TestDrawCaret(kTestChar0EndCaret); |
| } |
| |
| TEST_F(PdfCaretMoveTest, MoveCharUpDown) { |
| SetUpPagesWithCharCounts({4}); |
| SetUpPagesWithSynthesizedChars({{1, 2}}); |
| // "a\r\n" |
| // "b". |
| SetUpChar(kTestChar0, {kTestChar0ScreenRect}); |
| SetUpChar(kTestChar1, {}); |
| SetUpChar(kTestChar2, {}); |
| SetUpChar(kTestChar3, {gfx::Rect(10, 24, 12, 14)}); |
| |
| // Start at left of char 0. |
| InitializeVisibleCaretAtChar(kTestChar0); |
| |
| // Left of char 3 'b'. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_DOWN))); |
| TestDrawCaret(gfx::Rect(10, 24, 1, 14)); |
| |
| // Left of char 0. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_UP))); |
| TestDrawCaret(kTestChar0Caret); |
| } |
| |
| TEST_F(PdfCaretMoveTest, MoveCharUpDownNonTextPage) { |
| SetUpNoTextPageTest(); |
| |
| InitializeVisibleCaretAtChar(kTestChar0); |
| |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_DOWN))); |
| TestDrawCaret(kDefaultCaret); |
| |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_UP))); |
| TestDrawCaret(kDefaultCaret); |
| } |
| |
| TEST_F(PdfCaretMoveTest, MoveCharUpDownSingleLine) { |
| SetUpTwoCharLineTest(); |
| |
| // Start at right of char 0. |
| InitializeVisibleCaretAtChar(kTestChar1); |
| |
| // Left of char 0. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_UP))); |
| TestDrawCaret(kTestChar0Caret); |
| |
| // No change. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_UP))); |
| TestDrawCaret(kTestChar0Caret); |
| |
| // Right of char 1 'b'. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_DOWN))); |
| TestDrawCaret(kTestChar1EndCaret); |
| |
| // No change. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_DOWN))); |
| TestDrawCaret(kTestChar1EndCaret); |
| } |
| |
| TEST_F(PdfCaretMoveTest, MoveCharUpDownMultiLine) { |
| SetUpMultiLineTest(); |
| |
| // Start at left of char 1 'b'. |
| InitializeVisibleCaretAtChar(kTestChar1); |
| |
| // Left of char 5 'd'. |
| constexpr gfx::Rect kTestChar5Caret{21, 26, 1, 12}; |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_DOWN))); |
| TestDrawCaret(kTestChar5Caret); |
| |
| // Left of char 9 'f'. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_DOWN))); |
| TestDrawCaret(gfx::Rect(24, 50, 1, 16)); |
| |
| // Left of char 5. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_UP))); |
| TestDrawCaret(kTestChar5Caret); |
| |
| // Left of char 1. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_UP))); |
| TestDrawCaret(kTestChar1Caret); |
| } |
| |
| TEST_F(PdfCaretMoveTest, MoveCharUpDownStartOnNewline) { |
| SetUpPagesWithCharCounts({6}); |
| SetUpPagesWithSynthesizedChars({{2, 3}}); |
| // "ab\r\n" |
| // "cd". |
| SetUpChar(kTestChar0, {kTestChar0ScreenRect}); |
| SetUpChar(kTestChar1, {kTestChar1ScreenRect}); |
| SetUpChar(kTestChar2, {}); |
| SetUpChar(kTestChar3, {}); |
| SetUpChar(kTestChar4, {gfx::Rect(10, 22, 12, 14)}); |
| SetUpChar(kTestChar5, {gfx::Rect(22, 22, 12, 14)}); |
| |
| // Start at right of char 1 '\r'. |
| InitializeVisibleCaretAtChar(kTestChar2); |
| |
| TestDrawCaret(kTestChar1EndCaret); |
| |
| // Right of char 5 'd'. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_DOWN))); |
| TestDrawCaret(gfx::Rect(34, 22, 1, 14)); |
| |
| // Reset back to right of char 1. |
| caret().SetCharAndDraw(kTestChar2); |
| TestDrawCaret(kTestChar1EndCaret); |
| |
| // Left of char 0 'a'. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_UP))); |
| TestDrawCaret(kTestChar0Caret); |
| } |
| |
| TEST_F(PdfCaretMoveTest, MoveCharUpDownMultiPage) { |
| SetUpMultiPageTest(); |
| |
| // Start at right of page 0, char 0 'a'. |
| InitializeVisibleCaretAtChar(kTestChar1); |
| |
| // Left of page 1, char 1 'c', which is closer than the right. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_DOWN))); |
| TestDrawCaret(kTestMultiPage1Char1Caret); |
| |
| // Top-left of page 2. Page 2 does not have any chars. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_DOWN))); |
| TestDrawCaret(kTestMultiPage2NonTextScreenRect); |
| |
| // Left of page 3, char 0 'd', which is closer than the right. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_DOWN))); |
| TestDrawCaret(kTestMultiPage3Char0Caret); |
| |
| // Top-left of page 2. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_UP))); |
| TestDrawCaret(kTestMultiPage2NonTextScreenRect); |
| |
| // Right of page 1, char 1, which is closer than the left. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_UP))); |
| TestDrawCaret(kTestMultiPage1Char1EndCaret); |
| |
| // Right of page 0, char 0. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_UP))); |
| TestDrawCaret(kTestChar0EndCaret); |
| } |
| |
| TEST_F(PdfCaretMoveTest, MoveCharUpDownLongerFirstLine) { |
| SetUpPagesWithCharCounts({6}); |
| SetUpPagesWithSynthesizedChars({{3, 4}}); |
| // "abc\r\n" |
| // "d". |
| SetUpChar(kTestChar0, {kTestChar0ScreenRect}); |
| SetUpChar(kTestChar1, {kTestChar1ScreenRect}); |
| SetUpChar(kTestChar2, {gfx::Rect(34, 10, 12, 14)}); |
| SetUpChar(kTestChar3, {}); |
| SetUpChar(kTestChar4, {}); |
| SetUpChar(kTestChar5, {gfx::Rect(10, 22, 12, 14)}); |
| |
| // Start at left of char 2 'c'. |
| InitializeVisibleCaretAtChar(kTestChar2); |
| |
| TestDrawCaret(kTestChar2Caret); |
| |
| // Move down to char with closest screen rect. Right of char 5 'd'. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_DOWN))); |
| TestDrawCaret(gfx::Rect(22, 22, 1, 14)); |
| |
| // Move up to char with closest screen rect. Left of char 1 'b'. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_UP))); |
| TestDrawCaret(kTestChar1Caret); |
| } |
| |
| TEST_F(PdfCaretMoveTest, MoveCharUpDownLongerSecondLine) { |
| SetUpPagesWithCharCounts({6}); |
| SetUpPagesWithSynthesizedChars({{1, 2}}); |
| // "a\r\n" |
| // "bcd". |
| SetUpChar(kTestChar0, {kTestChar0ScreenRect}); |
| SetUpChar(kTestChar1, {}); |
| SetUpChar(kTestChar2, {}); |
| SetUpChar(kTestChar3, {gfx::Rect(10, 22, 12, 14)}); |
| SetUpChar(kTestChar4, {gfx::Rect(22, 22, 12, 14)}); |
| SetUpChar(kTestChar5, {gfx::Rect(34, 22, 12, 14)}); |
| |
| // Start at right of char 5 'd'. |
| InitializeVisibleCaretAtChar({0, 6}); |
| |
| TestDrawCaret(gfx::Rect(46, 22, 1, 14)); |
| |
| // Right of char 0 'a'. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_UP))); |
| TestDrawCaret(kTestChar0EndCaret); |
| |
| // Left of char 4 'c'. |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_DOWN))); |
| TestDrawCaret(gfx::Rect(22, 22, 1, 14)); |
| } |
| |
| TEST_F(PdfCaretMoveTest, MoveCharScroll) { |
| SetUpMultiPageTest(); |
| InitializeVisibleCaretAtChar(kTestPage1Char1); |
| |
| InSequence sequence; |
| |
| EXPECT_CALL(client(), ScrollToChar(kTestPage1Char0)); |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_LEFT))); |
| |
| EXPECT_CALL(client(), ScrollToChar(kTestPage1Char1)); |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_RIGHT))); |
| |
| // No-text page. |
| EXPECT_CALL(client(), ScrollToChar(kTestPage2Char0)); |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_DOWN))); |
| |
| EXPECT_CALL(client(), ScrollToChar(kTestPage1Char1)); |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_UP))); |
| |
| caret().SetCharAndDraw(kTestPage3Char0); |
| |
| // Page 3 char 1 does not have a screen rect, so scroll to the previous char |
| // with one. |
| EXPECT_CALL(client(), ScrollToChar(kTestPage3Char0)); |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_RIGHT))); |
| } |
| |
| TEST_F(PdfCaretMoveTest, MoveWordLeftRightNoTextPage) { |
| SetUpNoTextPageTest(); |
| |
| InitializeVisibleCaretAtChar(kTestChar0); |
| |
| EXPECT_TRUE(MoveLeftByWordWithKeyboard()); |
| TestDrawCaret(kDefaultCaret); |
| |
| EXPECT_TRUE(MoveRightByWordWithKeyboard()); |
| TestDrawCaret(kDefaultCaret); |
| } |
| |
| TEST_F(PdfCaretMoveTest, MoveWordLeft) { |
| SetUpTwoWordWithUnicodeTest(); |
| |
| // Start at the right of a word. |
| InitializeVisibleCaretAtChar(kTestChar5); |
| |
| EXPECT_TRUE(MoveLeftByWordWithKeyboard()); |
| TestDrawCaret(kTestChar3Caret); |
| |
| // Start at the middle of a word. |
| caret().SetCharAndDraw(kTestChar4); |
| |
| EXPECT_TRUE(MoveLeftByWordWithKeyboard()); |
| TestDrawCaret(kTestChar3Caret); |
| |
| // Start at the left of a word. |
| caret().SetCharAndDraw(kTestChar3); |
| |
| EXPECT_TRUE(MoveLeftByWordWithKeyboard()); |
| TestDrawCaret(kTestChar0Caret); |
| |
| // Start at the start of the PDF. |
| caret().SetCharAndDraw(kTestChar0); |
| |
| EXPECT_TRUE(MoveLeftByWordWithKeyboard()); |
| TestDrawCaret(kTestChar0Caret); |
| } |
| |
| TEST_F(PdfCaretMoveTest, MoveWordLeftWordBoundaries) { |
| SetUpPagesWithCharCounts({5}); |
| SetUpCharWithUnicode(kTestChar0, 'a', {kTestChar0ScreenRect}); |
| SetUpCharWithUnicode(kTestChar1, ',', {kTestChar1ScreenRect}); |
| SetUpCharWithUnicode(kTestChar2, ' ', {}); |
| SetUpCharWithUnicode(kTestChar3, 'b', {kTestChar3ScreenRect}); |
| SetUpCharWithUnicode(kTestChar4, 'c', {kTestChar4ScreenRect}); |
| |
| // Start at two to the right of a word boundary. |
| InitializeVisibleCaretAtChar(kTestChar4); |
| |
| EXPECT_TRUE(MoveLeftByWordWithKeyboard()); |
| TestDrawCaret(kTestChar3Caret); |
| |
| // Start at the right of a word boundary. |
| caret().SetCharAndDraw(kTestChar3); |
| |
| EXPECT_TRUE(MoveLeftByWordWithKeyboard()); |
| // Blink's behavior would be to draw the caret at `kTestChar1Caret`. |
| // `PdfCaret`'s behavior is a simpler approximation of Blink's. |
| TestDrawCaret(kTestChar0Caret); |
| |
| // Start at the second word boundary. |
| caret().SetCharAndDraw(kTestChar2); |
| |
| EXPECT_TRUE(MoveLeftByWordWithKeyboard()); |
| // Blink's behavior would be to draw the caret at `kTestChar1Caret`. |
| // `PdfCaret`'s behavior is a simpler approximation of Blink's. |
| TestDrawCaret(kTestChar0Caret); |
| |
| // Start at the first word boundary. |
| caret().SetCharAndDraw(kTestChar1); |
| |
| EXPECT_TRUE(MoveLeftByWordWithKeyboard()); |
| TestDrawCaret(kTestChar0Caret); |
| } |
| |
| TEST_F(PdfCaretMoveTest, MoveWordLeftNewlines) { |
| SetUpPagesWithCharCounts({6}); |
| SetUpPagesWithSynthesizedChars({{2, 3}}); |
| SetUpCharWithUnicode(kTestChar0, 'a', {kTestChar0ScreenRect}); |
| SetUpCharWithUnicode(kTestChar1, ',', {kTestChar1ScreenRect}); |
| SetUpCharWithUnicode(kTestChar2, '\r', {}); |
| SetUpCharWithUnicode(kTestChar3, '\n', {}); |
| SetUpCharWithUnicode(kTestChar4, 'b', {gfx::Rect(10, 24, 12, 14)}); |
| SetUpCharWithUnicode(kTestChar5, 'c', {gfx::Rect(22, 24, 12, 14)}); |
| |
| // Start at two to the right of a newline. |
| InitializeVisibleCaretAtChar(kTestChar5); |
| |
| EXPECT_TRUE(MoveLeftByWordWithKeyboard()); |
| TestDrawCaret(gfx::Rect(10, 24, 1, 14)); |
| |
| // Start at the right of a newline. |
| caret().SetCharAndDraw(kTestChar4); |
| |
| EXPECT_TRUE(MoveLeftByWordWithKeyboard()); |
| TestDrawCaret(kTestChar2Caret); |
| |
| // Start at the second newline. |
| caret().SetCharAndDraw(kTestChar3); |
| |
| EXPECT_TRUE(MoveLeftByWordWithKeyboard()); |
| TestDrawCaret(kTestChar2Caret); |
| |
| // Start at the first newline to the right of a word boundary. |
| caret().SetCharAndDraw(kTestChar2); |
| |
| EXPECT_TRUE(MoveLeftByWordWithKeyboard()); |
| // Blink's behavior would be to draw the caret at `kTestChar1Caret`. |
| // `PdfCaret`'s behavior is a simpler approximation of Blink's. |
| TestDrawCaret(kTestChar0Caret); |
| } |
| |
| TEST_F(PdfCaretMoveTest, MoveWordLeftMultiPage) { |
| SetUpPagesWithCharCounts({2, 1, 1}); |
| SetUpCharWithUnicode(kTestChar0, 'a', {kTestChar0ScreenRect}); |
| SetUpCharWithUnicode(kTestChar1, ',', {kTestChar1ScreenRect}); |
| SetUpCharWithUnicode(kTestPage1Char0, 'b', {kTestMultiPage1Char0ScreenRect}); |
| SetUpCharWithUnicode(kTestPage2Char0, 'c', {kTestMultiPage2Char0ScreenRect}); |
| |
| // Start at the end of page 2. |
| InitializeVisibleCaretAtChar({2, 1}); |
| |
| EXPECT_TRUE(MoveLeftByWordWithKeyboard()); |
| TestDrawCaret(kTestMultiPage2Char0Caret); |
| |
| // Start at the start of page 2. |
| caret().SetCharAndDraw(kTestPage2Char0); |
| |
| EXPECT_TRUE(MoveLeftByWordWithKeyboard()); |
| TestDrawCaret(kTestMultiPage1Char0EndCaret); |
| |
| // Start at the start of page 1. |
| caret().SetCharAndDraw(kTestPage1Char0); |
| |
| EXPECT_TRUE(MoveLeftByWordWithKeyboard()); |
| TestDrawCaret(kTestChar1EndCaret); |
| } |
| |
| TEST_F(PdfCaretMoveTest, MoveWordRight) { |
| SetUpTwoWordWithUnicodeTest(); |
| |
| // Start at the left of a word. |
| InitializeVisibleCaretAtChar(kTestChar0); |
| |
| EXPECT_TRUE(MoveRightByWordWithKeyboard()); |
| TestDrawCaret(kTestChar2Caret); |
| |
| // Start at the middle of a word. |
| caret().SetCharAndDraw(kTestChar1); |
| |
| EXPECT_TRUE(MoveRightByWordWithKeyboard()); |
| TestDrawCaret(kTestChar2Caret); |
| |
| // Start at the right of a word. |
| caret().SetCharAndDraw(kTestChar2); |
| |
| constexpr gfx::Rect kTestChar4EndCaret{70, 10, 1, 14}; |
| EXPECT_TRUE(MoveRightByWordWithKeyboard()); |
| TestDrawCaret(kTestChar4EndCaret); |
| |
| // Start at the end of the PDF. |
| caret().SetCharAndDraw(kTestChar5); |
| |
| EXPECT_TRUE(MoveRightByWordWithKeyboard()); |
| TestDrawCaret(kTestChar4EndCaret); |
| } |
| |
| TEST_F(PdfCaretMoveTest, MoveWordRightWordBoundaries) { |
| SetUpPagesWithCharCounts({4}); |
| SetUpCharWithUnicode(kTestChar0, 'a', {kTestChar0ScreenRect}); |
| SetUpCharWithUnicode(kTestChar1, ' ', {}); |
| SetUpCharWithUnicode(kTestChar2, '-', {gfx::Rect(34, 10, 12, 14)}); |
| SetUpCharWithUnicode(kTestChar3, 'c', {kTestChar3ScreenRect}); |
| |
| // Start at one to the left of a word boundary. |
| InitializeVisibleCaretAtChar(kTestChar0); |
| |
| EXPECT_TRUE(MoveRightByWordWithKeyboard()); |
| TestDrawCaret(kTestChar1Caret); |
| |
| // Start at the first word boundary. |
| caret().SetCharAndDraw(kTestChar1); |
| |
| EXPECT_TRUE(MoveRightByWordWithKeyboard()); |
| // Blink's behavior would be to draw the caret at `kTestChar3Caret`. |
| // `PdfCaret`'s behavior is a simpler approximation of Blink's. |
| TestDrawCaret(kTestChar2Caret); |
| |
| // Start at the second word boundary. |
| caret().SetCharAndDraw(kTestChar2); |
| |
| constexpr gfx::Rect kTestChar3EndCaret{58, 10, 1, 14}; |
| EXPECT_TRUE(MoveRightByWordWithKeyboard()); |
| // Blink's behavior would be to draw the caret at `kTestChar3Caret`. |
| // `PdfCaret`'s behavior is a simpler approximation of Blink's. |
| TestDrawCaret(kTestChar3EndCaret); |
| |
| // Start at the right of a word boundary. |
| caret().SetCharAndDraw(kTestChar3); |
| |
| EXPECT_TRUE(MoveRightByWordWithKeyboard()); |
| TestDrawCaret(kTestChar3EndCaret); |
| } |
| |
| TEST_F(PdfCaretMoveTest, MoveWordRightNewlines) { |
| SetUpPagesWithCharCounts({5}); |
| SetUpPagesWithSynthesizedChars({{1, 2}}); |
| SetUpCharWithUnicode(kTestChar0, 'a', {kTestChar0ScreenRect}); |
| SetUpCharWithUnicode(kTestChar1, '\r', {}); |
| SetUpCharWithUnicode(kTestChar2, '\n', {}); |
| SetUpCharWithUnicode(kTestChar3, '-', {gfx::Rect(10, 24, 12, 14)}); |
| SetUpCharWithUnicode(kTestChar4, 'c', {gfx::Rect(22, 24, 12, 14)}); |
| |
| // Start at one to the left of a newline. |
| InitializeVisibleCaretAtChar(kTestChar0); |
| |
| EXPECT_TRUE(MoveRightByWordWithKeyboard()); |
| TestDrawCaret(kTestChar1Caret); |
| |
| // Start at the first newline. |
| caret().SetCharAndDraw(kTestChar1); |
| |
| constexpr gfx::Rect kTestChar4Caret{22, 24, 1, 14}; |
| EXPECT_TRUE(MoveRightByWordWithKeyboard()); |
| TestDrawCaret(kTestChar4Caret); |
| |
| // Start at the second newline. |
| caret().SetCharAndDraw(kTestChar2); |
| |
| EXPECT_TRUE(MoveRightByWordWithKeyboard()); |
| TestDrawCaret(kTestChar4Caret); |
| |
| // Start at the right of a newline to the left of a word boundary. |
| caret().SetCharAndDraw(kTestChar3); |
| |
| EXPECT_TRUE(MoveRightByWordWithKeyboard()); |
| TestDrawCaret({34, 24, 1, 14}); |
| } |
| |
| TEST_F(PdfCaretMoveTest, MoveWordRightMultiPage) { |
| SetUpPagesWithCharCounts({1, 2, 1}); |
| SetUpCharWithUnicode(kTestChar0, 'a', {kTestChar0ScreenRect}); |
| SetUpCharWithUnicode(kTestPage1Char0, '-', {kTestMultiPage1Char0ScreenRect}); |
| SetUpCharWithUnicode(kTestPage1Char1, 'b', {kTestMultiPage1Char1ScreenRect}); |
| SetUpCharWithUnicode(kTestPage2Char0, 'c', {kTestMultiPage2Char0ScreenRect}); |
| |
| // Start at the start of page 0. |
| InitializeVisibleCaretAtChar(kTestChar0); |
| |
| EXPECT_TRUE(MoveRightByWordWithKeyboard()); |
| TestDrawCaret(kTestChar0EndCaret); |
| |
| // Start at the end of page 0. |
| caret().SetCharAndDraw(kTestChar1); |
| |
| EXPECT_TRUE(MoveRightByWordWithKeyboard()); |
| TestDrawCaret(kTestMultiPage1Char0Caret); |
| |
| // Start at the end of page 1. |
| caret().SetCharAndDraw({1, 2}); |
| |
| EXPECT_TRUE(MoveRightByWordWithKeyboard()); |
| TestDrawCaret(kTestMultiPage2Char0Caret); |
| } |
| |
| class PdfCaretSelectionTest : public PdfCaretMoveTest { |
| public: |
| // Same as `SetUpTwoCharLineTest()` but with unicode chars. |
| void SetUpTwoCharLineWithUnicodeTest() { |
| SetUpPagesWithCharCounts({2}); |
| SetUpCharWithUnicode(kTestChar0, 'a', {kTestChar0ScreenRect}); |
| SetUpCharWithUnicode(kTestChar1, 'b', {kTestChar1ScreenRect}); |
| } |
| |
| blink::WebKeyboardEvent GenerateShiftKeyboardEvent(ui::KeyboardCode key) { |
| blink::WebKeyboardEvent event = GenerateKeyboardEvent(key); |
| event.SetModifiers(blink::WebInputEvent::Modifiers::kShiftKey); |
| return event; |
| } |
| |
| void ExpectExtendAndInvalidateSelectionByChar( |
| const PageCharacterIndex& index) { |
| EXPECT_CALL(client(), ExtendAndInvalidateSelectionByChar(index)) |
| .WillOnce([&]() { |
| // When text selection is extended, the client will normally hide the |
| // caret. |
| caret().SetVisible(false); |
| }); |
| } |
| }; |
| |
| TEST_F(PdfCaretSelectionTest, SelectRight) { |
| SetUpTwoCharLineTest(); |
| |
| // Start at left of char 0. |
| InitializeVisibleCaretAtChar(kTestChar0); |
| |
| // Move right. Select char 1. |
| EXPECT_CALL(client(), IsSelecting()).WillOnce(Return(false)); |
| EXPECT_CALL(client(), StartSelection(kTestChar0)); |
| ExpectExtendAndInvalidateSelectionByChar(kTestChar1); |
| EXPECT_TRUE(caret().OnKeyDown( |
| GenerateShiftKeyboardEvent(ui::KeyboardCode::VKEY_RIGHT))); |
| |
| TestDrawCaretFails(kTestChar1Caret); |
| |
| // Move right. Select char 2. |
| EXPECT_CALL(client(), IsSelecting()).WillOnce(Return(true)); |
| ExpectExtendAndInvalidateSelectionByChar(kTestChar2); |
| EXPECT_TRUE(caret().OnKeyDown( |
| GenerateShiftKeyboardEvent(ui::KeyboardCode::VKEY_RIGHT))); |
| |
| TestDrawCaretFails(kTestChar1EndCaret); |
| |
| // Move right without shift. |
| EXPECT_CALL(client(), ClearTextSelection()); |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_RIGHT))); |
| TestDrawCaret(kTestChar1EndCaret); |
| } |
| |
| TEST_F(PdfCaretSelectionTest, SelectLeft) { |
| SetUpTwoCharLineTest(); |
| |
| // Start at right of char 1. |
| InitializeVisibleCaretAtChar(kTestChar2); |
| |
| // Move left. Select char 1. |
| EXPECT_CALL(client(), IsSelecting()).WillOnce(Return(false)); |
| EXPECT_CALL(client(), StartSelection(kTestChar2)); |
| ExpectExtendAndInvalidateSelectionByChar(kTestChar1); |
| EXPECT_TRUE(caret().OnKeyDown( |
| GenerateShiftKeyboardEvent(ui::KeyboardCode::VKEY_LEFT))); |
| |
| TestDrawCaretFails(kTestChar1Caret); |
| |
| // Move left. Select char 0. |
| EXPECT_CALL(client(), IsSelecting()).WillOnce(Return(true)); |
| ExpectExtendAndInvalidateSelectionByChar(kTestChar0); |
| EXPECT_TRUE(caret().OnKeyDown( |
| GenerateShiftKeyboardEvent(ui::KeyboardCode::VKEY_LEFT))); |
| |
| TestDrawCaretFails(kTestChar0Caret); |
| |
| // Move left without shift. |
| EXPECT_CALL(client(), ClearTextSelection()); |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_LEFT))); |
| TestDrawCaret(kTestChar0Caret); |
| } |
| |
| TEST_F(PdfCaretSelectionTest, SelectDown) { |
| SetUpMultiLineTest(); |
| |
| // Start at left of char 1 'b'. |
| InitializeVisibleCaretAtChar(kTestChar1); |
| |
| // Move down. Select chars 1, 2, 3, 4. |
| EXPECT_CALL(client(), IsSelecting()).WillOnce(Return(false)); |
| EXPECT_CALL(client(), StartSelection(kTestChar1)); |
| ExpectExtendAndInvalidateSelectionByChar(PageCharacterIndex(0, 5)); |
| EXPECT_TRUE(caret().OnKeyDown( |
| GenerateShiftKeyboardEvent(ui::KeyboardCode::VKEY_DOWN))); |
| |
| // Move down. Select chars 5, 6, 7, 8. |
| EXPECT_CALL(client(), IsSelecting()).WillOnce(Return(true)); |
| ExpectExtendAndInvalidateSelectionByChar(PageCharacterIndex(0, 9)); |
| EXPECT_TRUE(caret().OnKeyDown( |
| GenerateShiftKeyboardEvent(ui::KeyboardCode::VKEY_DOWN))); |
| |
| // Move down. Select char 9 'f' (end of page). |
| EXPECT_CALL(client(), IsSelecting()).WillOnce(Return(true)); |
| ExpectExtendAndInvalidateSelectionByChar(PageCharacterIndex(0, 10)); |
| EXPECT_TRUE(caret().OnKeyDown( |
| GenerateShiftKeyboardEvent(ui::KeyboardCode::VKEY_DOWN))); |
| |
| constexpr gfx::Rect kTestChar9EndCaret{38, 50, 1, 16}; |
| TestDrawCaretFails(kTestChar9EndCaret); |
| |
| // Move down without shift. |
| EXPECT_CALL(client(), ClearTextSelection()); |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_DOWN))); |
| TestDrawCaret(kTestChar9EndCaret); |
| } |
| |
| TEST_F(PdfCaretSelectionTest, SelectUp) { |
| SetUpMultiLineTest(); |
| |
| // Start at left of char 9 'f'. |
| constexpr PageCharacterIndex kTestChar9{0, 9}; |
| InitializeVisibleCaretAtChar(kTestChar9); |
| |
| // Move up. Select chars 8, 7, 6, 5. |
| EXPECT_CALL(client(), IsSelecting()).WillOnce(Return(false)); |
| EXPECT_CALL(client(), StartSelection(kTestChar9)); |
| ExpectExtendAndInvalidateSelectionByChar(PageCharacterIndex(0, 5)); |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateShiftKeyboardEvent(ui::KeyboardCode::VKEY_UP))); |
| |
| // Move up. Select chars 4, 3, 2, 1. |
| EXPECT_CALL(client(), IsSelecting()).WillOnce(Return(true)); |
| ExpectExtendAndInvalidateSelectionByChar(kTestChar1); |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateShiftKeyboardEvent(ui::KeyboardCode::VKEY_UP))); |
| |
| // Move up. Select char 0 'a' (start of page). |
| EXPECT_CALL(client(), IsSelecting()).WillOnce(Return(true)); |
| ExpectExtendAndInvalidateSelectionByChar(kTestChar0); |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateShiftKeyboardEvent(ui::KeyboardCode::VKEY_UP))); |
| |
| TestDrawCaretFails(kTestChar0Caret); |
| |
| // Move up without shift. |
| EXPECT_CALL(client(), ClearTextSelection()); |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateKeyboardEvent(ui::KeyboardCode::VKEY_UP))); |
| TestDrawCaret(kTestChar0Caret); |
| } |
| |
| TEST_F(PdfCaretSelectionTest, SelectCtrlRight) { |
| SetUpTwoCharLineWithUnicodeTest(); |
| |
| // Start at left of char 0. |
| InitializeVisibleCaretAtChar(kTestChar0); |
| |
| // Move right by word, selecting chars 0 and 1. |
| EXPECT_CALL(client(), IsSelecting()).WillOnce(Return(false)); |
| EXPECT_CALL(client(), StartSelection(kTestChar0)); |
| ExpectExtendAndInvalidateSelectionByChar(kTestChar2); |
| blink::WebKeyboardEvent event = |
| GenerateControlKeyboardEvent(ui::KeyboardCode::VKEY_RIGHT); |
| event.SetModifiers(event.GetModifiers() | |
| blink::WebInputEvent::Modifiers::kShiftKey); |
| EXPECT_TRUE(caret().OnKeyDown(event)); |
| |
| TestDrawCaretFails(kTestChar1EndCaret); |
| |
| // Move right without shift. |
| EXPECT_CALL(client(), ClearTextSelection()); |
| EXPECT_TRUE(MoveRightByWordWithKeyboard()); |
| TestDrawCaret(kTestChar1EndCaret); |
| } |
| |
| TEST_F(PdfCaretSelectionTest, SelectCtrlLeft) { |
| SetUpTwoCharLineWithUnicodeTest(); |
| |
| // Start at right of char 1. |
| InitializeVisibleCaretAtChar(kTestChar2); |
| |
| // Move left by word, selecting chars 0 and 1. |
| EXPECT_CALL(client(), IsSelecting()).WillOnce(Return(false)); |
| EXPECT_CALL(client(), StartSelection(kTestChar2)); |
| ExpectExtendAndInvalidateSelectionByChar(kTestChar0); |
| blink::WebKeyboardEvent event = |
| GenerateControlKeyboardEvent(ui::KeyboardCode::VKEY_LEFT); |
| event.SetModifiers(event.GetModifiers() | |
| blink::WebInputEvent::Modifiers::kShiftKey); |
| EXPECT_TRUE(caret().OnKeyDown(event)); |
| |
| TestDrawCaretFails(kTestChar0Caret); |
| |
| // Move left without shift. |
| EXPECT_CALL(client(), ClearTextSelection()); |
| EXPECT_TRUE(MoveLeftByWordWithKeyboard()); |
| TestDrawCaret(kTestChar0Caret); |
| } |
| |
| TEST_F(PdfCaretSelectionTest, SelectStartOnNonTextPageMoveToNonTextPage) { |
| SetUpPagesWithCharCounts({0, 0}); |
| // Page 0: No text. |
| // Page 1: No text. |
| SetUpChar(kTestChar0, {kDefaultScreenRect}); |
| SetUpChar(kTestPage1Char0, {gfx::Rect(10, 50, 1, 12)}); |
| |
| InitializeVisibleCaretAtChar(kTestChar0); |
| |
| // Moving from a no-text page to another no-text page should not start a |
| // selection. |
| EXPECT_CALL(client(), StartSelection(_)).Times(0); |
| |
| EXPECT_CALL(client(), IsSelecting()).WillOnce(Return(false)); |
| EXPECT_TRUE(caret().OnKeyDown( |
| GenerateShiftKeyboardEvent(ui::KeyboardCode::VKEY_RIGHT))); |
| |
| EXPECT_CALL(client(), IsSelecting()).WillOnce(Return(false)); |
| EXPECT_TRUE(caret().OnKeyDown( |
| GenerateShiftKeyboardEvent(ui::KeyboardCode::VKEY_LEFT))); |
| } |
| |
| TEST_F(PdfCaretSelectionTest, SelectStartOnTextPageMoveToNonTextPages) { |
| SetUpPagesWithCharCounts({1, 0, 0}); |
| // Page 0: "\0". |
| // Page 1: No text. |
| // Page 2: No text. |
| SetUpChar(kTestChar0, {kTestChar0ScreenRect}); |
| SetUpChar(kTestPage1Char0, {gfx::Rect(10, 50, 1, 12)}); |
| SetUpChar(kTestPage2Char0, {gfx::Rect(10, 100, 1, 12)}); |
| |
| InitializeVisibleCaretAtChar(kTestChar0); |
| |
| // Select page 0, char 0. |
| EXPECT_CALL(client(), IsSelecting()).WillOnce(Return(false)); |
| EXPECT_CALL(client(), StartSelection(kTestChar0)); |
| ExpectExtendAndInvalidateSelectionByChar(kTestChar1); |
| EXPECT_TRUE(caret().OnKeyDown( |
| GenerateShiftKeyboardEvent(ui::KeyboardCode::VKEY_RIGHT))); |
| |
| // Moving to multiple no-text pages should not extend selection. |
| EXPECT_CALL(client(), ExtendAndInvalidateSelectionByChar(_)).Times(0); |
| |
| EXPECT_CALL(client(), IsSelecting()).WillOnce(Return(true)); |
| EXPECT_TRUE(caret().OnKeyDown( |
| GenerateShiftKeyboardEvent(ui::KeyboardCode::VKEY_RIGHT))); |
| |
| EXPECT_CALL(client(), IsSelecting()).WillOnce(Return(true)); |
| EXPECT_TRUE(caret().OnKeyDown( |
| GenerateShiftKeyboardEvent(ui::KeyboardCode::VKEY_RIGHT))); |
| } |
| |
| TEST_F(PdfCaretSelectionTest, SelectNonTextPage) { |
| SetUpNoTextPageTest(); |
| |
| InitializeVisibleCaretAtChar(kTestChar0); |
| |
| EXPECT_CALL(client(), StartSelection(_)).Times(0); |
| EXPECT_CALL(client(), ExtendAndInvalidateSelectionByChar(_)).Times(0); |
| |
| EXPECT_TRUE(caret().OnKeyDown( |
| GenerateShiftKeyboardEvent(ui::KeyboardCode::VKEY_LEFT))); |
| EXPECT_TRUE(caret().OnKeyDown( |
| GenerateShiftKeyboardEvent(ui::KeyboardCode::VKEY_RIGHT))); |
| EXPECT_TRUE(caret().OnKeyDown( |
| GenerateShiftKeyboardEvent(ui::KeyboardCode::VKEY_DOWN))); |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateShiftKeyboardEvent(ui::KeyboardCode::VKEY_UP))); |
| } |
| |
| TEST_F(PdfCaretSelectionTest, SelectStartingOnNonTextPage) { |
| SetUpMultiPageTest(); |
| |
| // Start on the no-text page. |
| InitializeVisibleCaretAtChar(kTestPage2Char0); |
| |
| // `StartSelection()` should be called on the nearest caret position in the |
| // direction of movement. In this case, it would be right of page 1, char 1. |
| constexpr PageCharacterIndex kTestPage1Char1End{1, 2}; |
| EXPECT_CALL(client(), IsSelecting()).WillOnce(Return(false)); |
| EXPECT_CALL(client(), StartSelection(kTestPage1Char1End)); |
| ExpectExtendAndInvalidateSelectionByChar(kTestPage1Char1End); |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateShiftKeyboardEvent(ui::KeyboardCode::VKEY_UP))); |
| } |
| |
| TEST_F(PdfCaretSelectionTest, MoveCaretWithShiftDownMultiPage) { |
| SetUpMultiPageTest(); |
| |
| // Start at right of page 0, char 0. |
| InitializeVisibleCaretAtChar(kTestChar1); |
| |
| // Move down. Select page 1, char 0 'b'. |
| EXPECT_CALL(client(), IsSelecting()).WillOnce(Return(false)); |
| EXPECT_CALL(client(), StartSelection(kTestChar1)); |
| ExpectExtendAndInvalidateSelectionByChar(kTestPage1Char1); |
| EXPECT_TRUE(caret().OnKeyDown( |
| GenerateShiftKeyboardEvent(ui::KeyboardCode::VKEY_DOWN))); |
| |
| // Move down. Select page 1, char 1 'c'. Caret should be on the no-text page. |
| EXPECT_CALL(client(), IsSelecting()).WillOnce(Return(true)); |
| ExpectExtendAndInvalidateSelectionByChar(PageCharacterIndex(1, 2)); |
| EXPECT_TRUE(caret().OnKeyDown( |
| GenerateShiftKeyboardEvent(ui::KeyboardCode::VKEY_DOWN))); |
| |
| // Move down. The selection should extend past the no-text page. |
| EXPECT_CALL(client(), IsSelecting()).WillOnce(Return(true)); |
| ExpectExtendAndInvalidateSelectionByChar(PageCharacterIndex(3, 0)); |
| EXPECT_TRUE(caret().OnKeyDown( |
| GenerateShiftKeyboardEvent(ui::KeyboardCode::VKEY_DOWN))); |
| |
| // Move down. Select page 3, char 0 'd'. |
| EXPECT_CALL(client(), IsSelecting()).WillOnce(Return(true)); |
| ExpectExtendAndInvalidateSelectionByChar(PageCharacterIndex(3, 1)); |
| EXPECT_TRUE(caret().OnKeyDown( |
| GenerateShiftKeyboardEvent(ui::KeyboardCode::VKEY_DOWN))); |
| } |
| |
| TEST_F(PdfCaretSelectionTest, MoveCaretWithShiftUpMultiPage) { |
| SetUpMultiPageTest(); |
| |
| // Start at right of page 3, char 0 'd'. |
| InitializeVisibleCaretAtChar({3, 1}); |
| |
| // Move up. Select page 3, char 0. Caret should be on no-text page. |
| EXPECT_CALL(client(), IsSelecting()).WillOnce(Return(false)); |
| EXPECT_CALL(client(), StartSelection(PageCharacterIndex(3, 1))); |
| ExpectExtendAndInvalidateSelectionByChar(PageCharacterIndex(3, 0)); |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateShiftKeyboardEvent(ui::KeyboardCode::VKEY_UP))); |
| |
| // Move up. The selection should extend past the no-text page. |
| EXPECT_CALL(client(), IsSelecting()).WillOnce(Return(true)); |
| ExpectExtendAndInvalidateSelectionByChar(PageCharacterIndex(1, 2)); |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateShiftKeyboardEvent(ui::KeyboardCode::VKEY_UP))); |
| |
| // Move up. Select page 1, char 1 'c' and page 1, char 0 'b'. |
| EXPECT_CALL(client(), IsSelecting()).WillOnce(Return(true)); |
| ExpectExtendAndInvalidateSelectionByChar(kTestChar1); |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateShiftKeyboardEvent(ui::KeyboardCode::VKEY_UP))); |
| |
| // Move up. Select page 0, char 0 'a'. |
| EXPECT_CALL(client(), IsSelecting()).WillOnce(Return(true)); |
| ExpectExtendAndInvalidateSelectionByChar(kTestChar0); |
| EXPECT_TRUE( |
| caret().OnKeyDown(GenerateShiftKeyboardEvent(ui::KeyboardCode::VKEY_UP))); |
| } |
| |
| class PdfCaretMoveWithTextDirectionTest : public PdfCaretMoveTest { |
| public: |
| void SetUpTextDirectionTest(AccessibilityTextDirection direction) { |
| // To simplify tests, just use a single character. |
| SetUpSingleCharLineTest(); |
| EXPECT_CALL(client(), GetTextRunInfoAt(_)) |
| .WillRepeatedly(Return(GenerateTestTextRunInfo(direction))); |
| InitializeVisibleCaretAtChar(kTestChar0); |
| } |
| |
| void TestMove(ui::KeyboardCode key, const gfx::Rect& expected_caret) { |
| EXPECT_TRUE(caret().OnKeyDown(GenerateKeyboardEvent(key))); |
| TestDrawCaret(expected_caret); |
| } |
| }; |
| |
| TEST_F(PdfCaretMoveWithTextDirectionTest, LeftToRight) { |
| SetUpTextDirectionTest(AccessibilityTextDirection::kLeftToRight); |
| TestDrawCaret(kTestChar0Caret); |
| TestMove(ui::KeyboardCode::VKEY_RIGHT, kTestChar0EndCaret); |
| TestMove(ui::KeyboardCode::VKEY_LEFT, kTestChar0Caret); |
| TestMove(ui::KeyboardCode::VKEY_DOWN, kTestChar0EndCaret); |
| TestMove(ui::KeyboardCode::VKEY_UP, kTestChar0Caret); |
| } |
| |
| TEST_F(PdfCaretMoveWithTextDirectionTest, RightToLeft) { |
| SetUpTextDirectionTest(AccessibilityTextDirection::kRightToLeft); |
| TestDrawCaret(kTestChar0EndCaret); |
| TestMove(ui::KeyboardCode::VKEY_LEFT, kTestChar0Caret); |
| TestMove(ui::KeyboardCode::VKEY_RIGHT, kTestChar0EndCaret); |
| TestMove(ui::KeyboardCode::VKEY_DOWN, kTestChar0Caret); |
| TestMove(ui::KeyboardCode::VKEY_UP, kTestChar0EndCaret); |
| } |
| |
| TEST_F(PdfCaretMoveWithTextDirectionTest, TopToBottom) { |
| SetUpTextDirectionTest(AccessibilityTextDirection::kTopToBottom); |
| TestDrawCaret(kTestChar0TopCaret); |
| TestMove(ui::KeyboardCode::VKEY_DOWN, kTestChar0BottomCaret); |
| TestMove(ui::KeyboardCode::VKEY_UP, kTestChar0TopCaret); |
| TestMove(ui::KeyboardCode::VKEY_LEFT, kTestChar0BottomCaret); |
| TestMove(ui::KeyboardCode::VKEY_RIGHT, kTestChar0TopCaret); |
| } |
| |
| TEST_F(PdfCaretMoveWithTextDirectionTest, BottomToTop) { |
| SetUpTextDirectionTest(AccessibilityTextDirection::kBottomToTop); |
| TestDrawCaret(kTestChar0BottomCaret); |
| TestMove(ui::KeyboardCode::VKEY_UP, kTestChar0TopCaret); |
| TestMove(ui::KeyboardCode::VKEY_DOWN, kTestChar0BottomCaret); |
| TestMove(ui::KeyboardCode::VKEY_LEFT, kTestChar0TopCaret); |
| TestMove(ui::KeyboardCode::VKEY_RIGHT, kTestChar0BottomCaret); |
| } |
| |
| } // namespace |
| |
| } // namespace chrome_pdf |