diff --git a/third_party/blink/renderer/core/editing/frame_selection.cc b/third_party/blink/renderer/core/editing/frame_selection.cc index a322762432029..4b0dbb65c084a 100644 --- a/third_party/blink/renderer/core/editing/frame_selection.cc +++ b/third_party/blink/renderer/core/editing/frame_selection.cc @@ -154,6 +154,9 @@ Element* FrameSelection::RootEditableElementOrDocumentElement() const { // TODO(editing-dev): The use of UpdateStyleAndLayout // needs to be audited. See http://crbug.com/590369 for more details. GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kSelection); + if (!IsAvailable()) { + return nullptr; + } Element* selection_root = ComputeVisibleSelectionInDomTree().RootEditableElement(); diff --git a/third_party/blink/renderer/core/exported/web_view_test.cc b/third_party/blink/renderer/core/exported/web_view_test.cc index f788fedde71ad..6e279fac770ff 100644 --- a/third_party/blink/renderer/core/exported/web_view_test.cc +++ b/third_party/blink/renderer/core/exported/web_view_test.cc @@ -159,6 +159,7 @@ #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" #include "third_party/blink/renderer/platform/testing/url_loader_mock_factory.h" #include "third_party/blink/renderer/platform/testing/url_test_helpers.h" +#include "third_party/blink/renderer/platform/widget/widget_base.h" #include "third_party/blink/renderer/platform/wtf/casting.h" #include "third_party/blink/renderer/platform/wtf/functional.h" #include "third_party/skia/include/core/SkBitmap.h" @@ -6194,6 +6195,96 @@ TEST_F(WebViewTest, DetachPluginInLayout) { web_view_helper_.Reset(); // Remove dependency on locally scoped client. } +// Tests that requesting composition info on a child local root whose plugin +// detaches the local root during the layout it forces does not crash. +TEST_F(WebViewTest, RequestCompositionUpdatesPluginDetachesLocalRoot) { + class DetachInDestroyPlugin : public FakeWebPlugin { + public: + DetachInDestroyPlugin(WebFrame** frame_to_detach, + const WebPluginParams& params) + : FakeWebPlugin(params), frame_to_detach_(frame_to_detach) {} + + // WebPlugin overrides: + void Destroy() override { + if (*frame_to_detach_) { + (*frame_to_detach_)->Detach(); + } + // Deletes this. + FakeWebPlugin::Destroy(); + } + + private: + WebFrame** frame_to_detach_; // Unowned. + }; + + class PluginCreatingWebFrameClient + : public frame_test_helpers::TestWebFrameClient { + public: + // WebLocalFrameClient overrides: + WebPlugin* CreatePlugin(const WebPluginParams& params) override { + return new DetachInDestroyPlugin(&frame_to_detach_, params); + } + + void SetFrameToDetach(WebFrame* frame) { frame_to_detach_ = frame; } + + private: + WebFrame* frame_to_detach_ = nullptr; + }; + + PluginCreatingWebFrameClient frame_client; + web_view_helper_.InitializeRemote(); + WebLocalFrameImpl* local_frame = web_view_helper_.CreateLocalChild( + *web_view_helper_.RemoteMainFrame(), WebString(), + WebFrameOwnerProperties(), nullptr, &frame_client); + WebFrameWidgetImpl* frame_widget = local_frame->FrameWidgetImpl(); + frame_widget->Resize(gfx::Size(200, 200)); + + WebURL base_url = url_test_helpers::ToKURL("https://example.com/"); + frame_test_helpers::LoadHTMLString( + local_frame, + "
" + "