diff options
Diffstat (limited to 'chrome/browser/views/tabs/tab.cc')
-rw-r--r-- | chrome/browser/views/tabs/tab.cc | 610 |
1 files changed, 0 insertions, 610 deletions
diff --git a/chrome/browser/views/tabs/tab.cc b/chrome/browser/views/tabs/tab.cc deleted file mode 100644 index dda22fb..0000000 --- a/chrome/browser/views/tabs/tab.cc +++ /dev/null @@ -1,610 +0,0 @@ -// Copyright (c) 2010 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/views/tabs/tab.h" - -#include <limits> - -#include "app/multi_animation.h" -#include "app/resource_bundle.h" -#include "app/slide_animation.h" -#include "app/throb_animation.h" -#include "base/utf_string_conversions.h" -#include "chrome/browser/defaults.h" -#include "chrome/browser/themes/browser_theme_provider.h" -#include "gfx/canvas_skia.h" -#include "gfx/favicon_size.h" -#include "gfx/font.h" -#include "gfx/path.h" -#include "gfx/skbitmap_operations.h" -#include "grit/app_resources.h" -#include "grit/generated_resources.h" -#include "grit/theme_resources.h" -#include "third_party/skia/include/effects/SkGradientShader.h" -#include "views/controls/button/image_button.h" -#include "views/widget/tooltip_manager.h" -#include "views/widget/widget.h" -#include "views/window/non_client_view.h" -#include "views/window/window.h" - -static const int kLeftPadding = 16; -static const int kTopPadding = 6; -static const int kRightPadding = 15; -static const int kBottomPadding = 5; -static const int kDropShadowHeight = 2; -static const int kToolbarOverlap = 1; -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; - -// Vertical adjustment to the favicon when the tab has a large icon. -static const int kAppTapFaviconVerticalAdjustment = 2; - -// When a non-mini-tab becomes a mini-tab the width of the tab animates. If -// the width of a mini-tab is >= kMiniTabRendererAsNormalTabWidth then the tab -// is rendered as a normal tab. This is done to avoid having the title -// immediately disappear when transitioning a tab from normal to mini-tab. -static const int kMiniTabRendererAsNormalTabWidth = - browser_defaults::kMiniTabWidth + 30; - -// How opaque to make the hover state (out of 1). -static const double kHoverOpacity = 0.33; - -Tab::TabImage Tab::tab_alpha = {0}; -Tab::TabImage Tab::tab_active = {0}; -Tab::TabImage Tab::tab_inactive = {0}; - -// Durations for the various parts of the mini tab title animation. -static const int kMiniTitleChangeAnimationDuration1MS = 1600; -static const int kMiniTitleChangeAnimationStart1MS = 0; -static const int kMiniTitleChangeAnimationEnd1MS = 1900; -static const int kMiniTitleChangeAnimationDuration2MS = 0; -static const int kMiniTitleChangeAnimationDuration3MS = 550; -static const int kMiniTitleChangeAnimationStart3MS = 150; -static const int kMiniTitleChangeAnimationEnd3MS = 800; - -// Offset from the right edge for the start of the mini title change animation. -static const int kMiniTitleChangeInitialXOffset = 6; - -// Radius of the radial gradient used for mini title change animation. -static const int kMiniTitleChangeGradientRadius = 20; - -// Colors of the gradient used during the mini title change animation. -static const SkColor kMiniTitleChangeGradientColor1 = SK_ColorWHITE; -static const SkColor kMiniTitleChangeGradientColor2 = - SkColorSetARGB(0, 255, 255, 255); - -// Hit mask constants. -static const SkScalar kTabCapWidth = 15; -static const SkScalar kTabTopCurveWidth = 4; -static const SkScalar kTabBottomCurveWidth = 3; - -namespace { - -void InitTabResources() { - static bool initialized = false; - if (initialized) - return; - - initialized = true; - Tab::LoadTabImages(); -} - -} // namespace - -// static -const char Tab::kViewClassName[] = "browser/tabs/Tab"; - -//////////////////////////////////////////////////////////////////////////////// -// Tab, public: - -Tab::Tab(TabController* controller) - : BaseTab(controller), - showing_icon_(false), - showing_close_button_(false), - close_button_color_(NULL) { - InitTabResources(); -} - -Tab::~Tab() { -} - -void Tab::StartMiniTabTitleAnimation() { - if (!mini_title_animation_.get()) { - MultiAnimation::Parts parts; - parts.push_back(MultiAnimation::Part(kMiniTitleChangeAnimationDuration1MS, - Tween::EASE_OUT)); - parts.push_back(MultiAnimation::Part(kMiniTitleChangeAnimationDuration2MS, - Tween::ZERO)); - parts.push_back(MultiAnimation::Part(kMiniTitleChangeAnimationDuration3MS, - Tween::EASE_IN)); - parts[0].start_time_ms = kMiniTitleChangeAnimationStart1MS; - parts[0].end_time_ms = kMiniTitleChangeAnimationEnd1MS; - parts[2].start_time_ms = kMiniTitleChangeAnimationStart3MS; - parts[2].end_time_ms = kMiniTitleChangeAnimationEnd3MS; - mini_title_animation_.reset(new MultiAnimation(parts)); - mini_title_animation_->SetContainer(animation_container()); - mini_title_animation_->set_delegate(this); - } - mini_title_animation_->Start(); -} - -void Tab::StopMiniTabTitleAnimation() { - if (mini_title_animation_.get()) - mini_title_animation_->Stop(); -} - -void Tab::PaintIcon(gfx::Canvas* canvas) { - BaseTab::PaintIcon(canvas, favicon_bounds_.x(), favicon_bounds_.y()); -} - -// static -gfx::Size Tab::GetMinimumUnselectedSize() { - InitTabResources(); - - 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.image_l->height()); - return minimum_size; -} - -// static -gfx::Size Tab::GetMinimumSelectedSize() { - gfx::Size minimum_size = GetMinimumUnselectedSize(); - minimum_size.set_width(kLeftPadding + kFavIconSize + kRightPadding); - return minimum_size; -} - -// static -gfx::Size Tab::GetStandardSize() { - gfx::Size standard_size = GetMinimumUnselectedSize(); - standard_size.set_width( - standard_size.width() + kFavIconTitleSpacing + kStandardTitleWidth); - return standard_size; -} - -// static -int Tab::GetMiniWidth() { - return browser_defaults::kMiniTabWidth; -} - -//////////////////////////////////////////////////////////////////////////////// -// Tab, protected: - -void Tab::DataChanged(const TabRendererData& old) { - if (data().blocked == old.blocked) - return; - - if (data().blocked) - StartPulse(); - else - StopPulse(); -} - -//////////////////////////////////////////////////////////////////////////////// -// Tab, views::View overrides: - -void Tab::Paint(gfx::Canvas* canvas) { - // Don't paint if we're narrower than we can render correctly. (This should - // only happen during animations). - if (width() < GetMinimumUnselectedSize().width() && !data().mini) - return; - - // See if the model changes whether the icons should be painted. - const bool show_icon = ShouldShowIcon(); - const bool show_close_button = ShouldShowCloseBox(); - if (show_icon != showing_icon_ || show_close_button != showing_close_button_) - Layout(); - - PaintTabBackground(canvas); - - SkColor title_color = GetThemeProvider()-> - GetColor(IsSelected() ? - BrowserThemeProvider::COLOR_TAB_TEXT : - BrowserThemeProvider::COLOR_BACKGROUND_TAB_TEXT); - - if (!data().mini || width() > kMiniTabRendererAsNormalTabWidth) - PaintTitle(canvas, title_color); - - if (show_icon) - PaintIcon(canvas); - - // If the close button color has changed, generate a new one. - if (!close_button_color_ || title_color != close_button_color_) { - close_button_color_ = title_color; - ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - close_button()->SetBackground(close_button_color_, - rb.GetBitmapNamed(IDR_TAB_CLOSE), - rb.GetBitmapNamed(IDR_TAB_CLOSE_MASK)); - } -} - -void Tab::Layout() { - gfx::Rect lb = GetLocalBounds(false); - if (lb.IsEmpty()) - return; - lb.Inset(kLeftPadding, kTopPadding, kRightPadding, kBottomPadding); - - // 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, font_height()); - gfx::Size close_button_size(close_button()->GetPreferredSize()); - content_height = std::max(content_height, close_button_size.height()); - - // Size the Favicon. - showing_icon_ = ShouldShowIcon(); - if (showing_icon_) { - // Use the size of the favicon as apps use a bigger favicon size. - int favicon_size = - !data().favicon.empty() ? data().favicon.width() : kFavIconSize; - int favicon_top = kTopPadding + content_height / 2 - favicon_size / 2; - int favicon_left = lb.x(); - if (favicon_size != kFavIconSize) { - favicon_left -= (favicon_size - kFavIconSize) / 2; - favicon_top -= kAppTapFaviconVerticalAdjustment; - } - favicon_bounds_.SetRect(favicon_left, favicon_top, - favicon_size, favicon_size); - if (data().mini && width() < kMiniTabRendererAsNormalTabWidth) { - // Adjust the location of the favicon when transitioning from a normal - // tab to a mini-tab. - int mini_delta = kMiniTabRendererAsNormalTabWidth - GetMiniWidth(); - int ideal_delta = width() - GetMiniWidth(); - if (ideal_delta < mini_delta) { - int ideal_x = (GetMiniWidth() - favicon_size) / 2; - int x = favicon_bounds_.x() + static_cast<int>( - (1 - static_cast<float>(ideal_delta) / - static_cast<float>(mini_delta)) * - (ideal_x - favicon_bounds_.x())); - favicon_bounds_.set_x(x); - } - } - } else { - favicon_bounds_.SetRect(lb.x(), lb.y(), 0, 0); - } - - // Size the Close button. - showing_close_button_ = ShouldShowCloseBox(); - if (showing_close_button_) { - int close_button_top = kTopPadding + kCloseButtonVertFuzz + - (content_height - close_button_size.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_size.width(), - close_button_size.height()); - close_button()->SetVisible(true); - } else { - close_button()->SetBounds(0, 0, 0, 0); - close_button()->SetVisible(false); - } - - int title_left = favicon_bounds_.right() + kFavIconTitleSpacing; - int title_top = kTopPadding + (content_height - font_height()) / 2; - // Size the Title text to fill the remaining space. - if (!data().mini || width() >= kMiniTabRendererAsNormalTabWidth) { - // 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 = GetMinimumUnselectedSize(); - int text_height = title_top + 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()->x() - - kTitleCloseButtonSpacing - title_left, 0); - } else { - title_width = std::max(lb.width() - title_left, 0); - } - title_bounds_.SetRect(title_left, title_top, title_width, font_height()); - } else { - title_bounds_.SetRect(title_left, title_top, 0, 0); - } - - // Certain UI elements within the Tab (the favicon, 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 views::Button - // instance) are automatically mirrored by the mirroring infrastructure in - // views. The elements Tab draws directly on the canvas need to be manually - // mirrored if the View's layout is right-to-left. - title_bounds_.set_x(MirroredLeftPointForRect(title_bounds_)); -} - -void Tab::OnThemeChanged() { - Tab::LoadTabImages(); -} - -bool Tab::HasHitTestMask() const { - return true; -} - -void Tab::GetHitTestMask(gfx::Path* path) const { - DCHECK(path); - - SkScalar h = SkIntToScalar(height()); - SkScalar w = SkIntToScalar(width()); - - 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(); -} - -bool Tab::GetTooltipTextOrigin(const gfx::Point& p, gfx::Point* origin) { - origin->set_x(title_bounds().x() + 10); - origin->set_y(-views::TooltipManager::GetTooltipHeight() - 4); - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// Tab, private - -void Tab::PaintTabBackground(gfx::Canvas* canvas) { - if (IsSelected()) { - PaintActiveTabBackground(canvas); - } else { - if (mini_title_animation_.get() && mini_title_animation_->is_animating()) - PaintInactiveTabBackgroundWithTitleChange(canvas); - else - PaintInactiveTabBackground(canvas); - - double throb_value = GetThrobValue(); - if (throb_value > 0) { - canvas->SaveLayerAlpha(static_cast<int>(throb_value * 0xff), - gfx::Rect(width(), height())); - canvas->AsCanvasSkia()->drawARGB(0, 255, 255, 255, - SkXfermode::kClear_Mode); - PaintActiveTabBackground(canvas); - canvas->Restore(); - } - } -} - -void Tab::PaintInactiveTabBackgroundWithTitleChange(gfx::Canvas* canvas) { - // Render the inactive tab background. We'll use this for clipping. - gfx::CanvasSkia background_canvas(width(), height(), false); - PaintInactiveTabBackground(&background_canvas); - - SkBitmap background_image = background_canvas.ExtractBitmap(); - - // Draw a radial gradient to hover_canvas. - gfx::CanvasSkia hover_canvas(width(), height(), false); - int radius = kMiniTitleChangeGradientRadius; - int x0 = width() + radius - kMiniTitleChangeInitialXOffset; - int x1 = radius; - int x2 = -radius; - int x; - if (mini_title_animation_->current_part_index() == 0) { - x = mini_title_animation_->CurrentValueBetween(x0, x1); - } else if (mini_title_animation_->current_part_index() == 1) { - x = x1; - } else { - x = mini_title_animation_->CurrentValueBetween(x1, x2); - } - SkPaint paint; - SkPoint loc = { SkIntToScalar(x), SkIntToScalar(0) }; - SkColor colors[2]; - colors[0] = kMiniTitleChangeGradientColor1; - colors[1] = kMiniTitleChangeGradientColor2; - SkShader* shader = SkGradientShader::CreateRadial( - loc, - SkIntToScalar(radius), - colors, - NULL, - 2, - SkShader::kClamp_TileMode); - paint.setShader(shader); - shader->unref(); - hover_canvas.DrawRectInt(x - radius, -radius, radius * 2, radius * 2, paint); - - // Draw the radial gradient clipped to the background into hover_image. - SkBitmap hover_image = SkBitmapOperations::CreateMaskedBitmap( - hover_canvas.ExtractBitmap(), background_image); - - // Draw the tab background to the canvas. - canvas->DrawBitmapInt(background_image, 0, 0); - - // And then the gradient on top of that. - if (mini_title_animation_->current_part_index() == 2) { - canvas->SaveLayerAlpha(mini_title_animation_->CurrentValueBetween(255, 0)); - canvas->DrawBitmapInt(hover_image, 0, 0); - canvas->Restore(); - } else { - canvas->DrawBitmapInt(hover_image, 0, 0); - } -} - -void Tab::PaintInactiveTabBackground(gfx::Canvas* canvas) { - bool is_otr = data().off_the_record; - - // The tab image needs to be lined up with the background image - // so that it feels partially transparent. These offsets represent the tab - // position within the frame background image. - int offset = GetX(views::View::APPLY_MIRRORING_TRANSFORMATION) + - background_offset_.x(); - - int tab_id; - if (GetWidget() && - GetWidget()->GetWindow()->GetNonClientView()->UseNativeFrame()) { - tab_id = IDR_THEME_TAB_BACKGROUND_V; - } else { - tab_id = is_otr ? IDR_THEME_TAB_BACKGROUND_INCOGNITO : - IDR_THEME_TAB_BACKGROUND; - } - - SkBitmap* tab_bg = GetThemeProvider()->GetBitmapNamed(tab_id); - - TabImage* tab_image = &tab_active; - TabImage* tab_inactive_image = &tab_inactive; - TabImage* alpha = &tab_alpha; - - // If the theme is providing a custom background image, then its top edge - // should be at the top of the tab. Otherwise, we assume that the background - // image is a composited foreground + frame image. - int bg_offset_y = GetThemeProvider()->HasCustomImage(tab_id) ? - 0 : background_offset_.y(); - - // Draw left edge. Don't draw over the toolbar, as we're not the foreground - // tab. - SkBitmap tab_l = SkBitmapOperations::CreateTiledBitmap( - *tab_bg, offset, bg_offset_y, tab_image->l_width, height()); - SkBitmap theme_l = - SkBitmapOperations::CreateMaskedBitmap(tab_l, *alpha->image_l); - canvas->DrawBitmapInt(theme_l, - 0, 0, theme_l.width(), theme_l.height() - kToolbarOverlap, - 0, 0, theme_l.width(), theme_l.height() - kToolbarOverlap, - false); - - // Draw right edge. Again, don't draw over the toolbar. - SkBitmap tab_r = SkBitmapOperations::CreateTiledBitmap(*tab_bg, - offset + width() - tab_image->r_width, bg_offset_y, - tab_image->r_width, height()); - SkBitmap theme_r = - SkBitmapOperations::CreateMaskedBitmap(tab_r, *alpha->image_r); - canvas->DrawBitmapInt(theme_r, - 0, 0, theme_r.width(), theme_r.height() - kToolbarOverlap, - width() - theme_r.width(), 0, theme_r.width(), - theme_r.height() - kToolbarOverlap, false); - - // Draw center. Instead of masking out the top portion we simply skip over - // it by incrementing by kDropShadowHeight, since it's a simple rectangle. - // And again, don't draw over the toolbar. - canvas->TileImageInt(*tab_bg, - offset + tab_image->l_width, - bg_offset_y + kDropShadowHeight + tab_image->y_offset, - tab_image->l_width, - kDropShadowHeight + tab_image->y_offset, - width() - tab_image->l_width - tab_image->r_width, - height() - kDropShadowHeight - kToolbarOverlap - tab_image->y_offset); - - // Now draw the highlights/shadows around the tab edge. - canvas->DrawBitmapInt(*tab_inactive_image->image_l, 0, 0); - canvas->TileImageInt(*tab_inactive_image->image_c, - tab_inactive_image->l_width, 0, - width() - tab_inactive_image->l_width - - tab_inactive_image->r_width, - height()); - canvas->DrawBitmapInt(*tab_inactive_image->image_r, - width() - tab_inactive_image->r_width, 0); -} - -void Tab::PaintActiveTabBackground(gfx::Canvas* canvas) { - int offset = GetX(views::View::APPLY_MIRRORING_TRANSFORMATION) + - background_offset_.x(); - ThemeProvider* tp = GetThemeProvider(); - if (!tp) - NOTREACHED() << "Unable to get theme provider"; - - SkBitmap* tab_bg = GetThemeProvider()->GetBitmapNamed(IDR_THEME_TOOLBAR); - - TabImage* tab_image = &tab_active; - TabImage* alpha = &tab_alpha; - - // Draw left edge. - SkBitmap tab_l = SkBitmapOperations::CreateTiledBitmap( - *tab_bg, offset, 0, tab_image->l_width, height()); - SkBitmap theme_l = - SkBitmapOperations::CreateMaskedBitmap(tab_l, *alpha->image_l); - canvas->DrawBitmapInt(theme_l, 0, 0); - - // Draw right edge. - SkBitmap tab_r = SkBitmapOperations::CreateTiledBitmap(*tab_bg, - offset + width() - tab_image->r_width, 0, tab_image->r_width, height()); - SkBitmap theme_r = - SkBitmapOperations::CreateMaskedBitmap(tab_r, *alpha->image_r); - canvas->DrawBitmapInt(theme_r, width() - tab_image->r_width, 0); - - // Draw center. Instead of masking out the top portion we simply skip over it - // by incrementing by kDropShadowHeight, since it's a simple rectangle. - canvas->TileImageInt(*tab_bg, - offset + tab_image->l_width, - kDropShadowHeight + tab_image->y_offset, - tab_image->l_width, - kDropShadowHeight + tab_image->y_offset, - width() - tab_image->l_width - tab_image->r_width, - height() - kDropShadowHeight - tab_image->y_offset); - - // Now draw the highlights/shadows around the tab edge. - canvas->DrawBitmapInt(*tab_image->image_l, 0, 0); - canvas->TileImageInt(*tab_image->image_c, tab_image->l_width, 0, - width() - tab_image->l_width - tab_image->r_width, height()); - canvas->DrawBitmapInt(*tab_image->image_r, width() - tab_image->r_width, 0); -} - -int Tab::IconCapacity() const { - if (height() < GetMinimumUnselectedSize().height()) - return 0; - return (width() - kLeftPadding - kRightPadding) / kFavIconSize; -} - -bool Tab::ShouldShowIcon() const { - if (data().mini && height() >= GetMinimumUnselectedSize().height()) - return true; - 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 Tab::ShouldShowCloseBox() const { - // The selected tab never clips close button. - return !data().mini && IsCloseable() && - (IsSelected() || IconCapacity() >= 3); -} - -double Tab::GetThrobValue() { - if (pulse_animation() && pulse_animation()->is_animating()) - return pulse_animation()->GetCurrentValue() * kHoverOpacity; - - return hover_animation() ? - kHoverOpacity * hover_animation()->GetCurrentValue() : 0; -} - -//////////////////////////////////////////////////////////////////////////////// -// Tab, private: - -// static -void Tab::LoadTabImages() { - // We're not letting people override tab images just yet. - ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - - tab_alpha.image_l = rb.GetBitmapNamed(IDR_TAB_ALPHA_LEFT); - tab_alpha.image_r = rb.GetBitmapNamed(IDR_TAB_ALPHA_RIGHT); - - tab_active.image_l = rb.GetBitmapNamed(IDR_TAB_ACTIVE_LEFT); - tab_active.image_c = rb.GetBitmapNamed(IDR_TAB_ACTIVE_CENTER); - tab_active.image_r = rb.GetBitmapNamed(IDR_TAB_ACTIVE_RIGHT); - tab_active.l_width = tab_active.image_l->width(); - tab_active.r_width = tab_active.image_r->width(); - - tab_inactive.image_l = rb.GetBitmapNamed(IDR_TAB_INACTIVE_LEFT); - tab_inactive.image_c = rb.GetBitmapNamed(IDR_TAB_INACTIVE_CENTER); - tab_inactive.image_r = rb.GetBitmapNamed(IDR_TAB_INACTIVE_RIGHT); - tab_inactive.l_width = tab_inactive.image_l->width(); - tab_inactive.r_width = tab_inactive.image_r->width(); -} |