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