Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(117)

Side by Side Diff: chrome/browser/sessions/session_service_commands.cc

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

Powered by Google App Engine
This is Rietveld 408576698