| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2014 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 "chrome/browser/sessions/session_service_commands.h" |
| 6 |
| 7 #include <vector> |
| 8 |
| 9 #include "base/pickle.h" |
| 10 #include "chrome/browser/sessions/base_session_service_commands.h" |
| 11 #include "chrome/browser/sessions/base_session_service_delegate.h" |
| 12 #include "chrome/browser/sessions/session_command.h" |
| 13 #include "chrome/browser/sessions/session_types.h" |
| 14 |
| 15 // Identifier for commands written to file. |
| 16 static const SessionCommand::id_type kCommandSetTabWindow = 0; |
| 17 // OBSOLETE Superseded by kCommandSetWindowBounds3. |
| 18 // static const SessionCommand::id_type kCommandSetWindowBounds = 1; |
| 19 static const SessionCommand::id_type kCommandSetTabIndexInWindow = 2; |
| 20 static const SessionCommand::id_type |
| 21 kCommandTabNavigationPathPrunedFromBack = 5; |
| 22 static const SessionCommand::id_type kCommandUpdateTabNavigation = 6; |
| 23 static const SessionCommand::id_type kCommandSetSelectedNavigationIndex = 7; |
| 24 static const SessionCommand::id_type kCommandSetSelectedTabInIndex = 8; |
| 25 static const SessionCommand::id_type kCommandSetWindowType = 9; |
| 26 // OBSOLETE Superseded by kCommandSetWindowBounds3. Except for data migration. |
| 27 // static const SessionCommand::id_type kCommandSetWindowBounds2 = 10; |
| 28 static const SessionCommand::id_type |
| 29 kCommandTabNavigationPathPrunedFromFront = 11; |
| 30 static const SessionCommand::id_type kCommandSetPinnedState = 12; |
| 31 static const SessionCommand::id_type kCommandSetExtensionAppID = 13; |
| 32 static const SessionCommand::id_type kCommandSetWindowBounds3 = 14; |
| 33 static const SessionCommand::id_type kCommandSetWindowAppName = 15; |
| 34 static const SessionCommand::id_type kCommandTabClosed = 16; |
| 35 static const SessionCommand::id_type kCommandWindowClosed = 17; |
| 36 static const SessionCommand::id_type kCommandSetTabUserAgentOverride = 18; |
| 37 static const SessionCommand::id_type kCommandSessionStorageAssociated = 19; |
| 38 static const SessionCommand::id_type kCommandSetActiveWindow = 20; |
| 39 |
| 40 namespace { |
| 41 |
| 42 // Various payload structures. |
| 43 struct ClosedPayload { |
| 44 SessionID::id_type id; |
| 45 int64 close_time; |
| 46 }; |
| 47 |
| 48 struct WindowBoundsPayload2 { |
| 49 SessionID::id_type window_id; |
| 50 int32 x; |
| 51 int32 y; |
| 52 int32 w; |
| 53 int32 h; |
| 54 bool is_maximized; |
| 55 }; |
| 56 |
| 57 struct WindowBoundsPayload3 { |
| 58 SessionID::id_type window_id; |
| 59 int32 x; |
| 60 int32 y; |
| 61 int32 w; |
| 62 int32 h; |
| 63 int32 show_state; |
| 64 }; |
| 65 |
| 66 typedef SessionID::id_type ActiveWindowPayload; |
| 67 |
| 68 struct IDAndIndexPayload { |
| 69 SessionID::id_type id; |
| 70 int32 index; |
| 71 }; |
| 72 |
| 73 typedef IDAndIndexPayload TabIndexInWindowPayload; |
| 74 |
| 75 typedef IDAndIndexPayload TabNavigationPathPrunedFromBackPayload; |
| 76 |
| 77 typedef IDAndIndexPayload SelectedNavigationIndexPayload; |
| 78 |
| 79 typedef IDAndIndexPayload SelectedTabInIndexPayload; |
| 80 |
| 81 typedef IDAndIndexPayload WindowTypePayload; |
| 82 |
| 83 typedef IDAndIndexPayload TabNavigationPathPrunedFromFrontPayload; |
| 84 |
| 85 struct PinnedStatePayload { |
| 86 SessionID::id_type tab_id; |
| 87 bool pinned_state; |
| 88 }; |
| 89 |
| 90 // Persisted versions of ui::WindowShowState that are written to disk and can |
| 91 // never change. |
| 92 enum PersistedWindowShowState { |
| 93 // SHOW_STATE_DEFAULT (0) never persisted. |
| 94 PERSISTED_SHOW_STATE_NORMAL = 1, |
| 95 PERSISTED_SHOW_STATE_MINIMIZED = 2, |
| 96 PERSISTED_SHOW_STATE_MAXIMIZED = 3, |
| 97 // SHOW_STATE_INACTIVE (4) never persisted. |
| 98 PERSISTED_SHOW_STATE_FULLSCREEN = 5, |
| 99 PERSISTED_SHOW_STATE_DETACHED_DEPRECATED = 6, |
| 100 PERSISTED_SHOW_STATE_END = 6 |
| 101 }; |
| 102 |
| 103 // Assert to ensure PersistedWindowShowState is updated if ui::WindowShowState |
| 104 // is changed. |
| 105 COMPILE_ASSERT(ui::SHOW_STATE_END == |
| 106 static_cast<ui::WindowShowState>(PERSISTED_SHOW_STATE_END), |
| 107 persisted_show_state_mismatch); |
| 108 |
| 109 // Returns the show state to store to disk based |state|. |
| 110 PersistedWindowShowState ShowStateToPersistedShowState( |
| 111 ui::WindowShowState state) { |
| 112 switch (state) { |
| 113 case ui::SHOW_STATE_NORMAL: |
| 114 return PERSISTED_SHOW_STATE_NORMAL; |
| 115 case ui::SHOW_STATE_MINIMIZED: |
| 116 return PERSISTED_SHOW_STATE_MINIMIZED; |
| 117 case ui::SHOW_STATE_MAXIMIZED: |
| 118 return PERSISTED_SHOW_STATE_MAXIMIZED; |
| 119 case ui::SHOW_STATE_FULLSCREEN: |
| 120 return PERSISTED_SHOW_STATE_FULLSCREEN; |
| 121 |
| 122 case ui::SHOW_STATE_DEFAULT: |
| 123 case ui::SHOW_STATE_INACTIVE: |
| 124 return PERSISTED_SHOW_STATE_NORMAL; |
| 125 |
| 126 case ui::SHOW_STATE_END: |
| 127 break; |
| 128 } |
| 129 NOTREACHED(); |
| 130 return PERSISTED_SHOW_STATE_NORMAL; |
| 131 } |
| 132 |
| 133 // Lints show state values when read back from persited disk. |
| 134 ui::WindowShowState PersistedShowStateToShowState(int state) { |
| 135 switch (state) { |
| 136 case PERSISTED_SHOW_STATE_NORMAL: |
| 137 return ui::SHOW_STATE_NORMAL; |
| 138 case PERSISTED_SHOW_STATE_MINIMIZED: |
| 139 return ui::SHOW_STATE_MINIMIZED; |
| 140 case PERSISTED_SHOW_STATE_MAXIMIZED: |
| 141 return ui::SHOW_STATE_MAXIMIZED; |
| 142 case PERSISTED_SHOW_STATE_FULLSCREEN: |
| 143 return ui::SHOW_STATE_FULLSCREEN; |
| 144 case PERSISTED_SHOW_STATE_DETACHED_DEPRECATED: |
| 145 return ui::SHOW_STATE_NORMAL; |
| 146 } |
| 147 NOTREACHED(); |
| 148 return ui::SHOW_STATE_NORMAL; |
| 149 } |
| 150 |
| 151 } // namespace |
| 152 |
| 153 // SessionService ------------------------------------------------------------- |
| 154 |
| 155 SessionServiceCommands::SessionServiceCommands( |
| 156 SessionServiceCommandsDelegate* delegate) : delegate_(delegate) {} |
| 157 |
| 158 SessionServiceCommands::~SessionServiceCommands() { |
| 159 // The owner is responsible to save upon exit. |
| 160 } |
| 161 |
| 162 scoped_ptr<SessionCommand> |
| 163 SessionServiceCommands::CreateSetSelectedTabInWindowCommand( |
| 164 const SessionID& window_id, |
| 165 int index) { |
| 166 SelectedTabInIndexPayload payload = { 0 }; |
| 167 payload.id = window_id.id(); |
| 168 payload.index = index; |
| 169 scoped_ptr<SessionCommand> command( |
| 170 new SessionCommand(kCommandSetSelectedTabInIndex, sizeof(payload))); |
| 171 memcpy(command->contents(), &payload, sizeof(payload)); |
| 172 return command.Pass(); |
| 173 } |
| 174 |
| 175 scoped_ptr<SessionCommand> |
| 176 SessionServiceCommands::CreateSetTabWindowCommand( |
| 177 const SessionID& window_id, |
| 178 const SessionID& tab_id) { |
| 179 SessionID::id_type payload[] = { window_id.id(), tab_id.id() }; |
| 180 scoped_ptr<SessionCommand> command( |
| 181 new SessionCommand(kCommandSetTabWindow, sizeof(payload))); |
| 182 memcpy(command->contents(), payload, sizeof(payload)); |
| 183 return command.Pass(); |
| 184 } |
| 185 |
| 186 scoped_ptr<SessionCommand> |
| 187 SessionServiceCommands::CreateSetWindowBoundsCommand( |
| 188 const SessionID& window_id, |
| 189 const gfx::Rect& bounds, |
| 190 ui::WindowShowState show_state) { |
| 191 WindowBoundsPayload3 payload = { 0 }; |
| 192 payload.window_id = window_id.id(); |
| 193 payload.x = bounds.x(); |
| 194 payload.y = bounds.y(); |
| 195 payload.w = bounds.width(); |
| 196 payload.h = bounds.height(); |
| 197 payload.show_state = ShowStateToPersistedShowState(show_state); |
| 198 scoped_ptr<SessionCommand> command( |
| 199 new SessionCommand(kCommandSetWindowBounds3, sizeof(payload))); |
| 200 memcpy(command->contents(), &payload, sizeof(payload)); |
| 201 return command.Pass(); |
| 202 } |
| 203 |
| 204 scoped_ptr<SessionCommand> |
| 205 SessionServiceCommands::CreateSetTabIndexInWindowCommand( |
| 206 const SessionID& tab_id, |
| 207 int new_index) { |
| 208 TabIndexInWindowPayload payload = { 0 }; |
| 209 payload.id = tab_id.id(); |
| 210 payload.index = new_index; |
| 211 scoped_ptr<SessionCommand> command( |
| 212 new SessionCommand(kCommandSetTabIndexInWindow, sizeof(payload))); |
| 213 memcpy(command->contents(), &payload, sizeof(payload)); |
| 214 return command.Pass(); |
| 215 } |
| 216 |
| 217 scoped_ptr<SessionCommand> |
| 218 SessionServiceCommands::CreateTabClosedCommand( |
| 219 const SessionID::id_type tab_id) { |
| 220 ClosedPayload payload; |
| 221 // Because of what appears to be a compiler bug setting payload to {0} doesn't |
| 222 // set the padding to 0, resulting in Purify reporting an UMR when we write |
| 223 // the structure to disk. To avoid this we explicitly memset the struct. |
| 224 memset(&payload, 0, sizeof(payload)); |
| 225 payload.id = tab_id; |
| 226 payload.close_time = base::Time::Now().ToInternalValue(); |
| 227 scoped_ptr<SessionCommand> command( |
| 228 new SessionCommand(kCommandTabClosed, sizeof(payload))); |
| 229 memcpy(command->contents(), &payload, sizeof(payload)); |
| 230 return command.Pass(); |
| 231 } |
| 232 |
| 233 scoped_ptr<SessionCommand> |
| 234 SessionServiceCommands::CreateWindowClosedCommand( |
| 235 const SessionID::id_type window_id) { |
| 236 ClosedPayload payload; |
| 237 // See comment in CreateTabClosedCommand as to why we do this. |
| 238 memset(&payload, 0, sizeof(payload)); |
| 239 payload.id = window_id; |
| 240 payload.close_time = base::Time::Now().ToInternalValue(); |
| 241 scoped_ptr<SessionCommand> command( |
| 242 new SessionCommand(kCommandWindowClosed, sizeof(payload))); |
| 243 memcpy(command->contents(), &payload, sizeof(payload)); |
| 244 return command.Pass(); |
| 245 } |
| 246 |
| 247 scoped_ptr<SessionCommand> |
| 248 SessionServiceCommands::CreateSetSelectedNavigationIndexCommand( |
| 249 const SessionID& tab_id, |
| 250 int index) { |
| 251 SelectedNavigationIndexPayload payload = { 0 }; |
| 252 payload.id = tab_id.id(); |
| 253 payload.index = index; |
| 254 scoped_ptr<SessionCommand> command( |
| 255 new SessionCommand(kCommandSetSelectedNavigationIndex, sizeof(payload))); |
| 256 memcpy(command->contents(), &payload, sizeof(payload)); |
| 257 return command.Pass(); |
| 258 } |
| 259 |
| 260 scoped_ptr<SessionCommand> |
| 261 SessionServiceCommands::CreateSetWindowTypeCommand( |
| 262 const SessionID& window_id, |
| 263 SessionWindow::WindowType type) { |
| 264 WindowTypePayload payload = { 0 }; |
| 265 payload.id = window_id.id(); |
| 266 payload.index = static_cast<int32>(type); |
| 267 scoped_ptr<SessionCommand> command( |
| 268 new SessionCommand( kCommandSetWindowType, sizeof(payload))); |
| 269 memcpy(command->contents(), &payload, sizeof(payload)); |
| 270 return command.Pass(); |
| 271 } |
| 272 |
| 273 scoped_ptr<SessionCommand> |
| 274 SessionServiceCommands::CreatePinnedStateCommand( |
| 275 const SessionID& tab_id, |
| 276 bool is_pinned) { |
| 277 PinnedStatePayload payload = { 0 }; |
| 278 payload.tab_id = tab_id.id(); |
| 279 payload.pinned_state = is_pinned; |
| 280 scoped_ptr<SessionCommand> command( |
| 281 new SessionCommand(kCommandSetPinnedState, sizeof(payload))); |
| 282 memcpy(command->contents(), &payload, sizeof(payload)); |
| 283 return command.Pass(); |
| 284 } |
| 285 |
| 286 scoped_ptr<SessionCommand> |
| 287 SessionServiceCommands::CreateSessionStorageAssociatedCommand( |
| 288 const SessionID& tab_id, |
| 289 const std::string& session_storage_persistent_id) { |
| 290 Pickle pickle; |
| 291 pickle.WriteInt(tab_id.id()); |
| 292 pickle.WriteString(session_storage_persistent_id); |
| 293 return scoped_ptr<SessionCommand>( |
| 294 new SessionCommand(kCommandSessionStorageAssociated, pickle)); |
| 295 } |
| 296 |
| 297 scoped_ptr<SessionCommand> SessionServiceCommands::CreateSetActiveWindowCommand( |
| 298 const SessionID& window_id) { |
| 299 ActiveWindowPayload payload = 0; |
| 300 payload = window_id.id(); |
| 301 scoped_ptr<SessionCommand> command( |
| 302 new SessionCommand(kCommandSetActiveWindow, sizeof(payload))); |
| 303 memcpy(command->contents(), &payload, sizeof(payload)); |
| 304 return command.Pass(); |
| 305 } |
| 306 |
| 307 scoped_ptr<SessionCommand> |
| 308 SessionServiceCommands::CreateTabNavigationPathPrunedFromBackCommand( |
| 309 const SessionID& tab_id, |
| 310 int count) { |
| 311 TabNavigationPathPrunedFromBackPayload payload = { 0 }; |
| 312 payload.id = tab_id.id(); |
| 313 payload.index = count; |
| 314 scoped_ptr<SessionCommand> command( |
| 315 new SessionCommand(kCommandTabNavigationPathPrunedFromBack, |
| 316 sizeof(payload))); |
| 317 memcpy(command->contents(), &payload, sizeof(payload)); |
| 318 return command.Pass(); |
| 319 } |
| 320 |
| 321 scoped_ptr<SessionCommand> |
| 322 SessionServiceCommands::CreateTabNavigationPathPrunedFromFrontCommand( |
| 323 const SessionID& tab_id, |
| 324 int count) { |
| 325 TabNavigationPathPrunedFromFrontPayload payload = { 0 }; |
| 326 payload.id = tab_id.id(); |
| 327 payload.index = count; |
| 328 scoped_ptr<SessionCommand> command( |
| 329 new SessionCommand(kCommandTabNavigationPathPrunedFromFront, |
| 330 sizeof(payload))); |
| 331 memcpy(command->contents(), &payload, sizeof(payload)); |
| 332 return command.Pass(); |
| 333 } |
| 334 |
| 335 scoped_ptr<SessionCommand> |
| 336 SessionServiceCommands::CreateUpdateTabNavigationCommand( |
| 337 const SessionID& tab_id, |
| 338 const sessions::SerializedNavigationEntry& navigation) { |
| 339 // TODO(skuhne): Check why this command needs to be called from the base. |
| 340 // thus: could eliminate the use of that class here. |
| 341 return BaseSessionServiceCommands::CreateUpdateTabNavigationCommand( |
| 342 kCommandUpdateTabNavigation, |
| 343 tab_id.id(), |
| 344 navigation).Pass(); |
| 345 } |
| 346 |
| 347 scoped_ptr<SessionCommand> |
| 348 SessionServiceCommands::CreateSetTabExtensionAppIDCommand( |
| 349 const SessionID& tab_id, |
| 350 const std::string& extension_id) { |
| 351 return BaseSessionServiceCommands::CreateSetTabExtensionAppIDCommand( |
| 352 kCommandSetExtensionAppID, |
| 353 tab_id.id(), |
| 354 extension_id).Pass(); |
| 355 } |
| 356 |
| 357 scoped_ptr<SessionCommand> |
| 358 SessionServiceCommands::CreateSetTabUserAgentOverrideCommand( |
| 359 const SessionID& tab_id, |
| 360 const std::string& user_agent_override) { |
| 361 return BaseSessionServiceCommands::CreateSetTabUserAgentOverrideCommand( |
| 362 kCommandSetTabUserAgentOverride, |
| 363 tab_id.id(), |
| 364 user_agent_override).Pass(); |
| 365 } |
| 366 |
| 367 scoped_ptr<SessionCommand> |
| 368 SessionServiceCommands::CreateSetWindowAppNameCommand( |
| 369 const SessionID& window_id, |
| 370 const std::string& app_name) { |
| 371 return BaseSessionServiceCommands::CreateSetWindowAppNameCommand( |
| 372 kCommandSetWindowAppName, |
| 373 window_id.id(), |
| 374 app_name).Pass(); |
| 375 } |
| 376 |
| 377 bool SessionServiceCommands::ReplacePendingCommand( |
| 378 scoped_ptr<SessionCommand>* command, |
| 379 ScopedVector<SessionCommand>& pending_commands) { |
| 380 // We optimize page navigations, which can happen quite frequently and |
| 381 // is expensive. And activation is like Highlander, there can only be one! |
| 382 if ((*command)->id() != kCommandUpdateTabNavigation && |
| 383 (*command)->id() != kCommandSetActiveWindow) { |
| 384 return false; |
| 385 } |
| 386 for (ScopedVector<SessionCommand>::reverse_iterator i = |
| 387 pending_commands.rbegin(); i != pending_commands.rend(); ++i) { |
| 388 SessionCommand* existing_command = *i; |
| 389 if ((*command)->id() == kCommandUpdateTabNavigation && |
| 390 existing_command->id() == kCommandUpdateTabNavigation) { |
| 391 scoped_ptr<Pickle> command_pickle((*command)->PayloadAsPickle()); |
| 392 PickleIterator iterator(*command_pickle); |
| 393 SessionID::id_type command_tab_id; |
| 394 int command_nav_index; |
| 395 if (!command_pickle->ReadInt(&iterator, &command_tab_id) || |
| 396 !command_pickle->ReadInt(&iterator, &command_nav_index)) { |
| 397 return false; |
| 398 } |
| 399 SessionID::id_type existing_tab_id; |
| 400 int existing_nav_index; |
| 401 { |
| 402 // Creating a pickle like this means the Pickle references the data from |
| 403 // the command. Make sure we delete the pickle before the command, else |
| 404 // the pickle references deleted memory. |
| 405 scoped_ptr<Pickle> existing_pickle(existing_command->PayloadAsPickle()); |
| 406 iterator = PickleIterator(*existing_pickle); |
| 407 if (!existing_pickle->ReadInt(&iterator, &existing_tab_id) || |
| 408 !existing_pickle->ReadInt(&iterator, &existing_nav_index)) { |
| 409 return false; |
| 410 } |
| 411 } |
| 412 if (existing_tab_id == command_tab_id && |
| 413 existing_nav_index == command_nav_index) { |
| 414 // existing_command is an update for the same tab/index pair. Replace |
| 415 // it with the new one. We need to add to the end of the list just in |
| 416 // case there is a prune command after the update command. |
| 417 pending_commands.erase(i.base() - 1); |
| 418 pending_commands.push_back((*command).release()); |
| 419 return true; |
| 420 } |
| 421 return false; |
| 422 } |
| 423 if ((*command)->id() == kCommandSetActiveWindow && |
| 424 existing_command->id() == kCommandSetActiveWindow) { |
| 425 *i = (*command).release(); |
| 426 return true; |
| 427 } |
| 428 } |
| 429 return false; |
| 430 } |
| 431 |
| 432 bool SessionServiceCommands::IsClosingCommand(SessionCommand* command) const { |
| 433 return command->id() == kCommandTabClosed || |
| 434 command->id() == kCommandWindowClosed; |
| 435 } |
| 436 |
| 437 void SessionServiceCommands::RestoreSessionFromCommands( |
| 438 const ScopedVector<SessionCommand>& commands, |
| 439 std::vector<SessionWindow*>* valid_windows, |
| 440 SessionID::id_type* active_window_id) { |
| 441 std::map<int, SessionTab*> tabs; |
| 442 std::map<int, SessionWindow*> windows; |
| 443 |
| 444 VLOG(1) << "RestoreSessionFromCommands " << commands.size(); |
| 445 if (CreateTabsAndWindows(commands, &tabs, &windows, active_window_id)) { |
| 446 AddTabsToWindows(&tabs, &windows); |
| 447 SortTabsBasedOnVisualOrderAndPrune(&windows, valid_windows); |
| 448 UpdateSelectedTabIndex(valid_windows); |
| 449 } |
| 450 STLDeleteValues(&tabs); |
| 451 // Don't delete contents of windows, that is done by the caller as all |
| 452 // valid windows are added to valid_windows. |
| 453 } |
| 454 |
| 455 void SessionServiceCommands::UpdateSelectedTabIndex( |
| 456 std::vector<SessionWindow*>* windows) { |
| 457 for (std::vector<SessionWindow*>::const_iterator i = windows->begin(); |
| 458 i != windows->end(); ++i) { |
| 459 // See note in SessionWindow as to why we do this. |
| 460 int new_index = 0; |
| 461 for (std::vector<SessionTab*>::const_iterator j = (*i)->tabs.begin(); |
| 462 j != (*i)->tabs.end(); ++j) { |
| 463 if ((*j)->tab_visual_index == (*i)->selected_tab_index) { |
| 464 new_index = static_cast<int>(j - (*i)->tabs.begin()); |
| 465 break; |
| 466 } |
| 467 } |
| 468 (*i)->selected_tab_index = new_index; |
| 469 } |
| 470 } |
| 471 |
| 472 SessionWindow* SessionServiceCommands::GetWindow(SessionID::id_type window_id, |
| 473 IdToSessionWindow* windows) { |
| 474 std::map<int, SessionWindow*>::iterator i = windows->find(window_id); |
| 475 if (i == windows->end()) { |
| 476 SessionWindow* window = new SessionWindow(); |
| 477 window->window_id.set_id(window_id); |
| 478 (*windows)[window_id] = window; |
| 479 return window; |
| 480 } |
| 481 return i->second; |
| 482 } |
| 483 |
| 484 SessionTab* SessionServiceCommands::GetTab(SessionID::id_type tab_id, |
| 485 IdToSessionTab* tabs) { |
| 486 DCHECK(tabs); |
| 487 std::map<int, SessionTab*>::iterator i = tabs->find(tab_id); |
| 488 if (i == tabs->end()) { |
| 489 SessionTab* tab = new SessionTab(); |
| 490 tab->tab_id.set_id(tab_id); |
| 491 (*tabs)[tab_id] = tab; |
| 492 return tab; |
| 493 } |
| 494 return i->second; |
| 495 } |
| 496 |
| 497 std::vector<sessions::SerializedNavigationEntry>::iterator |
| 498 SessionServiceCommands::FindClosestNavigationWithIndex( |
| 499 std::vector<sessions::SerializedNavigationEntry>* navigations, |
| 500 int index) { |
| 501 DCHECK(navigations); |
| 502 for (std::vector<sessions::SerializedNavigationEntry>::iterator |
| 503 i = navigations->begin(); i != navigations->end(); ++i) { |
| 504 if (i->index() >= index) |
| 505 return i; |
| 506 } |
| 507 return navigations->end(); |
| 508 } |
| 509 |
| 510 // Function used in sorting windows. Sorting is done based on window id. As |
| 511 // window ids increment for each new window, this effectively sorts by creation |
| 512 // time. |
| 513 static bool WindowOrderSortFunction(const SessionWindow* w1, |
| 514 const SessionWindow* w2) { |
| 515 return w1->window_id.id() < w2->window_id.id(); |
| 516 } |
| 517 |
| 518 // Compares the two tabs based on visual index. |
| 519 static bool TabVisualIndexSortFunction(const SessionTab* t1, |
| 520 const SessionTab* t2) { |
| 521 const int delta = t1->tab_visual_index - t2->tab_visual_index; |
| 522 return delta == 0 ? (t1->tab_id.id() < t2->tab_id.id()) : (delta < 0); |
| 523 } |
| 524 |
| 525 void SessionServiceCommands::SortTabsBasedOnVisualOrderAndPrune( |
| 526 std::map<int, SessionWindow*>* windows, |
| 527 std::vector<SessionWindow*>* valid_windows) { |
| 528 std::map<int, SessionWindow*>::iterator i = windows->begin(); |
| 529 while (i != windows->end()) { |
| 530 SessionWindow* window = i->second; |
| 531 AppType app_type = window->app_name.empty() ? TYPE_NORMAL : TYPE_APP; |
| 532 if (window->tabs.empty() || window->is_constrained || |
| 533 !delegate_->ShouldRestoreWindowOfType(window->type, app_type)) { |
| 534 delete window; |
| 535 windows->erase(i++); |
| 536 } else { |
| 537 // Valid window; sort the tabs and add it to the list of valid windows. |
| 538 std::sort(window->tabs.begin(), window->tabs.end(), |
| 539 &TabVisualIndexSortFunction); |
| 540 // Otherwise, add the window such that older windows appear first. |
| 541 if (valid_windows->empty()) { |
| 542 valid_windows->push_back(window); |
| 543 } else { |
| 544 valid_windows->insert( |
| 545 std::upper_bound(valid_windows->begin(), valid_windows->end(), |
| 546 window, &WindowOrderSortFunction), |
| 547 window); |
| 548 } |
| 549 ++i; |
| 550 } |
| 551 } |
| 552 } |
| 553 |
| 554 void SessionServiceCommands::AddTabsToWindows( |
| 555 std::map<int, SessionTab*>* tabs, |
| 556 std::map<int, SessionWindow*>* windows) { |
| 557 VLOG(1) << "AddTabsToWindws"; |
| 558 VLOG(1) << "Tabs " << tabs->size() << ", windows " << windows->size(); |
| 559 std::map<int, SessionTab*>::iterator i = tabs->begin(); |
| 560 while (i != tabs->end()) { |
| 561 SessionTab* tab = i->second; |
| 562 if (tab->window_id.id() && !tab->navigations.empty()) { |
| 563 SessionWindow* window = GetWindow(tab->window_id.id(), windows); |
| 564 window->tabs.push_back(tab); |
| 565 tabs->erase(i++); |
| 566 |
| 567 // See note in SessionTab as to why we do this. |
| 568 std::vector<sessions::SerializedNavigationEntry>::iterator j = |
| 569 FindClosestNavigationWithIndex(&(tab->navigations), |
| 570 tab->current_navigation_index); |
| 571 if (j == tab->navigations.end()) { |
| 572 tab->current_navigation_index = |
| 573 static_cast<int>(tab->navigations.size() - 1); |
| 574 } else { |
| 575 tab->current_navigation_index = |
| 576 static_cast<int>(j - tab->navigations.begin()); |
| 577 } |
| 578 } else { |
| 579 // Never got a set tab index in window, or tabs are empty, nothing |
| 580 // to do. |
| 581 ++i; |
| 582 } |
| 583 } |
| 584 } |
| 585 |
| 586 bool SessionServiceCommands::CreateTabsAndWindows( |
| 587 const ScopedVector<SessionCommand>& data, |
| 588 std::map<int, SessionTab*>* tabs, |
| 589 std::map<int, SessionWindow*>* windows, |
| 590 SessionID::id_type* active_window_id) { |
| 591 // If the file is corrupt (command with wrong size, or unknown command), we |
| 592 // still return true and attempt to restore what we we can. |
| 593 VLOG(1) << "CreateTabsAndWindows"; |
| 594 |
| 595 for (std::vector<SessionCommand*>::const_iterator i = data.begin(); |
| 596 i != data.end(); ++i) { |
| 597 const SessionCommand::id_type kCommandSetWindowBounds2 = 10; |
| 598 const SessionCommand* command = *i; |
| 599 |
| 600 VLOG(1) << "Read command " << (int) command->id(); |
| 601 switch (command->id()) { |
| 602 case kCommandSetTabWindow: { |
| 603 SessionID::id_type payload[2]; |
| 604 if (!command->GetPayload(payload, sizeof(payload))) { |
| 605 VLOG(1) << "Failed reading command " << command->id(); |
| 606 return true; |
| 607 } |
| 608 GetTab(payload[1], tabs)->window_id.set_id(payload[0]); |
| 609 break; |
| 610 } |
| 611 |
| 612 // This is here for forward migration only. New data is saved with |
| 613 // |kCommandSetWindowBounds3|. |
| 614 case kCommandSetWindowBounds2: { |
| 615 WindowBoundsPayload2 payload; |
| 616 if (!command->GetPayload(&payload, sizeof(payload))) { |
| 617 VLOG(1) << "Failed reading command " << command->id(); |
| 618 return true; |
| 619 } |
| 620 GetWindow(payload.window_id, windows)->bounds.SetRect(payload.x, |
| 621 payload.y, |
| 622 payload.w, |
| 623 payload.h); |
| 624 GetWindow(payload.window_id, windows)->show_state = |
| 625 payload.is_maximized ? |
| 626 ui::SHOW_STATE_MAXIMIZED : ui::SHOW_STATE_NORMAL; |
| 627 break; |
| 628 } |
| 629 |
| 630 case kCommandSetWindowBounds3: { |
| 631 WindowBoundsPayload3 payload; |
| 632 if (!command->GetPayload(&payload, sizeof(payload))) { |
| 633 VLOG(1) << "Failed reading command " << command->id(); |
| 634 return true; |
| 635 } |
| 636 GetWindow(payload.window_id, windows)->bounds.SetRect(payload.x, |
| 637 payload.y, |
| 638 payload.w, |
| 639 payload.h); |
| 640 GetWindow(payload.window_id, windows)->show_state = |
| 641 PersistedShowStateToShowState(payload.show_state); |
| 642 break; |
| 643 } |
| 644 |
| 645 case kCommandSetTabIndexInWindow: { |
| 646 TabIndexInWindowPayload payload; |
| 647 if (!command->GetPayload(&payload, sizeof(payload))) { |
| 648 VLOG(1) << "Failed reading command " << command->id(); |
| 649 return true; |
| 650 } |
| 651 GetTab(payload.id, tabs)->tab_visual_index = payload.index; |
| 652 break; |
| 653 } |
| 654 |
| 655 case kCommandTabClosed: |
| 656 case kCommandWindowClosed: { |
| 657 ClosedPayload payload; |
| 658 if (!command->GetPayload(&payload, sizeof(payload))) { |
| 659 VLOG(1) << "Failed reading command " << command->id(); |
| 660 return true; |
| 661 } |
| 662 if (command->id() == kCommandTabClosed) { |
| 663 delete GetTab(payload.id, tabs); |
| 664 tabs->erase(payload.id); |
| 665 } else { |
| 666 delete GetWindow(payload.id, windows); |
| 667 windows->erase(payload.id); |
| 668 } |
| 669 break; |
| 670 } |
| 671 |
| 672 case kCommandTabNavigationPathPrunedFromBack: { |
| 673 TabNavigationPathPrunedFromBackPayload payload; |
| 674 if (!command->GetPayload(&payload, sizeof(payload))) { |
| 675 VLOG(1) << "Failed reading command " << command->id(); |
| 676 return true; |
| 677 } |
| 678 SessionTab* tab = GetTab(payload.id, tabs); |
| 679 tab->navigations.erase( |
| 680 FindClosestNavigationWithIndex(&(tab->navigations), payload.index), |
| 681 tab->navigations.end()); |
| 682 break; |
| 683 } |
| 684 |
| 685 case kCommandTabNavigationPathPrunedFromFront: { |
| 686 TabNavigationPathPrunedFromFrontPayload payload; |
| 687 if (!command->GetPayload(&payload, sizeof(payload)) || |
| 688 payload.index <= 0) { |
| 689 VLOG(1) << "Failed reading command " << command->id(); |
| 690 return true; |
| 691 } |
| 692 SessionTab* tab = GetTab(payload.id, tabs); |
| 693 |
| 694 // Update the selected navigation index. |
| 695 tab->current_navigation_index = |
| 696 std::max(-1, tab->current_navigation_index - payload.index); |
| 697 |
| 698 // And update the index of existing navigations. |
| 699 for (std::vector<sessions::SerializedNavigationEntry>::iterator |
| 700 i = tab->navigations.begin(); |
| 701 i != tab->navigations.end();) { |
| 702 i->set_index(i->index() - payload.index); |
| 703 if (i->index() < 0) |
| 704 i = tab->navigations.erase(i); |
| 705 else |
| 706 ++i; |
| 707 } |
| 708 break; |
| 709 } |
| 710 |
| 711 case kCommandUpdateTabNavigation: { |
| 712 sessions::SerializedNavigationEntry navigation; |
| 713 SessionID::id_type tab_id; |
| 714 if (!BaseSessionServiceCommands::RestoreUpdateTabNavigationCommand( |
| 715 *command, |
| 716 &navigation, |
| 717 &tab_id)) { |
| 718 VLOG(1) << "Failed reading command " << command->id(); |
| 719 return true; |
| 720 } |
| 721 SessionTab* tab = GetTab(tab_id, tabs); |
| 722 std::vector<sessions::SerializedNavigationEntry>::iterator i = |
| 723 FindClosestNavigationWithIndex(&(tab->navigations), |
| 724 navigation.index()); |
| 725 if (i != tab->navigations.end() && i->index() == navigation.index()) |
| 726 *i = navigation; |
| 727 else |
| 728 tab->navigations.insert(i, navigation); |
| 729 break; |
| 730 } |
| 731 |
| 732 case kCommandSetSelectedNavigationIndex: { |
| 733 SelectedNavigationIndexPayload payload; |
| 734 if (!command->GetPayload(&payload, sizeof(payload))) { |
| 735 VLOG(1) << "Failed reading command " << command->id(); |
| 736 return true; |
| 737 } |
| 738 GetTab(payload.id, tabs)->current_navigation_index = payload.index; |
| 739 break; |
| 740 } |
| 741 |
| 742 case kCommandSetSelectedTabInIndex: { |
| 743 SelectedTabInIndexPayload payload; |
| 744 if (!command->GetPayload(&payload, sizeof(payload))) { |
| 745 VLOG(1) << "Failed reading command " << command->id(); |
| 746 return true; |
| 747 } |
| 748 GetWindow(payload.id, windows)->selected_tab_index = payload.index; |
| 749 break; |
| 750 } |
| 751 |
| 752 case kCommandSetWindowType: { |
| 753 WindowTypePayload payload; |
| 754 if (!command->GetPayload(&payload, sizeof(payload))) { |
| 755 VLOG(1) << "Failed reading command " << command->id(); |
| 756 return true; |
| 757 } |
| 758 GetWindow(payload.id, windows)->is_constrained = false; |
| 759 GetWindow(payload.id, windows)->type = |
| 760 static_cast<SessionWindow::WindowType>(payload.index); |
| 761 break; |
| 762 } |
| 763 |
| 764 case kCommandSetPinnedState: { |
| 765 PinnedStatePayload payload; |
| 766 if (!command->GetPayload(&payload, sizeof(payload))) { |
| 767 VLOG(1) << "Failed reading command " << command->id(); |
| 768 return true; |
| 769 } |
| 770 GetTab(payload.tab_id, tabs)->pinned = payload.pinned_state; |
| 771 break; |
| 772 } |
| 773 |
| 774 case kCommandSetWindowAppName: { |
| 775 SessionID::id_type window_id; |
| 776 std::string app_name; |
| 777 if (!BaseSessionServiceCommands::RestoreSetWindowAppNameCommand( |
| 778 *command, |
| 779 &window_id, |
| 780 &app_name)) |
| 781 return true; |
| 782 |
| 783 GetWindow(window_id, windows)->app_name.swap(app_name); |
| 784 break; |
| 785 } |
| 786 |
| 787 case kCommandSetExtensionAppID: { |
| 788 SessionID::id_type tab_id; |
| 789 std::string extension_app_id; |
| 790 if (!BaseSessionServiceCommands::RestoreSetTabExtensionAppIDCommand( |
| 791 *command, |
| 792 &tab_id, |
| 793 &extension_app_id)) { |
| 794 VLOG(1) << "Failed reading command " << command->id(); |
| 795 return true; |
| 796 } |
| 797 |
| 798 GetTab(tab_id, tabs)->extension_app_id.swap(extension_app_id); |
| 799 break; |
| 800 } |
| 801 |
| 802 case kCommandSetTabUserAgentOverride: { |
| 803 SessionID::id_type tab_id; |
| 804 std::string user_agent_override; |
| 805 if (!BaseSessionServiceCommands::RestoreSetTabUserAgentOverrideCommand( |
| 806 *command, |
| 807 &tab_id, |
| 808 &user_agent_override)) { |
| 809 return true; |
| 810 } |
| 811 |
| 812 GetTab(tab_id, tabs)->user_agent_override.swap(user_agent_override); |
| 813 break; |
| 814 } |
| 815 |
| 816 case kCommandSessionStorageAssociated: { |
| 817 scoped_ptr<Pickle> command_pickle(command->PayloadAsPickle()); |
| 818 SessionID::id_type command_tab_id; |
| 819 std::string session_storage_persistent_id; |
| 820 PickleIterator iter(*command_pickle.get()); |
| 821 if (!command_pickle->ReadInt(&iter, &command_tab_id) || |
| 822 !command_pickle->ReadString(&iter, &session_storage_persistent_id)) |
| 823 return true; |
| 824 // Associate the session storage back. |
| 825 GetTab(command_tab_id, tabs)->session_storage_persistent_id = |
| 826 session_storage_persistent_id; |
| 827 break; |
| 828 } |
| 829 |
| 830 case kCommandSetActiveWindow: { |
| 831 ActiveWindowPayload payload; |
| 832 if (!command->GetPayload(&payload, sizeof(payload))) { |
| 833 VLOG(1) << "Failed reading command " << command->id(); |
| 834 return true; |
| 835 } |
| 836 *active_window_id = payload; |
| 837 break; |
| 838 } |
| 839 |
| 840 default: |
| 841 // TODO(skuhne): This might call back into a callback handler to extend |
| 842 // the command set for specific implementations. |
| 843 VLOG(1) << "Failed reading an unknown command " << command->id(); |
| 844 return true; |
| 845 } |
| 846 } |
| 847 return true; |
| 848 } |
| OLD | NEW |