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