diff options
author | beng@google.com <beng@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-09-12 22:44:06 +0000 |
---|---|---|
committer | beng@google.com <beng@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-09-12 22:44:06 +0000 |
commit | 3146282c2250c51569d971234fbc9756b4d7a2d4 (patch) | |
tree | 0f9f418993163cd7a67955d10e89928b28787978 /chrome/browser/tabs | |
parent | 5db2a6ed0d09ef82cf84ba2677ecfcdff6192c79 (diff) | |
download | chromium_src-3146282c2250c51569d971234fbc9756b4d7a2d4.zip chromium_src-3146282c2250c51569d971234fbc9756b4d7a2d4.tar.gz chromium_src-3146282c2250c51569d971234fbc9756b4d7a2d4.tar.bz2 |
Move View components of the Browser's tab strip into the browser_views project, and into the views/ subdirectory on disk.
B=2198
Review URL: http://codereview.chromium.org/3020
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@2140 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/tabs')
-rw-r--r-- | chrome/browser/tabs/dragged_tab_controller.cc | 798 | ||||
-rw-r--r-- | chrome/browser/tabs/dragged_tab_controller.h | 286 | ||||
-rw-r--r-- | chrome/browser/tabs/dragged_tab_view.cc | 244 | ||||
-rw-r--r-- | chrome/browser/tabs/dragged_tab_view.h | 119 | ||||
-rw-r--r-- | chrome/browser/tabs/hwnd_photobooth.cc | 159 | ||||
-rw-r--r-- | chrome/browser/tabs/hwnd_photobooth.h | 62 | ||||
-rw-r--r-- | chrome/browser/tabs/tab.cc | 241 | ||||
-rw-r--r-- | chrome/browser/tabs/tab.h | 125 | ||||
-rw-r--r-- | chrome/browser/tabs/tab_dragging_test.cc | 507 | ||||
-rw-r--r-- | chrome/browser/tabs/tab_renderer.cc | 691 | ||||
-rw-r--r-- | chrome/browser/tabs/tab_renderer.h | 174 | ||||
-rw-r--r-- | chrome/browser/tabs/tab_strip.cc | 1524 | ||||
-rw-r--r-- | chrome/browser/tabs/tab_strip.h | 373 |
13 files changed, 0 insertions, 5303 deletions
diff --git a/chrome/browser/tabs/dragged_tab_controller.cc b/chrome/browser/tabs/dragged_tab_controller.cc deleted file mode 100644 index 80cbe65..0000000 --- a/chrome/browser/tabs/dragged_tab_controller.cc +++ /dev/null @@ -1,798 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/tabs/dragged_tab_controller.h" - -#include <math.h> - -#include "chrome/browser/browser_window.h" -#include "chrome/browser/frame_util.h" -#include "chrome/browser/tab_contents.h" -#include "chrome/browser/tabs/dragged_tab_view.h" -#include "chrome/browser/tabs/hwnd_photobooth.h" -#include "chrome/browser/tabs/tab.h" -#include "chrome/browser/tabs/tab_strip.h" -#include "chrome/browser/web_contents.h" -#include "chrome/views/event.h" -#include "chrome/views/root_view.h" -#include "skia/include/SkBitmap.h" - -static const int kHorizontalMoveThreshold = 16; // pixels - -namespace { - -/////////////////////////////////////////////////////////////////////////////// -// WindowFinder -// A WindowForPoint facility that can ignore 2 provided window HWNDs. -// -class WindowFinder { - public: - static HWND WindowForPoint(const gfx::Point& screen_point, HWND ignore1) { - WindowFinder instance(screen_point, ignore1); - return instance.GetResult(); - } - private: - WindowFinder(const gfx::Point& screen_point, HWND ignore1) - : screen_point_(screen_point.ToPOINT()), - ignore1_(ignore1), - result_(NULL) { - } - - static BOOL CALLBACK WindowEnumProc(HWND hwnd, LPARAM lParam) { - WindowFinder* wf = reinterpret_cast<WindowFinder*>(lParam); - if (hwnd == wf->ignore1_) - return true; - - if (::IsWindowVisible(hwnd)) { - CRect r; - ::GetWindowRect(hwnd, &r); - if (r.PtInRect(wf->screen_point_)) { - // We always deal with the root HWND. - wf->result_ = GetAncestor(hwnd, GA_ROOT); - return FALSE; - } - } - return TRUE; - } - - HWND GetResult() { - EnumThreadWindows(GetCurrentThreadId(), WindowEnumProc, - reinterpret_cast<LPARAM>(this)); - return result_; - } - - POINT screen_point_; - HWND ignore1_; - HWND result_; - - DISALLOW_EVIL_CONSTRUCTORS(WindowFinder); -}; - -gfx::Point ConvertScreenPointToTabStripPoint(TabStrip* tabstrip, - const gfx::Point& screen_point) { - CPoint tabstrip_topleft(0, 0); - ChromeViews::View::ConvertPointToScreen(tabstrip, &tabstrip_topleft); - return gfx::Point(screen_point.x() - tabstrip_topleft.x, - screen_point.y() - tabstrip_topleft.y); -} - -} - -/////////////////////////////////////////////////////////////////////////////// -// DraggedTabController, public: - -DraggedTabController::DraggedTabController(Tab* source_tab, - TabStrip* source_tabstrip) - : dragged_contents_(NULL), - original_delegate_(NULL), - source_tab_(source_tab), - source_tabstrip_(source_tabstrip), - source_model_index_(source_tabstrip->GetIndexOfTab(source_tab)), - attached_tabstrip_(source_tabstrip), - old_focused_view_(NULL), - in_destructor_(false), - last_move_screen_x_(0) { - ChangeDraggedContents( - source_tabstrip_->model()->GetTabContentsAt(source_model_index_)); - // Listen for Esc key presses. - MessageLoopForUI::current()->AddObserver(this); -} - -DraggedTabController::~DraggedTabController() { - in_destructor_ = true; - CleanUpSourceTab(); - MessageLoopForUI::current()->RemoveObserver(this); - ChangeDraggedContents(NULL); // This removes our observer. -} - -void DraggedTabController::CaptureDragInfo(const gfx::Point& mouse_offset) { - start_screen_point_ = GetCursorScreenPoint(); - mouse_offset_ = mouse_offset; -} - -void DraggedTabController::Drag() { - // Before we get to dragging anywhere, ensure that we consider ourselves - // attached to the source tabstrip. - if (source_tab_->IsVisible() && CanStartDrag()) - Attach(source_tabstrip_, gfx::Point()); - - if (!source_tab_->IsVisible()) { - SaveFocus(); - ContinueDragging(); - } -} - -void DraggedTabController::EndDrag(bool canceled) { - EndDragImpl(canceled ? CANCELED : NORMAL); -} - -Tab* DraggedTabController::GetDragSourceTabForContents( - TabContents* contents) const { - if (attached_tabstrip_ == source_tabstrip_) - return contents == dragged_contents_ ? source_tab_ : NULL; - return NULL; -} - -bool DraggedTabController::IsDragSourceTab(Tab* tab) const { - return source_tab_ == tab; -} - -/////////////////////////////////////////////////////////////////////////////// -// DraggedTabController, PageNavigator implementation: - -void DraggedTabController::OpenURLFromTab( - TabContents* source, - const GURL& url, - WindowOpenDisposition disposition, - PageTransition::Type transition, - const std::string& override_encoding) { - if (original_delegate_) { - if (disposition == CURRENT_TAB) - disposition = NEW_WINDOW; - - original_delegate_->OpenURLFromTab(source, url, disposition, transition, - override_encoding); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// DraggedTabController, TabContentsDelegate implementation: - -void DraggedTabController::NavigationStateChanged(const TabContents* source, - unsigned changed_flags) { - if (view_.get()) - view_->Update(); -} - -void DraggedTabController::ReplaceContents(TabContents* source, - TabContents* new_contents) { - DCHECK(dragged_contents_ == source); - source->set_delegate(NULL); - new_contents->set_delegate(this); - - // If we're attached to a TabStrip, we need to tell the TabStrip that this - // TabContents was replaced. - if (attached_tabstrip_ && attached_tabstrip_->model() && dragged_contents_) { - int index = - attached_tabstrip_->model()->GetIndexOfTabContents(dragged_contents_); - if (index != TabStripModel::kNoTab) - attached_tabstrip_->model()->ReplaceTabContentsAt(index, new_contents); - } - - // Update our internal state. - ChangeDraggedContents(new_contents); - - if (view_.get()) - view_->Update(); -} - -void DraggedTabController::AddNewContents(TabContents* source, - TabContents* new_contents, - WindowOpenDisposition disposition, - const gfx::Rect& initial_pos, - bool user_gesture) { - // Theoretically could be called while dragging if the page tries to - // spawn a window. Route this message back to the browser in most cases. - if (disposition == CURRENT_TAB) { - ReplaceContents(source, new_contents); - } else if (original_delegate_) { - original_delegate_->AddNewContents(source, new_contents, disposition, - initial_pos, user_gesture); - } -} - -void DraggedTabController::ActivateContents(TabContents* contents) { - // Ignored. -} - -void DraggedTabController::LoadingStateChanged(TabContents* source) { - // It would be nice to respond to this message by changing the - // screen shot in the dragged tab. - if (view_.get()) - view_->Update(); -} - -void DraggedTabController::CloseContents(TabContents* source) { - // Theoretically could be called by a window. Should be ignored - // because window.close() is ignored (usually, even though this - // method gets called.) -} - -void DraggedTabController::MoveContents(TabContents* source, - const gfx::Rect& pos) { - // Theoretically could be called by a web page trying to move its - // own window. Should be ignored since we're moving the window... -} - -bool DraggedTabController::IsPopup(TabContents* source) { - return false; -} - -void DraggedTabController::ToolbarSizeChanged(TabContents* source, - bool finished) { - // Dragged tabs don't care about this. -} - -void DraggedTabController::URLStarredChanged(TabContents* source, - bool starred) { - // Ignored. -} - -void DraggedTabController::UpdateTargetURL(TabContents* source, - const GURL& url) { - // Ignored. -} - -/////////////////////////////////////////////////////////////////////////////// -// DraggedTabController, NotificationObserver implementation: - -void DraggedTabController::Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details) { - DCHECK(type == NOTIFY_TAB_CONTENTS_DESTROYED); - DCHECK(Source<TabContents>(source).ptr() == dragged_contents_); - EndDragImpl(TAB_DESTROYED); -} - -/////////////////////////////////////////////////////////////////////////////// -// DraggedTabController, MessageLoop::Observer implementation: - -void DraggedTabController::WillProcessMessage(const MSG& msg) { -} - -void DraggedTabController::DidProcessMessage(const MSG& msg) { - // If the user presses ESC during a drag, we need to abort and revert things - // to the way they were. This is the most reliable way to do this since no - // single view or window reliably receives events throughout all the various - // kinds of tab dragging. - if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE) - EndDrag(true); -} - -/////////////////////////////////////////////////////////////////////////////// -// DraggedTabController, private: - -void DraggedTabController::InitWindowCreatePoint() { - CPoint mouse_offset_cpoint(mouse_offset_.x(), mouse_offset_.y()); - Tab* first_tab = attached_tabstrip_->GetTabAt(0); - ChromeViews::View::ConvertPointToViewContainer(first_tab, - &mouse_offset_cpoint); - window_create_point_.SetPoint(mouse_offset_cpoint.x, mouse_offset_cpoint.y); -} - -gfx::Point DraggedTabController::GetWindowCreatePoint() const { - POINT pt; - GetCursorPos(&pt); - return gfx::Point(pt.x - window_create_point_.x(), - pt.y - window_create_point_.y()); -} - -void DraggedTabController::ChangeDraggedContents(TabContents* new_contents) { - if (dragged_contents_) { - NotificationService::current()->RemoveObserver(this, - NOTIFY_TAB_CONTENTS_DESTROYED, - Source<TabContents>(dragged_contents_)); - } - dragged_contents_ = new_contents; - if (dragged_contents_) { - NotificationService::current()->AddObserver(this, - NOTIFY_TAB_CONTENTS_DESTROYED, - Source<TabContents>(dragged_contents_)); - } -} - -void DraggedTabController::SaveFocus() { - if (!old_focused_view_) { - old_focused_view_ = source_tab_->GetRootView()->GetFocusedView(); - source_tab_->GetRootView()->FocusView(source_tab_); - } -} - -void DraggedTabController::RestoreFocus() { - if (old_focused_view_ && attached_tabstrip_ == source_tabstrip_) - old_focused_view_->GetRootView()->FocusView(old_focused_view_); - old_focused_view_ = NULL; -} - -bool DraggedTabController::CanStartDrag() const { - // Determine if the mouse has moved beyond a minimum elasticity distance in - // any direction from the starting point. - static const int kMinimumDragDistance = 10; - gfx::Point screen_point = GetCursorScreenPoint(); - int x_offset = abs(screen_point.x() - start_screen_point_.x()); - int y_offset = abs(screen_point.y() - start_screen_point_.y()); - return sqrt(pow(static_cast<float>(x_offset), 2) + - pow(static_cast<float>(y_offset), 2)) > kMinimumDragDistance; -} - -void DraggedTabController::ContinueDragging() { - EnsureDraggedView(); - - // Note that the coordinates given to us by |drag_event| are basically - // useless, since they're in source_tab_ coordinates. On the surface, you'd - // think we could just convert them to screen coordinates, however in the - // situation where we're dragging the last tab in a window when multiple - // windows are open, the coordinates of |source_tab_| are way off in - // hyperspace since the window was moved there instead of being closed so - // that we'd keep receiving events. And our ConvertPointToScreen methods - // aren't really multi-screen aware. So really it's just safer to get the - // actual position of the mouse cursor directly from Windows here, which is - // guaranteed to be correct regardless of monitor config. - gfx::Point screen_point = GetCursorScreenPoint(); - - // Determine whether or not we have dragged over a compatible TabStrip in - // another browser window. If we have, we should attach to it and start - // dragging within it. - TabStrip* target_tabstrip = GetTabStripForPoint(screen_point); - if (target_tabstrip != attached_tabstrip_) { - if (target_tabstrip) { - // We may receive this event before we're fully detached from the source, - // we check for that and force a detach now. - if (attached_tabstrip_) - Detach(); - Attach(target_tabstrip, screen_point); - } else { - Detach(); - } - } - MoveTab(screen_point); -} - -void DraggedTabController::MoveTab(const gfx::Point& screen_point) { - gfx::Point dragged_view_point = GetDraggedViewPoint(screen_point); - - if (attached_tabstrip_) { - // Determine the horizontal move threshold. This is dependent on the width - // of tabs. The smaller the tabs compared to the standard size, the smaller - // the threshold. - double unselected, selected; - attached_tabstrip_->GetCurrentTabWidths(&unselected, &selected); - double ratio = unselected / Tab::GetStandardSize().width(); - int threshold = static_cast<int>(ratio * kHorizontalMoveThreshold); - - // Update the model, moving the TabContents from one index to another. Do - // this only if we have moved a minimum distance since the last reorder (to - // prevent jitter). - if (abs(screen_point.x() - last_move_screen_x_) > threshold) { - TabStripModel* attached_model = attached_tabstrip_->model(); - int from_index = - attached_model->GetIndexOfTabContents(dragged_contents_); - gfx::Rect bounds = GetDraggedViewTabStripBounds(dragged_view_point); - int to_index = GetInsertionIndexForDraggedBounds(bounds); - to_index = NormalizeIndexToAttachedTabStrip(to_index); - if (from_index != to_index) { - last_move_screen_x_ = screen_point.x(); - attached_model->MoveTabContentsAt(from_index, to_index); - } - } - } - // Move the View. There are no changes to the model if we're detached. - view_->MoveTo(dragged_view_point); -} - -TabStrip* DraggedTabController::GetTabStripForPoint( - const gfx::Point& screen_point) const { - HWND dragged_hwnd = view_->GetViewContainer()->GetHWND(); - HWND other_hwnd = WindowFinder::WindowForPoint(screen_point, dragged_hwnd); - if (!other_hwnd) - return NULL; - - BrowserWindow* other_frame = FrameUtil::GetBrowserWindowForHWND(other_hwnd); - if (other_frame) { - TabStrip* other_tabstrip = other_frame->GetTabStrip(); - if (!other_tabstrip->IsCompatibleWith(source_tabstrip_)) - return NULL; - return GetTabStripIfItContains(other_tabstrip, screen_point); - } - return NULL; -} - -TabStrip* DraggedTabController::GetTabStripIfItContains( - TabStrip* tabstrip, const gfx::Point& screen_point) const { - static const int kVerticalDetachMagnetism = 15; - // Make sure the specified screen point is actually within the bounds of the - // specified tabstrip... - gfx::Rect tabstrip_bounds = GetViewScreenBounds(tabstrip); - if (screen_point.x() < tabstrip_bounds.right() && - screen_point.x() >= tabstrip_bounds.x()) { - // TODO(beng): make this be relative to the start position of the mouse for - // the source TabStrip. - int upper_threshold = tabstrip_bounds.bottom() + kVerticalDetachMagnetism; - int lower_threshold = tabstrip_bounds.y() - kVerticalDetachMagnetism; - if (screen_point.y() >= lower_threshold && - screen_point.y() <= upper_threshold) { - return tabstrip; - } - } - return NULL; -} - -void DraggedTabController::Attach(TabStrip* attached_tabstrip, - const gfx::Point& screen_point) { - attached_tabstrip_ = attached_tabstrip; - InitWindowCreatePoint(); - attached_tabstrip_->GenerateIdealBounds(); - - // We don't need the photo-booth while we're attached. - photobooth_.reset(NULL); - - Tab* tab = GetTabMatchingDraggedContents(attached_tabstrip_); - - // Update the View first, so we can ask it for its bounds and determine - // where to insert the hidden Tab. - - // If this is the first time Attach is called for this drag, we're attaching - // to the source TabStrip, and we should assume the tab count already - // includes this Tab since we haven't been detached yet. If we don't do this, - // the dragged representation will be a different size to others in the - // TabStrip. - int tab_count = attached_tabstrip_->GetTabCount(); - if (!tab) - ++tab_count; - double unselected_width, selected_width = 0; - attached_tabstrip_->GetDesiredTabWidths(tab_count, &unselected_width, - &selected_width); - EnsureDraggedView(); - view_->Attach(static_cast<int>(selected_width)); - - if (!tab) { - // There is no Tab in |attached_tabstrip| that corresponds to the dragged - // TabContents. We must now create one. - - // Remove ourselves as the delegate now that the dragged TabContents is - // being inserted back into a Browser. - dragged_contents_->set_delegate(NULL); - original_delegate_ = NULL; - - // Return the TabContents' to normalcy. - dragged_contents_->DidCaptureContents(); - - // We need to ask the TabStrip we're attached to to ensure that the ideal - // bounds for all its tabs are correctly generated, because the calculation - // in GetInsertionIndexForDraggedBounds needs them to be to figure out the - // appropriate insertion index. - attached_tabstrip_->GenerateIdealBounds(); - - // Inserting counts as a move. We don't want the tabs to jitter when the - // user moves the tab immediately after attaching it. - last_move_screen_x_ = screen_point.x(); - - // Figure out where to insert the tab based on the bounds of the dragged - // representation and the ideal bounds of the other Tabs already in the - // strip. ("ideal bounds" are stable even if the Tabs' actual bounds are - // changing due to animation). - gfx::Rect bounds = GetDraggedViewTabStripBounds(screen_point); - int index = GetInsertionIndexForDraggedBounds(bounds); - index = std::max(std::min(index, attached_tabstrip_->model()->count()), 0); - attached_tabstrip_->model()->InsertTabContentsAt(index, dragged_contents_, - true, false); - - tab = GetTabMatchingDraggedContents(attached_tabstrip_); - } - DCHECK(tab); // We should now have a tab. - tab->SetVisible(false); - - // Move the corresponding window to the front. - attached_tabstrip_->GetViewContainer()->MoveToFront(true); -} - -void DraggedTabController::Detach() { - // Prevent the TabContents' HWND from being hidden by any of the model - // operations performed during the drag. - dragged_contents_->WillCaptureContents(); - - // Update the Model. - TabStripModel* attached_model = attached_tabstrip_->model(); - int index = attached_model->GetIndexOfTabContents(dragged_contents_); - if (index >= 0 && index < attached_model->count()) { - attached_model->DetachTabContentsAt(index); - attached_tabstrip_->SchedulePaint(); - } - - // If we've removed the last Tab from the TabStrip, hide the frame now. - if (attached_model->empty()) - HideFrame(); - - // Set up the photo booth to start capturing the contents of the dragged - // TabContents. - if (!photobooth_.get()) - photobooth_.reset(new HWNDPhotobooth(dragged_contents_->GetContainerHWND())); - - // Update the View. - view_->Detach(photobooth_.get()); - - // We need to be the delegate so we receive messages about stuff, - // otherwise our dragged_contents() may be replaced and subsequently - // collected/destroyed while the drag is in process, leading to - // nasty crashes. - original_delegate_ = dragged_contents_->delegate(); - dragged_contents_->set_delegate(this); - - attached_tabstrip_ = NULL; -} - -int DraggedTabController::GetInsertionIndexForDraggedBounds( - const gfx::Rect& dragged_bounds) const { - int right_tab_x = 0; - - // If the UI layout of the tab strip is right-to-left, we need to mirror the - // bounds of the dragged tab before performing the drag/drop related - // calculations. We mirror the dragged bounds because we determine the - // position of each tab on the tab strip by calling GetBounds() (without the - // mirroring transformation flag) which effectively means that even though - // the tabs are rendered from right to left, the code performs the - // calculation as if the tabs are laid out from left to right. Mirroring the - // dragged bounds adjusts the coordinates of the tab we are dragging so that - // it uses the same orientation used by the tabs on the tab strip. - gfx::Rect adjusted_bounds(dragged_bounds); - adjusted_bounds.set_x( - attached_tabstrip_->MirroredLeftPointForRect(adjusted_bounds)); - - for (int i = 0; i < attached_tabstrip_->GetTabCount(); ++i) { - gfx::Rect ideal_bounds = attached_tabstrip_->GetIdealBounds(i); - gfx::Rect left_half = ideal_bounds; - left_half.set_width(left_half.width() / 2); - gfx::Rect right_half = ideal_bounds; - right_half.set_width(ideal_bounds.width() - left_half.width()); - right_half.set_x(left_half.right()); - right_tab_x = right_half.right(); - if (adjusted_bounds.x() >= right_half.x() && - adjusted_bounds.x() < right_half.right()) { - return i + 1; - } else if (adjusted_bounds.x() >= left_half.x() && - adjusted_bounds.x() < left_half.right()) { - return i; - } - } - if (adjusted_bounds.right() > right_tab_x) - return attached_tabstrip_->model()->count(); - return TabStripModel::kNoTab; -} - -gfx::Rect DraggedTabController::GetDraggedViewTabStripBounds( - const gfx::Point& screen_point) { - gfx::Point client_point = - ConvertScreenPointToTabStripPoint(attached_tabstrip_, screen_point); - gfx::Size view_size = view_->attached_tab_size(); - return gfx::Rect(client_point.x(), client_point.y(), - view_size.width(), view_size.height()); -} - -gfx::Point DraggedTabController::GetDraggedViewPoint( - const gfx::Point& screen_point) { - int x = screen_point.x() - mouse_offset_.x(); - int y = screen_point.y() - mouse_offset_.y(); - - // If we're not attached, we just use x and y from above. - if (attached_tabstrip_) { - gfx::Rect tabstrip_bounds = GetViewScreenBounds(attached_tabstrip_); - // Snap the dragged Tab to the TabStrip if we are attached, detaching - // only when the mouse position (screen_point) exceeds the screen bounds - // of the TabStrip. - if (x < tabstrip_bounds.x() && screen_point.x() >= tabstrip_bounds.x()) - x = tabstrip_bounds.x(); - - gfx::Size tab_size = view_->attached_tab_size(); - int vertical_drag_magnetism = tab_size.height() * 2; - int vertical_detach_point = tabstrip_bounds.y() - vertical_drag_magnetism; - if (y < tabstrip_bounds.y() && screen_point.y() >= vertical_detach_point) - y = tabstrip_bounds.y(); - - // Make sure the Tab can't be dragged off the right side of the TabStrip - // unless the mouse pointer passes outside the bounds of the strip by - // clamping the position of the dragged window to the tabstrip width less - // the width of one tab until the mouse pointer (screen_point) exceeds the - // screen bounds of the TabStrip. - int max_x = tabstrip_bounds.right() - tab_size.width(); - int max_y = tabstrip_bounds.bottom() - tab_size.height(); - if (x > max_x && screen_point.x() <= tabstrip_bounds.right()) - x = max_x; - if (y > max_y && screen_point.y() <= - (tabstrip_bounds.bottom() + vertical_drag_magnetism)) { - y = max_y; - } - } - return gfx::Point(x, y); -} - - -Tab* DraggedTabController::GetTabMatchingDraggedContents( - TabStrip* tabstrip) const { - int index = tabstrip->model()->GetIndexOfTabContents(dragged_contents_); - return index == TabStripModel::kNoTab ? NULL : tabstrip->GetTabAt(index); -} - -void DraggedTabController::EndDragImpl(EndDragType type) { - bool destroy_now = true; - if (type != TAB_DESTROYED) { - // We only finish up the drag if we were actually dragging. If we never - // constructed a view, the user just clicked and released and didn't move the - // mouse enough to trigger a drag. - if (view_.get()) { - RestoreFocus(); - if (type == CANCELED) { - RevertDrag(); - } else { - destroy_now = CompleteDrag(); - } - } - } else { - // If we get here it means the NavigationController is going down. Don't - // attempt to do any cleanup other than resetting the delegate (if we're - // still the delegate). - if (dragged_contents_ && dragged_contents_->delegate() == this) - dragged_contents_->set_delegate(NULL); - dragged_contents_ = NULL; - attached_tabstrip_ = NULL; - } - // If we're not destroyed now, we'll be destroyed asynchronously later. - if (destroy_now) - source_tabstrip_->DestroyDragController(); -} - -void DraggedTabController::RevertDrag() { - // We save this here because code below will modify |attached_tabstrip_|. - bool restore_frame = attached_tabstrip_ != source_tabstrip_; - if (attached_tabstrip_) { - int index = attached_tabstrip_->model()->GetIndexOfTabContents( - dragged_contents_); - if (attached_tabstrip_ != source_tabstrip_) { - // The Tab was inserted into another TabStrip. We need to put it back - // into the original one. - attached_tabstrip_->model()->DetachTabContentsAt(index); - // TODO(beng): (Cleanup) seems like we should use Attach() for this - // somehow. - attached_tabstrip_ = source_tabstrip_; - source_tabstrip_->model()->InsertTabContentsAt(source_model_index_, - dragged_contents_, true, false); - } else { - // The Tab was moved within the TabStrip where the drag was initiated. - // Move it back to the starting location. - source_tabstrip_->model()->MoveTabContentsAt(index, source_model_index_); - } - } else { - // TODO(beng): (Cleanup) seems like we should use Attach() for this - // somehow. - attached_tabstrip_ = source_tabstrip_; - // The Tab was detached from the TabStrip where the drag began, and has not - // been attached to any other TabStrip. We need to put it back into the - // source TabStrip. - source_tabstrip_->model()->InsertTabContentsAt(source_model_index_, - dragged_contents_, true, false); - } - // If we're not attached to any TabStrip, or attached to some other TabStrip, - // we need to restore the bounds of the original TabStrip's frame, in case - // it has been hidden. - if (restore_frame) { - if (!restore_bounds_.IsEmpty()) { - HWND frame_hwnd = source_tabstrip_->GetViewContainer()->GetHWND(); - MoveWindow(frame_hwnd, restore_bounds_.x(), restore_bounds_.y(), - restore_bounds_.width(), restore_bounds_.height(), TRUE); - } - } - source_tab_->SetVisible(true); -} - -bool DraggedTabController::CompleteDrag() { - bool destroy_immediately = true; - if (attached_tabstrip_) { - // We don't need to do anything other than make the Tab visible again, - // since the dragged View is going away. - Tab* tab = GetTabMatchingDraggedContents(attached_tabstrip_); - view_->AnimateToBounds( - GetViewScreenBounds(tab), - NewCallback(this, &DraggedTabController::OnAnimateToBoundsComplete)); - destroy_immediately = false; - } else { - // Compel the model to construct a new window for the detached TabContents. - source_tabstrip_->model()->TearOffTabContents( - dragged_contents_, - GetWindowCreatePoint()); - CleanUpHiddenFrame(); - } - - return destroy_immediately; -} - -void DraggedTabController::EnsureDraggedView() { - if (!view_.get()) { - RECT wr; - GetWindowRect(dragged_contents_->GetContainerHWND(), &wr); - - view_.reset(new DraggedTabView(dragged_contents_, mouse_offset_, - gfx::Size(wr.right - wr.left, wr.bottom - wr.top))); - } -} - -gfx::Point DraggedTabController::GetCursorScreenPoint() const { - POINT pt; - GetCursorPos(&pt); - return gfx::Point(pt); -} - -gfx::Rect DraggedTabController::GetViewScreenBounds( - ChromeViews::View* view) const { - CPoint view_topleft(0, 0); - ChromeViews::View::ConvertPointToScreen(view, &view_topleft); - CRect view_screen_bounds; - view->GetLocalBounds(&view_screen_bounds, true); - view_screen_bounds.OffsetRect(view_topleft); - return gfx::Rect(view_screen_bounds); -} - -int DraggedTabController::NormalizeIndexToAttachedTabStrip(int index) const { - DCHECK(attached_tabstrip_) << "Can only be called when attached!"; - TabStripModel* attached_model = attached_tabstrip_->model(); - if (index >= attached_model->count()) - return attached_model->count() - 1; - if (index == TabStripModel::kNoTab) - return 0; - return index; -} - -void DraggedTabController::HideFrame() { - // We don't actually hide the window, rather we just move it way off-screen. - // If we actually hide it, we stop receiving drag events. - HWND frame_hwnd = source_tabstrip_->GetViewContainer()->GetHWND(); - RECT wr; - GetWindowRect(frame_hwnd, &wr); - MoveWindow(frame_hwnd, 0xFFFF, 0xFFFF, wr.right - wr.left, - wr.bottom - wr.top, TRUE); - - // We also save the bounds of the window prior to it being moved, so that if - // the drag session is aborted we can restore them. - restore_bounds_ = gfx::Rect(wr); -} - -void DraggedTabController::CleanUpHiddenFrame() { - // If the model we started dragging from is now empty, we must ask the - // delegate to close the frame. - if (source_tabstrip_->model()->empty()) - source_tabstrip_->model()->delegate()->CloseFrameAfterDragSession(); -} - -void DraggedTabController::CleanUpSourceTab() { - // If we were attached to the source TabStrip, source Tab will be in use - // as the Tab. If we were detached or attached to another TabStrip, we can - // safely remove this item and delete it now. - if (attached_tabstrip_ != source_tabstrip_) { - source_tabstrip_->DestroyDraggedSourceTab(source_tab_); - source_tab_ = NULL; - } -} - -void DraggedTabController::OnAnimateToBoundsComplete() { - // Sometimes, for some reason, in automation we can be called back on a - // detach even though we aren't attached to a TabStrip. Guard against that. - if (attached_tabstrip_) { - Tab* tab = GetTabMatchingDraggedContents(attached_tabstrip_); - if (tab) - tab->SetVisible(true); - } - CleanUpHiddenFrame(); - - if (!in_destructor_) - source_tabstrip_->DestroyDragController(); -} - diff --git a/chrome/browser/tabs/dragged_tab_controller.h b/chrome/browser/tabs/dragged_tab_controller.h deleted file mode 100644 index 031a6ed..0000000 --- a/chrome/browser/tabs/dragged_tab_controller.h +++ /dev/null @@ -1,286 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_TABS_DRAGGED_TAB_CONTROLLER_H_ -#define CHROME_BROWSER_TABS_DRAGGED_TAB_CONTROLLER_H_ - -#include "base/gfx/rect.h" -#include "base/message_loop.h" -#include "chrome/browser/tab_contents_delegate.h" -#include "chrome/browser/tabs/tab_renderer.h" -#include "chrome/common/notification_service.h" - -namespace ChromeViews { -class MouseEvent; -class View; -} -class DraggedTabView; -class HWNDPhotobooth; -class SkBitmap; -class Tab; -class TabStrip; -class TabStripModel; - -/////////////////////////////////////////////////////////////////////////////// -// -// DraggedTabController -// -// An object that handles a drag session for an individual Tab within a -// TabStrip. This object is created whenever the mouse is pressed down on a -// Tab and destroyed when the mouse is released or the drag operation is -// aborted. The Tab that the user dragged (the "source tab") owns this object -// and must be the only one to destroy it (via |DestroyDragController|). -// -/////////////////////////////////////////////////////////////////////////////// -class DraggedTabController : public TabContentsDelegate, - public NotificationObserver, - public MessageLoopForUI::Observer{ - public: - DraggedTabController(Tab* source_tab, TabStrip* source_tabstrip); - virtual ~DraggedTabController(); - - // Capture information needed to be used during a drag session for this - // controller's associated source Tab and TabStrip. |mouse_offset| is the - // distance of the mouse pointer from the Tab's origin. - void CaptureDragInfo(const gfx::Point& mouse_offset); - - // Responds to drag events subsequent to StartDrag. If the mouse moves a - // sufficient distance before the mouse is released, a drag session is - // initiated. - void Drag(); - - // Complete the current drag session. If the drag session was canceled - // because the user pressed Escape or something interrupted it, |canceled| - // is true so the helper can revert the state to the world before the drag - // begun. - void EndDrag(bool canceled); - - // Retrieve the source Tab if the TabContents specified matches the one being - // dragged by this controller, or NULL if the specified TabContents is not - // the same as the one being dragged. - Tab* GetDragSourceTabForContents(TabContents* contents) const; - - // Returns true if the specified Tab matches the Tab being dragged. - bool IsDragSourceTab(Tab* tab) const; - - private: - // Enumeration of the ways a drag session can end. - enum EndDragType { - // Drag session exited normally: the user released the mouse. - NORMAL, - - // The drag session was canceled (alt-tab during drag, escape ...) - CANCELED, - - // The tab (NavigationController) was destroyed during the drag. - TAB_DESTROYED - }; - - // Overridden from TabContentsDelegate: - virtual void OpenURLFromTab(TabContents* source, - const GURL& url, - WindowOpenDisposition disposition, - PageTransition::Type transition, - const std::string& override_encoding); - virtual void NavigationStateChanged(const TabContents* source, - unsigned changed_flags); - virtual void ReplaceContents(TabContents* source, - TabContents* new_contents); - virtual void AddNewContents(TabContents* source, - TabContents* new_contents, - WindowOpenDisposition disposition, - const gfx::Rect& initial_pos, - bool user_gesture); - virtual void ActivateContents(TabContents* contents); - virtual void LoadingStateChanged(TabContents* source); - virtual void CloseContents(TabContents* source); - virtual void MoveContents(TabContents* source, const gfx::Rect& pos); - virtual bool IsPopup(TabContents* source); - virtual void ToolbarSizeChanged(TabContents* source, bool is_animating); - virtual void URLStarredChanged(TabContents* source, bool starred); - virtual void UpdateTargetURL(TabContents* source, const GURL& url); - - // Overridden from NotificationObserver: - virtual void Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details); - - // Overridden from MessageLoop::Observer: - virtual void WillProcessMessage(const MSG& msg); - virtual void DidProcessMessage(const MSG& msg); - - // Initialize the offset used to calculate the position to create windows - // in |GetWindowCreatePoint|. - void InitWindowCreatePoint(); - - // Returns the point where a detached window should be created given the - // current mouse position. - gfx::Point GetWindowCreatePoint() const; - - // Replaces the TabContents being dragged with the specified |new_contents|. - // This can occur if the active TabContents for the tab being dragged is - // replaced, e.g. if a transition from one TabContentsType to another occurs - // during the drag. - void ChangeDraggedContents(TabContents* new_contents); - - // Saves focus in the window that the drag initiated from. Focus will be - // restored appropriately if the drag ends within this same window. - void SaveFocus(); - - // Restore focus to the View that had focus before the drag was started, if - // the drag ends within the same Window as it began. - void RestoreFocus(); - - // Tests whether the position of the mouse is past a minimum elasticity - // threshold required to start a drag. - bool CanStartDrag() const; - - // Move the DraggedTabView according to the current mouse screen position, - // potentially updating the source and other TabStrips. - void ContinueDragging(); - - // Handles moving the Tab within a TabStrip as well as updating the View. - void MoveTab(const gfx::Point& screen_point); - - // Returns the compatible TabStrip that is under the specified point (screen - // coordinates), or NULL if there is none. - TabStrip* GetTabStripForPoint(const gfx::Point& screen_point) const; - - // Returns the specified |tabstrip| if it contains the specified point - // (screen coordinates), NULL if it does not. - TabStrip* GetTabStripIfItContains(TabStrip* tabstrip, - const gfx::Point& screen_point) const; - - // Attach the dragged Tab to the specified TabStrip. - void Attach(TabStrip* attached_tabstrip, const gfx::Point& screen_point); - - // Detach the dragged Tab from the current TabStrip. - void Detach(); - - // Returns the index where the dragged TabContents should be inserted into - // the attached TabStripModel given the DraggedTabView's bounds - // |dragged_bounds| in coordinates relative to the attached TabStrip. - int GetInsertionIndexForDraggedBounds(const gfx::Rect& dragged_bounds) const; - - // Retrieve the bounds of the DraggedTabView, relative to the attached - // TabStrip, given location of the dragged tab in screen coordinates. - gfx::Rect GetDraggedViewTabStripBounds(const gfx::Point& screen_point); - - // Get the position of the dragged tab view relative to the attached tab - // strip. - gfx::Point GetDraggedViewPoint(const gfx::Point& screen_point); - - // Finds the Tab within the specified TabStrip that corresponds to the - // dragged TabContents. - Tab* GetTabMatchingDraggedContents(TabStrip* tabstrip) const; - - // Does the work for EndDrag. - void EndDragImpl(EndDragType how_end); - - // If the drag was aborted for some reason, this function is called to un-do - // the changes made during the drag operation. - void RevertDrag(); - - // Finishes the drag operation. Returns true if the drag controller should - // be destroyed immediately, false otherwise. - bool CompleteDrag(); - - // Create the DraggedTabView, if it does not yet exist. - void EnsureDraggedView(); - - // Utility for getting the mouse position in screen coordinates. - gfx::Point GetCursorScreenPoint() const; - - // Returns the bounds (in screen coordinates) of the specified View. - gfx::Rect GetViewScreenBounds(ChromeViews::View* tabstrip) const; - - // Utility to convert the specified TabStripModel index to something valid - // for the attached TabStrip. - int NormalizeIndexToAttachedTabStrip(int index) const; - - // Hides the frame for the window that contains the TabStrip the current - // drag session was initiated from. - void HideFrame(); - - // Closes a hidden frame at the end of a drag session. - void CleanUpHiddenFrame(); - - // Cleans up a source tab that is no longer used. - void CleanUpSourceTab(); - - // Completes the drag session after the view has animated to its final - // position. - void OnAnimateToBoundsComplete(); - - // The TabContents being dragged. This can get replaced during the drag if - // the associated NavigationController is navigated to a different - // TabContentsType. - TabContents* dragged_contents_; - - // The original TabContentsDelegate of |dragged_contents_|, before it was - // detached from the browser window. We store this so that we can forward - // certain delegate notifications back to it if we can't handle them locally. - TabContentsDelegate* original_delegate_; - - // The Tab that initiated the drag session. - Tab* source_tab_; - - // The TabStrip |source_tab_| originated from. - TabStrip* source_tabstrip_; - - // This is the index of the |source_tab_| in |source_tabstrip_| when the drag - // began. This is used to restore the previous state if the drag is aborted. - int source_model_index_; - - // The TabStrip the dragged Tab is currently attached to, or NULL if the - // dragged Tab is detached. - TabStrip* attached_tabstrip_; - - // The visual representation of the dragged Tab. - scoped_ptr<DraggedTabView> view_; - - // The photo-booth the TabContents sits in when the Tab is detached, to - // obtain screen shots. - scoped_ptr<HWNDPhotobooth> photobooth_; - - // The position of the mouse (in screen coordinates) at the start of the drag - // operation. This is used to calculate minimum elasticity before a - // DraggedTabView is constructed. - gfx::Point start_screen_point_; - - // This is the offset of the mouse from the top left of the Tab where - // dragging begun. This is used to ensure that the dragged view is always - // positioned at the correct location during the drag, and to ensure that the - // detached window is created at the right location. - gfx::Point mouse_offset_; - - // A hint to use when positioning new windows created by detaching Tabs. This - // is the distance of the mouse from the top left of the dragged tab as if it - // were the distance of the mouse from the top left of the first tab in the - // attached TabStrip from the top left of the window. - gfx::Point window_create_point_; - - // The bounds of the browser window before the last Tab was detached. When - // the last Tab is detached, rather than destroying the frame (which would - // abort the drag session), the frame is moved off-screen. If the drag is - // aborted (e.g. by the user pressing Esc, or capture being lost), the Tab is - // attached to the hidden frame and the frame moved back to these bounds. - gfx::Rect restore_bounds_; - - // The last view that had focus in the window containing |source_tab_|. This - // is saved so that focus can be restored properly when a drag begins and - // ends within this same window. - ChromeViews::View* old_focused_view_; - - bool in_destructor_; - - // The horizontal position of the mouse cursor in screen coordinates at the - // time of the last re-order event. - int last_move_screen_x_; - - DISALLOW_COPY_AND_ASSIGN(DraggedTabController); -}; - -#endif // CHROME_BROWSER_TABS_DRAGGED_TAB_CONTROLLER_H_ - diff --git a/chrome/browser/tabs/dragged_tab_view.cc b/chrome/browser/tabs/dragged_tab_view.cc deleted file mode 100644 index 0878476..0000000 --- a/chrome/browser/tabs/dragged_tab_view.cc +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/tabs/dragged_tab_view.h" - -#include "chrome/common/gfx/chrome_canvas.h" -#include "chrome/browser/tab_contents.h" -#include "chrome/browser/tabs/hwnd_photobooth.h" -#include "chrome/browser/tabs/tab_renderer.h" -#include "chrome/browser/tabs/tab_strip_model.h" -#include "chrome/views/hwnd_view_container.h" -#include "skia/include/SkShader.h" - -const int kTransparentAlpha = 200; -const int kOpaqueAlpha = 255; -const int kDragFrameBorderSize = 2; -const int kTwiceDragFrameBorderSize = 2 * kDragFrameBorderSize; -const float kScalingFactor = 0.5; -const int kAnimateToBoundsDurationMs = 150; -static const SkColor kDraggedTabBorderColor = SkColorSetRGB(103, 129, 162); - -//////////////////////////////////////////////////////////////////////////////// -// DraggedTabView, public: - -DraggedTabView::DraggedTabView(TabContents* datasource, - const gfx::Point& mouse_tab_offset, - const gfx::Size& contents_size) - : container_(NULL), - renderer_(new TabRenderer), - attached_(false), - mouse_tab_offset_(mouse_tab_offset), - attached_tab_size_(TabRenderer::GetMinimumSelectedSize()), - photobooth_(NULL), - contents_size_(contents_size), - close_animation_(this) { - SetParentOwned(false); - - renderer_->UpdateData(datasource); - - container_ = new ChromeViews::HWNDViewContainer; - container_->set_window_style(WS_POPUP); - container_->set_window_ex_style( - WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_TOOLWINDOW); - container_->set_can_update_layered_window(false); - container_->Init(NULL, gfx::Rect(0, 0, 0, 0), false); - container_->SetContentsView(this); -} - -DraggedTabView::~DraggedTabView() { - if (close_animation_.IsAnimating()) - close_animation_.Stop(); - GetParent()->RemoveChildView(this); - container_->Close(); -} - -void DraggedTabView::MoveTo(const gfx::Point& screen_point) { - if (!container_->IsVisible()) - container_->ShowWindow(SW_SHOWNOACTIVATE); - - int x; - if (UILayoutIsRightToLeft() && !attached_) { - // On RTL locales, a dragged tab (when it is not attached to a tab strip) - // is rendered using a right-to-left orientation so we should calculate the - // window position differently. - CSize ps; - GetPreferredSize(&ps); - x = screen_point.x() - ScaleValue(ps.cx) + mouse_tab_offset_.x() + - ScaleValue( - renderer_->MirroredXCoordinateInsideView(mouse_tab_offset_.x())); - } else { - x = screen_point.x() + mouse_tab_offset_.x() - - ScaleValue(mouse_tab_offset_.x()); - } - int y = screen_point.y() + mouse_tab_offset_.y() - - ScaleValue(mouse_tab_offset_.y()); - - container_->SetWindowPos(NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE); -} - -void DraggedTabView::Attach(int selected_width) { - attached_ = true; - photobooth_ = NULL; - attached_tab_size_.set_width(selected_width); - container_->SetLayeredAlpha(kOpaqueAlpha); - ResizeContainer(); - Update(); -} - -void DraggedTabView::Detach(HWNDPhotobooth* photobooth) { - attached_ = false; - photobooth_ = photobooth; - container_->SetLayeredAlpha(kTransparentAlpha); - ResizeContainer(); - Update(); -} - -void DraggedTabView::Update() { - container_->set_can_update_layered_window(true); - SchedulePaint(); - container_->PaintNow(CRect()); - container_->set_can_update_layered_window(false); -} - -void DraggedTabView::AnimateToBounds(const gfx::Rect& bounds, - Callback0::Type* callback) { - animation_callback_.reset(callback); - - RECT wr; - GetWindowRect(GetViewContainer()->GetHWND(), &wr); - animation_start_bounds_ = wr; - animation_end_bounds_ = bounds; - - close_animation_.SetSlideDuration(kAnimateToBoundsDurationMs); - close_animation_.SetTweenType(SlideAnimation::EASE_OUT); - if (!close_animation_.IsShowing()) { - close_animation_.Reset(); - close_animation_.Show(); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// DraggedTabView, AnimationDelegate implementation: - -void DraggedTabView::AnimationProgressed(const Animation* animation) { - int delta_x = (animation_end_bounds_.x() - animation_start_bounds_.x()); - int x = animation_start_bounds_.x() + - static_cast<int>(delta_x * animation->GetCurrentValue()); - int y = animation_end_bounds_.y(); - container_->SetWindowPos(NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE); -} - -void DraggedTabView::AnimationEnded(const Animation* animation) { - animation_callback_->Run(); -} - -void DraggedTabView::AnimationCanceled(const Animation* animation) { - AnimationEnded(animation); -} - -/////////////////////////////////////////////////////////////////////////////// -// DraggedTabView, ChromeViews::View overrides: - -void DraggedTabView::Paint(ChromeCanvas* canvas) { - if (attached_) { - PaintAttachedTab(canvas); - } else { - PaintDetachedView(canvas); - } -} - -void DraggedTabView::Layout() { - CSize ps; - GetPreferredSize(&ps); - if (attached_) { - renderer_->SetBounds(CRect(0, 0, ps.cx, ps.cy)); - } else { - int left = 0; - if (UILayoutIsRightToLeft()) - left = ps.cx - attached_tab_size_.width(); - renderer_->SetBounds(CRect(left, 0, left + attached_tab_size_.width(), - attached_tab_size_.height())); - } -} - -void DraggedTabView::GetPreferredSize(CSize* out) { - DCHECK(out); - if (attached_) { - *out = attached_tab_size_.ToSIZE(); - } else { - int width = std::max(attached_tab_size_.width(), contents_size_.width()) + - kTwiceDragFrameBorderSize; - int height = attached_tab_size_.height() + kDragFrameBorderSize + - contents_size_.height(); - *out = CSize(width, height); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// DraggedTabView, private: - -void DraggedTabView::PaintAttachedTab(ChromeCanvas* canvas) { - renderer_->ProcessPaint(canvas); -} - -void DraggedTabView::PaintDetachedView(ChromeCanvas* canvas) { - CSize ps; - GetPreferredSize(&ps); - ChromeCanvas scale_canvas(ps.cx, ps.cy, false); - SkBitmap& bitmap_device = const_cast<SkBitmap&>( - scale_canvas.getTopPlatformDevice().accessBitmap(true)); - bitmap_device.eraseARGB(0, 0, 0, 0); - - scale_canvas.FillRectInt(kDraggedTabBorderColor, 0, - attached_tab_size_.height() - kDragFrameBorderSize, - ps.cx, ps.cy - attached_tab_size_.height()); - int image_x = kDragFrameBorderSize; - int image_y = attached_tab_size_.height(); - int image_w = ps.cx - kTwiceDragFrameBorderSize; - int image_h = - ps.cy - kTwiceDragFrameBorderSize - attached_tab_size_.height(); - scale_canvas.FillRectInt(SK_ColorBLACK, image_x, image_y, image_w, image_h); - photobooth_->PaintScreenshotIntoCanvas( - &scale_canvas, - gfx::Rect(image_x, image_y, image_w, image_h)); - renderer_->ProcessPaint(&scale_canvas); - - SkIRect subset; - subset.set(0, 0, ps.cx, ps.cy); - SkBitmap mipmap = scale_canvas.ExtractBitmap(); - mipmap.buildMipMap(true); - - SkShader* bitmap_shader = - SkShader::CreateBitmapShader(mipmap, SkShader::kClamp_TileMode, - SkShader::kClamp_TileMode); - - SkMatrix shader_scale; - shader_scale.setScale(kScalingFactor, kScalingFactor); - bitmap_shader->setLocalMatrix(shader_scale); - - SkPaint paint; - paint.setShader(bitmap_shader); - paint.setAntiAlias(true); - bitmap_shader->unref(); - - SkRect rc; - rc.fLeft = 0; - rc.fTop = 0; - rc.fRight = SkIntToScalar(ps.cx); - rc.fBottom = SkIntToScalar(ps.cy); - canvas->drawRect(rc, paint); -} - -void DraggedTabView::ResizeContainer() { - CSize ps; - GetPreferredSize(&ps); - SetWindowPos(container_->GetHWND(), HWND_TOPMOST, 0, 0, ScaleValue(ps.cx), - ScaleValue(ps.cy), SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); -} - -int DraggedTabView::ScaleValue(int value) { - return attached_ ? value : static_cast<int>(value * kScalingFactor); -} - diff --git a/chrome/browser/tabs/dragged_tab_view.h b/chrome/browser/tabs/dragged_tab_view.h deleted file mode 100644 index 8419342..0000000 --- a/chrome/browser/tabs/dragged_tab_view.h +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_TABS_DRAGGED_TAB_VIEW_H_ -#define CHROME_BROWSER_TABS_DRAGGED_TAB_VIEW_H_ - -#include "base/gfx/point.h" -#include "base/gfx/size.h" -#include "base/task.h" -#include "chrome/common/slide_animation.h" -#include "chrome/views/view.h" -#include "skia/include/SkBitmap.h" - -namespace ChromeViews { -class HWNDViewContainer; -} -namespace gfx { -class Point; -} -class HWNDPhotobooth; -class Tab; -class TabContents; -class TabRenderer; - -class DraggedTabView : public ChromeViews::View, - public AnimationDelegate { - public: - DraggedTabView(TabContents* datasource, - const gfx::Point& mouse_tab_offset, - const gfx::Size& contents_size); - virtual ~DraggedTabView(); - - // Moves the DraggedTabView to the appropriate location given the mouse - // pointer at |screen_point|. - void MoveTo(const gfx::Point& screen_point); - - // Notifies the DraggedTabView that it has become attached to a TabStrip. - void Attach(int selected_width); - - // Notifies the DraggedTabView that it has been detached from a TabStrip. - void Detach(HWNDPhotobooth* photobooth); - - // Notifies the DraggedTabView that it should update itself. - void Update(); - - // Animates the DraggedTabView to the specified bounds, then calls back to - // |callback|. - void AnimateToBounds(const gfx::Rect& bounds, Callback0::Type* callback); - - // Returns the size of the DraggedTabView. Used when attaching to a TabStrip - // to determine where to place the Tab in the attached TabStrip. - gfx::Size attached_tab_size() const { return attached_tab_size_; } - - private: - // Overridden from AnimationDelegate: - virtual void AnimationProgressed(const Animation* animation); - virtual void AnimationEnded(const Animation* animation); - virtual void AnimationCanceled(const Animation* animation); - - // Overridden from ChromeViews::View: - virtual void Paint(ChromeCanvas* canvas); - virtual void Layout(); - virtual void GetPreferredSize(CSize* out); - - // Paint the view, when it's attached to a TabStrip. - void PaintAttachedTab(ChromeCanvas* canvas); - - // Paint the view, when it's not attached to any TabStrip. - void PaintDetachedView(ChromeCanvas* canvas); - - // Resizes the container to fit the content for the current attachment mode. - void ResizeContainer(); - - // Utility for scaling a size by the current scaling factor. - int ScaleValue(int value); - - // The window that contains the DraggedTabView. - ChromeViews::HWNDViewContainer* container_; - - // The renderer that paints the Tab shape. - scoped_ptr<TabRenderer> renderer_; - - // True if the view is currently attached to a TabStrip. Controls rendering - // and sizing modes. - bool attached_; - - // The unscaled offset of the mouse from the top left of the dragged Tab. - // This is used to maintain an appropriate offset for the mouse pointer when - // dragging scaled and unscaled representations, and also to calculate the - // position of detached windows. - gfx::Point mouse_tab_offset_; - - // The desired width of the TabRenderer when the DraggedTabView is attached - // to a TabStrip. - gfx::Size attached_tab_size_; - - // A handle to the DIB containing the current screenshot of the TabContents - // we are dragging. - HWNDPhotobooth* photobooth_; - - // The dimensions of the TabContents being dragged. - gfx::Size contents_size_; - - // The animation used to slide the attached view to its final location. - SlideAnimation close_animation_; - - // A callback notified when the animation is complete. - scoped_ptr<Callback0::Type> animation_callback_; - - // The start and end bounds of the animation sequence. - gfx::Rect animation_start_bounds_; - gfx::Rect animation_end_bounds_; - - DISALLOW_EVIL_CONSTRUCTORS(DraggedTabView); -}; - -#endif // CHROME_BROWSER_TABS_DRAGGED_TAB_VIEW_H_ - diff --git a/chrome/browser/tabs/hwnd_photobooth.cc b/chrome/browser/tabs/hwnd_photobooth.cc deleted file mode 100644 index 7ae6c69..0000000 --- a/chrome/browser/tabs/hwnd_photobooth.cc +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/gfx/point.h" -#include "chrome/browser/tab_contents.h" -#include "chrome/browser/tabs/hwnd_photobooth.h" -#include "chrome/common/gfx/chrome_canvas.h" -#include "chrome/views/hwnd_view_container.h" -#include "skia/include/SkBitmap.h" - -namespace { - -static BOOL CALLBACK MonitorEnumProc(HMONITOR monitor, HDC monitor_dc, - RECT* monitor_rect, LPARAM data) { - gfx::Point* point = reinterpret_cast<gfx::Point*>(data); - if (monitor_rect->right > point->x() && monitor_rect->bottom > point->y()) { - point->set_x(monitor_rect->right); - point->set_y(monitor_rect->bottom); - } - return TRUE; -} - -gfx::Point GetCaptureWindowPosition() { - // Since the capture window must be visible to be painted, it must be opened - // off screen to avoid flashing. But if it is opened completely off-screen - // (e.g. at 0xFFFFx0xFFFF) then on Windows Vista it will not paint even if it - // _is_ visible. So we need to find the right/bottommost monitor, and - // position it so that 1x1 pixel is on-screen on that monitor which is enough - // to convince Vista to paint it. Don't ask why this is so - this appears to - // be a regression over XP. - gfx::Point point(0, 0); - EnumDisplayMonitors(NULL, NULL, &MonitorEnumProc, - reinterpret_cast<LPARAM>(&point)); - return gfx::Point(point.x() - 1, point.y() - 1); -} - -} - -/////////////////////////////////////////////////////////////////////////////// -// HWNDPhotobooth, public: - -HWNDPhotobooth::HWNDPhotobooth(HWND initial_hwnd) - : capture_window_(NULL), - current_hwnd_(initial_hwnd) { - DCHECK(IsWindow(current_hwnd_)); - CreateCaptureWindow(initial_hwnd); -} - -HWNDPhotobooth::~HWNDPhotobooth() { - // Detach the attached HWND. The creator of the photo-booth is responsible - // for destroying it. - ReplaceHWND(NULL); - capture_window_->Close(); -} - -void HWNDPhotobooth::ReplaceHWND(HWND new_hwnd) { - if (IsWindow(current_hwnd_) && - GetParent(current_hwnd_) == capture_window_->GetHWND()) { - // We need to hide the window too, so it doesn't show up in the TaskBar or - // be parented to the desktop. - ShowWindow(current_hwnd_, SW_HIDE); - SetParent(current_hwnd_, NULL); - } - current_hwnd_ = new_hwnd; - - if (IsWindow(new_hwnd)) { - // Insert the TabContents into the capture window. - SetParent(current_hwnd_, capture_window_->GetHWND()); - - // Show the window (it may not be visible). This is the only safe way of - // doing this. ShowWindow does not work. - SetWindowPos(current_hwnd_, NULL, 0, 0, 0, 0, - SWP_DEFERERASE | SWP_NOACTIVATE | SWP_NOCOPYBITS | - SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | SWP_NOZORDER | - SWP_SHOWWINDOW | SWP_NOSIZE); - } -} - -void HWNDPhotobooth::PaintScreenshotIntoCanvas( - ChromeCanvas* canvas, - const gfx::Rect& target_bounds) { - // Our contained window may have been re-parented. Make sure it belongs to - // us until someone calls ReplaceHWND(NULL). - if (IsWindow(current_hwnd_) && - GetParent(current_hwnd_) != capture_window_->GetHWND()) { - ReplaceHWND(current_hwnd_); - } - - // We compel the contained HWND to paint now, synchronously. We do this to - // populate the device context with valid and current data. - RedrawWindow(current_hwnd_, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); - - // Transfer the contents of the layered capture window to the screen-shot - // canvas' DIB. - HDC target_dc = canvas->beginPlatformPaint(); - HDC source_dc = GetDC(current_hwnd_); - RECT window_rect = {0}; - GetWindowRect(current_hwnd_, &window_rect); - BitBlt(target_dc, target_bounds.x(), target_bounds.y(), - target_bounds.width(), target_bounds.height(), source_dc, 0, 0, - SRCCOPY); - // Windows screws up the alpha channel on all text it draws, and so we need - // to call makeOpaque _after_ the blit to correct for this. - canvas->getTopPlatformDevice().makeOpaque(target_bounds.x(), - target_bounds.y(), - target_bounds.width(), - target_bounds.height()); - ReleaseDC(current_hwnd_, source_dc); - canvas->endPlatformPaint(); -} - -/////////////////////////////////////////////////////////////////////////////// -// HWNDPhotobooth, private: - -void HWNDPhotobooth::CreateCaptureWindow(HWND initial_hwnd) { - // Snapshotting a HWND is tricky - if the HWND is clipped (e.g. positioned - // partially off-screen) then just blitting from the HWND' DC to the capture - // bitmap would be incorrect, since the capture bitmap would show only the - // visible area of the HWND. - // - // The approach turns out to be to create a second layered window in - // hyperspace the to act as a "photo booth." The window is created with the - // size of the unclipped HWND, and we attach the HWND as a child, refresh the - // HWND' by calling |Paint| on it, and then blitting from the HWND's DC to - // the capture bitmap. This results in the entire unclipped HWND display - // bitmap being captured. - // - // The capture window must be layered so that Windows generates a backing - // store for it, so that blitting from a child window's DC produces data. If - // the window is not layered, because it is off-screen Windows does not - // retain its contents and blitting results in blank data. The capture window - // is a "basic" (1 level of alpha) layered window because that is the mode - // that supports having child windows (variable alpha layered windows do not - // support child HWNDs). - // - // This function sets up the off-screen capture window, and attaches the - // associated HWND to it. Note that the details are important here, see below - // for further comments. - // - CRect contents_rect; - GetClientRect(initial_hwnd, &contents_rect); - gfx::Point window_position = GetCaptureWindowPosition(); - gfx::Rect capture_bounds(window_position.x(), window_position.y(), - contents_rect.Width(), contents_rect.Height()); - capture_window_ = new ChromeViews::HWNDViewContainer; - capture_window_->set_window_style(WS_POPUP); - // WS_EX_TOOLWINDOW ensures the capture window doesn't produce a Taskbar - // button. - capture_window_->set_window_ex_style(WS_EX_LAYERED | WS_EX_TOOLWINDOW); - capture_window_->Init(NULL, capture_bounds, false); - // If the capture window isn't visible, blitting from the TabContents' - // HWND's DC to the capture bitmap produces blankness. - capture_window_->ShowWindow(SW_SHOWNOACTIVATE); - SetLayeredWindowAttributes( - capture_window_->GetHWND(), RGB(0xFF, 0xFF, 0xFF), 0xFF, LWA_ALPHA); - - ReplaceHWND(initial_hwnd); -} diff --git a/chrome/browser/tabs/hwnd_photobooth.h b/chrome/browser/tabs/hwnd_photobooth.h deleted file mode 100644 index 608236b..0000000 --- a/chrome/browser/tabs/hwnd_photobooth.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_HWND_PHOTOBOOTH_H__ -#define CHROME_BROWSER_HWND_PHOTOBOOTH_H__ - -#include "base/basictypes.h" -#include "base/gfx/rect.h" - -class ChromeCanvas; -namespace ChromeViews { -class HWNDViewContainer; -} - -/////////////////////////////////////////////////////////////////////////////// -// HWNDPhotobooth -// -// An object that a HWND "steps into" to have its picture taken. This is used -// to generate a full size screen shot of the contents of a HWND including -// any child windows. -// -// Implementation note: This causes the HWND to be re-parented to a mostly -// off-screen layered window. -// -class HWNDPhotobooth { - public: - // Creates the photo booth. Constructs a nearly off-screen window, parents - // the HWND, then shows it. The caller is responsible for destroying this - // window, since the photo-booth will detach it before it is destroyed. - // |canvas| is a canvas to paint the contents into, and dest_bounds is the - // target area in |canvas| to which painted contents will be clipped. - explicit HWNDPhotobooth(HWND initial_hwnd); - - // Destroys the photo booth window. - virtual ~HWNDPhotobooth(); - - // Replaces the HWND in the photo booth with the specified one. The caller is - // responsible for destroying this HWND since it will be detached from the - // capture window before the capture window is destroyed. - void ReplaceHWND(HWND new_hwnd); - - // Paints the current display image of the window into |canvas|, clipped to - // |target_bounds|. - void PaintScreenshotIntoCanvas(ChromeCanvas* canvas, - const gfx::Rect& target_bounds); - - private: - // Creates a mostly off-screen window to contain the HWND to be captured. - void CreateCaptureWindow(HWND initial_hwnd); - - // The nearly off-screen photo-booth layered window used to hold the HWND. - ChromeViews::HWNDViewContainer* capture_window_; - - // The current HWND being captured. - HWND current_hwnd_; - - DISALLOW_EVIL_CONSTRUCTORS(HWNDPhotobooth); -}; - -#endif // #ifndef CHROME_BROWSER_HWND_PHOTOBOOTH_H__ - diff --git a/chrome/browser/tabs/tab.cc b/chrome/browser/tabs/tab.cc deleted file mode 100644 index f855701..0000000 --- a/chrome/browser/tabs/tab.cc +++ /dev/null @@ -1,241 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/tabs/tab.h" - -#include "base/gfx/size.h" -#include "chrome/views/view_container.h" -#include "chrome/common/gfx/chrome_canvas.h" -#include "chrome/common/gfx/path.h" -#include "chrome/common/resource_bundle.h" -#include "chrome/views/chrome_menu.h" -#include "chrome/views/tooltip_manager.h" -#include "generated_resources.h" - -const std::string Tab::kTabClassName = "browser/tabs/Tab"; - -static const SkScalar kTabCapWidth = 15; -static const SkScalar kTabTopCurveWidth = 4; -static const SkScalar kTabBottomCurveWidth = 3; - -class TabContextMenuController : public ChromeViews::MenuDelegate { - public: - explicit TabContextMenuController(Tab* tab) - : tab_(tab), - last_command_(TabStripModel::CommandFirst) { - menu_.reset(new ChromeViews::MenuItemView(this)); - menu_->AppendMenuItemWithLabel(TabStripModel::CommandNewTab, - l10n_util::GetString(IDS_TAB_CXMENU_NEWTAB)); - menu_->AppendSeparator(); - menu_->AppendMenuItemWithLabel(TabStripModel::CommandReload, - l10n_util::GetString(IDS_TAB_CXMENU_RELOAD)); - menu_->AppendMenuItemWithLabel( - TabStripModel::CommandDuplicate, - l10n_util::GetString(IDS_TAB_CXMENU_DUPLICATE)); - menu_->AppendSeparator(); - menu_->AppendMenuItemWithLabel( - TabStripModel::CommandCloseTab, - l10n_util::GetString(IDS_TAB_CXMENU_CLOSETAB)); - menu_->AppendMenuItemWithLabel( - TabStripModel::CommandCloseOtherTabs, - l10n_util::GetString(IDS_TAB_CXMENU_CLOSEOTHERTABS)); - menu_->AppendMenuItemWithLabel( - TabStripModel::CommandCloseTabsToRight, - l10n_util::GetString(IDS_TAB_CXMENU_CLOSETABSTORIGHT)); - menu_->AppendMenuItemWithLabel( - TabStripModel::CommandCloseTabsOpenedBy, - l10n_util::GetString(IDS_TAB_CXMENU_CLOSETABSOPENEDBY)); - } - virtual ~TabContextMenuController() { - tab_->delegate()->StopAllHighlighting(); - } - - void RunMenuAt(int x, int y) { - menu_->RunMenuAt(tab_->GetViewContainer()->GetHWND(), - gfx::Rect(x, y, 0, 0), ChromeViews::MenuItemView::TOPLEFT, - false); - } - - private: - // ChromeViews::MenuDelegate implementation: - virtual bool IsCommandEnabled(int id) const { - // The MenuItemView used to contain the contents of the Context Menu itself - // has a command id of 0, and it will check to see if it's enabled for - // some reason during its construction. The TabStripModel can't handle - // command indices it doesn't know about, so we need to filter this out - // here. - if (id == 0) - return false; - return tab_->delegate()->IsCommandEnabledForTab( - static_cast<TabStripModel::ContextMenuCommand>(id), - tab_); - } - - virtual void ExecuteCommand(int id) { - tab_->delegate()->ExecuteCommandForTab( - static_cast<TabStripModel::ContextMenuCommand>(id), - tab_); - } - - virtual void SelectionChanged(ChromeViews::MenuItemView* menu) { - TabStripModel::ContextMenuCommand command = - static_cast<TabStripModel::ContextMenuCommand>(menu->GetCommand()); - tab_->delegate()->StopHighlightTabsForCommand(last_command_, tab_); - last_command_ = command; - tab_->delegate()->StartHighlightTabsForCommand(command, tab_); - } - - private: - // The context menu. - scoped_ptr<ChromeViews::MenuItemView> menu_; - - // The Tab the context menu was brought up for. - Tab* tab_; - - // The last command that was selected, so that we can start/stop highlighting - // appropriately as the user moves through the menu. - TabStripModel::ContextMenuCommand last_command_; - - DISALLOW_EVIL_CONSTRUCTORS(TabContextMenuController); -}; - -/////////////////////////////////////////////////////////////////////////////// -// Tab, public: - -Tab::Tab(TabDelegate* delegate) - : TabRenderer(), - delegate_(delegate), - closing_(false) { - close_button()->SetListener(this, 0); - close_button()->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_CLOSE)); - close_button()->SetAnimationDuration(0); - SetContextMenuController(this); -} - -Tab::~Tab() { -} - -/////////////////////////////////////////////////////////////////////////////// -// Tab, TabRenderer overrides: - -bool Tab::IsSelected() const { - return delegate_->IsTabSelected(this); -} - -/////////////////////////////////////////////////////////////////////////////// -// Tab, ChromeViews::View overrides: - -bool Tab::HitTest(const CPoint &l) const { - gfx::Path path; - MakePathForTab(&path); - ScopedHRGN rgn(path.CreateHRGN()); - return !!PtInRegion(rgn, l.x, l.y); -} - -bool Tab::OnMousePressed(const ChromeViews::MouseEvent& event) { - if (event.IsOnlyLeftMouseButton()) { - // Store whether or not we were selected just now... we only want to be - // able to drag foreground tabs, so we don't start dragging the tab if - // it was in the background. - bool just_selected = !IsSelected(); - if (just_selected) - delegate_->SelectTab(this); - delegate_->MaybeStartDrag(this, event); - } - return true; -} - -bool Tab::OnMouseDragged(const ChromeViews::MouseEvent& event) { - delegate_->ContinueDrag(event); - return true; -} - -void Tab::OnMouseReleased(const ChromeViews::MouseEvent& event, - bool canceled) { - // Notify the drag helper that we're done with any potential drag operations. - // Clean up the drag helper, which is re-created on the next mouse press. - delegate_->EndDrag(canceled); - if (event.IsMiddleMouseButton()) - delegate_->CloseTab(this); -} - -bool Tab::GetTooltipText(int x, int y, std::wstring* tooltip) { - std::wstring title = GetTitle(); - if (!title.empty()) { - // Only show the tooltip if the title is truncated. - ChromeFont font; - if (font.GetStringWidth(title) > title_bounds().width()) { - *tooltip = title; - return true; - } - } - return false; -} - -bool Tab::GetTooltipTextOrigin(int x, int y, CPoint* origin) { - ChromeFont font; - origin->x = title_bounds().x() + 10; - origin->y = -ChromeViews::TooltipManager::GetTooltipHeight() - 4; - return true; -} - -bool Tab::GetAccessibleRole(VARIANT* role) { - DCHECK(role); - - role->vt = VT_I4; - role->lVal = ROLE_SYSTEM_PAGETAB; - return true; -} - -bool Tab::GetAccessibleName(std::wstring* name) { - *name = GetTitle(); - return !name->empty(); -} - -/////////////////////////////////////////////////////////////////////////////// -// Tab, ChromeViews::ContextMenuController implementation: - -void Tab::ShowContextMenu(ChromeViews::View* source, int x, int y, - bool is_mouse_gesture) { - TabContextMenuController controller(this); - controller.RunMenuAt(x, y); -} - - -/////////////////////////////////////////////////////////////////////////////// -// ChromeViews::BaseButton::ButtonListener implementation: - -void Tab::ButtonPressed(ChromeViews::BaseButton* sender) { - if (sender == close_button()) - delegate_->CloseTab(this); -} - -/////////////////////////////////////////////////////////////////////////////// -// Tab, private: - -void Tab::MakePathForTab(gfx::Path* path) const { - DCHECK(path); - - SkScalar h = SkIntToScalar(GetHeight()); - SkScalar w = SkIntToScalar(GetWidth()); - - path->moveTo(0, h); - - // Left end cap. - path->lineTo(kTabBottomCurveWidth, h - kTabBottomCurveWidth); - path->lineTo(kTabCapWidth - kTabTopCurveWidth, kTabTopCurveWidth); - path->lineTo(kTabCapWidth, 0); - - // Connect to the right cap. - path->lineTo(w - kTabCapWidth, 0); - - // Right end cap. - path->lineTo(w - kTabCapWidth - kTabTopCurveWidth, kTabTopCurveWidth); - path->lineTo(w - kTabBottomCurveWidth, h - kTabBottomCurveWidth); - path->lineTo(w, h); - - // Close out the path. - path->lineTo(0, h); - path->close(); -} diff --git a/chrome/browser/tabs/tab.h b/chrome/browser/tabs/tab.h deleted file mode 100644 index 10346ef..0000000 --- a/chrome/browser/tabs/tab.h +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_TABS_TAB_H_ -#define CHROME_BROWSER_TABS_TAB_H_ - -#include "chrome/browser/tabs/tab_renderer.h" -#include "chrome/browser/tabs/tab_strip_model.h" -#include "chrome/views/base_button.h" - -namespace gfx { -class Path; -class Point; -} -class TabContents; -class Profile; - -/////////////////////////////////////////////////////////////////////////////// -// -// Tab -// -// A subclass of TabRenderer that represents an individual Tab in a TabStrip. -// -/////////////////////////////////////////////////////////////////////////////// -class Tab : public TabRenderer, - public ChromeViews::ContextMenuController, - public ChromeViews::BaseButton::ButtonListener { - public: - static const std::string kTabClassName; - - // An interface implemented by an object that can help this Tab complete - // various actions. The index parameter is the index of this Tab in the - // TabRenderer::Model. - class TabDelegate { - public: - // Returns true if the specified Tab is selected. - virtual bool IsTabSelected(const Tab* tab) const = 0; - - // Selects the specified Tab. - virtual void SelectTab(Tab* tab) = 0; - - // Closes the specified Tab. - virtual void CloseTab(Tab* tab) = 0; - - // Returns true if the specified command is enabled for the specified Tab. - virtual bool IsCommandEnabledForTab( - TabStripModel::ContextMenuCommand command_id, const Tab* tab) const = 0; - - // Executes the specified command for the specified Tab. - virtual void ExecuteCommandForTab( - TabStripModel::ContextMenuCommand command_id, Tab* tab) = 0; - - // Starts/Stops highlighting the tabs that will be affected by the - // specified command for the specified Tab. - virtual void StartHighlightTabsForCommand( - TabStripModel::ContextMenuCommand command_id, Tab* tab) = 0; - virtual void StopHighlightTabsForCommand( - TabStripModel::ContextMenuCommand command_id, Tab* tab) = 0; - virtual void StopAllHighlighting() = 0; - - // Potentially starts a drag for the specified Tab. - virtual void MaybeStartDrag(Tab* tab, - const ChromeViews::MouseEvent& event) = 0; - - // Continues dragging a Tab. - virtual void ContinueDrag(const ChromeViews::MouseEvent& event) = 0; - - // Ends dragging a Tab. |canceled| is true if the drag was aborted in a way - // other than the user releasing the mouse. - virtual void EndDrag(bool canceled) = 0; - }; - - explicit Tab(TabDelegate* delegate); - virtual ~Tab(); - - // Access the delegate. - TabDelegate* delegate() const { return delegate_; } - - // Used to set/check whether this Tab is being animated closed. - void set_closing(bool closing) { closing_ = closing; } - bool closing() const { return closing_; } - - // TabRenderer overrides: - virtual bool IsSelected() const; - - // ChromeViews::View overrides: - virtual bool HitTest(const CPoint &l) const; - private: - // ChromeViews::View overrides: - virtual bool OnMousePressed(const ChromeViews::MouseEvent& event); - virtual bool OnMouseDragged(const ChromeViews::MouseEvent& event); - virtual void OnMouseReleased(const ChromeViews::MouseEvent& event, - bool canceled); - virtual bool GetTooltipText(int x, int y, std::wstring* tooltip); - virtual bool GetTooltipTextOrigin(int x, int y, CPoint* origin); - virtual std::string GetClassName() const { return kTabClassName; } - virtual bool GetAccessibleRole(VARIANT* role); - virtual bool GetAccessibleName(std::wstring* name); - - // ChromeViews::ContextMenuController overrides: - virtual void ShowContextMenu(ChromeViews::View* source, - int x, - int y, - bool is_mouse_gesture); - - // ChromeViews::BaseButton::ButtonListener overrides: - virtual void ButtonPressed(ChromeViews::BaseButton* sender); - - // Creates a path that contains the clickable region of the tab's visual - // representation. Used by GetViewForPoint for hit-testing. - void MakePathForTab(gfx::Path* path) const; - - // An instance of a delegate object that can perform various actions based on - // user gestures. - TabDelegate* delegate_; - - // True if the tab is being animated closed. - bool closing_; - - DISALLOW_COPY_AND_ASSIGN(Tab); -}; - -#endif // CHROME_BROWSER_TABS_TAB_H_ - diff --git a/chrome/browser/tabs/tab_dragging_test.cc b/chrome/browser/tabs/tab_dragging_test.cc deleted file mode 100644 index 631a0f0..0000000 --- a/chrome/browser/tabs/tab_dragging_test.cc +++ /dev/null @@ -1,507 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/command_line.h" -#include "base/file_util.h" -#include "base/time.h" -#include "chrome/app/chrome_dll_resource.h" -#include "chrome/browser/view_ids.h" -#include "chrome/common/chrome_paths.h" -#include "chrome/common/chrome_switches.h" -#include "chrome/common/pref_names.h" -#include "chrome/test/automation/tab_proxy.h" -#include "chrome/test/automation/browser_proxy.h" -#include "chrome/test/automation/window_proxy.h" -#include "chrome/test/ui/ui_test.h" -#include "chrome/views/event.h" -#include "googleurl/src/gurl.h" -#include "net/base/net_util.h" - - -class TabDraggingTest : public UITest { -protected: - TabDraggingTest() { - show_window_ = true; - } -}; - -// Automated UI test to open three tabs in a new window, and drag Tab_1 into -// the position of Tab_2. -TEST_F(TabDraggingTest, Tab1Tab2) { - scoped_ptr<BrowserProxy> browser(automation()->GetBrowserWindow(0)); - ASSERT_TRUE(browser.get()); - scoped_ptr<WindowProxy> window( - automation()->GetWindowForBrowser(browser.get())); - ASSERT_TRUE(window.get()); - - // Get initial tab count. - int initial_tab_count = 0; - ASSERT_TRUE(browser->GetTabCount(&initial_tab_count)); - ASSERT_TRUE(1 == initial_tab_count); - - // Get Tab_1 which comes with the browser window. - scoped_ptr<TabProxy> tab1(browser->GetTab(0)); - ASSERT_TRUE(tab1.get()); - GURL tab1_url; - ASSERT_TRUE(tab1->GetCurrentURL(&tab1_url)); - - // Add Tab_2. - GURL tab2_url("about:"); - ASSERT_TRUE(browser->AppendTab(tab2_url)); - scoped_ptr<TabProxy> tab2(browser->GetTab(1)); - ASSERT_TRUE(tab2.get()); - - // Add Tab_3. - GURL tab3_url("about:plugins"); - ASSERT_TRUE(browser->AppendTab(tab3_url)); - scoped_ptr<TabProxy> tab3(browser->GetTab(2)); - ASSERT_TRUE(tab3.get()); - - // Make sure 3 tabs are open - int final_tab_count = 0; - ASSERT_TRUE(browser->WaitForTabCountToChange(initial_tab_count, - &final_tab_count, - 10000)); - ASSERT_TRUE(final_tab_count == initial_tab_count + 2); - - // Get bounds for the tabs. - gfx::Rect bounds1; - ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_0, &bounds1, false)); - EXPECT_LT(0, bounds1.x()); - EXPECT_LT(0, bounds1.width()); - EXPECT_LT(0, bounds1.height()); - - gfx::Rect bounds2; - ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_1, &bounds2, false)); - EXPECT_LT(0, bounds2.width()); - EXPECT_LT(0, bounds2.height()); - EXPECT_LT(bounds1.x(), bounds2.x()); - EXPECT_EQ(bounds2.y(), bounds1.y()); - - gfx::Rect bounds3; - ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_2, &bounds3, false)); - EXPECT_LT(0, bounds3.width()); - EXPECT_LT(0, bounds3.height()); - EXPECT_LT(bounds2.x(), bounds3.x()); - EXPECT_EQ(bounds3.y(), bounds2.y()); - - // Get url Bar bounds. - gfx::Rect urlbar_bounds; - ASSERT_TRUE(window->GetViewBounds(VIEW_ID_LOCATION_BAR, &urlbar_bounds, - false)); - EXPECT_LT(0, urlbar_bounds.x()); - EXPECT_LT(0, urlbar_bounds.y()); - EXPECT_LT(0, urlbar_bounds.width()); - EXPECT_LT(0, urlbar_bounds.height()); - - // TEST: Move Tab_1 to the position of Tab_2 - // ____________ ____________ ____________ - // / \ / \ / \ - // | Tab_1 | Tab_2 | Tab_3 | - // ---- ---- ---- ---- ---- ---- ---- ---- ---- - // x---- ----> - // ____________ - // / X \ - // | Tab_1 | - // ---- ---- ---- - - POINT start; - POINT end; - start.x = bounds1.x() + bounds1.width()/2; - start.y = bounds1.y() + bounds1.height()/2; - end.x = start.x + 2*bounds1.width()/3; - end.y = start.y; - ASSERT_TRUE(browser->SimulateDrag(start, end, - ChromeViews::Event::EF_LEFT_BUTTON_DOWN, - false)); - - // Now check for expected results. - tab1.reset(browser->GetTab(0)); - ASSERT_TRUE(tab1.get()); - GURL tab1_new_url; - ASSERT_TRUE(tab1->GetCurrentURL(&tab1_new_url)); - - tab2.reset(browser->GetTab(1)); - ASSERT_TRUE(tab2.get()); - GURL tab2_new_url; - ASSERT_TRUE(tab2->GetCurrentURL(&tab2_new_url)); - - EXPECT_EQ(tab1_url.spec(), tab2_new_url.spec()); - EXPECT_EQ(tab2_url.spec(), tab1_new_url.spec()); -} - -// Drag Tab_1 into the position of Tab_3. -TEST_F(TabDraggingTest, Tab1Tab3) { - scoped_ptr<BrowserProxy> browser(automation()->GetBrowserWindow(0)); - ASSERT_TRUE(browser.get()); - scoped_ptr<WindowProxy> window( - automation()->GetWindowForBrowser(browser.get())); - ASSERT_TRUE(window.get()); - - // Get initial tab count. - int initial_tab_count = 0; - ASSERT_TRUE(browser->GetTabCount(&initial_tab_count)); - ASSERT_TRUE(1 == initial_tab_count); - - // Get Tab_1 which comes with the browser window. - scoped_ptr<TabProxy> tab1(browser->GetTab(0)); - ASSERT_TRUE(tab1.get()); - GURL tab1_url; - ASSERT_TRUE(tab1->GetCurrentURL(&tab1_url)); - - // Add Tab_2. - GURL tab2_url("about:"); - ASSERT_TRUE(browser->AppendTab(tab2_url)); - scoped_ptr<TabProxy> tab2(browser->GetTab(1)); - ASSERT_TRUE(tab2.get()); - - // Add Tab_3. - GURL tab3_url("about:plugins"); - ASSERT_TRUE(browser->AppendTab(tab3_url)); - scoped_ptr<TabProxy> tab3(browser->GetTab(2)); - ASSERT_TRUE(tab3.get()); - - // Make sure 3 tabs are open - int final_tab_count = 0; - ASSERT_TRUE(browser->WaitForTabCountToChange(initial_tab_count, - &final_tab_count, - 10000)); - ASSERT_TRUE(final_tab_count == initial_tab_count + 2); - - // Get bounds for the tabs. - gfx::Rect bounds1; - ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_0, &bounds1, false)); - EXPECT_LT(0, bounds1.x()); - EXPECT_LT(0, bounds1.width()); - EXPECT_LT(0, bounds1.height()); - - gfx::Rect bounds2; - ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_1, &bounds2, false)); - EXPECT_LT(0, bounds2.width()); - EXPECT_LT(0, bounds2.height()); - EXPECT_LT(bounds1.x(), bounds2.x()); - EXPECT_EQ(bounds2.y(), bounds1.y()); - - gfx::Rect bounds3; - ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_2, &bounds3, false)); - EXPECT_LT(0, bounds3.width()); - EXPECT_LT(0, bounds3.height()); - EXPECT_LT(bounds2.x(), bounds3.x()); - EXPECT_EQ(bounds3.y(), bounds2.y()); - - // Get url Bar bounds. - gfx::Rect urlbar_bounds; - ASSERT_TRUE(window->GetViewBounds(VIEW_ID_LOCATION_BAR, &urlbar_bounds, - false)); - EXPECT_LT(0, urlbar_bounds.x()); - EXPECT_LT(0, urlbar_bounds.y()); - EXPECT_LT(0, urlbar_bounds.width()); - EXPECT_LT(0, urlbar_bounds.height()); - - // TEST: Move Tab_1 to the middle position of Tab_3 - // ____________ ____________ ____________ - // / \ / \ / \ - // | Tab_1 | Tab_2 | Tab_3 | - // ---- ---- ---- ---- ---- ---- ---- ---- ---- - // x---- ---- ---- ---- ---- ----> - // ____________ - // / X \ - // | Tab_1 | - // ---- ---- ---- - - POINT start; - POINT end; - start.x = bounds1.x() + bounds1.width()/2; - start.y = bounds1.y() + bounds1.height()/2; - end.x = start.x + bounds1.width()/2 + bounds2.width() + bounds3.width()/2; - end.y = start.y; - ASSERT_TRUE(browser->SimulateDrag(start, end, - ChromeViews::Event::EF_LEFT_BUTTON_DOWN, - false)); - - // Now check for expected results. - tab1.reset(browser->GetTab(0)); - ASSERT_TRUE(tab1.get()); - GURL tab1_new_url; - ASSERT_TRUE(tab1->GetCurrentURL(&tab1_new_url)); - - tab2.reset(browser->GetTab(1)); - ASSERT_TRUE(tab2.get()); - GURL tab2_new_url; - ASSERT_TRUE(tab2->GetCurrentURL(&tab2_new_url)); - - tab3.reset(browser->GetTab(2)); - ASSERT_TRUE(tab3.get()); - GURL tab3_new_url; - ASSERT_TRUE(tab3->GetCurrentURL(&tab3_new_url)); - - EXPECT_EQ(tab1_new_url.spec(), tab2_url.spec()); - EXPECT_EQ(tab2_new_url.spec(), tab3_url.spec()); - EXPECT_EQ(tab3_new_url.spec(), tab1_url.spec()); -} - -// Drag Tab_1 into the position of Tab_3, and press ESCAPE before releasing the -// left mouse button. -TEST_F(TabDraggingTest, Tab1Tab3Escape) { - scoped_ptr<BrowserProxy> browser(automation()->GetBrowserWindow(0)); - ASSERT_TRUE(browser.get()); - scoped_ptr<WindowProxy> window( - automation()->GetWindowForBrowser(browser.get())); - ASSERT_TRUE(window.get()); - - // Get initial tab count. - int initial_tab_count = 0; - ASSERT_TRUE(browser->GetTabCount(&initial_tab_count)); - ASSERT_TRUE(1 == initial_tab_count); - - // Get Tab_1 which comes with the browser window. - scoped_ptr<TabProxy> tab1(browser->GetTab(0)); - ASSERT_TRUE(tab1.get()); - GURL tab1_url; - ASSERT_TRUE(tab1->GetCurrentURL(&tab1_url)); - - // Add Tab_2. - GURL tab2_url("about:"); - ASSERT_TRUE(browser->AppendTab(tab2_url)); - scoped_ptr<TabProxy> tab2(browser->GetTab(1)); - ASSERT_TRUE(tab2.get()); - - // Add Tab_3. - GURL tab3_url("about:plugins"); - ASSERT_TRUE(browser->AppendTab(tab3_url)); - scoped_ptr<TabProxy> tab3(browser->GetTab(2)); - ASSERT_TRUE(tab3.get()); - - // Make sure 3 tabs are open - int final_tab_count = 0; - ASSERT_TRUE(browser->WaitForTabCountToChange(initial_tab_count, - &final_tab_count, - 10000)); - ASSERT_TRUE(final_tab_count == initial_tab_count + 2); - - // Get bounds for the tabs. - gfx::Rect bounds1; - ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_0, &bounds1, false)); - EXPECT_LT(0, bounds1.x()); - EXPECT_LT(0, bounds1.width()); - EXPECT_LT(0, bounds1.height()); - - gfx::Rect bounds2; - ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_1, &bounds2, false)); - EXPECT_LT(0, bounds2.width()); - EXPECT_LT(0, bounds2.height()); - EXPECT_LT(bounds1.x(), bounds2.x()); - EXPECT_EQ(bounds2.y(), bounds1.y()); - - gfx::Rect bounds3; - ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_2, &bounds3, false)); - EXPECT_LT(0, bounds3.width()); - EXPECT_LT(0, bounds3.height()); - EXPECT_LT(bounds2.x(), bounds3.x()); - EXPECT_EQ(bounds3.y(), bounds2.y()); - - // Get url Bar bounds. - gfx::Rect urlbar_bounds; - ASSERT_TRUE(window->GetViewBounds(VIEW_ID_LOCATION_BAR, &urlbar_bounds, - false)); - EXPECT_LT(0, urlbar_bounds.x()); - EXPECT_LT(0, urlbar_bounds.y()); - EXPECT_LT(0, urlbar_bounds.width()); - EXPECT_LT(0, urlbar_bounds.height()); - - // TEST: Move Tab_1 to the middle position of Tab_3 - // ____________ ____________ ____________ - // / \ / \ / \ - // | Tab_1 | Tab_2 | Tab_3 | - // ---- ---- ---- ---- ---- ---- ---- ---- ---- - // x---- ---- ---- ---- ---- ----> + ESCAPE - // ____________ - // / X \ - // | Tab_1 | - // ---- ---- ---- - - POINT start; - POINT end; - start.x = bounds1.x() + bounds1.width()/2; - start.y = bounds1.y() + bounds1.height()/2; - end.x = start.x + bounds1.width()/2 + bounds2.width() + bounds3.width()/2; - end.y = start.y; - - // Simulate drag with 'true' as the last parameter. This will interrupt - // in-flight with Escape. - ASSERT_TRUE(browser->SimulateDrag(start, end, - ChromeViews::Event::EF_LEFT_BUTTON_DOWN, - true)); - - // Now check for expected results. - tab1.reset(browser->GetTab(0)); - ASSERT_TRUE(tab1.get()); - GURL tab1_new_url; - ASSERT_TRUE(tab1->GetCurrentURL(&tab1_new_url)); - - tab2.reset(browser->GetTab(1)); - ASSERT_TRUE(tab2.get()); - GURL tab2_new_url; - ASSERT_TRUE(tab2->GetCurrentURL(&tab2_new_url)); - - tab3.reset(browser->GetTab(2)); - ASSERT_TRUE(tab3.get()); - GURL tab3_new_url; - ASSERT_TRUE(tab3->GetCurrentURL(&tab3_new_url)); - - // The tabs should be in their original positions. - EXPECT_EQ(tab1_new_url.spec(), tab1_url.spec()); - EXPECT_EQ(tab2_new_url.spec(), tab2_url.spec()); - EXPECT_EQ(tab3_new_url.spec(), tab3_url.spec()); -} - -// Drag Tab_2 out of the Tab strip. A new window should open with this tab. -TEST_F(TabDraggingTest, Tab2OutOfTabStrip) { - scoped_ptr<BrowserProxy> browser(automation()->GetBrowserWindow(0)); - ASSERT_TRUE(browser.get()); - scoped_ptr<WindowProxy> window( - automation()->GetWindowForBrowser(browser.get())); - ASSERT_TRUE(window.get()); - - // Get initial tab count. - int initial_tab_count = 0; - ASSERT_TRUE(browser->GetTabCount(&initial_tab_count)); - ASSERT_TRUE(1 == initial_tab_count); - - // Get Tab_1 which comes with the browser window. - scoped_ptr<TabProxy> tab1(browser->GetTab(0)); - ASSERT_TRUE(tab1.get()); - GURL tab1_url; - ASSERT_TRUE(tab1->GetCurrentURL(&tab1_url)); - - // Add Tab_2. - GURL tab2_url("about:version"); - ASSERT_TRUE(browser->AppendTab(tab2_url)); - scoped_ptr<TabProxy> tab2(browser->GetTab(1)); - ASSERT_TRUE(tab2.get()); - - // Add Tab_3. - GURL tab3_url("about:plugins"); - ASSERT_TRUE(browser->AppendTab(tab3_url)); - scoped_ptr<TabProxy> tab3(browser->GetTab(2)); - ASSERT_TRUE(tab3.get()); - - // Make sure 3 tabs are opened. - int final_tab_count = 0; - ASSERT_TRUE(browser->WaitForTabCountToChange(initial_tab_count, - &final_tab_count, - 10000)); - ASSERT_TRUE(final_tab_count == initial_tab_count + 2); - - // Make sure all the tab URL specs are different. - ASSERT_TRUE(tab1_url != tab2_url); - ASSERT_TRUE(tab1_url != tab3_url); - ASSERT_TRUE(tab2_url != tab3_url); - - // Get bounds for the tabs. - gfx::Rect bounds1; - ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_0, &bounds1, false)); - EXPECT_LT(0, bounds1.x()); - EXPECT_LT(0, bounds1.width()); - EXPECT_LT(0, bounds1.height()); - - gfx::Rect bounds2; - ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_1, &bounds2, false)); - EXPECT_LT(0, bounds2.width()); - EXPECT_LT(0, bounds2.height()); - EXPECT_LT(bounds1.x(), bounds2.x()); - EXPECT_EQ(bounds2.y(), bounds1.y()); - - gfx::Rect bounds3; - ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_2, &bounds3, false)); - EXPECT_LT(0, bounds3.width()); - EXPECT_LT(0, bounds3.height()); - EXPECT_LT(bounds2.x(), bounds3.x()); - EXPECT_EQ(bounds3.y(), bounds2.y()); - - // Get url Bar bounds. - gfx::Rect urlbar_bounds; - ASSERT_TRUE(window->GetViewBounds(VIEW_ID_LOCATION_BAR, &urlbar_bounds, - false)); - EXPECT_LT(0, urlbar_bounds.x()); - EXPECT_LT(0, urlbar_bounds.y()); - EXPECT_LT(0, urlbar_bounds.width()); - EXPECT_LT(0, urlbar_bounds.height()); - - // TEST: Move Tab_2 down, out of the tab strip. - // This should result in the following: - // 1- Tab_3 shift left in place of Tab_2 in Window 1 - // 2- Tab_1 to remain in its place - // 3- Tab_2 openes in a new window - // - // ____________ ____________ ____________ - // / \ / \ / \ - // | Tab_1 | Tab_2 | Tab_3 | - // ---- ---- ---- ---- ---- ---- ---- ---- ---- - // x - // | - // | (Drag this below, out of tab strip) - // V - // ____________ - // / X \ - // | Tab_2 | (New Window) - // ---- ---- ---- ---- ---- ---- ---- - - POINT start; - POINT end; - start.x = bounds2.x() + bounds2.width()/2; - start.y = bounds2.y() + bounds2.height()/2; - end.x = start.x; - end.y = start.y + 3*urlbar_bounds.height(); - - // Simulate tab drag. - ASSERT_TRUE(browser->SimulateDrag(start, end, - ChromeViews::Event::EF_LEFT_BUTTON_DOWN, - false)); - - // Now, first make sure that the old window has only two tabs remaining. - int new_tab_count = 0; - ASSERT_TRUE(browser->GetTabCount(&new_tab_count)); - ASSERT_EQ(2, new_tab_count); - - // Get the two tabs - they are called Tab_1 and Tab_2 in the old window. - tab1.reset(browser->GetTab(0)); - ASSERT_TRUE(tab1.get()); - GURL tab1_new_url; - ASSERT_TRUE(tab1->GetCurrentURL(&tab1_new_url)); - - tab2.reset(browser->GetTab(1)); - ASSERT_TRUE(tab2.get()); - GURL tab2_new_url; - ASSERT_TRUE(tab2->GetCurrentURL(&tab2_new_url)); - - // Now check for proper shifting of tabs; i.e., Tab_3 in window 1 should - // shift left to the position of Tab_2; Tab_1 should stay where it was. - EXPECT_EQ(tab1_new_url.spec(), tab1_url.spec()); - EXPECT_EQ(tab2_new_url.spec(), tab3_url.spec()); - - // Now check to make sure a new window has opened. - scoped_ptr<BrowserProxy> browser2(automation()->GetBrowserWindow(1)); - ASSERT_TRUE(browser2.get()); - scoped_ptr<WindowProxy> window2( - automation()->GetWindowForBrowser(browser2.get())); - ASSERT_TRUE(window2.get()); - - // Make sure that the new window has only one tab. - int tab_count_window_2 = 0; - ASSERT_TRUE(browser2->GetTabCount(&tab_count_window_2)); - ASSERT_EQ(1, tab_count_window_2); - - // Get Tab_1_2 which should be Tab_1 in Window 2. - scoped_ptr<TabProxy> tab1_2(browser2->GetTab(0)); - ASSERT_TRUE(tab1_2.get()); - GURL tab1_2_url; - ASSERT_TRUE(tab1_2->GetCurrentURL(&tab1_2_url)); - - // Tab_1_2 of Window 2 should essentially be Tab_2 of Window 1. - EXPECT_EQ(tab1_2_url.spec(), tab2_url.spec()); - EXPECT_NE(tab1_2_url.spec(), tab1_url.spec()); - EXPECT_NE(tab1_2_url.spec(), tab3_url.spec()); -} - diff --git a/chrome/browser/tabs/tab_renderer.cc b/chrome/browser/tabs/tab_renderer.cc deleted file mode 100644 index 3437900..0000000 --- a/chrome/browser/tabs/tab_renderer.cc +++ /dev/null @@ -1,691 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <limits> - -#include "chrome/browser/tabs/tab_renderer.h" - -#include "base/gfx/image_operations.h" -#include "chrome/app/theme/theme_resources.h" -#include "chrome/browser/browser.h" -#include "chrome/browser/tabs/tab_strip_model.h" -#include "chrome/browser/tab_contents.h" -#include "chrome/common/gfx/chrome_canvas.h" -#include "chrome/common/gfx/chrome_font.h" -#include "chrome/common/resource_bundle.h" -#include "chrome/common/win_util.h" -#include "generated_resources.h" - -static const int kLeftPadding = 16; -static const int kTopPadding = 6; -static const int kRightPadding = 15; -static const int kBottomPadding = 5; -static const int kFavIconTitleSpacing = 4; -static const int kTitleCloseButtonSpacing = 5; -static const int kStandardTitleWidth = 175; -static const int kCloseButtonVertFuzz = 0; -static const int kCloseButtonHorzFuzz = 5; -static const int kFaviconSize = 16; -static const int kSelectedTitleColor = SK_ColorBLACK; -static const int kUnselectedTitleColor = SkColorSetRGB(64, 64, 64); - -// How long the hover state takes. -static const int kHoverDurationMs = 90; - -// How long the pulse throb takes. -static const int kPulseDurationMs = 200; - -// How opaque to make the hover state (out of 1). -static const double kHoverOpacity = 0.33; -static const double kHoverOpacityVista = 0.7; - -// TODO(beng): (Cleanup) This stuff should move onto the class. -static ChromeFont title_font; -static int title_font_height = 0; -static SkBitmap* close_button_n = NULL; -static SkBitmap* close_button_h = NULL; -static SkBitmap* close_button_p = NULL; -static int close_button_height = 0; -static int close_button_width = 0; -static SkBitmap* tab_active_l = NULL; -static SkBitmap* tab_active_c = NULL; -static SkBitmap* tab_active_r = NULL; -static int tab_active_l_width = 0; -static int tab_active_r_width = 0; -static SkBitmap* tab_inactive_l = NULL; -static SkBitmap* tab_inactive_c = NULL; -static SkBitmap* tab_inactive_r = NULL; -static SkBitmap* tab_inactive_otr_l = NULL; -static SkBitmap* tab_inactive_otr_c = NULL; -static SkBitmap* tab_inactive_otr_r = NULL; -static SkBitmap* tab_hover_l = NULL; -static SkBitmap* tab_hover_c = NULL; -static SkBitmap* tab_hover_r = NULL; -static int tab_inactive_l_width = 0; -static int tab_inactive_r_width = 0; -static SkBitmap* waiting_animation_frames = NULL; -static SkBitmap* loading_animation_frames = NULL; -static SkBitmap* crashed_fav_icon = NULL; -static int loading_animation_frame_count = 0; -static int waiting_animation_frame_count = 0; -static int waiting_to_loading_frame_count_ratio = 0; -static SkBitmap* download_icon = NULL; -static int download_icon_width = 0; -static int download_icon_height = 0; - -namespace { - -void InitResources() { - static bool initialized = false; - if (!initialized) { - ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - title_font = rb.GetFont(ResourceBundle::BaseFont); - title_font_height = title_font.height(); - - close_button_n = rb.GetBitmapNamed(IDR_TAB_CLOSE); - close_button_h = rb.GetBitmapNamed(IDR_TAB_CLOSE_H); - close_button_p = rb.GetBitmapNamed(IDR_TAB_CLOSE_P); - close_button_width = close_button_n->width(); - close_button_height = close_button_n->height(); - - tab_active_l = rb.GetBitmapNamed(IDR_TAB_ACTIVE_LEFT); - tab_active_c = rb.GetBitmapNamed(IDR_TAB_ACTIVE_CENTER); - tab_active_r = rb.GetBitmapNamed(IDR_TAB_ACTIVE_RIGHT); - tab_active_l_width = tab_active_l->width(); - tab_active_r_width = tab_active_r->width(); - - if (win_util::ShouldUseVistaFrame()) { - tab_inactive_l = rb.GetBitmapNamed(IDR_TAB_INACTIVE_LEFT_V); - tab_inactive_c = rb.GetBitmapNamed(IDR_TAB_INACTIVE_CENTER_V); - tab_inactive_r = rb.GetBitmapNamed(IDR_TAB_INACTIVE_RIGHT_V); - - // Our Vista frame doesn't change background color to show OTR, - // so we continue to use the existing background tabs. - tab_inactive_otr_l = rb.GetBitmapNamed(IDR_TAB_INACTIVE_LEFT_V); - tab_inactive_otr_c = rb.GetBitmapNamed(IDR_TAB_INACTIVE_CENTER_V); - tab_inactive_otr_r = rb.GetBitmapNamed(IDR_TAB_INACTIVE_RIGHT_V); - } else { - tab_inactive_l = rb.GetBitmapNamed(IDR_TAB_INACTIVE_LEFT); - tab_inactive_c = rb.GetBitmapNamed(IDR_TAB_INACTIVE_CENTER); - tab_inactive_r = rb.GetBitmapNamed(IDR_TAB_INACTIVE_RIGHT); - - tab_inactive_otr_l = rb.GetBitmapNamed(IDR_TAB_INACTIVE_LEFT_OTR); - tab_inactive_otr_c = rb.GetBitmapNamed(IDR_TAB_INACTIVE_CENTER_OTR); - tab_inactive_otr_r = rb.GetBitmapNamed(IDR_TAB_INACTIVE_RIGHT_OTR); - } - - tab_hover_l = rb.GetBitmapNamed(IDR_TAB_HOVER_LEFT); - tab_hover_c = rb.GetBitmapNamed(IDR_TAB_HOVER_CENTER); - tab_hover_r = rb.GetBitmapNamed(IDR_TAB_HOVER_RIGHT); - - tab_inactive_l_width = tab_inactive_l->width(); - tab_inactive_r_width = tab_inactive_r->width(); - - // The loading animation image is a strip of states. Each state must be - // square, so the height must divide the width evenly. - loading_animation_frames = rb.GetBitmapNamed(IDR_THROBBER); - DCHECK(loading_animation_frames); - DCHECK(loading_animation_frames->width() % - loading_animation_frames->height() == 0); - loading_animation_frame_count = - loading_animation_frames->width() / loading_animation_frames->height(); - - waiting_animation_frames = rb.GetBitmapNamed(IDR_THROBBER_WAITING); - DCHECK(waiting_animation_frames); - DCHECK(waiting_animation_frames->width() % - waiting_animation_frames->height() == 0); - waiting_animation_frame_count = - waiting_animation_frames->width() / waiting_animation_frames->height(); - - waiting_to_loading_frame_count_ratio = - waiting_animation_frame_count / loading_animation_frame_count; - - crashed_fav_icon = rb.GetBitmapNamed(IDR_SAD_FAVICON); - - download_icon = rb.GetBitmapNamed(IDR_DOWNLOAD_ICON); - download_icon_width = download_icon->width(); - download_icon_height = download_icon->height(); - - initialized = true; - } -} - -int GetContentHeight() { - // The height of the content of the Tab is the largest of the favicon, - // the title text and the close button graphic. - int content_height = std::max(kFaviconSize, title_font_height); - return std::max(content_height, close_button_height); -} - -//////////////////////////////////////////////////////////////////////////////// -// TabCloseButton -// -// This is a Button subclass that causes middle clicks to be forwarded to the -// parent View by explicitly not handling them in OnMousePressed. -class TabCloseButton : public ChromeViews::Button { - public: - TabCloseButton() : Button() {} - virtual ~TabCloseButton() {} - - virtual bool OnMousePressed(const ChromeViews::MouseEvent& event) { - return !event.IsOnlyMiddleMouseButton(); - } - - // We need to let the parent know about mouse state so that it - // can highlight itself appropriately. Note that Exit events - // fire before Enter events, so this works. - virtual void OnMouseEntered(const ChromeViews::MouseEvent& event) { - BaseButton::OnMouseEntered(event); - GetParent()->OnMouseEntered(event); - } - - virtual void OnMouseExited(const ChromeViews::MouseEvent& event) { - BaseButton::OnMouseExited(event); - GetParent()->OnMouseExited(event); - } - - private: - DISALLOW_EVIL_CONSTRUCTORS(TabCloseButton); -}; - -} // namespace - -//////////////////////////////////////////////////////////////////////////////// -// FaviconCrashAnimation -// -// A custom animation subclass to manage the favicon crash animation. -class TabRenderer::FavIconCrashAnimation : public Animation, - public AnimationDelegate { - public: - explicit FavIconCrashAnimation(TabRenderer* target) - : Animation(1000, 25, this), - target_(target) { - } - virtual ~FavIconCrashAnimation() {} - - // Animation overrides: - virtual void AnimateToState(double state) { - const double kHidingOffset = 27; - - if (state < .5) { - target_->SetFavIconHidingOffset( - static_cast<int>(floor(kHidingOffset * 2.0 * state))); - } else { - target_->DisplayCrashedFavIcon(); - target_->SetFavIconHidingOffset( - static_cast<int>( - floor(kHidingOffset - ((state - .5) * 2.0 * kHidingOffset)))); - } - } - - // AnimationDelegate overrides: - virtual void AnimationCanceled(const Animation* animation) { - target_->SetFavIconHidingOffset(0); - } - - private: - TabRenderer* target_; - - DISALLOW_EVIL_CONSTRUCTORS(FavIconCrashAnimation); -}; - -//////////////////////////////////////////////////////////////////////////////// -// TabRenderer, public: - -TabRenderer::TabRenderer() - : animation_state_(ANIMATION_NONE), - animation_frame_(0), - showing_icon_(false), - showing_download_icon_(false), - showing_close_button_(false), - crash_animation_(NULL), - fav_icon_hiding_offset_(0), - should_display_crashed_favicon_(false) { - InitResources(); - - // Add the Close Button. - close_button_ = new TabCloseButton; - close_button_->SetImage(ChromeViews::Button::BS_NORMAL, close_button_n); - close_button_->SetImage(ChromeViews::Button::BS_HOT, close_button_h); - close_button_->SetImage(ChromeViews::Button::BS_PUSHED, close_button_p); - AddChildView(close_button_); - - hover_animation_.reset(new SlideAnimation(this)); - hover_animation_->SetSlideDuration(kHoverDurationMs); - - pulse_animation_.reset(new ThrobAnimation(this)); - pulse_animation_->SetSlideDuration(kPulseDurationMs); -} - -TabRenderer::~TabRenderer() { - delete crash_animation_; -} - -void TabRenderer::UpdateData(TabContents* contents) { - DCHECK(contents); - data_.favicon = contents->GetFavIcon(); - data_.title = contents->GetTitle(); - data_.loading = contents->is_loading(); - data_.off_the_record = contents->profile()->IsOffTheRecord(); - data_.show_icon = contents->ShouldDisplayFavIcon(); - data_.show_download_icon = contents->IsDownloadShelfVisible(); - data_.crashed = contents->IsCrashed(); -} - -void TabRenderer::UpdateFromModel() { - // Force a layout, since the tab may have grown a favicon. - Layout(); - SchedulePaint(); - - if (data_.crashed) { - if (!should_display_crashed_favicon_ && !IsPerformingCrashAnimation()) - StartCrashAnimation(); - } else { - if (IsPerformingCrashAnimation()) - StopCrashAnimation(); - ResetCrashedFavIcon(); - } -} - -bool TabRenderer::IsSelected() const { - return true; -} - -void TabRenderer::ValidateLoadingAnimation(AnimationState animation_state) { - if (animation_state_ != animation_state) { - // The waiting animation is the reverse of the loading animation, but at a - // different rate - the following reverses and scales the animation_frame_ - // so that the frame is at an equivalent position when going from one - // animation to the other. - if (animation_state_ == ANIMATION_WAITING && - animation_state == ANIMATION_LOADING) { - animation_frame_ = loading_animation_frame_count - - (animation_frame_ / waiting_to_loading_frame_count_ratio); - } - animation_state_ = animation_state; - } - - if (animation_state_ != ANIMATION_NONE) { - animation_frame_ = ++animation_frame_ % - ((animation_state_ == ANIMATION_WAITING) ? - waiting_animation_frame_count : - loading_animation_frame_count); - } else { - animation_frame_ = 0; - } - - SchedulePaint(); -} - -void TabRenderer::StartPulse() { - pulse_animation_->Reset(); - pulse_animation_->StartThrobbing(std::numeric_limits<int>::max()); -} - -void TabRenderer::StopPulse() { - if (pulse_animation_->IsAnimating()) - pulse_animation_->Stop(); -} - -// static -gfx::Size TabRenderer::GetMinimumSize() { - InitResources(); - - gfx::Size minimum_size; - minimum_size.set_width(kLeftPadding + kRightPadding); - // Since we use bitmap images, the real minimum height of the image is - // defined most accurately by the height of the end cap images. - minimum_size.set_height(tab_active_l->height()); - return minimum_size; -} - -// static -gfx::Size TabRenderer::GetMinimumSelectedSize() { - gfx::Size minimum_size = GetMinimumSize(); - minimum_size.set_width(kLeftPadding + kFaviconSize + kRightPadding); - return minimum_size; -} - -// static -gfx::Size TabRenderer::GetStandardSize() { - gfx::Size standard_size = GetMinimumSize(); - standard_size.set_width( - standard_size.width() + kFavIconTitleSpacing + kStandardTitleWidth); - return standard_size; -} - -//////////////////////////////////////////////////////////////////////////////// -// TabRenderer, protected: - -std::wstring TabRenderer::GetTitle() const { - return data_.title; -} - -//////////////////////////////////////////////////////////////////////////////// -// TabRenderer, ChromeViews::View overrides: - -void TabRenderer::Paint(ChromeCanvas* canvas) { - // Don't paint if we're narrower than we can render correctly. (This should - // only happen during animations). - if (GetWidth() < GetMinimumSize().width()) - return; - - // See if the model changes whether the icons should be painted. - const bool show_icon = ShouldShowIcon(); - const bool show_download_icon = data_.show_download_icon; - const bool show_close_button = ShouldShowCloseBox(); - if (show_icon != showing_icon_ || - show_download_icon != showing_download_icon_ || - show_close_button != showing_close_button_) - Layout(); - - PaintTabBackground(canvas); - - // Paint the loading animation if the page is currently loading, otherwise - // show the page's favicon. - if (show_icon) { - if (animation_state_ != ANIMATION_NONE) { - PaintLoadingAnimation(canvas); - } else { - canvas->save(); - canvas->ClipRectInt(0, 0, GetWidth(), GetHeight() - 4); - if (should_display_crashed_favicon_) { - canvas->DrawBitmapInt(*crashed_fav_icon, 0, 0, - crashed_fav_icon->width(), - crashed_fav_icon->height(), - favicon_bounds_.x(), - favicon_bounds_.y() + fav_icon_hiding_offset_, - kFaviconSize, kFaviconSize, - true); - } else { - if (!data_.favicon.isNull()) { - canvas->DrawBitmapInt(data_.favicon, 0, 0, - data_.favicon.width(), - data_.favicon.height(), - favicon_bounds_.x(), - favicon_bounds_.y() + fav_icon_hiding_offset_, - kFaviconSize, kFaviconSize, - true); - } - } - canvas->restore(); - } - } - - if (show_download_icon) { - canvas->DrawBitmapInt(*download_icon, - download_icon_bounds_.x(), download_icon_bounds_.y()); - } - - // Paint the Title. - std::wstring title = data_.title; - if (title.empty()) { - if (data_.loading) { - title = l10n_util::GetString(IDS_TAB_LOADING_TITLE); - } else { - title = l10n_util::GetString(IDS_TAB_UNTITLED_TITLE); - } - } else { - Browser::FormatTitleForDisplay(&title); - } - - SkColor title_color = IsSelected() ? kSelectedTitleColor - : kUnselectedTitleColor; - canvas->DrawStringInt(title, title_font, title_color, title_bounds_.x(), - title_bounds_.y(), title_bounds_.width(), - title_bounds_.height()); -} - -void TabRenderer::Layout() { - CRect lb; - GetLocalBounds(&lb, false); - if (lb.IsRectEmpty()) - return; - - lb.left += kLeftPadding; - lb.top += kTopPadding; - lb.bottom -= kBottomPadding; - lb.right -= kRightPadding; - - // First of all, figure out who is tallest. - int content_height = GetContentHeight(); - - // Size the Favicon. - showing_icon_ = ShouldShowIcon(); - if (showing_icon_) { - int favicon_top = kTopPadding + (content_height - kFaviconSize) / 2; - favicon_bounds_.SetRect(lb.left, favicon_top, kFaviconSize, kFaviconSize); - } else { - favicon_bounds_.SetRect(lb.left, lb.top, 0, 0); - } - - // Size the download icon. - showing_download_icon_ = data_.show_download_icon; - if (showing_download_icon_) { - int icon_top = kTopPadding + (content_height - download_icon_height) / 2; - download_icon_bounds_.SetRect(lb.Width() - download_icon_width, icon_top, - download_icon_width, download_icon_height); - } - - // Size the Close button. - showing_close_button_ = ShouldShowCloseBox(); - if (showing_close_button_) { - int close_button_top = - kTopPadding + kCloseButtonVertFuzz + - (content_height - close_button_height) / 2; - // If the ratio of the close button size to tab width exceeds the maximum. - close_button_->SetBounds(lb.Width() + kCloseButtonHorzFuzz, - close_button_top, close_button_width, - close_button_height); - close_button_->SetVisible(true); - } else { - close_button_->SetBounds(0, 0, 0, 0); - close_button_->SetVisible(false); - } - - // Size the Title text to fill the remaining space. - int title_left = favicon_bounds_.right() + kFavIconTitleSpacing; - int title_top = kTopPadding + (content_height - title_font_height) / 2; - - // If the user has big fonts, the title will appear rendered too far down on - // the y-axis if we use the regular top padding, so we need to adjust it so - // that the text appears centered. - gfx::Size minimum_size = GetMinimumSize(); - int text_height = title_top + title_font_height + kBottomPadding; - if (text_height > minimum_size.height()) - title_top -= (text_height - minimum_size.height()) / 2; - - int title_width; - if (close_button_->IsVisible()) { - title_width = std::max(close_button_->GetX() - - kTitleCloseButtonSpacing - title_left, 0); - } else { - title_width = std::max(lb.Width() - title_left, 0); - } - if (data_.show_download_icon) - title_width = std::max(title_width - download_icon_width, 0); - title_bounds_.SetRect(title_left, title_top, title_width, title_font_height); - - // Certain UI elements within the Tab (the favicon, the download icon, etc.) - // are not represented as child Views (which is the preferred method). - // Instead, these UI elements are drawn directly on the canvas from within - // Tab::Paint(). The Tab's child Views (for example, the Tab's close button - // which is a ChromeViews::Button instance) are automatically mirrored by the - // mirroring infrastructure in ChromeViews. The elements Tab draws directly - // on the canvas need to be manually mirrored if the View's layout is - // right-to-left. - favicon_bounds_.set_x(MirroredLeftPointForRect(favicon_bounds_)); - title_bounds_.set_x(MirroredLeftPointForRect(title_bounds_)); - download_icon_bounds_.set_x(MirroredLeftPointForRect(download_icon_bounds_)); -} - -void TabRenderer::DidChangeBounds(const CRect& previous, - const CRect& current) { - Layout(); -} - - -void TabRenderer::OnMouseEntered(const ChromeViews::MouseEvent& e) { - hover_animation_->SetTweenType(SlideAnimation::EASE_OUT); - hover_animation_->Show(); -} - -void TabRenderer::OnMouseExited(const ChromeViews::MouseEvent& e) { - hover_animation_->SetTweenType(SlideAnimation::EASE_IN); - hover_animation_->Hide(); -} - -/////////////////////////////////////////////////////////////////////////////// -// TabRenderer, AnimationDelegate implementation: - -void TabRenderer::AnimationProgressed(const Animation* animation) { - SchedulePaint(); -} - -void TabRenderer::AnimationCanceled(const Animation* animation) { - AnimationEnded(animation); -} - -void TabRenderer::AnimationEnded(const Animation* animation) { - SchedulePaint(); -} - -//////////////////////////////////////////////////////////////////////////////// -// TabRenderer, private - -void TabRenderer::PaintTabBackground(ChromeCanvas* canvas) { - if (IsSelected()) { - // Sometimes detaching a tab quickly can result in the model reporting it - // as not being selected, so is_drag_clone_ ensures that we always paint - // the active representation for the dragged tab. - PaintActiveTabBackground(canvas); - } else { - // Draw our hover state. - Animation* animation = hover_animation_.get(); - if (pulse_animation_->IsAnimating()) - animation = pulse_animation_.get(); - if (animation->GetCurrentValue() > 0) { - PaintHoverTabBackground(canvas, animation->GetCurrentValue() * - (win_util::ShouldUseVistaFrame() ? - kHoverOpacityVista : kHoverOpacity)); - } else { - PaintInactiveTabBackground(canvas); - } - } -} - -void TabRenderer::PaintInactiveTabBackground(ChromeCanvas* canvas) { - bool is_otr = data_.off_the_record; - canvas->DrawBitmapInt(is_otr ? *tab_inactive_otr_l : *tab_inactive_l, 0, 0); - canvas->TileImageInt(is_otr ? *tab_inactive_otr_c : *tab_inactive_c, - tab_inactive_l_width, 0, - GetWidth() - tab_inactive_l_width - tab_inactive_r_width, - GetHeight()); - canvas->DrawBitmapInt(is_otr ? *tab_inactive_otr_r : *tab_inactive_r, - GetWidth() - tab_inactive_r_width, 0); -} - -void TabRenderer::PaintActiveTabBackground(ChromeCanvas* canvas) { - canvas->DrawBitmapInt(*tab_active_l, 0, 0); - canvas->TileImageInt(*tab_active_c, tab_active_l_width, 0, - GetWidth() - tab_active_l_width - tab_active_r_width, GetHeight()); - canvas->DrawBitmapInt(*tab_active_r, GetWidth() - tab_active_r_width, 0); -} - -void TabRenderer::PaintHoverTabBackground(ChromeCanvas* canvas, - double opacity) { - bool is_otr = data_.off_the_record; - SkBitmap left = gfx::ImageOperations::CreateBlendedBitmap( - (is_otr ? *tab_inactive_otr_l : *tab_inactive_l), - *tab_hover_l, opacity); - SkBitmap center = gfx::ImageOperations::CreateBlendedBitmap( - (is_otr ? *tab_inactive_otr_c : *tab_inactive_c), - *tab_hover_c, opacity); - SkBitmap right = gfx::ImageOperations::CreateBlendedBitmap( - (is_otr ? *tab_inactive_otr_r : *tab_inactive_r), - *tab_hover_r, opacity); - - canvas->DrawBitmapInt(left, 0, 0); - canvas->TileImageInt(center, tab_active_l_width, 0, - GetWidth() - tab_active_l_width - tab_active_r_width, GetHeight()); - canvas->DrawBitmapInt(right, GetWidth() - tab_active_r_width, 0); -} - -void TabRenderer::PaintLoadingAnimation(ChromeCanvas* canvas) { - SkBitmap* frames = (animation_state_ == ANIMATION_WAITING) ? - waiting_animation_frames : loading_animation_frames; - int image_size = frames->height(); - int image_offset = animation_frame_ * image_size; - int dst_y = (GetHeight() - image_size) / 2; - - // Just like with the Tab's title and favicon, the position for the page - // loading animation also needs to be mirrored if the View's UI layout is - // right-to-left. - int dst_x; - if (UILayoutIsRightToLeft()) { - dst_x = GetWidth() - kLeftPadding - image_size; - } else { - dst_x = kLeftPadding; - } - canvas->DrawBitmapInt(*frames, image_offset, 0, image_size, - image_size, dst_x, dst_y, image_size, image_size, - false); -} - -int TabRenderer::IconCapacity() const { - if (GetHeight() < GetMinimumSize().height()) { - return 0; - } - return (GetWidth() - kLeftPadding - kRightPadding) / kFaviconSize; -} - -bool TabRenderer::ShouldShowIcon() const { - if (!data_.show_icon) { - return false; - } else if (IsSelected()) { - // The selected tab clips favicon before close button. - return IconCapacity() >= 2; - } - // Non-selected tabs clip close button before favicon. - return IconCapacity() >= 1; -} - -bool TabRenderer::ShouldShowCloseBox() const { - // The selected tab never clips close button. - return IsSelected() || IconCapacity() >= 3; -} - -//////////////////////////////////////////////////////////////////////////////// -// TabRenderer, private: - -void TabRenderer::StartCrashAnimation() { - if (!crash_animation_) - crash_animation_ = new FavIconCrashAnimation(this); - crash_animation_->Reset(); - crash_animation_->Start(); -} - -void TabRenderer::StopCrashAnimation() { - if (!crash_animation_) - return; - crash_animation_->Stop(); -} - -bool TabRenderer::IsPerformingCrashAnimation() const { - return crash_animation_ && crash_animation_->IsAnimating(); -} - -void TabRenderer::SetFavIconHidingOffset(int offset) { - fav_icon_hiding_offset_ = offset; - SchedulePaint(); -} - -void TabRenderer::DisplayCrashedFavIcon() { - should_display_crashed_favicon_ = true; -} - -void TabRenderer::ResetCrashedFavIcon() { - should_display_crashed_favicon_ = false; -} - diff --git a/chrome/browser/tabs/tab_renderer.h b/chrome/browser/tabs/tab_renderer.h deleted file mode 100644 index 25c2de8..0000000 --- a/chrome/browser/tabs/tab_renderer.h +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_TABS_TAB_RENDERER_H__ -#define CHROME_BROWSER_TABS_TAB_RENDERER_H__ - -#include "base/gfx/point.h" -#include "chrome/common/animation.h" -#include "chrome/common/slide_animation.h" -#include "chrome/common/throb_animation.h" -#include "chrome/views/button.h" -#include "chrome/views/menu.h" -#include "chrome/views/view.h" - -class TabContents; - -/////////////////////////////////////////////////////////////////////////////// -// -// TabRenderer -// -// A View that renders a Tab, either in a TabStrip or in a DraggedTabView. -// -/////////////////////////////////////////////////////////////////////////////// -class TabRenderer : public ChromeViews::View, - public AnimationDelegate { - public: - // Possible animation states. - enum AnimationState { - ANIMATION_NONE, - ANIMATION_WAITING, - ANIMATION_LOADING - }; - - TabRenderer(); - virtual ~TabRenderer(); - - // Updates the data the Tab uses to render itself from the specified - // TabContents. - void UpdateData(TabContents* contents); - - // Updates the display to reflect the contents of this TabRenderer's model. - void UpdateFromModel(); - - // Returns true if the Tab is selected, false otherwise. - virtual bool IsSelected() const; - - // Advance the Loading Animation to the next frame, or hide the animation if - // the tab isn't loading. - void ValidateLoadingAnimation(AnimationState animation_state); - - // Starts/Stops a pulse animation. - void StartPulse(); - void StopPulse(); - - // Returns the minimum possible size of a single unselected Tab. - static gfx::Size GetMinimumSize(); - // Returns the minimum possible size of a selected Tab. Selected tabs must - // always show a close button and have a larger minimum size than unselected - // tabs. - static gfx::Size GetMinimumSelectedSize(); - // Returns the preferred size of a single Tab, assuming space is - // available. - static gfx::Size GetStandardSize(); - - protected: - ChromeViews::Button* close_button() const { return close_button_; } - const gfx::Rect& title_bounds() const { return title_bounds_; } - - // Returns the title of the Tab. - std::wstring GetTitle() const; - - private: - // Overridden from ChromeViews::View: - virtual void Paint(ChromeCanvas* canvas); - virtual void Layout(); - virtual void DidChangeBounds(const CRect& previous, const CRect& current); - virtual void OnMouseEntered(const ChromeViews::MouseEvent& event); - virtual void OnMouseExited(const ChromeViews::MouseEvent& event); - - // Overridden from AnimationDelegate: - virtual void AnimationProgressed(const Animation* animation); - virtual void AnimationCanceled(const Animation* animation); - virtual void AnimationEnded(const Animation* animation); - - // Starts/Stops the crash animation. - void StartCrashAnimation(); - void StopCrashAnimation(); - - // Return true if the crash animation is currently running. - bool IsPerformingCrashAnimation() const; - - // Set the temporary offset for the favicon. This is used during animation. - void SetFavIconHidingOffset(int offset); - - void DisplayCrashedFavIcon(); - void ResetCrashedFavIcon(); - - // Paint various portions of the Tab - void PaintTabBackground(ChromeCanvas* canvas); - void PaintInactiveTabBackground(ChromeCanvas* canvas); - void PaintActiveTabBackground(ChromeCanvas* canvas); - void PaintHoverTabBackground(ChromeCanvas* canvas, double opacity); - void PaintLoadingAnimation(ChromeCanvas* canvas); - - // Returns the number of favicon-size elements that can fit in the tab's - // current size. - int IconCapacity() const; - - // Returns whether the Tab should display a favicon. - bool ShouldShowIcon() const; - - // Returns whether the Tab should display a close button. - bool ShouldShowCloseBox() const; - - // The bounds of various sections of the display. - gfx::Rect favicon_bounds_; - gfx::Rect download_icon_bounds_; - gfx::Rect title_bounds_; - - // Current state of the animation. - AnimationState animation_state_; - - // The current index into the Animation image strip. - int animation_frame_; - - // Close Button. - ChromeViews::Button* close_button_; - - // Hover animation. - scoped_ptr<SlideAnimation> hover_animation_; - - // Pulse animation. - scoped_ptr<ThrobAnimation> pulse_animation_; - - // Model data. We store this here so that we don't need to ask the underlying - // model, which is tricky since instances of this object can outlive the - // corresponding objects in the underlying model. - struct TabData { - SkBitmap favicon; - std::wstring title; - bool loading; - bool crashed; - bool off_the_record; - bool show_icon; - bool show_download_icon; - }; - TabData data_; - - // Whether we're showing the icon. It is cached so that we can detect when it - // changes and layout appropriately. - bool showing_icon_; - - // Whether we are showing the download icon. Comes from the model. - bool showing_download_icon_; - - // Whether we are showing the close button. It is cached so that we can - // detect when it changes and layout appropriately. - bool showing_close_button_; - - // The offset used to animate the favicon location. - int fav_icon_hiding_offset_; - - // The animation object used to swap the favicon with the sad tab icon. - class FavIconCrashAnimation; - FavIconCrashAnimation* crash_animation_; - - bool should_display_crashed_favicon_; - - DISALLOW_EVIL_CONSTRUCTORS(TabRenderer); -}; - -#endif // CHROME_BROWSER_TABS_TAB_RENDERER_H__ - diff --git a/chrome/browser/tabs/tab_strip.cc b/chrome/browser/tabs/tab_strip.cc deleted file mode 100644 index 57a8e32..0000000 --- a/chrome/browser/tabs/tab_strip.cc +++ /dev/null @@ -1,1524 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/tabs/tab_strip.h" - -#include "base/gfx/size.h" -#include "chrome/app/theme/theme_resources.h" -#include "chrome/browser/profile.h" -#include "chrome/browser/tab_contents.h" -#include "chrome/browser/tabs/dragged_tab_controller.h" -#include "chrome/browser/tabs/tab.h" -#include "chrome/browser/tabs/tab_strip_model.h" -#include "chrome/browser/user_metrics.h" -#include "chrome/browser/view_ids.h" -#include "chrome/browser/vista_frame.h" -#include "chrome/browser/web_contents.h" -#include "chrome/common/drag_drop_types.h" -#include "chrome/common/gfx/chrome_canvas.h" -#include "chrome/common/l10n_util.h" -#include "chrome/common/os_exchange_data.h" -#include "chrome/common/pref_names.h" -#include "chrome/common/resource_bundle.h" -#include "chrome/common/slide_animation.h" -#include "chrome/common/stl_util-inl.h" -#include "chrome/common/win_util.h" -#include "chrome/views/image_view.h" -#include "chrome/views/painter.h" - -#include "generated_resources.h" - -#undef min -#undef max - -using ChromeViews::DropTargetEvent; - -static const int kDefaultAnimationDurationMs = 100; -static const int kResizeLayoutAnimationDurationMs = 166; -static const int kReorderAnimationDurationMs = 166; - -static const int kLoadingAnimationFrameTimeMs = 30; -static const int kNewTabButtonHOffset = -5; -static const int kNewTabButtonVOffset = 5; -static const int kResizeTabsTimeMs = 300; -static const int kSuspendAnimationsTimeMs = 200; -static const int kTabHOffset = -16; -static const int kTabStripAnimationVSlop = 40; - -// Size of the drop indicator. -static int drop_indicator_width; -static int drop_indicator_height; - -static inline int Round(double x) { - // Why oh why is this not in a standard header? - return static_cast<int>(floor(x + 0.5)); -} - -/////////////////////////////////////////////////////////////////////////////// -// -// TabAnimation -// -// A base class for all TabStrip animations. -// -class TabStrip::TabAnimation : public AnimationDelegate { - public: - friend class TabStrip; - - // Possible types of animation. - enum Type { - INSERT, - REMOVE, - MOVE, - RESIZE - }; - - TabAnimation(TabStrip* tabstrip, Type type) - : tabstrip_(tabstrip), - animation_(this), - start_selected_width_(0), - start_unselected_width_(0), - end_selected_width_(0), - end_unselected_width_(0), - layout_on_completion_(false), - type_(type) { - } - virtual ~TabAnimation() {} - - Type type() const { return type_; } - - void Start() { - animation_.SetSlideDuration(GetDuration()); - animation_.SetTweenType(SlideAnimation::EASE_OUT); - if (!animation_.IsShowing()) { - animation_.Reset(); - animation_.Show(); - } - } - - void Stop() { - animation_.Stop(); - } - - void set_layout_on_completion(bool layout_on_completion) { - layout_on_completion_ = layout_on_completion; - } - - // Retrieves the width for the Tab at the specified index if an animation is - // active. - static double GetCurrentTabWidth(TabStrip* tabstrip, - TabStrip::TabAnimation* animation, - int index) { - double unselected, selected; - tabstrip->GetCurrentTabWidths(&unselected, &selected); - Tab* tab = tabstrip->GetTabAt(index); - double tab_width = tab->IsSelected() ? selected : unselected; - if (animation) { - double specified_tab_width = animation->GetWidthForTab(index); - if (specified_tab_width != -1) - tab_width = specified_tab_width; - } - return tab_width; - } - - // Overridden from AnimationDelegate: - virtual void AnimationProgressed(const Animation* animation) { - tabstrip_->AnimationLayout(end_unselected_width_); - } - - virtual void AnimationEnded(const Animation* animation) { - tabstrip_->FinishAnimation(this, layout_on_completion_); - // This object is destroyed now, so we can't do anything else after this. - } - - virtual void AnimationCanceled(const Animation* animation) { - AnimationEnded(animation); - } - - protected: - // Returns the duration of the animation. - virtual int GetDuration() const { - return kDefaultAnimationDurationMs; - } - - // Subclasses override to return the width of the Tab at the specified index - // at the current animation frame. -1 indicates the default width should be - // used for the Tab. - virtual double GetWidthForTab(int index) const { - return -1; // Use default. - } - - // Figure out the desired start and end widths for the specified pre- and - // post- animation tab counts. - void GenerateStartAndEndWidths(int start_tab_count, int end_tab_count) { - tabstrip_->GetDesiredTabWidths(start_tab_count, &start_unselected_width_, - &start_selected_width_); - double standard_tab_width = - static_cast<double>(TabRenderer::GetStandardSize().width()); - if (start_tab_count < end_tab_count && - start_unselected_width_ < standard_tab_width) { - double minimum_tab_width = - static_cast<double>(TabRenderer::GetMinimumSize().width()); - start_unselected_width_ -= minimum_tab_width / start_tab_count; - } - tabstrip_->GenerateIdealBounds(); - tabstrip_->GetDesiredTabWidths(end_tab_count, - &end_unselected_width_, - &end_selected_width_); - } - - TabStrip* tabstrip_; - SlideAnimation animation_; - - double start_selected_width_; - double start_unselected_width_; - double end_selected_width_; - double end_unselected_width_; - - private: - // True if a complete re-layout is required upon completion of the animation. - // Subclasses set this if they don't perform a complete layout - // themselves and canceling the animation may leave the strip in an - // inconsistent state. - bool layout_on_completion_; - - const Type type_; - - DISALLOW_EVIL_CONSTRUCTORS(TabAnimation); -}; - -/////////////////////////////////////////////////////////////////////////////// - -// Handles insertion of a Tab at |index|. -class InsertTabAnimation : public TabStrip::TabAnimation { - public: - explicit InsertTabAnimation(TabStrip* tabstrip, int index) - : TabAnimation(tabstrip, INSERT), - index_(index) { - int tab_count = tabstrip->GetTabCount(); - GenerateStartAndEndWidths(tab_count - 1, tab_count); - } - virtual ~InsertTabAnimation() {} - - protected: - // Overridden from TabStrip::TabAnimation: - virtual double GetWidthForTab(int index) const { - if (index == index_) { - bool is_selected = tabstrip_->model()->selected_index() == index; - double target_width = - is_selected ? end_unselected_width_ : end_selected_width_; - double start_width = is_selected ? Tab::GetMinimumSelectedSize().width() : - Tab::GetMinimumSize().width(); - double delta = target_width - start_width; - if (delta > 0) - return start_width + (delta * animation_.GetCurrentValue()); - return start_width; - } - if (tabstrip_->GetTabAt(index)->IsSelected()) { - double delta = end_selected_width_ - start_selected_width_; - return start_selected_width_ + (delta * animation_.GetCurrentValue()); - } - double delta = end_unselected_width_ - start_unselected_width_; - return start_unselected_width_ + (delta * animation_.GetCurrentValue()); - } - - private: - int index_; - - DISALLOW_EVIL_CONSTRUCTORS(InsertTabAnimation); -}; - -/////////////////////////////////////////////////////////////////////////////// - -// Handles removal of a Tab from |index| -class RemoveTabAnimation : public TabStrip::TabAnimation { - public: - RemoveTabAnimation(TabStrip* tabstrip, int index, TabContents* contents) - : TabAnimation(tabstrip, REMOVE), - index_(index) { - int tab_count = tabstrip->GetTabCount(); - GenerateStartAndEndWidths(tab_count, tab_count - 1); - } - - // Returns the index of the tab being removed. - int index() const { return index_; } - - virtual ~RemoveTabAnimation() { - } - - protected: - // Overridden from TabStrip::TabAnimation: - virtual double GetWidthForTab(int index) const { - Tab* tab = tabstrip_->GetTabAt(index); - if (index == index_) { - // The tab(s) being removed are gradually shrunken depending on the state - // of the animation. - // Removed animated Tabs are never selected. - double start_width = start_unselected_width_; - double target_width = Tab::GetMinimumSize().width() + kTabHOffset; - double delta = start_width - target_width; - return start_width - (delta * animation_.GetCurrentValue()); - } - if (tabstrip_->available_width_for_tabs_ != -1 && - index_ != tabstrip_->GetTabCount() - 1) { - return TabStrip::TabAnimation::GetWidthForTab(index); - } - // All other tabs are sized according to the start/end widths specified at - // the start of the animation. - if (tab->IsSelected()) { - double delta = end_selected_width_ - start_selected_width_; - return start_selected_width_ + (delta * animation_.GetCurrentValue()); - } - double delta = end_unselected_width_ - start_unselected_width_; - return start_unselected_width_ + (delta * animation_.GetCurrentValue()); - } - - virtual void AnimationEnded(const Animation* animation) { - RemoveTabAt(index_); - HighlightCloseButton(); - TabStrip::TabAnimation::AnimationEnded(animation); - } - - private: - // Cleans up the Tab from the TabStrip at the specified |index| once its - // animated removal is complete. - void RemoveTabAt(int index) const { - // Save a pointer to the Tab before we remove the TabData, we'll need this - // later. - Tab* removed = tabstrip_->tab_data_.at(index).tab; - - // Remove the Tab from the TabStrip's list... - tabstrip_->tab_data_.erase(tabstrip_->tab_data_.begin() + index); - - // If the TabContents being detached was removed as a result of a drag - // gesture from its corresponding Tab, we don't want to remove the Tab from - // the child list, because if we do so it'll stop receiving events and the - // drag will stall. So we only remove if a drag isn't active, or the Tab - // was for some other TabContents. - if (!tabstrip_->IsDragSessionActive() || - !tabstrip_->drag_controller_->IsDragSourceTab(removed)) { - tabstrip_->RemoveChildView(removed); - delete removed; - } - } - - // When the animation completes, we send the ViewContainer a message to - // simulate a mouse moved event at the current mouse position. This tickles - // the Tab the mouse is currently over to show the "hot" state of the close - // button. - void HighlightCloseButton() { - if (tabstrip_->available_width_for_tabs_ == -1 || - tabstrip_->IsDragSessionActive()) { - // This function is not required (and indeed may crash!) for removes - // spawned by non-mouse closes and drag-detaches. - return; - } - - POINT pt; - GetCursorPos(&pt); - ChromeViews::ViewContainer* vc = tabstrip_->GetViewContainer(); - RECT wr; - GetWindowRect(vc->GetHWND(), &wr); - pt.x -= wr.left; - pt.y -= wr.top; - - // Return to message loop - otherwise we may disrupt some operation that's - // in progress. - PostMessage(vc->GetHWND(), WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y)); - } - - int index_; - - DISALLOW_EVIL_CONSTRUCTORS(RemoveTabAnimation); -}; - -/////////////////////////////////////////////////////////////////////////////// - -// Handles the movement of a Tab from one position to another. -class MoveTabAnimation : public TabStrip::TabAnimation { - public: - MoveTabAnimation(TabStrip* tabstrip, int tab_a_index, int tab_b_index) - : TabAnimation(tabstrip, MOVE), - start_tab_a_bounds_(tabstrip_->GetIdealBounds(tab_b_index)), - start_tab_b_bounds_(tabstrip_->GetIdealBounds(tab_a_index)) { - tab_a_ = tabstrip_->GetTabAt(tab_a_index); - tab_b_ = tabstrip_->GetTabAt(tab_b_index); - - // Since we don't do a full TabStrip re-layout, we need to force a full - // layout upon completion since we're not guaranteed to be in a good state - // if for example the animation is canceled. - set_layout_on_completion(true); - } - virtual ~MoveTabAnimation() {} - - // Overridden from AnimationDelegate: - virtual void AnimationProgressed(const Animation* animation) { - // Position Tab A - double distance = start_tab_b_bounds_.x() - start_tab_a_bounds_.x(); - double delta = distance * animation_.GetCurrentValue(); - double new_x = start_tab_a_bounds_.x() + delta; - tab_a_->SetBounds(Round(new_x), tab_a_->GetY(), tab_a_->GetWidth(), - tab_a_->GetHeight()); - - // Position Tab B - distance = start_tab_a_bounds_.x() - start_tab_b_bounds_.x(); - delta = distance * animation_.GetCurrentValue(); - new_x = start_tab_b_bounds_.x() + delta; - tab_b_->SetBounds(Round(new_x), tab_b_->GetY(), tab_b_->GetWidth(), - tab_b_->GetHeight()); - - tabstrip_->SchedulePaint(); - } - - protected: - // Overridden from TabStrip::TabAnimation: - virtual int GetDuration() const { return kReorderAnimationDurationMs; } - - private: - // The two tabs being exchanged. - Tab* tab_a_; - Tab* tab_b_; - - // ...and their bounds. - gfx::Rect start_tab_a_bounds_; - gfx::Rect start_tab_b_bounds_; - - DISALLOW_EVIL_CONSTRUCTORS(MoveTabAnimation); -}; - -/////////////////////////////////////////////////////////////////////////////// - -// Handles the animated resize layout of the entire TabStrip from one width -// to another. -class ResizeLayoutAnimation : public TabStrip::TabAnimation { - public: - explicit ResizeLayoutAnimation(TabStrip* tabstrip) - : TabAnimation(tabstrip, RESIZE) { - int tab_count = tabstrip->GetTabCount(); - GenerateStartAndEndWidths(tab_count, tab_count); - InitStartState(); - } - virtual ~ResizeLayoutAnimation() { - } - - // Overridden from AnimationDelegate: - virtual void AnimationEnded(const Animation* animation) { - tabstrip_->resize_layout_scheduled_ = false; - TabStrip::TabAnimation::AnimationEnded(animation); - } - - protected: - // Overridden from TabStrip::TabAnimation: - virtual int GetDuration() const { - return kResizeLayoutAnimationDurationMs; - } - - virtual double GetWidthForTab(int index) const { - if (tabstrip_->GetTabAt(index)->IsSelected()) { - double delta = end_selected_width_ - start_selected_width_; - return start_selected_width_ + (delta * animation_.GetCurrentValue()); - } - double delta = end_unselected_width_ - start_unselected_width_; - return start_unselected_width_ + (delta * animation_.GetCurrentValue()); - } - - private: - // We need to start from the current widths of the Tabs as they were last - // laid out, _not_ the last known good state, which is what'll be done if we - // don't measure the Tab sizes here and just go with the default TabAnimation - // behavior... - void InitStartState() { - for (int i = 0; i < tabstrip_->GetTabCount(); ++i) { - Tab* current_tab = tabstrip_->GetTabAt(i); - if (current_tab->IsSelected()) { - start_selected_width_ = current_tab->GetWidth(); - } else { - start_unselected_width_ = current_tab->GetWidth(); - } - } - } - - DISALLOW_EVIL_CONSTRUCTORS(ResizeLayoutAnimation); -}; - -/////////////////////////////////////////////////////////////////////////////// -// TabStrip, public: - -TabStrip::TabStrip(TabStripModel* model) - : model_(model), - resize_layout_factory_(this), - added_as_message_loop_observer_(false), - resize_layout_scheduled_(false), - current_unselected_width_(Tab::GetStandardSize().width()), - current_selected_width_(Tab::GetStandardSize().width()), - available_width_for_tabs_(-1) { - Init(); -} - -TabStrip::~TabStrip() { - // TODO(beng): (1031854) Restore this line once XPFrame/VistaFrame are dead. - //model_->RemoveObserver(this); - - // TODO(beng): remove this if it doesn't work to fix the TabSelectedAt bug. - drag_controller_.reset(NULL); - - // Make sure we unhook ourselves as a message loop observer so that we don't - // crash in the case where the user closes the window after closing a tab - // but before moving the mouse. - RemoveMessageLoopObserver(); -} - -int TabStrip::GetPreferredHeight() { - CSize preferred_size; - GetPreferredSize(&preferred_size); - return preferred_size.cy; -} - -bool TabStrip::HasAvailableDragActions() const { - return model_->delegate()->GetDragActions() != 0; -} - -void TabStrip::ShowApplicationMenu(const gfx::Point& p) { - TabStripModelDelegate* delegate = model_->delegate(); - if (delegate) - delegate->ShowApplicationMenu(p); -} - -bool TabStrip::CanProcessInputEvents() const { - return IsAnimating() == NULL; -} - -bool TabStrip::PointIsWithinWindowCaption(const CPoint& point) { - ChromeViews::View* v = GetViewForPoint(point); - - // If there is no control at this location, claim the hit was in the title - // bar to get a move action. - if (v == this) - return true; - - // If the point is within the bounds of a Tab, the point can be considered - // part of the caption if there are no available drag operations for the Tab. - if (v->GetClassName() == Tab::kTabClassName && !HasAvailableDragActions()) - return true; - - // All other regions, including the new Tab button, should be considered part - // of the containing Window's client area so that regular events can be - // processed for them. - return false; -} - -bool TabStrip::IsCompatibleWith(TabStrip* other) { - return model_->profile() == other->model()->profile(); -} - -bool TabStrip::IsAnimating() const { - return active_animation_.get() != NULL; -} - -void TabStrip::DestroyDragController() { - if (IsDragSessionActive()) - drag_controller_.reset(NULL); -} - -void TabStrip::DestroyDraggedSourceTab(Tab* tab) { - // We could be running an animation that references this Tab. - if (active_animation_.get()) - active_animation_->Stop(); - // Make sure we leave the tab_data_ vector in a consistent state, otherwise - // we'll be pointing to tabs that have been deleted and removed from the - // child view list. - std::vector<TabData>::iterator it = tab_data_.begin(); - for (; it != tab_data_.end(); ++it) { - if (it->tab == tab) { - NOTREACHED() << "Leaving in an inconsistent state!"; - tab_data_.erase(it); - break; - } - } - tab->GetParent()->RemoveChildView(tab); - delete tab; - // Force a layout here, because if we've just quickly drag detached a Tab, - // the stopping of the active animation above may have left the TabStrip in a - // bad (visual) state. - Layout(); -} - -gfx::Rect TabStrip::GetIdealBounds(int index) { - DCHECK(index >= 0 && index < GetTabCount()); - return tab_data_.at(index).ideal_bounds; -} - -/////////////////////////////////////////////////////////////////////////////// -// TabStrip, ChromeViews::View overrides: - -void TabStrip::PaintChildren(ChromeCanvas* canvas) { - // Paint the tabs in reverse order, so they stack to the left. - Tab* selected_tab = NULL; - for (int i = GetTabCount() - 1; i >= 0; --i) { - Tab* tab = GetTabAt(i); - // We must ask the _Tab's_ model, not ourselves, because in some situations - // the model will be different to this object, e.g. when a Tab is being - // removed after its TabContents has been destroyed. - if (!tab->IsSelected()) { - tab->ProcessPaint(canvas); - } else { - selected_tab = tab; - } - } - - if (win_util::ShouldUseVistaFrame()) { - // Make sure unselected tabs are somewhat transparent. - SkPaint paint; - paint.setColor(SkColorSetARGB(200, 255, 255, 255)); - paint.setPorterDuffXfermode(SkPorterDuff::kDstIn_Mode); - paint.setStyle(SkPaint::kFill_Style); - canvas->FillRectInt( - 0, 0, GetWidth(), - GetHeight() - 2, // Visible region that overlaps the toolbar. - paint); - } - - // Paint the selected tab last, so it overlaps all the others. - if (selected_tab) - selected_tab->ProcessPaint(canvas); - - // Paint the New Tab button. - newtab_button_->ProcessPaint(canvas); -} - -void TabStrip::DidChangeBounds(const CRect& prev, const CRect& curr) { - Layout(); -} - -// Overridden to support automation. See automation_proxy_uitest.cc. -ChromeViews::View* TabStrip::GetViewByID(int view_id) const { - if (GetTabCount() > 0) { - if (view_id == VIEW_ID_TAB_LAST) { - return GetTabAt(GetTabCount() - 1); - } else if ((view_id >= VIEW_ID_TAB_0) && (view_id < VIEW_ID_TAB_LAST)) { - int index = view_id - VIEW_ID_TAB_0; - if (index >= 0 && index < GetTabCount()) { - return GetTabAt(index); - } else { - return NULL; - } - } - } - - return View::GetViewByID(view_id); -} - -void TabStrip::Layout() { - // Called from: - // - window resize - // - animation completion - if (active_animation_.get()) - active_animation_->Stop(); - GenerateIdealBounds(); - int tab_count = GetTabCount(); - int tab_right = 0; - for (int i = 0; i < tab_count; ++i) { - const gfx::Rect& bounds = tab_data_.at(i).ideal_bounds; - GetTabAt(i)->SetBounds(bounds.x(), bounds.y(), bounds.width(), - bounds.height()); - tab_right = bounds.right() + kTabHOffset; - } - LayoutNewTabButton(static_cast<double>(tab_right), current_unselected_width_); - SchedulePaint(); -} - -void TabStrip::GetPreferredSize(CSize* preferred_size) { - DCHECK(preferred_size); - preferred_size->cx = 0; - preferred_size->cy = Tab::GetMinimumSize().height(); -} - -void TabStrip::OnDragEntered(const DropTargetEvent& event) { - UpdateDropIndex(event); -} - -int TabStrip::OnDragUpdated(const DropTargetEvent& event) { - UpdateDropIndex(event); - return GetDropEffect(event); -} - -void TabStrip::OnDragExited() { - SetDropIndex(-1, false); -} - -int TabStrip::OnPerformDrop(const DropTargetEvent& event) { - if (!drop_info_.get()) - return DragDropTypes::DRAG_NONE; - - const int drop_index = drop_info_->drop_index; - const bool drop_before = drop_info_->drop_before; - - // Hide the drop indicator. - SetDropIndex(-1, false); - - GURL url; - std::wstring title; - if (!event.GetData().GetURLAndTitle(&url, &title) || !url.is_valid()) - return DragDropTypes::DRAG_NONE; - - if (drop_before) { - UserMetrics::RecordAction(L"Tab_DropURLBetweenTabs", model_->profile()); - - // Insert a new tab. - TabContents* contents = - model_->delegate()->CreateTabContentsForURL( - url, model_->profile(), PageTransition::TYPED, false, NULL); - model_->AddTabContents(contents, drop_index, PageTransition::GENERATED, - true); - } else { - UserMetrics::RecordAction(L"Tab_DropURLOnTab", model_->profile()); - - model_->GetTabContentsAt(drop_index)->controller()-> - LoadURL(url, PageTransition::GENERATED); - model_->SelectTabContentsAt(drop_index, true); - } - - return GetDropEffect(event); -} - -bool TabStrip::GetAccessibleRole(VARIANT* role) { - DCHECK(role); - - role->vt = VT_I4; - role->lVal = ROLE_SYSTEM_GROUPING; - return true; -} - -bool TabStrip::GetAccessibleName(std::wstring* name) { - if (!accessible_name_.empty()) { - (*name).assign(accessible_name_); - return true; - } - return false; -} - -void TabStrip::SetAccessibleName(const std::wstring& name) { - accessible_name_.assign(name); -} - -ChromeViews::View* TabStrip::GetViewForPoint(const CPoint& point) { - return GetViewForPoint(point, false); -} - -ChromeViews::View* TabStrip::GetViewForPoint(const CPoint& point, - bool can_create_floating) { - // Return any view that isn't a Tab or this TabStrip immediately. We don't - // want to interfere. - ChromeViews::View* v = View::GetViewForPoint(point, can_create_floating); - if (v && v != this && v->GetClassName() != Tab::kTabClassName) - return v; - - // The display order doesn't necessarily match the child list order, so we - // walk the display list hit-testing Tabs. Since the selected tab always - // renders on top of adjacent tabs, it needs to be hit-tested before any - // left-adjacent Tab, so we look ahead for it as we walk. - int tab_count = GetTabCount(); - for (int i = 0; i < tab_count; ++i) { - Tab* next_tab = i < (tab_count - 1) ? GetTabAt(i + 1) : NULL; - if (next_tab && next_tab->IsSelected() && IsPointInTab(next_tab, point)) - return next_tab; - Tab* tab = GetTabAt(i); - if (IsPointInTab(tab, point)) - return tab; - } - - // No need to do any floating view stuff, we don't use them in the TabStrip. - return this; -} - -/////////////////////////////////////////////////////////////////////////////// -// TabStrip, TabStripModelObserver implementation: - -void TabStrip::TabInsertedAt(TabContents* contents, - int index, - bool foreground) { - DCHECK(contents); - DCHECK(index == TabStripModel::kNoTab || model_->ContainsIndex(index)); - - if (active_animation_.get()) - active_animation_->Stop(); - - bool contains_tab = false; - Tab* tab = NULL; - // First see if this Tab is one that was dragged out of this TabStrip and is - // now being dragged back in. In this case, the DraggedTabController actually - // has the Tab already constructed and we can just insert it into our list - // again. - if (IsDragSessionActive()) { - tab = drag_controller_->GetDragSourceTabForContents(contents); - if (tab) { - // If the Tab was detached, it would have been animated closed but not - // removed, so we need to reset this property. - tab->set_closing(false); - tab->ValidateLoadingAnimation(TabRenderer::ANIMATION_NONE); - tab->SetVisible(true); - } - - // See if we're already in the list. We don't want to add ourselves twice. - std::vector<TabData>::const_iterator iter = tab_data_.begin(); - for (; iter != tab_data_.end() && !contains_tab; ++iter) { - if (iter->tab == tab) - contains_tab = true; - } - } - - // Otherwise we need to make a new Tab. - if (!tab) - tab = new Tab(this); - - // Only insert if we're not already in the list. - if (!contains_tab) { - if (index == TabStripModel::kNoTab) { - TabData d = { tab, gfx::Rect() }; - tab_data_.push_back(d); - tab->UpdateData(contents); - } else { - TabData d = { tab, gfx::Rect() }; - tab_data_.insert(tab_data_.begin() + index, d); - tab->UpdateData(contents); - } - } - - // We only add the tab to the child list if it's not already - an invisible - // tab maintained by the DraggedTabController will already be parented. - if (!tab->GetParent()) - AddChildView(tab); - - // Don't animate the first tab, it looks weird, and don't animate anything - // if the containing window isn't visible yet. - if (GetTabCount() > 1 && IsWindowVisible(GetViewContainer()->GetHWND())) { - StartInsertTabAnimation(index); - } else { - Layout(); - } -} - -void TabStrip::TabDetachedAt(TabContents* contents, int index) { - if (CanUpdateDisplay()) { - GenerateIdealBounds(); - StartRemoveTabAnimation(index, contents); - // Have to do this _after_ calling StartRemoveTabAnimation, so that any - // previous remove is completed fully and index is valid in sync with the - // model index. - GetTabAt(index)->set_closing(true); - } -} - -void TabStrip::TabSelectedAt(TabContents* old_contents, - TabContents* new_contents, - int index, - bool user_gesture) { - DCHECK(index >= 0 && index < GetTabCount()); - if (CanUpdateDisplay()) { - // We have "tiny tabs" if the tabs are so tiny that the unselected ones are - // a different size to the selected ones. - bool tiny_tabs = current_unselected_width_ != current_selected_width_; - if (!IsAnimating() && (!resize_layout_scheduled_ || tiny_tabs)) { - Layout(); - } else { - SchedulePaint(); - } - } -} - -void TabStrip::TabMoved(TabContents* contents, int from_index, int to_index) { - Tab* tab = GetTabAt(from_index); - Tab* other_tab = GetTabAt(to_index); - tab_data_.erase(tab_data_.begin() + from_index); - TabData data = {tab, gfx::Rect()}; - tab_data_.insert(tab_data_.begin() + to_index, data); - GenerateIdealBounds(); - StartMoveTabAnimation(from_index, to_index); -} - -void TabStrip::TabChangedAt(TabContents* contents, int index) { - // Index is in terms of the model. Need to make sure we adjust that index in - // case we have an animation going. - Tab* tab = GetTabAtAdjustForAnimation(index); - tab->UpdateData(contents); - tab->UpdateFromModel(); -} - -void TabStrip::TabValidateAnimations() { - if (model_->TabsAreLoading()) { - if (!loading_animation_timer_.IsRunning()) { - // Loads are happening, and the timer isn't running, so start it. - loading_animation_timer_.Start( - TimeDelta::FromMilliseconds(kLoadingAnimationFrameTimeMs), this, - &TabStrip::LoadingAnimationCallback); - } - } else { - if (loading_animation_timer_.IsRunning()) { - loading_animation_timer_.Stop(); - // Loads are now complete, update the state if a task was scheduled. - LoadingAnimationCallback(); - } - } -} - -/////////////////////////////////////////////////////////////////////////////// -// TabStrip, Tab::Delegate implementation: - -bool TabStrip::IsTabSelected(const Tab* tab) const { - if (tab->closing()) - return false; - - int tab_count = GetTabCount(); - for (int i = 0, index = 0; i < tab_count; ++i, ++index) { - Tab* current_tab = GetTabAt(i); - if (current_tab->closing()) - --index; - if (current_tab == tab) - return index == model_->selected_index(); - } - return false; -} - -void TabStrip::SelectTab(Tab* tab) { - int index = GetIndexOfTab(tab); - if (model_->ContainsIndex(index)) - model_->SelectTabContentsAt(index, true); -} - -void TabStrip::CloseTab(Tab* tab) { - int tab_index = GetIndexOfTab(tab); - if (model_->ContainsIndex(tab_index)) { - TabContents* contents = model_->GetTabContentsAt(tab_index); - if (contents) - UserMetrics::RecordAction(L"CloseTab_Mouse", contents->profile()); - Tab* last_tab = GetTabAt(GetTabCount() - 1); - // Limit the width available to the TabStrip for laying out Tabs, so that - // Tabs are not resized until a later time (when the mouse pointer leaves - // the TabStrip). - available_width_for_tabs_ = GetAvailableWidthForTabs(last_tab); - resize_layout_scheduled_ = true; - AddMessageLoopObserver(); - model_->CloseTabContentsAt(tab_index); - } -} - -bool TabStrip::IsCommandEnabledForTab( - TabStripModel::ContextMenuCommand command_id, const Tab* tab) const { - int index = GetIndexOfTab(tab); - if (model_->ContainsIndex(index)) - return model_->IsContextMenuCommandEnabled(index, command_id); - return false; -} - -void TabStrip::ExecuteCommandForTab( - TabStripModel::ContextMenuCommand command_id, Tab* tab) { - int index = GetIndexOfTab(tab); - if (model_->ContainsIndex(index)) - model_->ExecuteContextMenuCommand(index, command_id); -} - -void TabStrip::StartHighlightTabsForCommand( - TabStripModel::ContextMenuCommand command_id, Tab* tab) { - if (command_id == TabStripModel::CommandCloseTabsOpenedBy) { - int index = GetIndexOfTab(tab); - if (model_->ContainsIndex(index)) { - std::vector<int> indices = model_->GetIndexesOpenedBy(index); - std::vector<int>::const_iterator iter = indices.begin(); - for (; iter != indices.end(); ++iter) { - int current_index = *iter; - DCHECK(current_index >= 0 && current_index < GetTabCount()); - Tab* current_tab = GetTabAt(current_index); - current_tab->StartPulse(); - } - } - } else if (command_id == TabStripModel::CommandCloseTabsToRight) { - int index = GetIndexOfTab(tab); - if (model_->ContainsIndex(index)) { - for (int i = index + 1; i < GetTabCount(); ++i) { - Tab* current_tab = GetTabAt(i); - current_tab->StartPulse(); - } - } - } else if (command_id == TabStripModel::CommandCloseOtherTabs) { - for (int i = 0; i < GetTabCount(); ++i) { - Tab* current_tab = GetTabAt(i); - if (current_tab != tab) - current_tab->StartPulse(); - } - } -} - -void TabStrip::StopHighlightTabsForCommand( - TabStripModel::ContextMenuCommand command_id, Tab* tab) { - if (command_id == TabStripModel::CommandCloseTabsOpenedBy || - command_id == TabStripModel::CommandCloseTabsToRight || - command_id == TabStripModel::CommandCloseOtherTabs) { - // Just tell all Tabs to stop pulsing - it's safe. - StopAllHighlighting(); - } -} - -void TabStrip::StopAllHighlighting() { - for (int i = 0; i < GetTabCount(); ++i) - GetTabAt(i)->StopPulse(); -} - -void TabStrip::MaybeStartDrag(Tab* tab, const ChromeViews::MouseEvent& event) { - // Don't accidentally start any drag operations during animations if the - // mouse is down... during an animation tabs are being resized automatically, - // so the View system can misinterpret this easily if the mouse is down that - // the user is dragging. - if (IsAnimating() || tab->closing()) - return; - drag_controller_.reset(new DraggedTabController(tab, this)); - drag_controller_->CaptureDragInfo(gfx::Point(event.GetX(), event.GetY())); -} - -void TabStrip::ContinueDrag(const ChromeViews::MouseEvent& event) { - // We can get called even if |MaybeStartDrag| wasn't called in the event of - // a TabStrip animation when the mouse button is down. In this case we should - // _not_ continue the drag because it can lead to weird bugs. - if (drag_controller_.get()) - drag_controller_->Drag(); -} - -void TabStrip::EndDrag(bool canceled) { - if (drag_controller_.get()) - drag_controller_->EndDrag(canceled); -} - -/////////////////////////////////////////////////////////////////////////////// -// TabStrip, ChromeViews::BaseButton::ButtonListener implementation: - -void TabStrip::ButtonPressed(ChromeViews::BaseButton* sender) { - if (sender == newtab_button_) - model_->AddBlankTab(true); -} - -/////////////////////////////////////////////////////////////////////////////// -// TabStrip, MessageLoop::Observer implementation: - -void TabStrip::WillProcessMessage(const MSG& msg) { -} - -void TabStrip::DidProcessMessage(const MSG& msg) { - // We spy on three different Windows messages here to see if the mouse has - // moved out of the bounds of the tabstrip, which we use as our cue to kick - // of the resize animation. The messages are: - // - // WM_MOUSEMOVE: - // For when the mouse moves from the tabstrip over into the rest of the - // browser UI, i.e. within the bounds of the same windows HWND. - // WM_MOUSELEAVE: - // For when the mouse moves very rapidly from a tab closed in the middle of - // the tabstrip (_not_ the end) out of the bounds of the browser's HWND and - // over some other HWND. - // WM_NCMOUSELEAVE: - // For when the mouse moves very rapidly from the end of the tabstrip (when - // the last tab is closed and the mouse is left floating over the title - // bar). Because the empty area of the tabstrip at the end of the title bar - // is registered by the ChromeFrame as part of the "caption" area of the - // window (the frame's OnNCHitTest method returns HTCAPTION for this - // region), the frame's HWND receives a WM_MOUSEMOVE message immediately, - // because as far as it is concerned the mouse has _left_ the client area - // of the window (and is now over the non-client area). To be notified - // again when the mouse leaves the _non-client_ area, we use the - // WM_NCMOUSELEAVE message, which causes us to re-evaluate the cursor - // position and correctly resize the tabstrip. - // - switch (msg.message) { - case WM_MOUSEMOVE: - case WM_MOUSELEAVE: - case WM_NCMOUSELEAVE: - if (!IsCursorInTabStripZone()) { - // Mouse moved outside the tab slop zone, start a timer to do a resize - // layout after a short while... - if (resize_layout_factory_.empty()) { - MessageLoop::current()->PostDelayedTask(FROM_HERE, - resize_layout_factory_.NewRunnableMethod( - &TabStrip::ResizeLayoutTabs), - kResizeTabsTimeMs); - } - } else { - // Mouse moved quickly out of the tab strip and then into it again, so - // cancel the timer so that the strip doesn't move when the mouse moves - // back over it. - resize_layout_factory_.RevokeAll(); - } - break; - } -} - -/////////////////////////////////////////////////////////////////////////////// -// TabStrip, private: - -void TabStrip::Init() { - model_->AddObserver(this); - newtab_button_ = new ChromeViews::Button; - newtab_button_->SetListener(this, TabStripModel::kNoTab); - ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - SkBitmap* bitmap; - - bitmap = rb.GetBitmapNamed(IDR_NEWTAB_BUTTON); - newtab_button_->SetImage(ChromeViews::Button::BS_NORMAL, bitmap); - newtab_button_->SetImage(ChromeViews::Button::BS_PUSHED, - rb.GetBitmapNamed(IDR_NEWTAB_BUTTON_P)); - newtab_button_->SetImage(ChromeViews::Button::BS_HOT, - rb.GetBitmapNamed(IDR_NEWTAB_BUTTON_H)); - - newtab_button_size_.SetSize(bitmap->width(), bitmap->height()); - actual_newtab_button_size_ = newtab_button_size_; - - newtab_button_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_NEWTAB)); - AddChildView(newtab_button_); - - if (drop_indicator_width == 0) { - // Direction doesn't matter, both images are the same size. - SkBitmap* drop_image = GetDropArrowImage(true); - drop_indicator_width = drop_image->width(); - drop_indicator_height = drop_image->height(); - } -} - -Tab* TabStrip::GetTabAt(int index) const { - DCHECK(index >= 0 && index < GetTabCount()); - return tab_data_.at(index).tab; -} - -Tab* TabStrip::GetTabAtAdjustForAnimation(int index) const { - if (active_animation_.get() && - active_animation_->type() == TabAnimation::REMOVE && - index >= - static_cast<RemoveTabAnimation*>(active_animation_.get())->index()) { - index++; - } - return GetTabAt(index); -} - -int TabStrip::GetTabCount() const { - return static_cast<int>(tab_data_.size()); -} - -void TabStrip::GetCurrentTabWidths(double* unselected_width, - double* selected_width) const { - *unselected_width = current_unselected_width_; - *selected_width = current_selected_width_; -} - -void TabStrip::GetDesiredTabWidths(int tab_count, - double* unselected_width, - double* selected_width) const { - const double min_unselected_width = Tab::GetMinimumSize().width(); - const double min_selected_width = Tab::GetMinimumSelectedSize().width(); - if (tab_count == 0) { - // Return immediately to avoid divide-by-zero below. - *unselected_width = min_unselected_width; - *selected_width = min_selected_width; - return; - } - - // Determine how much space we can actually allocate to tabs. - int available_width; - if (available_width_for_tabs_ < 0) { - available_width = GetWidth(); - available_width -= (kNewTabButtonHOffset + newtab_button_size_.width()); - } else { - // Interesting corner case: if |available_width_for_tabs_| > the result - // of the calculation in the conditional arm above, the strip is in - // overflow. We can either use the specified width or the true available - // width here; the first preserves the consistent "leave the last tab under - // the user's mouse so they can close many tabs" behavior at the cost of - // prolonging the glitchy appearance of the overflow state, while the second - // gets us out of overflow as soon as possible but forces the user to move - // their mouse for a few tabs' worth of closing. We choose visual - // imperfection over behavioral imperfection and select the first option. - available_width = available_width_for_tabs_; - } - - // Calculate the desired tab widths by dividing the available space into equal - // portions. Don't let tabs get larger than the "standard width" or smaller - // than the minimum width for each type, respectively. - const int total_offset = kTabHOffset * (tab_count - 1); - const double desired_tab_width = std::min((static_cast<double>( - available_width - total_offset) / static_cast<double>(tab_count)), - static_cast<double>(Tab::GetStandardSize().width())); - *unselected_width = std::max(desired_tab_width, min_unselected_width); - *selected_width = std::max(desired_tab_width, min_selected_width); - - // When there are multiple tabs, we'll have one selected and some unselected - // tabs. If the desired width was between the minimum sizes of these types, - // try to shrink the tabs with the smaller minimum. For example, if we have - // a strip of width 10 with 4 tabs, the desired width per tab will be 2.5. If - // selected tabs have a minimum width of 4 and unselected tabs have a minimum - // width of 1, the above code would set *unselected_width = 2.5, - // *selected_width = 4, which results in a total width of 11.5. Instead, we - // want to set *unselected_width = 2, *selected_width = 4, for a total width - // of 10. - if (tab_count > 1) { - if ((min_unselected_width < min_selected_width) && - (desired_tab_width < min_selected_width)) { - // Unselected width = (total width - selected width) / (num_tabs - 1) - *unselected_width = std::max(static_cast<double>( - available_width - total_offset - min_selected_width) / - static_cast<double>(tab_count - 1), min_unselected_width); - } else if ((min_unselected_width > min_selected_width) && - (desired_tab_width < min_unselected_width)) { - // Selected width = (total width - (unselected width * (num_tabs - 1))) - *selected_width = std::max(available_width - total_offset - - (min_unselected_width * (tab_count - 1)), min_selected_width); - } - } -} - -void TabStrip::ResizeLayoutTabs() { - resize_layout_factory_.RevokeAll(); - - // It is critically important that this is unhooked here, otherwise we will - // keep spying on messages forever. - RemoveMessageLoopObserver(); - - available_width_for_tabs_ = -1; - double unselected, selected; - GetDesiredTabWidths(GetTabCount(), &unselected, &selected); - Tab* first_tab = GetTabAt(0); - int w = Round(first_tab->IsSelected() ? selected : selected); - - // We only want to run the animation if we're not already at the desired - // size. - if (abs(first_tab->GetWidth() - w) > 1) - StartResizeLayoutAnimation(); -} - -bool TabStrip::IsCursorInTabStripZone() { - CRect bounds; - GetLocalBounds(&bounds, true); - CPoint tabstrip_topleft = bounds.TopLeft(); - View::ConvertPointToScreen(this, &tabstrip_topleft); - bounds.MoveToXY(tabstrip_topleft); - bounds.bottom += kTabStripAnimationVSlop; - - CPoint cursor_point; - GetCursorPos(&cursor_point); - - return !!bounds.PtInRect(cursor_point); -} - -void TabStrip::AddMessageLoopObserver() { - if (!added_as_message_loop_observer_) { - MessageLoopForUI::current()->AddObserver(this); - added_as_message_loop_observer_ = true; - } -} - -void TabStrip::RemoveMessageLoopObserver() { - if (added_as_message_loop_observer_) { - MessageLoopForUI::current()->RemoveObserver(this); - added_as_message_loop_observer_ = false; - } -} - -void TabStrip::LoadingAnimationCallback() { - for (int i = 0, index = 0; i < GetTabCount(); ++i, ++index) { - Tab* current_tab = GetTabAt(i); - if (current_tab->closing()) { - --index; - } else { - TabContents* contents = model_->GetTabContentsAt(index); - if (!contents || !contents->is_loading()) { - current_tab->ValidateLoadingAnimation(Tab::ANIMATION_NONE); - } else if (contents->response_started()) { - current_tab->ValidateLoadingAnimation(Tab::ANIMATION_WAITING); - } else { - current_tab->ValidateLoadingAnimation(Tab::ANIMATION_LOADING); - } - } - } - - // Make sure the model delegates updates the animation as well. - TabStripModelDelegate* delegate; - if (model_ && (delegate = model_->delegate())) - delegate->ValidateLoadingAnimations(); -} - -gfx::Rect TabStrip::GetDropBounds(int drop_index, - bool drop_before, - bool* is_beneath) { - DCHECK(drop_index != -1); - int center_x; - if (drop_index < GetTabCount()) { - Tab* tab = GetTabAt(drop_index); - if (drop_before) - center_x = tab->GetX() - (kTabHOffset / 2); - else - center_x = tab->GetX() + (tab->GetWidth() / 2); - } else { - Tab* last_tab = GetTabAt(drop_index - 1); - center_x = last_tab->GetX() + last_tab->GetWidth() + (kTabHOffset / 2); - } - - // Mirror the center point if necessary. - center_x = MirroredXCoordinateInsideView(center_x); - - // Determine the screen bounds. - CPoint drop_loc(center_x - drop_indicator_width / 2, -drop_indicator_height); - ConvertPointToScreen(this, &drop_loc); - gfx::Rect drop_bounds(drop_loc.x, drop_loc.y, drop_indicator_width, - drop_indicator_height); - - // If the rect doesn't fit on the monitor, push the arrow to the bottom. - gfx::Rect monitor_bounds = win_util::GetMonitorBoundsForRect(drop_bounds); - *is_beneath = (monitor_bounds.IsEmpty() || - !monitor_bounds.Contains(drop_bounds)); - if (*is_beneath) - drop_bounds.Offset(0, drop_bounds.height() + GetHeight()); - - return drop_bounds; -} - -void TabStrip::UpdateDropIndex(const DropTargetEvent& event) { - // If the UI layout is right-to-left, we need to mirror the mouse - // coordinates since we calculate the drop index based on the - // original (and therefore non-mirrored) positions of the tabs. - const int x = MirroredXCoordinateInsideView(event.GetX()); - for (int i = 0; i < GetTabCount(); ++i) { - Tab* tab = GetTabAt(i); - const int tab_max_x = tab->GetX() + tab->GetWidth(); - const int hot_width = tab->GetWidth() / 3; - if (x < tab_max_x) { - if (x < tab->GetX() + hot_width) - SetDropIndex(i, true); - else if (x >= tab_max_x - hot_width) - SetDropIndex(i + 1, true); - else - SetDropIndex(i, false); - return; - } - } - - // The drop isn't over a tab, add it to the end. - SetDropIndex(GetTabCount(), true); -} - -void TabStrip::SetDropIndex(int index, bool drop_before) { - if (index == -1) { - if (drop_info_.get()) - drop_info_.reset(NULL); - return; - } - - if (drop_info_.get() && drop_info_->drop_index == index && - drop_info_->drop_before == drop_before) { - return; - } - - bool is_beneath; - gfx::Rect drop_bounds = GetDropBounds(index, drop_before, &is_beneath); - - if (!drop_info_.get()) { - drop_info_.reset(new DropInfo(index, drop_before, !is_beneath)); - } else { - drop_info_->drop_index = index; - drop_info_->drop_before = drop_before; - if (is_beneath == drop_info_->point_down) { - drop_info_->point_down = !is_beneath; - drop_info_->arrow_view->SetImage( - GetDropArrowImage(drop_info_->point_down)); - } - } - - // Reposition the window. Need to show it too as the window is initially - // hidden. - - drop_info_->arrow_window->SetWindowPos( - HWND_TOPMOST, drop_bounds.x(), drop_bounds.y(), drop_bounds.width(), - drop_bounds.height(), SWP_NOACTIVATE | SWP_SHOWWINDOW); -} - -int TabStrip::GetDropEffect(const ChromeViews::DropTargetEvent& event) { - const int source_ops = event.GetSourceOperations(); - if (source_ops & DragDropTypes::DRAG_COPY) - return DragDropTypes::DRAG_COPY; - if (source_ops & DragDropTypes::DRAG_LINK) - return DragDropTypes::DRAG_LINK; - return DragDropTypes::DRAG_MOVE; -} - -// static -SkBitmap* TabStrip::GetDropArrowImage(bool is_down) { - return ResourceBundle::GetSharedInstance().GetBitmapNamed( - is_down ? IDR_TAB_DROP_DOWN : IDR_TAB_DROP_UP); -} - -// TabStrip::DropInfo ---------------------------------------------------------- - -TabStrip::DropInfo::DropInfo(int drop_index, bool drop_before, bool point_down) - : drop_index(drop_index), - drop_before(drop_before), - point_down(point_down) { - arrow_window = new ChromeViews::HWNDViewContainer(); - arrow_window->set_window_style(WS_POPUP); - arrow_window->set_window_ex_style(WS_EX_TOPMOST | WS_EX_NOACTIVATE | - WS_EX_LAYERED | WS_EX_TRANSPARENT); - - arrow_view = new ChromeViews::ImageView; - arrow_view->SetImage(GetDropArrowImage(point_down)); - - arrow_window->Init( - NULL, - gfx::Rect(0, 0, drop_indicator_width, drop_indicator_height), - true); - arrow_window->SetContentsView(arrow_view); -} - -TabStrip::DropInfo::~DropInfo() { - // Close eventually deletes the window, which deletes arrow_view too. - arrow_window->Close(); -} - -/////////////////////////////////////////////////////////////////////////////// - -// Called from: -// - BasicLayout -// - Tab insertion/removal -// - Tab reorder -void TabStrip::GenerateIdealBounds() { - int tab_count = GetTabCount(); - double unselected, selected; - GetDesiredTabWidths(tab_count, &unselected, &selected); - - current_unselected_width_ = unselected; - current_selected_width_ = selected; - - // NOTE: This currently assumes a tab's height doesn't differ based on - // selected state or the number of tabs in the strip! - int tab_height = Tab::GetStandardSize().height(); - double tab_x = 0; - for (int i = 0; i < tab_count; ++i) { - Tab* tab = GetTabAt(i); - double tab_width = unselected; - if (tab->IsSelected()) - tab_width = selected; - double end_of_tab = tab_x + tab_width; - int rounded_tab_x = Round(tab_x); - gfx::Rect state(rounded_tab_x, 0, Round(end_of_tab) - rounded_tab_x, - tab_height); - tab_data_.at(i).ideal_bounds = state; - tab_x = end_of_tab + kTabHOffset; - } -} - -void TabStrip::LayoutNewTabButton(double last_tab_right, - double unselected_width) { - int delta = abs(Round(unselected_width) - Tab::GetStandardSize().width()); - if (delta > 1 && !resize_layout_scheduled_) { - // We're shrinking tabs, so we need to anchor the New Tab button to the - // right edge of the TabStrip's bounds, rather than the right edge of the - // right-most Tab, otherwise it'll bounce when animating. - newtab_button_->SetBounds(GetWidth() - newtab_button_size_.width(), - kNewTabButtonVOffset, - newtab_button_size_.width(), - newtab_button_size_.height()); - } else { - newtab_button_->SetBounds( - Round(last_tab_right - kTabHOffset) + kNewTabButtonHOffset, - kNewTabButtonVOffset, newtab_button_size_.width(), - newtab_button_size_.height()); - } -} - -// Called from: -// - animation tick -void TabStrip::AnimationLayout(double unselected_width) { - int tab_height = Tab::GetStandardSize().height(); - double tab_x = 0; - for (int i = 0; i < GetTabCount(); ++i) { - TabAnimation* animation = active_animation_.get(); - double tab_width = TabAnimation::GetCurrentTabWidth(this, animation, i); - double end_of_tab = tab_x + tab_width; - int rounded_tab_x = Round(tab_x); - Tab* tab = GetTabAt(i); - tab->SetBounds(rounded_tab_x, 0, Round(end_of_tab) - rounded_tab_x, - tab_height); - tab_x = end_of_tab + kTabHOffset; - } - LayoutNewTabButton(tab_x, unselected_width); - SchedulePaint(); -} - -void TabStrip::StartResizeLayoutAnimation() { - if (active_animation_.get()) - active_animation_->Stop(); - active_animation_.reset(new ResizeLayoutAnimation(this)); - active_animation_->Start(); -} - -void TabStrip::StartInsertTabAnimation(int index) { - // The TabStrip can now use its entire width to lay out Tabs. - available_width_for_tabs_ = -1; - if (active_animation_.get()) - active_animation_->Stop(); - active_animation_.reset(new InsertTabAnimation(this, index)); - active_animation_->Start(); -} - -void TabStrip::StartRemoveTabAnimation(int index, TabContents* contents) { - if (active_animation_.get()) { - // Some animations (e.g. MoveTabAnimation) cause there to be a Layout when - // they're completed (which includes canceled). Since |tab_data_| is now - // inconsistent with TabStripModel, doing this Layout will crash now, so - // we ask the MoveTabAnimation to skip its Layout (the state will be - // corrected by the RemoveTabAnimation we're about to initiate). - active_animation_->set_layout_on_completion(false); - active_animation_->Stop(); - } - active_animation_.reset(new RemoveTabAnimation(this, index, contents)); - active_animation_->Start(); -} - -void TabStrip::StartMoveTabAnimation(int from_index, int to_index) { - if (active_animation_.get()) - active_animation_->Stop(); - active_animation_.reset(new MoveTabAnimation(this, from_index, to_index)); - active_animation_->Start(); -} - -bool TabStrip::CanUpdateDisplay() { - // Don't bother laying out/painting when we're closing all tabs. - if (model_->closing_all()) { - // Make sure any active animation is ended, too. - if (active_animation_.get()) - active_animation_->Stop(); - return false; - } - return true; -} - -void TabStrip::FinishAnimation(TabStrip::TabAnimation* animation, - bool layout) { - active_animation_.reset(NULL); - if (layout) - Layout(); -} - -int TabStrip::GetIndexOfTab(const Tab* tab) const { - for (int i = 0, index = 0; i < GetTabCount(); ++i, ++index) { - Tab* current_tab = GetTabAt(i); - if (current_tab->closing()) { - --index; - } else if (current_tab == tab) { - return index; - } - } - return -1; -} - -int TabStrip::GetAvailableWidthForTabs(Tab* last_tab) const { - return last_tab->GetX() + last_tab->GetWidth(); -} - -bool TabStrip::IsPointInTab(Tab* tab, const CPoint& point_in_tabstrip_coords) { - CPoint point_in_tab_coords(point_in_tabstrip_coords); - View::ConvertPointToView(this, tab, &point_in_tab_coords); - return tab->HitTest(point_in_tab_coords); -} - diff --git a/chrome/browser/tabs/tab_strip.h b/chrome/browser/tabs/tab_strip.h deleted file mode 100644 index 11f6f64..0000000 --- a/chrome/browser/tabs/tab_strip.h +++ /dev/null @@ -1,373 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_TABS_TAB_STRIP_H__ -#define CHROME_BROWSER_TABS_TAB_STRIP_H__ - -#include "base/gfx/point.h" -#include "chrome/browser/tabs/tab.h" -#include "chrome/browser/tabs/tab_strip_model.h" -#include "chrome/views/button.h" -#include "chrome/views/hwnd_view_container.h" -#include "chrome/views/menu.h" -#include "chrome/views/view.h" - -class DraggedTabController; -class ScopedMouseCloseWidthCalculator; -class TabStripModel; - -namespace ChromeViews { -class ImageView; -} - -/////////////////////////////////////////////////////////////////////////////// -// -// TabStrip -// -// A View that represents the TabStripModel. The TabStrip has the -// following responsibilities: -// - It implements the TabStripModelObserver interface, and acts as a -// container for Tabs, and is also responsible for creating them. -// - It takes part in Tab Drag & Drop with Tab, TabDragHelper and -// DraggedTab, focusing on tasks that require reshuffling other tabs -// in response to dragged tabs. -// -/////////////////////////////////////////////////////////////////////////////// -class TabStrip : public ChromeViews::View, - public TabStripModelObserver, - public Tab::TabDelegate, - public ChromeViews::Button::ButtonListener, - public MessageLoopForUI::Observer { - public: - TabStrip(TabStripModel* model); - virtual ~TabStrip(); - - // Returns the preferred height of this TabStrip. This is based on the - // typical height of its constituent tabs. - int GetPreferredHeight(); - - // Returns true if the associated TabStrip's delegate supports tab moving or - // detaching. Used by the Frame to determine if dragging on the Tab - // itself should move the window in cases where there's only one - // non drag-able Tab. - bool HasAvailableDragActions() const; - - // Ask the delegate to show the application menu at the provided point. - // The point is in screen coordinate system. - void ShowApplicationMenu(const gfx::Point& p); - - // Returns true if the TabStrip can accept input events. This returns false - // when the TabStrip is animating to a new state and as such the user should - // not be allowed to interact with the TabStrip. - bool CanProcessInputEvents() const; - - // Returns true if the specified point (in TabStrip coordinates) is within a - // portion of the TabStrip that should be treated as the containing Window's - // titlebar for dragging purposes. - // TODO(beng): (Cleanup) should be const, but GetViewForPoint isn't, so fie! - bool PointIsWithinWindowCaption(const CPoint& point); - - // Return true if this tab strip is compatible with the provided tab strip. - // Compatible tab strips can transfer tabs during drag and drop. - bool IsCompatibleWith(TabStrip* other); - - // Returns true if Tabs in this TabStrip are currently changing size or - // position. - bool IsAnimating() const; - - // Accessors for the model and individual Tabs. - TabStripModel* model() { return model_; } - - // Returns true if there is an active drag session. - bool IsDragSessionActive() const { return drag_controller_.get() != NULL; } - - // Aborts any active drag session. This is called from XP/VistaFrame's - // end session handler to make sure there are no drag sessions in flight that - // could prevent the frame from being closed right away. - void AbortActiveDragSession() { EndDrag(true); } - - // Destroys the active drag controller. - void DestroyDragController(); - - // Removes the drag source Tab from this TabStrip, and deletes it. - void DestroyDraggedSourceTab(Tab* tab); - - // Retrieve the ideal bounds for the Tab at the specified index. - gfx::Rect GetIdealBounds(int index); - - // ChromeViews::View overrides: - virtual void PaintChildren(ChromeCanvas* canvas); - virtual void DidChangeBounds(const CRect& previous, const CRect& current); - virtual ChromeViews::View* GetViewByID(int id) const; - virtual void Layout(); - virtual void GetPreferredSize(CSize* preferred_size); - // NOTE: the drag and drop methods are invoked from FrameView. This is done to - // allow for a drop region that extends outside the bounds of the TabStrip. - virtual void OnDragEntered(const ChromeViews::DropTargetEvent& event); - virtual int OnDragUpdated(const ChromeViews::DropTargetEvent& event); - virtual void OnDragExited(); - virtual int OnPerformDrop(const ChromeViews::DropTargetEvent& event); - virtual bool GetAccessibleRole(VARIANT* role); - virtual bool GetAccessibleName(std::wstring* name); - virtual void SetAccessibleName(const std::wstring& name); - virtual ChromeViews::View* GetViewForPoint(const CPoint& point); - virtual ChromeViews::View* GetViewForPoint(const CPoint& point, - bool can_create_floating); - - protected: - // TabStripModelObserver implementation: - virtual void TabInsertedAt(TabContents* contents, - int index, - bool foreground); - virtual void TabDetachedAt(TabContents* contents, int index); - virtual void TabSelectedAt(TabContents* old_contents, - TabContents* contents, - int index, - bool user_gesture); - virtual void TabMoved(TabContents* contents, int from_index, int to_index); - virtual void TabChangedAt(TabContents* contents, int index); - virtual void TabValidateAnimations(); - - // Tab::Delegate implementation: - virtual bool IsTabSelected(const Tab* tab) const; - virtual void SelectTab(Tab* tab); - virtual void CloseTab(Tab* tab); - virtual bool IsCommandEnabledForTab( - TabStripModel::ContextMenuCommand command_id, const Tab* tab) const; - virtual void ExecuteCommandForTab( - TabStripModel::ContextMenuCommand command_id, Tab* tab); - virtual void StartHighlightTabsForCommand( - TabStripModel::ContextMenuCommand command_id, Tab* tab); - virtual void StopHighlightTabsForCommand( - TabStripModel::ContextMenuCommand command_id, Tab* tab); - virtual void StopAllHighlighting(); - virtual void MaybeStartDrag(Tab* tab, - const ChromeViews::MouseEvent& event); - virtual void ContinueDrag(const ChromeViews::MouseEvent& event); - virtual void EndDrag(bool canceled); - - // ChromeViews::Button::ButtonListener implementation: - virtual void ButtonPressed(ChromeViews::BaseButton* sender); - - // MessageLoop::Observer implementation: - virtual void WillProcessMessage(const MSG& msg); - virtual void DidProcessMessage(const MSG& msg); - - private: - friend class DraggedTabController; - friend class InsertTabAnimation; - friend class MoveTabAnimation; - friend class RemoveTabAnimation; - friend class ResizeLayoutAnimation; - friend class SuspendAnimationsTask; - friend class TabAnimation; - - TabStrip(); - void Init(); - - // Retrieves the Tab at the specified index. Take care in using this, you may - // need to use GetTabAtAdjustForAnimation. - Tab* GetTabAt(int index) const; - - // Returns the tab at the specified index. If a remove animation is on going - // and the index is >= the index of the tab being removed, the index is - // incremented. While a remove operation is on going the indices of the model - // do not line up with the indices of the view. This method adjusts the index - // accordingly. - // - // Use this instead of GetTabAt if the index comes from the model. - Tab* GetTabAtAdjustForAnimation(int index) const; - - // Gets the number of Tabs in the collection. - int GetTabCount() const; - - // -- Tab Resize Layout ----------------------------------------------------- - - // Returns the exact (unrounded) current width of each tab. - void GetCurrentTabWidths(double* unselected_width, - double* selected_width) const; - - // Returns the exact (unrounded) desired width of each tab, based on the - // desired strip width and number of tabs. If - // |width_of_tabs_for_mouse_close_| is nonnegative we use that value in - // calculating the desired strip width; otherwise we use the current width. - void GetDesiredTabWidths(int tab_count, - double* unselected_width, - double* selected_width) const; - - // Perform an animated resize-relayout of the TabStrip immediately. - void ResizeLayoutTabs(); - - // Returns whether or not the cursor is currently in the "tab strip zone" - // which is defined as the region above the TabStrip and a bit below it. - // Note: this method cannot be const because |ConvertPointToScreen| is not. - // #@*($&(#!!! - bool IsCursorInTabStripZone(); - - // Ensure that the message loop observer used for event spying is added and - // removed appropriately so we can tell when to resize layout the tab strip. - void AddMessageLoopObserver(); - void RemoveMessageLoopObserver(); - - // Called to update the frame of the Loading animations. - void LoadingAnimationCallback(); - - // -- Link Drag & Drop ------------------------------------------------------ - - // Returns the bounds to render the drop at, in screen coordinates. Sets - // |is_beneath| to indicate whether the arrow is beneath the tab, or above - // it. - gfx::Rect GetDropBounds(int drop_index, bool drop_before, bool* is_beneath); - - // Updates the location of the drop based on the event. - void UpdateDropIndex(const ChromeViews::DropTargetEvent& event); - - // Sets the location of the drop, repainting as necessary. - void SetDropIndex(int index, bool drop_before); - - // Returns the drop effect for dropping a URL on the tab strip. This does - // not query the data in anyway, it only looks at the source operations. - int GetDropEffect(const ChromeViews::DropTargetEvent& event); - - // Returns the image to use for indicating a drop on a tab. If is_down is - // true, this returns an arrow pointing down. - static SkBitmap* GetDropArrowImage(bool is_down); - - // -- Animations ------------------------------------------------------------ - - // Generates the ideal bounds of the TabStrip when all Tabs have finished - // animating to their desired position/bounds. This is used by the standard - // Layout method and other callers like the DraggedTabController that need - // stable representations of Tab positions. - void GenerateIdealBounds(); - - // Lays out the New Tab button, assuming the right edge of the last Tab on - // the TabStrip at |last_tab_right|. - void LayoutNewTabButton(double last_tab_right, double unselected_width); - - // A generic Layout method for various classes of TabStrip animations, - // including Insert, Remove and Resize Layout cases/ - void AnimationLayout(double unselected_width); - - // Starts various types of TabStrip animations. - void StartResizeLayoutAnimation(); - void StartInsertTabAnimation(int index); - void StartRemoveTabAnimation(int index, TabContents* contents); - void StartMoveTabAnimation(int from_index, int to_index); - - // Returns true if detach or select changes in the model should be reflected - // in the TabStrip. This returns false if we're closing all tabs in the - // TabStrip and so we should prevent updating. This is not const because we - // use this as a signal to cancel any active animations. - bool CanUpdateDisplay(); - - // Notifies the TabStrip that the specified TabAnimation has completed. - // Optionally a full Layout will be performed, specified by |layout|. - class TabAnimation; - void FinishAnimation(TabAnimation* animation, bool layout); - - // Finds the index of the TabContents corresponding to |tab| in our - // associated TabStripModel, or -1 if there is none (e.g. the specified |tab| - // is being animated closed). - int GetIndexOfTab(const Tab* tab) const; - - // Calculates the available width for tabs, assuming a Tab is to be closed. - int GetAvailableWidthForTabs(Tab* last_tab) const; - - // Returns true if the specified point in TabStrip coords is within the - // hit-test region of the specified Tab. - bool IsPointInTab(Tab* tab, const CPoint& point_in_tabstrip_coords); - - // -- Member Variables ------------------------------------------------------ - - // Our model. - TabStripModel* model_; - - // A factory that is used to construct a delayed callback to the - // ResizeLayoutTabsNow method. - ScopedRunnableMethodFactory<TabStrip> resize_layout_factory_; - - // True if the TabStrip has already been added as a MessageLoop observer. - bool added_as_message_loop_observer_; - - // True if a resize layout animation should be run a short delay after the - // mouse exits the TabStrip. - // TODO(beng): (Cleanup) this would be better named "needs_resize_layout_". - bool resize_layout_scheduled_; - - // The timer used to update frames for the Loading Animation. - base::RepeatingTimer<TabStrip> loading_animation_timer_; - - // The "New Tab" button. - ChromeViews::Button* newtab_button_; - gfx::Size newtab_button_size_; - gfx::Size actual_newtab_button_size_; - - // The current widths of various types of tabs. We save these so that, as - // users close tabs while we're holding them at the same size, we can lay out - // tabs exactly and eliminate the "pixel jitter" we'd get from just leaving - // them all at their existing, rounded widths. - double current_unselected_width_; - double current_selected_width_; - - // If this value is nonnegative, it is used in GetDesiredTabWidths() to - // calculate how much space in the tab strip to use for tabs. Most of the - // time this will be -1, but while we're handling closing a tab via the mouse, - // we'll set this to the edge of the last tab before closing, so that if we - // are closing the last tab and need to resize immediately, we'll resize only - // back to this width, thus once again placing the last tab under the mouse - // cursor. - int available_width_for_tabs_; - - // Storage of strings needed for accessibility. - std::wstring accessible_name_; - - // Used during a drop session of a url. Tracks the position of the drop as - // well as a window used to highlight where the drop occurs. - struct DropInfo { - DropInfo(int index, bool drop_before, bool paint_down); - ~DropInfo(); - - // Index of the tab to drop on. If drop_before is true, the drop should - // occur between the tab at drop_index - 1 and drop_index. - // WARNING: if drop_before is true it is possible this will == tab_count, - // which indicates the drop should create a new tab at the end of the tabs. - int drop_index; - bool drop_before; - - // Direction the arrow should point in. If true, the arrow is displayed - // above the tab and points down. If false, the arrow is displayed beneath - // the tab and points up. - bool point_down; - - // Renders the drop indicator. - ChromeViews::HWNDViewContainer* arrow_window; - ChromeViews::ImageView* arrow_view; - - private: - DISALLOW_EVIL_CONSTRUCTORS(DropInfo); - }; - - // Valid for the lifetime of a drag over us. - scoped_ptr<DropInfo> drop_info_; - - // The controller for a drag initiated from a Tab. Valid for the lifetime of - // the drag session. - scoped_ptr<DraggedTabController> drag_controller_; - - // The Tabs we contain, and their last generated "good" bounds. - struct TabData { - Tab* tab; - gfx::Rect ideal_bounds; - }; - std::vector<TabData> tab_data_; - - // The currently running animation. - scoped_ptr<TabAnimation> active_animation_; - - DISALLOW_EVIL_CONSTRUCTORS(TabStrip); -}; - -#endif // CHROME_BROWSER_TABS_TAB_STRIP_H__ - |