| Index: chrome/browser/ui/views/frame/browser_view.cc | 
| diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc | 
| index b5c17fb15e71e9b7e202041aa9628d64a321b239..d25f24b33b60cee9afc48609d020e5b2f1701a7d 100644 | 
| --- a/chrome/browser/ui/views/frame/browser_view.cc | 
| +++ b/chrome/browser/ui/views/frame/browser_view.cc | 
| @@ -21,6 +21,8 @@ | 
| #include "chrome/browser/browser_process.h" | 
| #include "chrome/browser/chrome_notification_types.h" | 
| #include "chrome/browser/extensions/extension_util.h" | 
| +#include "chrome/browser/extensions/sidebar_container.h" | 
| +#include "chrome/browser/extensions/sidebar_manager.h" | 
| #include "chrome/browser/extensions/tab_helper.h" | 
| #include "chrome/browser/infobars/infobar_service.h" | 
| #include "chrome/browser/native_window_notification_source.h" | 
| @@ -131,10 +133,13 @@ | 
| #include "ui/gfx/screen.h" | 
| #include "ui/strings/grit/ui_strings.h" | 
| #include "ui/views/controls/button/menu_button.h" | 
| +#include "ui/views/controls/single_split_view.h" | 
| +#include "ui/views/controls/single_split_view_listener.h" | 
| #include "ui/views/controls/textfield/textfield.h" | 
| #include "ui/views/controls/webview/webview.h" | 
| #include "ui/views/focus/external_focus_tracker.h" | 
| #include "ui/views/focus/view_storage.h" | 
| +#include "ui/views/layout/box_layout.h" | 
| #include "ui/views/layout/grid_layout.h" | 
| #include "ui/views/widget/native_widget.h" | 
| #include "ui/views/widget/root_view.h" | 
| @@ -519,6 +524,10 @@ void BrowserView::Init(Browser* browser) { | 
| browser_->tab_strip_model()->AddObserver(this); | 
| immersive_mode_controller_.reset( | 
| chrome::CreateImmersiveModeController(browser_->host_desktop_type())); | 
| + | 
| +  extensions::SidebarManager* sidebar_manager = | 
| +      extensions::SidebarManager::GetFromContext(browser_->profile()); | 
| +  sidebar_manager->AddObserver(this); | 
| } | 
|  | 
| // static | 
| @@ -540,6 +549,14 @@ void BrowserView::InitStatusBubble() { | 
| contents_web_view_->SetStatusBubble(status_bubble_.get()); | 
| } | 
|  | 
| +bool BrowserView::SplitHandleMoved(views::SingleSplitView* sender) { | 
| +  for (int i = 0; i < sender->child_count(); ++i) | 
| +    sender->child_at(i)->InvalidateLayout(); | 
| +  SchedulePaint(); | 
| +  Layout(); | 
| +  return false; | 
| +} | 
| + | 
| gfx::Rect BrowserView::GetToolbarBounds() const { | 
| gfx::Rect toolbar_bounds(toolbar_->bounds()); | 
| if (toolbar_bounds.IsEmpty()) | 
| @@ -654,6 +671,16 @@ gfx::ImageSkia BrowserView::GetOTRAvatarIcon() const { | 
| return *GetThemeProvider()->GetImageSkiaNamed(IDR_OTR_ICON); | 
| } | 
|  | 
| +void BrowserView::OnSidebarShown(content::WebContents* tab, | 
| +                                 const std::string& content_id) { | 
| +  UpdateSidebarForContents(tab); | 
| +} | 
| + | 
| +void BrowserView::OnSidebarHidden(content::WebContents* tab, | 
| +                                  const std::string& content_id) { | 
| +  UpdateSidebarForContents(tab); | 
| +} | 
| + | 
| /////////////////////////////////////////////////////////////////////////////// | 
| // BrowserView, BrowserWindow implementation: | 
|  | 
| @@ -883,6 +910,7 @@ void BrowserView::OnActiveTabChanged(content::WebContents* old_contents, | 
| // to avoid toggling the size of any of them. | 
| UpdateDevToolsForContents(new_contents, !change_tab_contents); | 
|  | 
| +  UpdateSidebarForContents(new_contents); | 
| if (change_tab_contents) { | 
| web_contents_close_handler_->ActiveTabChanged(); | 
| contents_web_view_->SetWebContents(new_contents); | 
| @@ -1311,6 +1339,12 @@ void BrowserView::ShowOneClickSigninBubble( | 
| } | 
| #endif | 
|  | 
| +int BrowserView::GetSidebarWidth() const { | 
| +  if (!sidebar_container_ || !sidebar_container_->visible()) | 
| +    return 0; | 
| +  return sidebar_split_->divider_offset(); | 
| +} | 
| + | 
| void BrowserView::SetDownloadShelfVisible(bool visible) { | 
| // This can be called from the superclass destructor, when it destroys our | 
| // child views. At that point, browser_ is already gone. | 
| @@ -1564,6 +1598,7 @@ void BrowserView::TabDetachedAt(WebContents* contents, int index) { | 
| infobar_container_->ChangeInfoBarManager(nullptr); | 
| UpdateDevToolsForContents(nullptr, true); | 
| } | 
| +  UpdateSidebarForContents(NULL); | 
| } | 
|  | 
| void BrowserView::TabDeactivated(WebContents* contents) { | 
| @@ -2042,8 +2077,27 @@ void BrowserView::InitViews() { | 
| contents_container_->AddChildView(contents_web_view_); | 
| contents_container_->SetLayoutManager(new ContentsLayoutManager( | 
| devtools_web_view_, contents_web_view_)); | 
| -  AddChildView(contents_container_); | 
| -  set_contents_view(contents_container_); | 
| + | 
| +  sidebar_web_view_ = new views::WebView(browser_->profile()); | 
| +  sidebar_web_view_->set_id(VIEW_ID_SIDE_BAR_VIEW); | 
| +  sidebar_web_view_->SetVisible(false); | 
| + | 
| +  sidebar_container_ = new views::View(); | 
| +  sidebar_container_->AddChildView(sidebar_web_view_); | 
| +  sidebar_container_->set_id(VIEW_ID_SIDE_BAR_CONTAINER); | 
| +  sidebar_container_->SetVisible(false); | 
| + | 
| +  sidebar_split_ = new views::SingleSplitView( | 
| +      contents_container_, sidebar_container_, | 
| +      views::SingleSplitView::HORIZONTAL_SPLIT, this); | 
| + | 
| +  sidebar_split_->set_id(VIEW_ID_SIDE_BAR_SPLIT); | 
| +  sidebar_split_->set_background(views::Background::CreateSolidBackground( | 
| +      GetWidget()->GetThemeProvider()->GetColor( | 
| +          ThemeProperties::COLOR_TOOLBAR))); | 
| +  sidebar_split_->set_resize_leading_on_bounds_change(false); | 
| +  AddChildView(sidebar_split_); | 
| +  set_contents_view(sidebar_split_); | 
|  | 
| // Top container holds tab strip and toolbar and lives at the front of the | 
| // view hierarchy. | 
| @@ -2072,16 +2126,10 @@ void BrowserView::InitViews() { | 
| immersive_mode_controller_->Init(this); | 
|  | 
| BrowserViewLayout* browser_view_layout = new BrowserViewLayout; | 
| -  browser_view_layout->Init(new BrowserViewLayoutDelegateImpl(this), | 
| -                            browser(), | 
| -                            this, | 
| -                            top_container_, | 
| -                            tabstrip_, | 
| -                            toolbar_, | 
| -                            infobar_container_, | 
| -                            contents_container_, | 
| -                            GetContentsLayoutManager(), | 
| -                            immersive_mode_controller_.get()); | 
| +  browser_view_layout->Init( | 
| +      new BrowserViewLayoutDelegateImpl(this), browser(), this, top_container_, | 
| +      tabstrip_, toolbar_, infobar_container_, sidebar_split_, | 
| +      GetContentsLayoutManager(), immersive_mode_controller_.get()); | 
| SetLayoutManager(browser_view_layout); | 
|  | 
| #if defined(OS_WIN) | 
| @@ -2095,6 +2143,67 @@ void BrowserView::InitViews() { | 
| GetLocationBar()->GetOmniboxView()->model()->popup_model()->AddObserver(this); | 
| } | 
|  | 
| +void BrowserView::UpdateSidebarForContents(content::WebContents* new_contents) { | 
| +  if (!sidebar_container_) | 
| +    return;  // Happens when sidebar is not allowed. | 
| +  extensions::SidebarManager* sidebar_manager = | 
| +      extensions::SidebarManager::GetFromContext(browser_->profile()); | 
| +  if (!sidebar_manager) | 
| +    return;  // Happens only in tests.s | 
| + | 
| +  WebContents* sidebar_contents = NULL; | 
| +  if (new_contents) { | 
| +    SidebarContainer* client_host = | 
| +        sidebar_manager->GetActiveSidebarContainerFor(new_contents); | 
| +    if (client_host) | 
| +      sidebar_contents = client_host->host_contents(); | 
| +  } | 
| + | 
| +  bool visible = NULL != sidebar_contents; | 
| + | 
| +  bool should_show = visible && !sidebar_container_->visible(); | 
| +  bool should_hide = !visible && sidebar_container_->visible(); | 
| + | 
| +  // Update sidebar content. | 
| +  WebContents* old_contents = | 
| +      static_cast<WebContents*>(sidebar_web_view_->web_contents()); | 
| + | 
| +  sidebar_web_view_->SetWebContents(sidebar_contents); | 
| + | 
| +  sidebar_manager->NotifyStateChanges(old_contents, sidebar_contents); | 
| + | 
| +  // Update sidebar UI width. | 
| +  if (should_show) { | 
| +    // Restore split offset. | 
| +    int sidebar_width = g_browser_process->local_state()->GetInteger( | 
| +        prefs::kExtensionSidebarWidth); | 
| +    if (sidebar_width < 0) { | 
| +      // By default sidebar width is 1/7th of the current page content width. | 
| +      sidebar_width = sidebar_split_->width() / 7; | 
| +    } | 
| +    int min_sidebar_width = sidebar_split_->GetMinimumSize().width(); | 
| +    // Not allowed to be wider than 50% of the split-view's frame | 
| +    sidebar_width = std::min(sidebar_split_->width() / 2 - min_sidebar_width, | 
| +                             std::max(min_sidebar_width, sidebar_width)); | 
| +    sidebar_split_->set_divider_offset(sidebar_split_->width() - sidebar_width); | 
| + | 
| +    sidebar_container_->SetVisible(true); | 
| +    sidebar_web_view_->SetVisible(true); | 
| +    sidebar_split_->InvalidateLayout(); | 
| +    Layout(); | 
| + | 
| +  } else if (should_hide) { | 
| +    // Store split offset when hiding sidebar only. | 
| +    g_browser_process->local_state()->SetInteger( | 
| +        prefs::kExtensionSidebarWidth, | 
| +        sidebar_split_->width() - sidebar_split_->divider_offset()); | 
| + | 
| +    sidebar_container_->SetVisible(false); | 
| +    sidebar_split_->InvalidateLayout(); | 
| +    Layout(); | 
| +  } | 
| +} | 
| + | 
| void BrowserView::LoadingAnimationCallback() { | 
| base::TimeTicks now = base::TimeTicks::Now(); | 
| if (!last_animation_time_.is_null()) { | 
|  |