172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/views/tabs/base_tab.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <limits> 8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/command_line.h" 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/utf_string_conversions.h" 114a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/browser/ui/browser.h" 12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" 1321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/ui/view_ids.h" 1421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/ui/views/tabs/tab_controller.h" 15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_switches.h" 16dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/tab_contents.h" 17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/app_resources.h" 18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/generated_resources.h" 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/theme_resources.h" 20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "ui/base/accessibility/accessible_view_state.h" 21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "ui/base/animation/animation_container.h" 223f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "ui/base/animation/slide_animation.h" 233f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "ui/base/animation/throb_animation.h" 2472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/l10n/l10n_util.h" 2572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/resource/resource_bundle.h" 26ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "ui/base/text/text_elider.h" 2772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/theme_provider.h" 2872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/canvas_skia.h" 2972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/favicon_size.h" 3072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/font.h" 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/controls/button/image_button.h" 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// How long the pulse throb takes. 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kPulseDurationMs = 200; 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// How long the hover state takes. 3721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenstatic const int kHoverDurationMs = 400; 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace { 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////////// 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TabCloseButton 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This is a Button subclass that causes middle clicks to be forwarded to the 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// parent View by explicitly not handling them in OnMousePressed. 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass TabCloseButton : public views::ImageButton { 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch explicit TabCloseButton(views::ButtonListener* listener) 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : views::ImageButton(listener) { 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual ~TabCloseButton() {} 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 53ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen virtual bool OnMousePressed(const views::MouseEvent& event) OVERRIDE { 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool handled = ImageButton::OnMousePressed(event); 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Explicitly mark midle-mouse clicks as non-handled to ensure the tab 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // sees them. 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return event.IsOnlyMiddleMouseButton() ? false : handled; 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We need to let the parent know about mouse state so that it 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // can highlight itself appropriately. Note that Exit events 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // fire before Enter events, so this works. 63ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen virtual void OnMouseEntered(const views::MouseEvent& event) OVERRIDE { 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CustomButton::OnMouseEntered(event); 6572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen parent()->OnMouseEntered(event); 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen virtual void OnMouseExited(const views::MouseEvent& event) OVERRIDE { 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CustomButton::OnMouseExited(event); 7072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen parent()->OnMouseExited(event); 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DISALLOW_COPY_AND_ASSIGN(TabCloseButton); 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 77dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// Draws the icon image at the center of |bounds|. 78dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid DrawIconCenter(gfx::Canvas* canvas, 79dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const SkBitmap& image, 80dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen int image_offset, 81dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen int icon_width, 82dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen int icon_height, 83dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const gfx::Rect& bounds, 84dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen bool filter) { 85dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Center the image within bounds. 86dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen int dst_x = bounds.x() - (icon_width - bounds.width()) / 2; 87dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen int dst_y = bounds.y() - (icon_height - bounds.height()) / 2; 88dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // NOTE: the clipping is a work around for 69528, it shouldn't be necessary. 89dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen canvas->Save(); 90dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen canvas->ClipRectInt(dst_x, dst_y, icon_width, icon_height); 91dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen canvas->DrawBitmapInt(image, 92dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen image_offset, 0, icon_width, icon_height, 93dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen dst_x, dst_y, icon_width, icon_height, 94dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen filter); 95dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen canvas->Restore(); 96dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 97dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Font* BaseTab::font_ = NULL; 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint BaseTab::font_height_ = 0; 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////////// 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// FaviconCrashAnimation 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// A custom animation subclass to manage the favicon crash animation. 109ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenclass BaseTab::FaviconCrashAnimation : public ui::LinearAnimation, 1103f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen public ui::AnimationDelegate { 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 112ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen explicit FaviconCrashAnimation(BaseTab* target) 1133f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen : ALLOW_THIS_IN_INITIALIZER_LIST(ui::LinearAnimation(1000, 25, this)), 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch target_(target) { 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 116ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen virtual ~FaviconCrashAnimation() {} 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1183f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // ui::Animation overrides: 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual void AnimateToState(double state) { 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const double kHidingOffset = 27; 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (state < .5) { 123ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen target_->SetFaviconHidingOffset( 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<int>(floor(kHidingOffset * 2.0 * state))); 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 126ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen target_->DisplayCrashedFavicon(); 127ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen target_->SetFaviconHidingOffset( 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<int>( 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch floor(kHidingOffset - ((state - .5) * 2.0 * kHidingOffset)))); 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1333f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // ui::AnimationDelegate overrides: 1343f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen virtual void AnimationCanceled(const ui::Animation* animation) { 135ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen target_->SetFaviconHidingOffset(0); 136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BaseTab* target_; 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 141ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DISALLOW_COPY_AND_ASSIGN(FaviconCrashAnimation); 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 144c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBaseTab::BaseTab(TabController* controller) 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : controller_(controller), 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch closing_(false), 147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch dragging_(false), 148ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen favicon_hiding_offset_(0), 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch loading_animation_frame_(0), 15072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen should_display_crashed_favicon_(false), 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch throbber_disabled_(false), 15272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen theme_provider_(NULL) { 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BaseTab::InitResources(); 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetID(VIEW_ID_TAB); 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Add the Close Button. 1583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick close_button_ = new TabCloseButton(this); 1593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 1603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick close_button_->SetImage(views::CustomButton::BS_NORMAL, 1613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick rb.GetBitmapNamed(IDR_TAB_CLOSE)); 1623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick close_button_->SetImage(views::CustomButton::BS_HOT, 1633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick rb.GetBitmapNamed(IDR_TAB_CLOSE_H)); 1643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick close_button_->SetImage(views::CustomButton::BS_PUSHED, 1653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick rb.GetBitmapNamed(IDR_TAB_CLOSE_P)); 1663f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen close_button_->SetTooltipText( 1673f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen UTF16ToWide(l10n_util::GetStringUTF16(IDS_TOOLTIP_CLOSE_TAB))); 1683f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen close_button_->SetAccessibleName( 16972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen l10n_util::GetStringUTF16(IDS_ACCNAME_CLOSE)); 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Disable animation so that the red danger sign shows up immediately 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // to help avoid mis-clicks. 1723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick close_button_->SetAnimationDuration(0); 1733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick AddChildView(close_button_); 174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetContextMenuController(this); 176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 178c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBaseTab::~BaseTab() { 179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BaseTab::SetData(const TabRendererData& data) { 182dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (data_.Equals(data)) 183dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return; 184dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabRendererData old(data_); 186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch data_ = data; 187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 18872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (data_.IsCrashed()) { 18972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!should_display_crashed_favicon_ && !IsPerformingCrashAnimation()) { 19072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // When --reload-killed-tabs is specified, then the idea is that 19172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // when tab is killed, the tab has no visual indication that it 19272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // died and should reload when the tab is next focused without 19372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // the user seeing the killed tab page. 19472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // 19572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // The only exception to this is when the tab is in the 19672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // foreground (i.e. when it's the selected tab), because we 19772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // don't want to go into an infinite loop reloading a page that 19872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // will constantly get killed, or if it's the only tab. So this 19972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // code makes it so that the favicon will only be shown for 20072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // killed tabs when the tab is currently selected. 20172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (CommandLine::ForCurrentProcess()-> 20272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen HasSwitch(switches::kReloadKilledTabs) && !IsSelected()) { 20372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // If we're reloading killed tabs, we don't want to display 20472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // the crashed animation at all if the process was killed and 20572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // the tab wasn't the current tab. 20672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (data_.crashed_status != base::TERMINATION_STATUS_PROCESS_WAS_KILLED) 20772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen StartCrashAnimation(); 20872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } else { 20972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen StartCrashAnimation(); 21072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 21172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (IsPerformingCrashAnimation()) 214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StopCrashAnimation(); 215ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ResetCrashedFavicon(); 216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DataChanged(old); 219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Layout(); 221dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen SchedulePaint(); 222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BaseTab::UpdateLoadingAnimation(TabRendererData::NetworkState state) { 225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If this is an extension app and a command line flag is set, 226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // then disable the throbber. 227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch throbber_disabled_ = data().app && 228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CommandLine::ForCurrentProcess()->HasSwitch(switches::kAppsNoThrob); 229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (throbber_disabled_) 231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (state == data_.network_state && 234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch state == TabRendererData::NETWORK_STATE_NONE) { 235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the network state is none and hasn't changed, do nothing. Otherwise we 236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // need to advance the animation frame. 237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabRendererData::NetworkState old_state = data_.network_state; 241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch data_.network_state = state; 242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AdvanceLoadingAnimation(old_state, state); 243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BaseTab::StartPulse() { 246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!pulse_animation_.get()) { 2473f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen pulse_animation_.reset(new ui::ThrobAnimation(this)); 248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch pulse_animation_->SetSlideDuration(kPulseDurationMs); 249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (animation_container_.get()) 250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch pulse_animation_->SetContainer(animation_container_.get()); 251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch pulse_animation_->Reset(); 253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch pulse_animation_->StartThrobbing(std::numeric_limits<int>::max()); 254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BaseTab::StopPulse() { 257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!pulse_animation_.get()) 258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch pulse_animation_->Stop(); // Do stop so we get notified. 261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch pulse_animation_.reset(NULL); 262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 264ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BaseTab::set_animation_container(ui::AnimationContainer* container) { 265ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen animation_container_ = container; 266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BaseTab::IsCloseable() const { 269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return controller() ? controller()->IsTabCloseable(this) : true; 270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 272ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool BaseTab::IsActive() const { 273ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return controller() ? controller()->IsActiveTab(this) : true; 274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 276ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool BaseTab::IsSelected() const { 277ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return controller() ? controller()->IsTabSelected(this) : true; 278ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 279ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 280ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenui::ThemeProvider* BaseTab::GetThemeProvider() const { 281ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ui::ThemeProvider* tp = View::GetThemeProvider(); 282ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return tp ? tp : theme_provider_; 283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BaseTab::OnMousePressed(const views::MouseEvent& event) { 286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!controller()) 287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (event.IsOnlyLeftMouseButton()) { 290ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (event.IsShiftDown() && event.IsControlDown()) { 291ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen controller()->AddSelectionFromAnchorTo(this); 292ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } else if (event.IsShiftDown()) { 293ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen controller()->ExtendSelectionTo(this); 294ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } else if (event.IsControlDown()) { 295ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen controller()->ToggleSelected(this); 296ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!IsSelected()) { 297ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Don't allow dragging non-selected tabs. 298ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return false; 299ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 300ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } else if (!IsSelected()) { 301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch controller()->SelectTab(this); 302ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch controller()->MaybeStartDrag(this, event); 304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BaseTab::OnMouseDragged(const views::MouseEvent& event) { 309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (controller()) 310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch controller()->ContinueDrag(event); 311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 314ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BaseTab::OnMouseReleased(const views::MouseEvent& event) { 315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!controller()) 316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Notify the drag helper that we're done with any potential drag operations. 319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Clean up the drag helper, which is re-created on the next mouse press. 320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // In some cases, ending the drag will schedule the tab for destruction; if 321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // so, bail immediately, since our members are already dead and we shouldn't 322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // do anything else except drop the tab where it is. 323ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (controller()->EndDrag(false)) 324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Close tab on middle click, but only if the button is released over the tab 327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // (normal windows behavior is to discard presses of a UI element where the 328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // releases happen off the element). 329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (event.IsMiddleMouseButton()) { 330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (HitTest(event.location())) { 331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch controller()->CloseTab(this); 332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (closing_) { 333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We're animating closed and a middle mouse button was pushed on us but 334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // we don't contain the mouse anymore. We assume the user is clicking 335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // quicker than the animation and we should close the tab that falls under 336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the mouse. 337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BaseTab* closest_tab = controller()->GetTabAt(this, event.location()); 338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (closest_tab) 339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch controller()->CloseTab(closest_tab); 340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 341ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } else if (event.IsOnlyLeftMouseButton() && !event.IsShiftDown() && 342ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen !event.IsControlDown()) { 343ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // If the tab was already selected mouse pressed doesn't change the 344ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // selection. Reset it now to handle the case where multiple tabs were 345ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // selected. 346ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen controller()->SelectTab(this); 347ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 348ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 349ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 350ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BaseTab::OnMouseCaptureLost() { 351ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (controller()) 352ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen controller()->EndDrag(true); 353ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 354ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 355ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BaseTab::OnMouseEntered(const views::MouseEvent& event) { 356ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!hover_animation_.get()) { 357ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen hover_animation_.reset(new ui::SlideAnimation(this)); 358ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen hover_animation_->SetContainer(animation_container_.get()); 359ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen hover_animation_->SetSlideDuration(kHoverDurationMs); 360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 361ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen hover_animation_->SetTweenType(ui::Tween::EASE_OUT); 362ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen hover_animation_->Show(); 363ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 364ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 365ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BaseTab::OnMouseExited(const views::MouseEvent& event) { 366ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen hover_animation_->SetTweenType(ui::Tween::EASE_IN); 367ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen hover_animation_->Hide(); 368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BaseTab::GetTooltipText(const gfx::Point& p, std::wstring* tooltip) { 371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (data_.title.empty()) 372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Only show the tooltip if the title is truncated. 375dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (font_->GetStringWidth(data_.title) > GetTitleBounds().width()) { 3763f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen *tooltip = UTF16ToWide(data_.title); 377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 382ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BaseTab::GetAccessibleState(ui::AccessibleViewState* state) { 383ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen state->role = ui::AccessibilityTypes::ROLE_PAGETAB; 384ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen state->name = data_.title; 385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BaseTab::AdvanceLoadingAnimation(TabRendererData::NetworkState old_state, 388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabRendererData::NetworkState state) { 3893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick static bool initialized = false; 3903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick static int loading_animation_frame_count = 0; 3913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick static int waiting_animation_frame_count = 0; 3923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick static int waiting_to_loading_frame_count_ratio = 0; 3933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!initialized) { 3943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick initialized = true; 3953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 3963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SkBitmap loading_animation(*rb.GetBitmapNamed(IDR_THROBBER)); 3973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick loading_animation_frame_count = 3983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick loading_animation.width() / loading_animation.height(); 3993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SkBitmap waiting_animation(*rb.GetBitmapNamed(IDR_THROBBER_WAITING)); 4003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick waiting_animation_frame_count = 4013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick waiting_animation.width() / waiting_animation.height(); 4023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick waiting_to_loading_frame_count_ratio = 4033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick waiting_animation_frame_count / loading_animation_frame_count; 4043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 4053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The waiting animation is the reverse of the loading animation, but at a 407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // different rate - the following reverses and scales the animation_frame_ 408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // so that the frame is at an equivalent position when going from one 409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // animation to the other. 410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (state != old_state) { 411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch loading_animation_frame_ = loading_animation_frame_count - 412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (loading_animation_frame_ / waiting_to_loading_frame_count_ratio); 413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (state != TabRendererData::NETWORK_STATE_NONE) { 416731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick loading_animation_frame_ = (loading_animation_frame_ + 1) % 417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ((state == TabRendererData::NETWORK_STATE_WAITING) ? 418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch waiting_animation_frame_count : loading_animation_frame_count); 419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch loading_animation_frame_ = 0; 421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 422dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ScheduleIconPaint(); 423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 425dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid BaseTab::PaintIcon(gfx::Canvas* canvas) { 426dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen gfx::Rect bounds = GetIconBounds(); 427dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (bounds.IsEmpty()) 428dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return; 429dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 430ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // The size of bounds has to be kFaviconSize x kFaviconSize. 431ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK_EQ(kFaviconSize, bounds.width()); 432ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK_EQ(kFaviconSize, bounds.height()); 433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 434dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen bounds.set_x(GetMirroredXForRect(bounds)); 435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (data().network_state != TabRendererData::NETWORK_STATE_NONE) { 43772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ui::ThemeProvider* tp = GetThemeProvider(); 4383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SkBitmap frames(*tp->GetBitmapNamed( 439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (data().network_state == TabRendererData::NETWORK_STATE_WAITING) ? 4403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick IDR_THROBBER_WAITING : IDR_THROBBER)); 441dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 442dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen int icon_size = frames.height(); 443dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen int image_offset = loading_animation_frame_ * icon_size; 444dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen DrawIconCenter(canvas, frames, image_offset, 445dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen icon_size, icon_size, bounds, false); 446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch canvas->Save(); 448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch canvas->ClipRectInt(0, 0, width(), height()); 449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (should_display_crashed_favicon_) { 4503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 451ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen SkBitmap crashed_favicon(*rb.GetBitmapNamed(IDR_SAD_FAVICON)); 452ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bounds.set_y(bounds.y() + favicon_hiding_offset_); 453ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DrawIconCenter(canvas, crashed_favicon, 0, 454ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen crashed_favicon.width(), 455ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen crashed_favicon.height(), bounds, true); 456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!data().favicon.isNull()) { 458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(pkasting): Use code in tab_icon_view.cc:PaintIcon() (or switch 459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // to using that class to render the favicon). 460dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen DrawIconCenter(canvas, data().favicon, 0, 461dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen data().favicon.width(), 462dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen data().favicon.height(), 463dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen bounds, true); 464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch canvas->Restore(); 467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BaseTab::PaintTitle(gfx::Canvas* canvas, SkColor title_color) { 471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Paint the Title. 472ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const gfx::Rect& title_bounds = GetTitleBounds(); 473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch string16 title = data().title; 474ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (title.empty()) { 476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch title = data().loading ? 477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch l10n_util::GetStringUTF16(IDS_TAB_LOADING_TITLE) : 478dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen TabContentsWrapper::GetDefaultTitle(); 479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Browser::FormatTitleForDisplay(&title); 481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 482ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 483ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#if defined(OS_WIN) 484ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen canvas->AsCanvasSkia()->DrawFadeTruncatingString(title, 485ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen gfx::CanvasSkia::TruncateFadeTail, 0, *font_, title_color, title_bounds); 486ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#else 48772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen canvas->DrawStringInt(title, *font_, title_color, 488dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen title_bounds.x(), title_bounds.y(), 489dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen title_bounds.width(), title_bounds.height()); 490ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif 491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 4933f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenvoid BaseTab::AnimationProgressed(const ui::Animation* animation) { 494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SchedulePaint(); 495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 4973f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenvoid BaseTab::AnimationCanceled(const ui::Animation* animation) { 498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SchedulePaint(); 499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5013f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenvoid BaseTab::AnimationEnded(const ui::Animation* animation) { 502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SchedulePaint(); 503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BaseTab::ButtonPressed(views::Button* sender, const views::Event& event) { 506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(sender == close_button_); 507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch controller()->CloseTab(this); 508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 510dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid BaseTab::ShowContextMenuForView(views::View* source, 511dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const gfx::Point& p, 512dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen bool is_mouse_gesture) { 513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (controller()) 514dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen controller()->ShowContextMenuForTab(this, p); 515dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 516dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 517dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenint BaseTab::loading_animation_frame() const { 518dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return loading_animation_frame_; 519dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 520dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 521dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenbool BaseTab::should_display_crashed_favicon() const { 522dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return should_display_crashed_favicon_; 523dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 524dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 525ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenint BaseTab::favicon_hiding_offset() const { 526ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return favicon_hiding_offset_; 527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 529ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BaseTab::SetFaviconHidingOffset(int offset) { 530ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen favicon_hiding_offset_ = offset; 531dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ScheduleIconPaint(); 532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 534ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BaseTab::DisplayCrashedFavicon() { 535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch should_display_crashed_favicon_ = true; 536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 538ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BaseTab::ResetCrashedFavicon() { 539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch should_display_crashed_favicon_ = false; 540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BaseTab::StartCrashAnimation() { 543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!crash_animation_.get()) 544ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen crash_animation_.reset(new FaviconCrashAnimation(this)); 545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch crash_animation_->Stop(); 546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch crash_animation_->Start(); 547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BaseTab::StopCrashAnimation() { 550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!crash_animation_.get()) 551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch crash_animation_->Stop(); 553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BaseTab::IsPerformingCrashAnimation() const { 556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return crash_animation_.get() && crash_animation_->is_animating(); 557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 559dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid BaseTab::ScheduleIconPaint() { 560dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen gfx::Rect bounds = GetIconBounds(); 561dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (bounds.IsEmpty()) 562dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return; 563dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 564dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Extends the area to the bottom when sad_favicon is 565dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // animating. 566dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (IsPerformingCrashAnimation()) 567dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen bounds.set_height(height() - bounds.y()); 568dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen bounds.set_x(GetMirroredXForRect(bounds)); 569dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen SchedulePaintInRect(bounds); 570dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 571dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BaseTab::InitResources() { 574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static bool initialized = false; 5753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!initialized) { 5763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick initialized = true; 5773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick font_ = new gfx::Font( 5783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BaseFont)); 5793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick font_height_ = font_->GetHeight(); 580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 582