| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "components/web_view/frame.h" | |
| 6 | |
| 7 #include <stdint.h> | |
| 8 #include <utility> | |
| 9 | |
| 10 #include "base/bind.h" | |
| 11 #include "base/location.h" | |
| 12 #include "base/logging.h" | |
| 13 #include "base/macros.h" | |
| 14 #include "base/message_loop/message_loop.h" | |
| 15 #include "base/run_loop.h" | |
| 16 #include "base/test/test_timeouts.h" | |
| 17 #include "base/time/time.h" | |
| 18 #include "build/build_config.h" | |
| 19 #include "components/mus/public/cpp/window_observer.h" | |
| 20 #include "components/mus/public/cpp/window_tree_connection.h" | |
| 21 #include "components/mus/public/cpp/window_tree_delegate.h" | |
| 22 #include "components/mus/public/cpp/window_tree_host_factory.h" | |
| 23 #include "components/mus/public/interfaces/window_tree_host.mojom.h" | |
| 24 #include "components/web_view/frame_connection.h" | |
| 25 #include "components/web_view/frame_tree.h" | |
| 26 #include "components/web_view/frame_tree_delegate.h" | |
| 27 #include "components/web_view/frame_user_data.h" | |
| 28 #include "components/web_view/test_frame_tree_delegate.h" | |
| 29 #include "mojo/shell/public/cpp/application_test_base.h" | |
| 30 | |
| 31 using mus::Window; | |
| 32 using mus::WindowTreeConnection; | |
| 33 | |
| 34 namespace web_view { | |
| 35 | |
| 36 namespace { | |
| 37 | |
| 38 base::RunLoop* current_run_loop = nullptr; | |
| 39 | |
| 40 void TimeoutRunLoop(const base::Closure& timeout_task, bool* timeout) { | |
| 41 CHECK(current_run_loop); | |
| 42 *timeout = true; | |
| 43 timeout_task.Run(); | |
| 44 } | |
| 45 | |
| 46 bool DoRunLoopWithTimeout() { | |
| 47 if (current_run_loop != nullptr) | |
| 48 return false; | |
| 49 | |
| 50 bool timeout = false; | |
| 51 base::RunLoop run_loop; | |
| 52 base::MessageLoop::current()->PostDelayedTask( | |
| 53 FROM_HERE, base::Bind(&TimeoutRunLoop, run_loop.QuitClosure(), &timeout), | |
| 54 TestTimeouts::action_timeout()); | |
| 55 | |
| 56 current_run_loop = &run_loop; | |
| 57 current_run_loop->Run(); | |
| 58 current_run_loop = nullptr; | |
| 59 return !timeout; | |
| 60 } | |
| 61 | |
| 62 void QuitRunLoop() { | |
| 63 current_run_loop->Quit(); | |
| 64 current_run_loop = nullptr; | |
| 65 } | |
| 66 | |
| 67 } // namespace | |
| 68 | |
| 69 void OnGotIdCallback(base::RunLoop* run_loop) { | |
| 70 run_loop->Quit(); | |
| 71 } | |
| 72 | |
| 73 // Creates a new FrameConnection. This runs a nested message loop until the | |
| 74 // content handler id is obtained. | |
| 75 scoped_ptr<FrameConnection> CreateFrameConnection(mojo::Shell* shell, | |
| 76 const std::string& url) { | |
| 77 scoped_ptr<FrameConnection> frame_connection(new FrameConnection); | |
| 78 mojo::URLRequestPtr request(mojo::URLRequest::New()); | |
| 79 request->url = mojo::String::From(url); | |
| 80 base::RunLoop run_loop; | |
| 81 frame_connection->Init(shell, std::move(request), | |
| 82 base::Bind(&OnGotIdCallback, &run_loop)); | |
| 83 run_loop.Run(); | |
| 84 return frame_connection; | |
| 85 } | |
| 86 | |
| 87 class TestFrameClient : public mojom::FrameClient { | |
| 88 public: | |
| 89 TestFrameClient() | |
| 90 : connect_count_(0), last_dispatch_load_event_frame_id_(0) {} | |
| 91 ~TestFrameClient() override {} | |
| 92 | |
| 93 int connect_count() const { return connect_count_; } | |
| 94 | |
| 95 mojo::Array<mojom::FrameDataPtr> connect_frames() { | |
| 96 return std::move(connect_frames_); | |
| 97 } | |
| 98 | |
| 99 mojo::Array<mojom::FrameDataPtr> adds() { return std::move(adds_); } | |
| 100 | |
| 101 // Sets a callback to run once OnConnect() is received. | |
| 102 void set_on_connect_callback(const base::Closure& closure) { | |
| 103 on_connect_callback_ = closure; | |
| 104 } | |
| 105 | |
| 106 void set_on_loading_state_changed_callback(const base::Closure& closure) { | |
| 107 on_loading_state_changed_callback_ = closure; | |
| 108 } | |
| 109 | |
| 110 void set_on_dispatch_load_event_callback(const base::Closure& closure) { | |
| 111 on_dispatch_load_event_callback_ = closure; | |
| 112 } | |
| 113 | |
| 114 mojom::Frame* server_frame() { return server_frame_.get(); } | |
| 115 | |
| 116 mojo::InterfaceRequest<mojom::Frame> GetServerFrameRequest() { | |
| 117 return GetProxy(&server_frame_); | |
| 118 } | |
| 119 | |
| 120 void last_loading_state_changed_notification(uint32_t* frame_id, | |
| 121 bool* loading) const { | |
| 122 *frame_id = last_loading_state_changed_notification_.frame_id; | |
| 123 *loading = last_loading_state_changed_notification_.loading; | |
| 124 } | |
| 125 | |
| 126 uint32_t last_dispatch_load_event_frame_id() const { | |
| 127 return last_dispatch_load_event_frame_id_; | |
| 128 } | |
| 129 | |
| 130 base::TimeTicks last_navigation_start_time() const { | |
| 131 return last_navigation_start_time_; | |
| 132 } | |
| 133 | |
| 134 // mojom::FrameClient: | |
| 135 void OnConnect(mojom::FramePtr frame, | |
| 136 uint32_t change_id, | |
| 137 uint32_t window_id, | |
| 138 mojom::WindowConnectType window_connect_type, | |
| 139 mojo::Array<mojom::FrameDataPtr> frames, | |
| 140 int64_t navigation_start_time_ticks, | |
| 141 const OnConnectCallback& callback) override { | |
| 142 connect_count_++; | |
| 143 connect_frames_ = std::move(frames); | |
| 144 if (frame) | |
| 145 server_frame_ = std::move(frame); | |
| 146 callback.Run(); | |
| 147 if (!on_connect_callback_.is_null()) | |
| 148 on_connect_callback_.Run(); | |
| 149 | |
| 150 last_navigation_start_time_ = | |
| 151 base::TimeTicks::FromInternalValue(navigation_start_time_ticks); | |
| 152 } | |
| 153 void OnFrameAdded(uint32_t change_id, mojom::FrameDataPtr frame) override { | |
| 154 adds_.push_back(std::move(frame)); | |
| 155 } | |
| 156 void OnFrameRemoved(uint32_t change_id, uint32_t frame_id) override {} | |
| 157 void OnFrameClientPropertyChanged(uint32_t frame_id, | |
| 158 const mojo::String& name, | |
| 159 mojo::Array<uint8_t> new_data) override {} | |
| 160 void OnPostMessageEvent(uint32_t source_frame_id, | |
| 161 uint32_t target_frame_id, | |
| 162 mojom::HTMLMessageEventPtr event) override {} | |
| 163 void OnWillNavigate(const mojo::String& origin, | |
| 164 const OnWillNavigateCallback& callback) override { | |
| 165 callback.Run(); | |
| 166 } | |
| 167 void OnFrameLoadingStateChanged(uint32_t frame_id, bool loading) override { | |
| 168 last_loading_state_changed_notification_.frame_id = frame_id; | |
| 169 last_loading_state_changed_notification_.loading = loading; | |
| 170 | |
| 171 if (!on_loading_state_changed_callback_.is_null()) | |
| 172 on_loading_state_changed_callback_.Run(); | |
| 173 } | |
| 174 void OnDispatchFrameLoadEvent(uint32_t frame_id) override { | |
| 175 last_dispatch_load_event_frame_id_ = frame_id; | |
| 176 | |
| 177 if (!on_dispatch_load_event_callback_.is_null()) | |
| 178 on_dispatch_load_event_callback_.Run(); | |
| 179 } | |
| 180 void Find(int32_t request_id, | |
| 181 const mojo::String& search_text, | |
| 182 mojom::FindOptionsPtr options, | |
| 183 bool wrap_within_frame, | |
| 184 const FindCallback& callback) override {} | |
| 185 void StopFinding(bool clear_selection) override {} | |
| 186 void HighlightFindResults(int32_t request_id, | |
| 187 const mojo::String& search_test, | |
| 188 mojom::FindOptionsPtr options, | |
| 189 bool reset) override {} | |
| 190 void StopHighlightingFindResults() override {} | |
| 191 | |
| 192 private: | |
| 193 struct LoadingStateChangedNotification { | |
| 194 LoadingStateChangedNotification() : frame_id(0), loading(false) {} | |
| 195 ~LoadingStateChangedNotification() {} | |
| 196 | |
| 197 uint32_t frame_id; | |
| 198 bool loading; | |
| 199 }; | |
| 200 | |
| 201 int connect_count_; | |
| 202 mojo::Array<mojom::FrameDataPtr> connect_frames_; | |
| 203 mojom::FramePtr server_frame_; | |
| 204 mojo::Array<mojom::FrameDataPtr> adds_; | |
| 205 base::Closure on_connect_callback_; | |
| 206 base::Closure on_loading_state_changed_callback_; | |
| 207 base::Closure on_dispatch_load_event_callback_; | |
| 208 LoadingStateChangedNotification last_loading_state_changed_notification_; | |
| 209 uint32_t last_dispatch_load_event_frame_id_; | |
| 210 base::TimeTicks last_navigation_start_time_; | |
| 211 | |
| 212 DISALLOW_COPY_AND_ASSIGN(TestFrameClient); | |
| 213 }; | |
| 214 | |
| 215 class FrameTest; | |
| 216 | |
| 217 // WindowAndFrame maintains the Window and TestFrameClient associated with | |
| 218 // a single FrameClient. In other words this maintains the data structures | |
| 219 // needed to represent a client side frame. To obtain one use | |
| 220 // FrameTest::WaitForViewAndFrame(). | |
| 221 class WindowAndFrame : public mus::WindowTreeDelegate { | |
| 222 public: | |
| 223 ~WindowAndFrame() override { | |
| 224 if (window_) | |
| 225 delete window_->connection(); | |
| 226 } | |
| 227 | |
| 228 // The Window associated with the frame. | |
| 229 mus::Window* window() { return window_; } | |
| 230 TestFrameClient* test_frame_client() { return &test_frame_tree_client_; } | |
| 231 mojom::Frame* server_frame() { | |
| 232 return test_frame_tree_client_.server_frame(); | |
| 233 } | |
| 234 | |
| 235 private: | |
| 236 friend class FrameTest; | |
| 237 | |
| 238 WindowAndFrame() | |
| 239 : window_(nullptr), frame_client_binding_(&test_frame_tree_client_) {} | |
| 240 | |
| 241 void set_window(Window* window) { window_ = window; } | |
| 242 | |
| 243 // Runs a message loop until the window and frame data have been received. | |
| 244 void WaitForViewAndFrame() { run_loop_.Run(); } | |
| 245 | |
| 246 mojo::InterfaceRequest<mojom::Frame> GetServerFrameRequest() { | |
| 247 return test_frame_tree_client_.GetServerFrameRequest(); | |
| 248 } | |
| 249 | |
| 250 mojom::FrameClientPtr GetFrameClientPtr() { | |
| 251 return frame_client_binding_.CreateInterfacePtrAndBind(); | |
| 252 } | |
| 253 | |
| 254 void Bind(mojo::InterfaceRequest<mojom::FrameClient> request) { | |
| 255 ASSERT_FALSE(frame_client_binding_.is_bound()); | |
| 256 test_frame_tree_client_.set_on_connect_callback( | |
| 257 base::Bind(&WindowAndFrame::OnGotConnect, base::Unretained(this))); | |
| 258 frame_client_binding_.Bind(std::move(request)); | |
| 259 } | |
| 260 | |
| 261 void OnGotConnect() { QuitRunLoopIfNecessary(); } | |
| 262 | |
| 263 void QuitRunLoopIfNecessary() { | |
| 264 if (window_ && test_frame_tree_client_.connect_count()) | |
| 265 run_loop_.Quit(); | |
| 266 } | |
| 267 | |
| 268 // Overridden from WindowTreeDelegate: | |
| 269 void OnEmbed(Window* root) override { | |
| 270 window_ = root; | |
| 271 QuitRunLoopIfNecessary(); | |
| 272 } | |
| 273 void OnConnectionLost(WindowTreeConnection* connection) override { | |
| 274 window_ = nullptr; | |
| 275 } | |
| 276 | |
| 277 mus::Window* window_; | |
| 278 base::RunLoop run_loop_; | |
| 279 TestFrameClient test_frame_tree_client_; | |
| 280 mojo::Binding<mojom::FrameClient> frame_client_binding_; | |
| 281 | |
| 282 DISALLOW_COPY_AND_ASSIGN(WindowAndFrame); | |
| 283 }; | |
| 284 | |
| 285 class FrameTest : public mojo::test::ApplicationTestBase, | |
| 286 public mojo::ShellClient, | |
| 287 public mus::WindowTreeDelegate, | |
| 288 public mojo::InterfaceFactory<mus::mojom::WindowTreeClient>, | |
| 289 public mojo::InterfaceFactory<mojom::FrameClient> { | |
| 290 public: | |
| 291 FrameTest() : most_recent_connection_(nullptr), window_manager_(nullptr) {} | |
| 292 | |
| 293 WindowTreeConnection* most_recent_connection() { | |
| 294 return most_recent_connection_; | |
| 295 } | |
| 296 | |
| 297 protected: | |
| 298 WindowTreeConnection* window_manager() { return window_manager_; } | |
| 299 TestFrameTreeDelegate* frame_tree_delegate() { | |
| 300 return frame_tree_delegate_.get(); | |
| 301 } | |
| 302 FrameTree* frame_tree() { return frame_tree_.get(); } | |
| 303 WindowAndFrame* root_window_and_frame() { | |
| 304 return root_window_and_frame_.get(); | |
| 305 } | |
| 306 | |
| 307 scoped_ptr<WindowAndFrame> NavigateFrameWithStartTime( | |
| 308 WindowAndFrame* window_and_frame, | |
| 309 base::TimeTicks navigation_start_time) { | |
| 310 mojo::URLRequestPtr request(mojo::URLRequest::New()); | |
| 311 request->url = mojo::String::From(shell_url()); | |
| 312 request->originating_time_ticks = navigation_start_time.ToInternalValue(); | |
| 313 window_and_frame->server_frame()->RequestNavigate( | |
| 314 mojom::NavigationTargetType::EXISTING_FRAME, | |
| 315 window_and_frame->window()->id(), std::move(request)); | |
| 316 return WaitForViewAndFrame(); | |
| 317 } | |
| 318 | |
| 319 scoped_ptr<WindowAndFrame> NavigateFrame(WindowAndFrame* window_and_frame) { | |
| 320 return NavigateFrameWithStartTime(window_and_frame, base::TimeTicks()); | |
| 321 } | |
| 322 | |
| 323 // Creates a new shared frame as a child of |parent|. | |
| 324 scoped_ptr<WindowAndFrame> CreateChildWindowAndFrame(WindowAndFrame* parent) { | |
| 325 mus::Window* child_frame_window = | |
| 326 parent->window()->connection()->NewWindow(); | |
| 327 parent->window()->AddChild(child_frame_window); | |
| 328 | |
| 329 scoped_ptr<WindowAndFrame> window_and_frame(new WindowAndFrame); | |
| 330 window_and_frame->set_window(child_frame_window); | |
| 331 | |
| 332 mojo::Map<mojo::String, mojo::Array<uint8_t>> client_properties; | |
| 333 client_properties.mark_non_null(); | |
| 334 parent->server_frame()->OnCreatedFrame( | |
| 335 window_and_frame->GetServerFrameRequest(), | |
| 336 window_and_frame->GetFrameClientPtr(), child_frame_window->id(), | |
| 337 std::move(client_properties)); | |
| 338 frame_tree_delegate()->WaitForCreateFrame(); | |
| 339 return HasFatalFailure() ? nullptr : std::move(window_and_frame); | |
| 340 } | |
| 341 | |
| 342 // Runs a message loop until the data necessary to represent to a client side | |
| 343 // frame has been obtained. | |
| 344 scoped_ptr<WindowAndFrame> WaitForViewAndFrame() { | |
| 345 DCHECK(!window_and_frame_); | |
| 346 window_and_frame_.reset(new WindowAndFrame); | |
| 347 window_and_frame_->WaitForViewAndFrame(); | |
| 348 return std::move(window_and_frame_); | |
| 349 } | |
| 350 | |
| 351 private: | |
| 352 // ApplicationTestBase: | |
| 353 mojo::ShellClient* GetShellClient() override { return this; } | |
| 354 | |
| 355 // mojo::ShellClient implementation. | |
| 356 bool AcceptConnection(mojo::Connection* connection) override { | |
| 357 connection->AddService<mus::mojom::WindowTreeClient>(this); | |
| 358 connection->AddService<mojom::FrameClient>(this); | |
| 359 return true; | |
| 360 } | |
| 361 | |
| 362 // Overridden from WindowTreeDelegate: | |
| 363 void OnEmbed(Window* root) override { | |
| 364 most_recent_connection_ = root->connection(); | |
| 365 QuitRunLoop(); | |
| 366 } | |
| 367 void OnConnectionLost(WindowTreeConnection* connection) override {} | |
| 368 | |
| 369 // Overridden from testing::Test: | |
| 370 void SetUp() override { | |
| 371 ApplicationTestBase::SetUp(); | |
| 372 | |
| 373 mus::CreateWindowTreeHost(shell(), this, &host_, nullptr); | |
| 374 | |
| 375 ASSERT_TRUE(DoRunLoopWithTimeout()); | |
| 376 std::swap(window_manager_, most_recent_connection_); | |
| 377 | |
| 378 // Creates a FrameTree, which creates a single frame. Wait for the | |
| 379 // FrameClient to be connected to. | |
| 380 frame_tree_delegate_.reset(new TestFrameTreeDelegate(shell())); | |
| 381 scoped_ptr<FrameConnection> frame_connection = | |
| 382 CreateFrameConnection(shell(), shell_url()); | |
| 383 mojom::FrameClient* frame_client = frame_connection->frame_client(); | |
| 384 mus::mojom::WindowTreeClientPtr window_tree_client = | |
| 385 frame_connection->GetWindowTreeClient(); | |
| 386 mus::Window* frame_root_view = window_manager()->NewWindow(); | |
| 387 (*window_manager()->GetRoots().begin())->AddChild(frame_root_view); | |
| 388 frame_tree_.reset(new FrameTree( | |
| 389 0u, frame_root_view, std::move(window_tree_client), | |
| 390 frame_tree_delegate_.get(), frame_client, std::move(frame_connection), | |
| 391 Frame::ClientPropertyMap(), base::TimeTicks::Now())); | |
| 392 root_window_and_frame_ = WaitForViewAndFrame(); | |
| 393 } | |
| 394 | |
| 395 // Overridden from testing::Test: | |
| 396 void TearDown() override { | |
| 397 root_window_and_frame_.reset(); | |
| 398 frame_tree_.reset(); | |
| 399 frame_tree_delegate_.reset(); | |
| 400 ApplicationTestBase::TearDown(); | |
| 401 } | |
| 402 | |
| 403 // Overridden from mojo::InterfaceFactory<mus::mojom::WindowTreeClient>: | |
| 404 void Create( | |
| 405 mojo::Connection* connection, | |
| 406 mojo::InterfaceRequest<mus::mojom::WindowTreeClient> request) override { | |
| 407 if (window_and_frame_) { | |
| 408 mus::WindowTreeConnection::Create( | |
| 409 window_and_frame_.get(), std::move(request), | |
| 410 mus::WindowTreeConnection::CreateType::DONT_WAIT_FOR_EMBED); | |
| 411 } else { | |
| 412 mus::WindowTreeConnection::Create( | |
| 413 this, std::move(request), | |
| 414 mus::WindowTreeConnection::CreateType::DONT_WAIT_FOR_EMBED); | |
| 415 } | |
| 416 } | |
| 417 | |
| 418 // Overridden from mojo::InterfaceFactory<mojom::FrameClient>: | |
| 419 void Create(mojo::Connection* connection, | |
| 420 mojo::InterfaceRequest<mojom::FrameClient> request) override { | |
| 421 ASSERT_TRUE(window_and_frame_); | |
| 422 window_and_frame_->Bind(std::move(request)); | |
| 423 } | |
| 424 | |
| 425 scoped_ptr<TestFrameTreeDelegate> frame_tree_delegate_; | |
| 426 scoped_ptr<FrameTree> frame_tree_; | |
| 427 scoped_ptr<WindowAndFrame> root_window_and_frame_; | |
| 428 | |
| 429 mus::mojom::WindowTreeHostPtr host_; | |
| 430 | |
| 431 // Used to receive the most recent window manager loaded by an embed action. | |
| 432 WindowTreeConnection* most_recent_connection_; | |
| 433 // The Window Manager connection held by the window manager (app running at | |
| 434 // the | |
| 435 // root window). | |
| 436 WindowTreeConnection* window_manager_; | |
| 437 | |
| 438 scoped_ptr<WindowAndFrame> window_and_frame_; | |
| 439 | |
| 440 MOJO_DISALLOW_COPY_AND_ASSIGN(FrameTest); | |
| 441 }; | |
| 442 | |
| 443 // Verifies the FrameData supplied to the root FrameClient::OnConnect(). | |
| 444 TEST_F(FrameTest, RootFrameClientConnectData) { | |
| 445 mojo::Array<mojom::FrameDataPtr> frames = | |
| 446 root_window_and_frame()->test_frame_client()->connect_frames(); | |
| 447 ASSERT_EQ(1u, frames.size()); | |
| 448 EXPECT_EQ(root_window_and_frame()->window()->id(), frames[0]->frame_id); | |
| 449 EXPECT_EQ(0u, frames[0]->parent_id); | |
| 450 } | |
| 451 | |
| 452 // Verifies the FrameData supplied to a child FrameClient::OnConnect(). | |
| 453 // Crashes on linux_chromium_rel_ng only. http://crbug.com/567337 | |
| 454 #if defined(OS_LINUX) | |
| 455 #define MAYBE_ChildFrameClientConnectData DISABLED_ChildFrameClientConnectData | |
| 456 #else | |
| 457 #define MAYBE_ChildFrameClientConnectData ChildFrameClientConnectData | |
| 458 #endif | |
| 459 TEST_F(FrameTest, MAYBE_ChildFrameClientConnectData) { | |
| 460 scoped_ptr<WindowAndFrame> child_view_and_frame( | |
| 461 CreateChildWindowAndFrame(root_window_and_frame())); | |
| 462 ASSERT_TRUE(child_view_and_frame); | |
| 463 // Initially created child frames don't get OnConnect(). | |
| 464 EXPECT_EQ(0, child_view_and_frame->test_frame_client()->connect_count()); | |
| 465 | |
| 466 scoped_ptr<WindowAndFrame> navigated_child_view_and_frame = | |
| 467 NavigateFrame(child_view_and_frame.get()); | |
| 468 | |
| 469 mojo::Array<mojom::FrameDataPtr> frames_in_child = | |
| 470 navigated_child_view_and_frame->test_frame_client()->connect_frames(); | |
| 471 EXPECT_EQ(child_view_and_frame->window()->id(), | |
| 472 navigated_child_view_and_frame->window()->id()); | |
| 473 // We expect 2 frames. One for the root, one for the child. | |
| 474 ASSERT_EQ(2u, frames_in_child.size()); | |
| 475 EXPECT_EQ(frame_tree()->root()->id(), frames_in_child[0]->frame_id); | |
| 476 EXPECT_EQ(0u, frames_in_child[0]->parent_id); | |
| 477 EXPECT_EQ(navigated_child_view_and_frame->window()->id(), | |
| 478 frames_in_child[1]->frame_id); | |
| 479 EXPECT_EQ(frame_tree()->root()->id(), frames_in_child[1]->parent_id); | |
| 480 } | |
| 481 | |
| 482 TEST_F(FrameTest, OnViewEmbeddedInFrameDisconnected) { | |
| 483 scoped_ptr<WindowAndFrame> child_view_and_frame( | |
| 484 CreateChildWindowAndFrame(root_window_and_frame())); | |
| 485 ASSERT_TRUE(child_view_and_frame); | |
| 486 | |
| 487 scoped_ptr<WindowAndFrame> navigated_child_view_and_frame = | |
| 488 NavigateFrame(child_view_and_frame.get()); | |
| 489 | |
| 490 // Delete the WindowTreeConnection for the child, which should trigger | |
| 491 // notification. | |
| 492 delete navigated_child_view_and_frame->window()->connection(); | |
| 493 ASSERT_EQ(1u, frame_tree()->root()->children().size()); | |
| 494 ASSERT_NO_FATAL_FAILURE(frame_tree_delegate()->WaitForFrameDisconnected( | |
| 495 frame_tree()->root()->children()[0])); | |
| 496 ASSERT_EQ(1u, frame_tree()->root()->children().size()); | |
| 497 } | |
| 498 | |
| 499 TEST_F(FrameTest, NotifyRemoteParentWithLoadingState) { | |
| 500 scoped_ptr<WindowAndFrame> child_view_and_frame( | |
| 501 CreateChildWindowAndFrame(root_window_and_frame())); | |
| 502 uint32_t child_frame_id = child_view_and_frame->window()->id(); | |
| 503 | |
| 504 { | |
| 505 base::RunLoop run_loop; | |
| 506 root_window_and_frame() | |
| 507 ->test_frame_client() | |
| 508 ->set_on_loading_state_changed_callback(run_loop.QuitClosure()); | |
| 509 | |
| 510 child_view_and_frame->server_frame()->LoadingStateChanged(true, .5); | |
| 511 | |
| 512 run_loop.Run(); | |
| 513 | |
| 514 uint32_t frame_id = 0; | |
| 515 bool loading = false; | |
| 516 root_window_and_frame() | |
| 517 ->test_frame_client() | |
| 518 ->last_loading_state_changed_notification(&frame_id, &loading); | |
| 519 EXPECT_EQ(child_frame_id, frame_id); | |
| 520 EXPECT_TRUE(loading); | |
| 521 } | |
| 522 { | |
| 523 base::RunLoop run_loop; | |
| 524 root_window_and_frame() | |
| 525 ->test_frame_client() | |
| 526 ->set_on_loading_state_changed_callback(run_loop.QuitClosure()); | |
| 527 | |
| 528 ASSERT_TRUE(child_view_and_frame); | |
| 529 ASSERT_TRUE(child_view_and_frame->server_frame()); | |
| 530 | |
| 531 child_view_and_frame->server_frame()->LoadingStateChanged(false, 1); | |
| 532 | |
| 533 run_loop.Run(); | |
| 534 | |
| 535 uint32_t frame_id = 0; | |
| 536 bool loading = false; | |
| 537 root_window_and_frame() | |
| 538 ->test_frame_client() | |
| 539 ->last_loading_state_changed_notification(&frame_id, &loading); | |
| 540 EXPECT_EQ(child_frame_id, frame_id); | |
| 541 EXPECT_FALSE(loading); | |
| 542 } | |
| 543 } | |
| 544 | |
| 545 TEST_F(FrameTest, NotifyRemoteParentWithLoadEvent) { | |
| 546 scoped_ptr<WindowAndFrame> child_view_and_frame( | |
| 547 CreateChildWindowAndFrame(root_window_and_frame())); | |
| 548 uint32_t child_frame_id = child_view_and_frame->window()->id(); | |
| 549 | |
| 550 base::RunLoop run_loop; | |
| 551 root_window_and_frame() | |
| 552 ->test_frame_client() | |
| 553 ->set_on_dispatch_load_event_callback(run_loop.QuitClosure()); | |
| 554 | |
| 555 child_view_and_frame->server_frame()->DispatchLoadEventToParent(); | |
| 556 | |
| 557 run_loop.Run(); | |
| 558 | |
| 559 uint32_t frame_id = root_window_and_frame() | |
| 560 ->test_frame_client() | |
| 561 ->last_dispatch_load_event_frame_id(); | |
| 562 EXPECT_EQ(child_frame_id, frame_id); | |
| 563 } | |
| 564 | |
| 565 TEST_F(FrameTest, PassAlongNavigationStartTime) { | |
| 566 scoped_ptr<WindowAndFrame> child_view_and_frame( | |
| 567 CreateChildWindowAndFrame(root_window_and_frame())); | |
| 568 ASSERT_TRUE(child_view_and_frame); | |
| 569 | |
| 570 base::TimeTicks navigation_start_time = base::TimeTicks::FromInternalValue(1); | |
| 571 scoped_ptr<WindowAndFrame> navigated_child_view_and_frame = | |
| 572 NavigateFrameWithStartTime(child_view_and_frame.get(), | |
| 573 navigation_start_time); | |
| 574 EXPECT_EQ(navigation_start_time, | |
| 575 navigated_child_view_and_frame->test_frame_client() | |
| 576 ->last_navigation_start_time()); | |
| 577 } | |
| 578 | |
| 579 } // namespace web_view | |
| OLD | NEW |