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