diff options
Diffstat (limited to 'chromium/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc')
-rw-r--r-- | chromium/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc | 335 |
1 files changed, 335 insertions, 0 deletions
diff --git a/chromium/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc b/chromium/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc new file mode 100644 index 00000000000..d553821ebfe --- /dev/null +++ b/chromium/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc @@ -0,0 +1,335 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/core/display_lock/display_lock_context.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h" +#include "third_party/blink/renderer/core/editing/finder/text_finder.h" +#include "third_party/blink/renderer/core/frame/find_in_page.h" +#include "third_party/blink/renderer/core/frame/frame_test_helpers.h" +#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h" +#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h" +#include "third_party/blink/renderer/platform/runtime_enabled_features.h" +#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" + +namespace blink { +namespace { +class DisplayLockTestFindInPageClient : public mojom::blink::FindInPageClient { + public: + DisplayLockTestFindInPageClient() + : find_results_are_ready_(false), count_(-1), binding_(this) {} + + ~DisplayLockTestFindInPageClient() override = default; + + void SetFrame(WebLocalFrameImpl* frame) { + mojom::blink::FindInPageClientPtr client; + binding_.Bind(MakeRequest(&client)); + frame->GetFindInPage()->SetClient(std::move(client)); + } + + void SetNumberOfMatches( + int request_id, + unsigned int current_number_of_matches, + mojom::blink::FindMatchUpdateType final_update) final { + count_ = current_number_of_matches; + find_results_are_ready_ = + (final_update == mojom::blink::FindMatchUpdateType::kFinalUpdate); + } + + void SetActiveMatch(int request_id, + const WebRect& active_match_rect, + int active_match_ordinal, + mojom::blink::FindMatchUpdateType final_update) final { + find_results_are_ready_ = + (final_update == mojom::blink::FindMatchUpdateType::kFinalUpdate); + } + + bool FindResultsAreReady() const { return find_results_are_ready_; } + int Count() const { return count_; } + void Reset() { + find_results_are_ready_ = false; + count_ = -1; + } + + private: + bool find_results_are_ready_; + int count_; + mojo::Binding<mojom::blink::FindInPageClient> binding_; +}; + +} // namespace + +class DisplayLockContextTest : public testing::Test { + public: + void SetUp() override { + features_backup_.emplace(); + RuntimeEnabledFeatures::SetDisplayLockingEnabled(true); + web_view_helper_.Initialize(); + } + + void TearDown() override { + if (features_backup_) { + features_backup_->Restore(); + features_backup_.reset(); + } + web_view_helper_.Reset(); + } + + Document& GetDocument() { + return *static_cast<Document*>( + web_view_helper_.LocalMainFrame()->GetDocument()); + } + TextFinder& GetTextFinder() { + return web_view_helper_.LocalMainFrame()->EnsureTextFinder(); + } + FindInPage* GetFindInPage() { + return web_view_helper_.LocalMainFrame()->GetFindInPage(); + } + WebLocalFrameImpl* LocalMainFrame() { + return web_view_helper_.LocalMainFrame(); + } + + void UpdateAllLifecyclePhasesForTest() { + GetDocument().View()->UpdateAllLifecyclePhases( + DocumentLifecycle::LifecycleUpdateReason::kTest); + } + + void SetHtmlInnerHTML(const char* content) { + GetDocument().documentElement()->SetInnerHTMLFromString( + String::FromUTF8(content)); + UpdateAllLifecyclePhasesForTest(); + } + + void ResizeAndFocus() { + web_view_helper_.Resize(WebSize(640, 480)); + web_view_helper_.GetWebView()->MainFrameWidget()->SetFocus(true); + test::RunPendingTasks(); + } + + private: + base::Optional<RuntimeEnabledFeatures::Backup> features_backup_; + frame_test_helpers::WebViewHelper web_view_helper_; +}; + +TEST_F(DisplayLockContextTest, LockedElementIsNotSearchableViaTextFinder) { + SetHtmlInnerHTML(R"HTML( + <style> + #container { + width: 100px; + height: 100px; + contain: content; + } + </style> + <body><div id="container">testing</div></body> + )HTML"); + + int identifier = 0; + WebString search_text(String("testing")); + auto& text_finder = GetTextFinder(); + auto find_options = mojom::blink::FindOptions::New(); + bool wrap_within_frame = true; + + ASSERT_TRUE(text_finder.Find(identifier, search_text, *find_options, + wrap_within_frame)); + text_finder.ClearActiveFindMatch(); + + auto* element = GetDocument().getElementById("container"); + { + auto* script_state = ToScriptStateForMainWorld(GetDocument().GetFrame()); + ScriptState::Scope scope(script_state); + element->getDisplayLockForBindings()->acquire(script_state, nullptr); + } + + // We should be in pending acquire state, which means we would allow things + // like style and layout but disallow paint. + EXPECT_TRUE(element->GetDisplayLockContext()->ShouldStyle()); + EXPECT_TRUE(element->GetDisplayLockContext()->ShouldLayout()); + EXPECT_FALSE(element->GetDisplayLockContext()->ShouldPaint()); + + UpdateAllLifecyclePhasesForTest(); + + // Sanity checks to ensure the element is locked. + EXPECT_FALSE(element->GetDisplayLockContext()->ShouldStyle()); + EXPECT_FALSE(element->GetDisplayLockContext()->ShouldLayout()); + EXPECT_FALSE(element->GetDisplayLockContext()->ShouldPaint()); + + EXPECT_FALSE(element->GetDisplayLockContext()->IsSearchable()); + + EXPECT_FALSE(text_finder.Find(identifier, search_text, *find_options, + wrap_within_frame)); + + // Now commit the lock and ensure we can find the text. + { + auto* script_state = ToScriptStateForMainWorld(GetDocument().GetFrame()); + ScriptState::Scope scope(script_state); + element->getDisplayLockForBindings()->commit(script_state); + } + + EXPECT_TRUE(element->GetDisplayLockContext()->ShouldStyle()); + EXPECT_TRUE(element->GetDisplayLockContext()->ShouldLayout()); + EXPECT_TRUE(element->GetDisplayLockContext()->ShouldPaint()); + + UpdateAllLifecyclePhasesForTest(); + + EXPECT_TRUE(text_finder.Find(identifier, search_text, *find_options, + wrap_within_frame)); +} + +TEST_F(DisplayLockContextTest, LockedElementIsNotSearchableViaFindInPage) { + ResizeAndFocus(); + SetHtmlInnerHTML(R"HTML( + <style> + #container { + width: 100px; + height: 100px; + contain: content; + } + </style> + <body><div id="container">testing</div></body> + )HTML"); + + WebString search_text(String("testing")); + auto* find_in_page = GetFindInPage(); + ASSERT_TRUE(find_in_page); + + DisplayLockTestFindInPageClient client; + client.SetFrame(LocalMainFrame()); + + auto find_options = mojom::blink::FindOptions::New(); + find_options->run_synchronously_for_testing = true; + find_options->find_next = false; + find_options->forward = true; + + int current_id = 123; + find_in_page->Find(current_id++, "testing", find_options->Clone()); + EXPECT_FALSE(client.FindResultsAreReady()); + test::RunPendingTasks(); + EXPECT_TRUE(client.FindResultsAreReady()); + EXPECT_EQ(1, client.Count()); + client.Reset(); + + auto* element = GetDocument().getElementById("container"); + { + auto* script_state = ToScriptStateForMainWorld(GetDocument().GetFrame()); + ScriptState::Scope scope(script_state); + element->getDisplayLockForBindings()->acquire(script_state, nullptr); + } + + // We should be in pending acquire state, which means we would allow things + // like style and layout but disallow paint. + EXPECT_TRUE(element->GetDisplayLockContext()->ShouldStyle()); + EXPECT_TRUE(element->GetDisplayLockContext()->ShouldLayout()); + EXPECT_FALSE(element->GetDisplayLockContext()->ShouldPaint()); + + UpdateAllLifecyclePhasesForTest(); + + // Sanity checks to ensure the element is locked. + EXPECT_FALSE(element->GetDisplayLockContext()->ShouldStyle()); + EXPECT_FALSE(element->GetDisplayLockContext()->ShouldLayout()); + EXPECT_FALSE(element->GetDisplayLockContext()->ShouldPaint()); + + EXPECT_FALSE(element->GetDisplayLockContext()->IsSearchable()); + + find_in_page->Find(current_id++, "testing", find_options->Clone()); + EXPECT_FALSE(client.FindResultsAreReady()); + test::RunPendingTasks(); + EXPECT_TRUE(client.FindResultsAreReady()); + EXPECT_EQ(0, client.Count()); + client.Reset(); + + // Now commit the lock and ensure we can find the text. + { + auto* script_state = ToScriptStateForMainWorld(GetDocument().GetFrame()); + ScriptState::Scope scope(script_state); + element->getDisplayLockForBindings()->commit(script_state); + } + + EXPECT_TRUE(element->GetDisplayLockContext()->ShouldStyle()); + EXPECT_TRUE(element->GetDisplayLockContext()->ShouldLayout()); + EXPECT_TRUE(element->GetDisplayLockContext()->ShouldPaint()); + + UpdateAllLifecyclePhasesForTest(); + + find_in_page->Find(current_id++, "testing", find_options->Clone()); + EXPECT_FALSE(client.FindResultsAreReady()); + test::RunPendingTasks(); + EXPECT_TRUE(client.FindResultsAreReady()); + EXPECT_EQ(1, client.Count()); + client.Reset(); +} + +TEST_F(DisplayLockContextTest, LockedElementAndDescendantsAreNotFocusable) { + ResizeAndFocus(); + SetHtmlInnerHTML(R"HTML( + <style> + #container { + width: 100px; + height: 100px; + contain: content; + } + </style> + <body> + <div id="container"> + <input id="textfield", type="text"> + </div> + </body> + )HTML"); + + // We start off as being focusable. + ASSERT_TRUE(GetDocument().getElementById("textfield")->IsKeyboardFocusable()); + ASSERT_TRUE(GetDocument().getElementById("textfield")->IsMouseFocusable()); + ASSERT_TRUE(GetDocument().getElementById("textfield")->IsFocusable()); + + auto* element = GetDocument().getElementById("container"); + { + auto* script_state = ToScriptStateForMainWorld(GetDocument().GetFrame()); + ScriptState::Scope scope(script_state); + element->getDisplayLockForBindings()->acquire(script_state, nullptr); + } + + // We should be in pending acquire state, which means we would allow things + // like style and layout but disallow paint. + EXPECT_TRUE(element->GetDisplayLockContext()->ShouldStyle()); + EXPECT_TRUE(element->GetDisplayLockContext()->ShouldLayout()); + EXPECT_FALSE(element->GetDisplayLockContext()->ShouldPaint()); + + UpdateAllLifecyclePhasesForTest(); + + // Sanity checks to ensure the element is locked. + EXPECT_FALSE(element->GetDisplayLockContext()->ShouldStyle()); + EXPECT_FALSE(element->GetDisplayLockContext()->ShouldLayout()); + EXPECT_FALSE(element->GetDisplayLockContext()->ShouldPaint()); + + // The input should not be focusable now. + EXPECT_FALSE( + GetDocument().getElementById("textfield")->IsKeyboardFocusable()); + EXPECT_FALSE(GetDocument().getElementById("textfield")->IsMouseFocusable()); + EXPECT_FALSE(GetDocument().getElementById("textfield")->IsFocusable()); + + // Calling explicit focus() should also not focus the element. + GetDocument().getElementById("textfield")->focus(); + EXPECT_FALSE(GetDocument().FocusedElement()); + + // Now commit the lock and ensure we can focus the input + { + auto* script_state = ToScriptStateForMainWorld(GetDocument().GetFrame()); + ScriptState::Scope scope(script_state); + element->getDisplayLockForBindings()->commit(script_state); + } + + EXPECT_TRUE(element->GetDisplayLockContext()->ShouldStyle()); + EXPECT_TRUE(element->GetDisplayLockContext()->ShouldLayout()); + EXPECT_TRUE(element->GetDisplayLockContext()->ShouldPaint()); + + UpdateAllLifecyclePhasesForTest(); + + EXPECT_TRUE(GetDocument().getElementById("textfield")->IsKeyboardFocusable()); + EXPECT_TRUE(GetDocument().getElementById("textfield")->IsMouseFocusable()); + EXPECT_TRUE(GetDocument().getElementById("textfield")->IsFocusable()); + + // Calling explicit focus() should focus the element + GetDocument().getElementById("textfield")->focus(); + EXPECT_EQ(GetDocument().FocusedElement(), + GetDocument().getElementById("textfield")); +} +} // namespace blink |