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