15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/tabs/tab.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <limits>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/command_line.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/debug/alias.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/defaults.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/themes/theme_properties.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/browser.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/tab_contents/core_tab_helper.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/tabs/tab_resources.h"
1768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "chrome/browser/ui/tabs/tab_utils.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/view_ids.h"
191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/ui/views/tabs/media_indicator_button.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/tabs/tab_controller.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/views/theme_image_mapper.h"
22eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/ui/views/touch_uma/touch_uma.h"
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/chrome_switches.h"
241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/grit/generated_resources.h"
251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/browser/user_metrics.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/theme_resources.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/effects/SkGradientShader.h"
28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/accessibility/ax_view_state.h"
29f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "ui/aura/env.h"
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/models/list_selection_model.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/theme_provider.h"
34d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/gfx/animation/animation_container.h"
35d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/gfx/animation/multi_animation.h"
36d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/gfx/animation/throb_animation.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/canvas.h"
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/gfx/color_analysis.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/favicon_size.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image_skia_operations.h"
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/path.h"
420f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "ui/gfx/rect_conversions.h"
430f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "ui/gfx/skia_util.h"
4403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "ui/resources/grit/ui_resources.h"
45a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/views/border.h"
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/button/image_button.h"
47f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "ui/views/controls/label.h"
48f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/views/rect_based_targeting_utils.h"
49116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "ui/views/view_targeter.h"
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/tooltip_manager.h"
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget.h"
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/window/non_client_view.h"
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciusing base::UserMetricsAction;
551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Padding around the "content" of a tab, occupied by the tab border graphics.
595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuconst int kLeftPadding = 22;
605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)const int kTopPadding = 4;
615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuconst int kRightPadding = 17;
625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)const int kBottomPadding = 2;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Height of the shadow at the top of the tab image assets.
655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuconst int kDropShadowHeight = 4;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// How long the pulse throb takes.
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kPulseDurationMs = 200;
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Width of touch tabs.
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kTouchWidth = 120;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kToolbarOverlap = 1;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kFaviconTitleSpacing = 4;
755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static const int kViewSpacing = 3;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kStandardTitleWidth = 175;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// When a non-mini-tab becomes a mini-tab the width of the tab animates. If
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the width of a mini-tab is >= kMiniTabRendererAsNormalTabWidth then the tab
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is rendered as a normal tab. This is done to avoid having the title
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// immediately disappear when transitioning a tab from normal to mini-tab.
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kMiniTabRendererAsNormalTabWidth =
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    browser_defaults::kMiniTabWidth + 30;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// How opaque to make the hover state (out of 1).
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const double kHoverOpacity = 0.33;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Opacity for non-active selected tabs.
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const double kSelectedTabOpacity = .45;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Selected (but not active) tabs have their throb value scaled down by this.
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const double kSelectedTabThrobScale = .5;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Durations for the various parts of the mini tab title animation.
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kMiniTitleChangeAnimationDuration1MS = 1600;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kMiniTitleChangeAnimationStart1MS = 0;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kMiniTitleChangeAnimationEnd1MS = 1900;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kMiniTitleChangeAnimationDuration2MS = 0;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kMiniTitleChangeAnimationDuration3MS = 550;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kMiniTitleChangeAnimationStart3MS = 150;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kMiniTitleChangeAnimationEnd3MS = 800;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kMiniTitleChangeAnimationIntervalMS = 40;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Offset from the right edge for the start of the mini title change animation.
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kMiniTitleChangeInitialXOffset = 6;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Radius of the radial gradient used for mini title change animation.
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kMiniTitleChangeGradientRadius = 20;
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Colors of the gradient used during the mini title change animation.
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const SkColor kMiniTitleChangeGradientColor1 = SK_ColorWHITE;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const SkColor kMiniTitleChangeGradientColor2 =
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkColorSetARGB(0, 255, 255, 255);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Max number of images to cache. This has to be at least two since rounding
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// errors may lead to tabs in the same tabstrip having different sizes.
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const size_t kMaxImageCacheSize = 4;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Height of the miniature tab strip in immersive mode.
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kImmersiveTabHeight = 3;
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Height of the small tab indicator rectangles in immersive mode.
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kImmersiveBarHeight = 2;
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Color for active and inactive tabs in the immersive mode light strip. These
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// should be a little brighter than the color of the normal art assets for tabs,
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// which for active tabs is 230, 230, 230 and for inactive is 184, 184, 184.
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const SkColor kImmersiveActiveTabColor = SkColorSetRGB(235, 235, 235);
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const SkColor kImmersiveInactiveTabColor = SkColorSetRGB(190, 190, 190);
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
131ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// The minimum opacity (out of 1) when a tab (either active or inactive) is
132ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// throbbing in the immersive mode light strip.
133ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochconst double kImmersiveTabMinThrobOpacity = 0.66;
134ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Number of steps in the immersive mode loading animation.
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kImmersiveLoadingStepCount = 32;
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1380f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)const char kTabCloseButtonName[] = "TabCloseButton";
1390f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DrawIconAtLocation(gfx::Canvas* canvas,
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        const gfx::ImageSkia& image,
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        int image_offset,
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        int dst_x,
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        int dst_y,
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        int icon_width,
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        int icon_height,
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        bool filter,
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        const SkPaint& paint) {
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // NOTE: the clipping is a work around for 69528, it shouldn't be necessary.
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  canvas->Save();
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  canvas->ClipRect(gfx::Rect(dst_x, dst_y, icon_width, icon_height));
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  canvas->DrawImageInt(image,
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       image_offset, 0, icon_width, icon_height,
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       dst_x, dst_y, icon_width, icon_height,
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       filter, paint);
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  canvas->Restore();
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Draws the icon image at the center of |bounds|.
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DrawIconCenter(gfx::Canvas* canvas,
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    const gfx::ImageSkia& image,
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    int image_offset,
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    int icon_width,
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    int icon_height,
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    const gfx::Rect& bounds,
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    bool filter,
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    const SkPaint& paint) {
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Center the image within bounds.
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int dst_x = bounds.x() - (icon_width - bounds.width()) / 2;
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int dst_y = bounds.y() - (icon_height - bounds.height()) / 2;
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DrawIconAtLocation(canvas, image, image_offset, dst_x, dst_y, icon_width,
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     icon_height, filter, paint);
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)chrome::HostDesktopType GetHostDesktopType(views::View* view) {
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Widget is NULL when tabs are detached.
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  views::Widget* widget = view->GetWidget();
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return chrome::GetHostDesktopTypeForNativeView(
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      widget ? widget->GetNativeView() : NULL);
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
182116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Stop()s |animation| and then deletes it. We do this rather than just deleting
183116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// so that the delegate is notified before the destruction.
184116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid StopAndDeleteAnimation(scoped_ptr<gfx::Animation> animation) {
185116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (animation)
186116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    animation->Stop();
187116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
188116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// FaviconCrashAnimation
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//  A custom animation subclass to manage the favicon crash animation.
195d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)class Tab::FaviconCrashAnimation : public gfx::LinearAnimation,
196d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                                   public gfx::AnimationDelegate {
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  explicit FaviconCrashAnimation(Tab* target)
199d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      : gfx::LinearAnimation(1000, 25, this),
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        target_(target) {
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~FaviconCrashAnimation() {}
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
204d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // gfx::Animation overrides:
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void AnimateToState(double state) OVERRIDE {
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const double kHidingOffset = 27;
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (state < .5) {
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      target_->SetFaviconHidingOffset(
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          static_cast<int>(floor(kHidingOffset * 2.0 * state)));
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      target_->DisplayCrashedFavicon();
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      target_->SetFaviconHidingOffset(
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          static_cast<int>(
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              floor(kHidingOffset - ((state - .5) * 2.0 * kHidingOffset))));
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
219d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // gfx::AnimationDelegate overrides:
220d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  virtual void AnimationCanceled(const gfx::Animation* animation) OVERRIDE {
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    target_->SetFaviconHidingOffset(0);
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Tab* target_;
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(FaviconCrashAnimation);
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// TabCloseButton
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//  This is a Button subclass that causes middle clicks to be forwarded to the
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//  parent View by explicitly not handling them in OnMousePressed.
235116680a4aac90f2aa7413d9095a592090648e557Ben Murdochclass Tab::TabCloseButton : public views::ImageButton,
236116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                            public views::MaskedTargeterDelegate {
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
238116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  explicit TabCloseButton(Tab* tab)
239116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      : views::ImageButton(tab),
240116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        tab_(tab) {
241116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    SetEventTargeter(
242116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        scoped_ptr<views::ViewTargeter>(new views::ViewTargeter(this)));
243116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
244116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~TabCloseButton() {}
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
247116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // views::View:
248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  virtual View* GetTooltipHandlerForPoint(const gfx::Point& point) OVERRIDE {
249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Tab close button has no children, so tooltip handler should be the same
250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // as the event handler.
251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // In addition, a hit test has to be performed for the point (as
252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // GetTooltipHandlerForPoint() is responsible for it).
253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!HitTestPoint(point))
254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return NULL;
255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return GetEventHandlerForPoint(point);
256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    tab_->controller_->OnMouseEventInTab(this, event);
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool handled = ImageButton::OnMousePressed(event);
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Explicitly mark midle-mouse clicks as non-handled to ensure the tab
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // sees them.
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return event.IsOnlyMiddleMouseButton() ? false : handled;
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void OnMouseMoved(const ui::MouseEvent& event) OVERRIDE {
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    tab_->controller_->OnMouseEventInTab(this, event);
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CustomButton::OnMouseMoved(event);
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE {
2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    tab_->controller_->OnMouseEventInTab(this, event);
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CustomButton::OnMouseReleased(event);
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Consume all gesture events here so that the parent (Tab) does not
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // start consuming gestures.
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ImageButton::OnGestureEvent(event);
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    event->SetHandled();
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
284116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  virtual const char* GetClassName() const OVERRIDE {
285116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return kTabCloseButtonName;
2860f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
2870f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
288116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch private:
289116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Returns the rectangular bounds of parent tab's visible region in the
290116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // local coordinate space of |this|.
291116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  gfx::Rect GetTabBounds() const {
2920f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    gfx::Path tab_mask;
293116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    tab_->GetHitTestMask(&tab_mask);
2940f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
2950f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    gfx::RectF tab_bounds_f(gfx::SkRectToRectF(tab_mask.getBounds()));
2960f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    views::View::ConvertRectToTarget(tab_, this, &tab_bounds_f);
297116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return gfx::ToEnclosingRect(tab_bounds_f);
298116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
299116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
300116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Returns the rectangular bounds of the tab close button in the local
301116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // coordinate space of |this|, not including clipped regions on the top
302116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // or bottom of the button. |tab_bounds| is the rectangular bounds of
303116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // the parent tab's visible region in the local coordinate space of |this|.
304116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  gfx::Rect GetTabCloseButtonBounds(const gfx::Rect& tab_bounds) const {
305116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    gfx::Rect button_bounds(GetContentsBounds());
306116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    button_bounds.set_x(GetMirroredXForRect(button_bounds));
3070f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int top_overflow = tab_bounds.y() - button_bounds.y();
3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int bottom_overflow = button_bounds.bottom() - tab_bounds.bottom();
3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (top_overflow > 0)
3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      button_bounds.set_y(tab_bounds.y());
3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    else if (bottom_overflow > 0)
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      button_bounds.set_height(button_bounds.height() - bottom_overflow);
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
315116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return button_bounds;
316116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
317116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
3185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // views::ViewTargeterDelegate:
3195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  virtual View* TargetForRect(View* root, const gfx::Rect& rect) OVERRIDE {
3205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    CHECK_EQ(root, this);
3215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (!views::UsePointBasedTargeting(rect))
3235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return ViewTargeterDelegate::TargetForRect(root, rect);
3245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // Ignore the padding set on the button.
3265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    gfx::Rect contents_bounds = GetContentsBounds();
3275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    contents_bounds.set_x(GetMirroredXForRect(contents_bounds));
3285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // Include the padding in hit-test for touch events.
3305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (aura::Env::GetInstance()->is_touch_down())
3315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      contents_bounds = GetLocalBounds();
3325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return contents_bounds.Intersects(rect) ? this : parent();
3345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
3355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
336116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // views:MaskedTargeterDelegate:
337116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  virtual bool GetHitTestMask(gfx::Path* mask) const OVERRIDE {
338116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    DCHECK(mask);
339116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    mask->reset();
340116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
341116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // The parent tab may be partially occluded by another tab if we are
342116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // in stacked tab mode, which means that the tab close button may also
343116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // be partially occluded. Define the hit test mask of the tab close
344116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // button to be the intersection of the parent tab's visible bounds
345116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // and the bounds of the tab close button.
346116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    gfx::Rect tab_bounds(GetTabBounds());
347116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    gfx::Rect button_bounds(GetTabCloseButtonBounds(tab_bounds));
3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    gfx::Rect intersection(gfx::IntersectRects(tab_bounds, button_bounds));
3490f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
350116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!intersection.IsEmpty()) {
351116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      mask->addRect(RectToSkRect(intersection));
352116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return true;
3530f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    }
354116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
355116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return false;
3560f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
3570f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
358116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  virtual bool DoesIntersectRect(const View* target,
359116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                 const gfx::Rect& rect) const OVERRIDE {
360116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    CHECK_EQ(target, this);
361116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
362116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // If the request is not made in response to a gesture, use the
363116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // default implementation.
364116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (views::UsePointBasedTargeting(rect))
365116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return MaskedTargeterDelegate::DoesIntersectRect(target, rect);
366116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
367116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // The hit test request is in response to a gesture. Return false if any
368116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // part of the tab close button is hidden from the user.
369116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // TODO(tdanderson): Consider always returning the intersection if the
370116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    //                   non-rectangular shape of the tab can be accounted for.
371116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    gfx::Rect tab_bounds(GetTabBounds());
372116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    gfx::Rect button_bounds(GetTabCloseButtonBounds(tab_bounds));
373116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!tab_bounds.Contains(button_bounds))
374116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return false;
375116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
376116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return MaskedTargeterDelegate::DoesIntersectRect(target, rect);
3770f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
3780f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Tab* tab_;
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(TabCloseButton);
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// ImageCacheEntry
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Tab::ImageCacheEntry::ImageCacheEntry()
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : resource_id(-1),
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scale_factor(ui::SCALE_FACTOR_NONE) {
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Tab::ImageCacheEntry::~ImageCacheEntry() {}
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Tab, statics:
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
398b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)const char Tab::kViewClassName[] = "Tab";
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Tab::TabImage Tab::tab_active_ = {0};
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Tab::TabImage Tab::tab_inactive_ = {0};
401f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)Tab::TabImage Tab::tab_alpha_ = {0};
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Tab::ImageCache* Tab::image_cache_ = NULL;
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Tab, public:
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Tab::Tab(TabController* controller)
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : controller_(controller),
4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      closing_(false),
4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      dragging_(false),
411116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      detached_(false),
4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      favicon_hiding_offset_(0),
4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      loading_animation_frame_(0),
4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      immersive_loading_step_(0),
4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      should_display_crashed_favicon_(false),
416f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      close_button_(NULL),
4171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      media_indicator_button_(NULL),
418f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      title_(new views::Label()),
4195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      tab_activated_with_last_tap_down_(false),
420c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      hover_controller_(this),
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      showing_icon_(false),
4224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      showing_media_indicator_(false),
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      showing_close_button_(false),
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      close_button_color_(0) {
4255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(controller);
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InitTabResources();
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // So we get don't get enter/exit on children and don't prematurely stop the
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // hover.
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  set_notify_enter_exit_on_child(true);
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  set_id(VIEW_ID_TAB);
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
434f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  title_->SetHorizontalAlignment(gfx::ALIGN_TO_HEAD);
435f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  title_->SetElideBehavior(gfx::FADE_TAIL);
436f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  title_->SetAutoColorReadabilityEnabled(false);
437f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  title_->SetText(CoreTabHelper::GetDefaultTitle());
438f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  AddChildView(title_);
439f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
440116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  SetEventTargeter(
441116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      scoped_ptr<views::ViewTargeter>(new views::ViewTargeter(this)));
442116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Add the Close Button.
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  close_button_ = new TabCloseButton(this);
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  close_button_->SetImage(views::CustomButton::STATE_NORMAL,
447c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          rb.GetImageSkiaNamed(IDR_CLOSE_1));
4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  close_button_->SetImage(views::CustomButton::STATE_HOVERED,
449c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          rb.GetImageSkiaNamed(IDR_CLOSE_1_H));
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  close_button_->SetImage(views::CustomButton::STATE_PRESSED,
451c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          rb.GetImageSkiaNamed(IDR_CLOSE_1_P));
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  close_button_->SetAccessibleName(
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      l10n_util::GetStringUTF16(IDS_ACCNAME_CLOSE));
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Disable animation so that the red danger sign shows up immediately
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // to help avoid mis-clicks.
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  close_button_->SetAnimationDuration(0);
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AddChildView(close_button_);
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  set_context_menu_controller(this);
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Tab::~Tab() {
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void Tab::set_animation_container(gfx::AnimationContainer* container) {
4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  animation_container_ = container;
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  hover_controller_.SetAnimationContainer(container);
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Tab::IsActive() const {
4715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return controller_->IsActiveTab(this);
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Tab::IsSelected() const {
4755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return controller_->IsTabSelected(this);
4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Tab::SetData(const TabRendererData& data) {
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (data_.Equals(data))
4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  TabRendererData old(data_);
4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  data_ = data;
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
485f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  base::string16 title = data_.title;
486f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (title.empty()) {
487f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    title = data_.loading ?
488f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        l10n_util::GetStringUTF16(IDS_TAB_LOADING_TITLE) :
489f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        CoreTabHelper::GetDefaultTitle();
490f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  } else {
491f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    Browser::FormatTitleForDisplay(&title);
492f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
493f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  title_->SetText(title);
494f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (data_.IsCrashed()) {
4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!should_display_crashed_favicon_ && !IsPerformingCrashAnimation()) {
4974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      data_.media_state = TAB_MEDIA_STATE_NONE;
4982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_CHROMEOS)
4992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // On Chrome OS, we reload killed tabs automatically when the user
5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // switches to them.  Don't display animations for these unless they're
5012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // selected (i.e. in the foreground) -- we won't reload these
5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // automatically since we don't want to get into a crash loop.
5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (IsSelected() ||
5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          data_.crashed_status != base::TERMINATION_STATUS_PROCESS_WAS_KILLED)
5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        StartCrashAnimation();
5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#else
5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      StartCrashAnimation();
5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
5112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (IsPerformingCrashAnimation())
5124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      StopCrashAnimation();
5132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ResetCrashedFavicon();
5142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (data_.media_state != old.media_state)
5171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    GetMediaIndicatorButton()->TransitionToMediaState(data_.media_state);
5184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (old.mini != data_.mini) {
520116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    StopAndDeleteAnimation(
521116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        mini_title_change_animation_.PassAs<gfx::Animation>());
5222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DataChanged(old);
5252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Layout();
5272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SchedulePaint();
5282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Tab::UpdateLoadingAnimation(TabRendererData::NetworkState state) {
5312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (state == data_.network_state &&
5322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      state == TabRendererData::NETWORK_STATE_NONE) {
5332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // If the network state is none and hasn't changed, do nothing. Otherwise we
5342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // need to advance the animation frame.
5352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
5362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  TabRendererData::NetworkState old_state = data_.network_state;
5392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  data_.network_state = state;
5402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AdvanceLoadingAnimation(old_state, state);
5412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Tab::StartPulse() {
544116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  pulse_animation_.reset(new gfx::ThrobAnimation(this));
545116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  pulse_animation_->SetSlideDuration(kPulseDurationMs);
5461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (animation_container_.get())
547116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    pulse_animation_->SetContainer(animation_container_.get());
548116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  pulse_animation_->StartThrobbing(std::numeric_limits<int>::max());
5492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Tab::StopPulse() {
552116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  StopAndDeleteAnimation(pulse_animation_.PassAs<gfx::Animation>());
5532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Tab::StartMiniTabTitleAnimation() {
5562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!data().mini)
5572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
558116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!mini_title_change_animation_) {
559d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    gfx::MultiAnimation::Parts parts;
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parts.push_back(
561d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        gfx::MultiAnimation::Part(kMiniTitleChangeAnimationDuration1MS,
562d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                                 gfx::Tween::EASE_OUT));
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parts.push_back(
564d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        gfx::MultiAnimation::Part(kMiniTitleChangeAnimationDuration2MS,
565d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                                 gfx::Tween::ZERO));
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parts.push_back(
567d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        gfx::MultiAnimation::Part(kMiniTitleChangeAnimationDuration3MS,
568d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                                 gfx::Tween::EASE_IN));
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parts[0].start_time_ms = kMiniTitleChangeAnimationStart1MS;
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parts[0].end_time_ms = kMiniTitleChangeAnimationEnd1MS;
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parts[2].start_time_ms = kMiniTitleChangeAnimationStart3MS;
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parts[2].end_time_ms = kMiniTitleChangeAnimationEnd3MS;
5732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::TimeDelta timeout =
5742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::TimeDelta::FromMilliseconds(kMiniTitleChangeAnimationIntervalMS);
575116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    mini_title_change_animation_.reset(new gfx::MultiAnimation(parts, timeout));
5761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (animation_container_.get())
577116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      mini_title_change_animation_->SetContainer(animation_container_.get());
578116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    mini_title_change_animation_->set_delegate(this);
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
580116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  mini_title_change_animation_->Start();
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Tab::StopMiniTabTitleAnimation() {
584116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  StopAndDeleteAnimation(mini_title_change_animation_.PassAs<gfx::Animation>());
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Size Tab::GetBasicMinimumUnselectedSize() {
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InitTabResources();
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Size minimum_size;
5925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  minimum_size.set_width(kLeftPadding + kRightPadding);
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Since we use image images, the real minimum height of the image is
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // defined most accurately by the height of the end cap images.
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  minimum_size.set_height(tab_active_.image_l->height());
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return minimum_size;
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Size Tab::GetMinimumUnselectedSize() {
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetBasicMinimumUnselectedSize();
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Size Tab::GetMinimumSelectedSize() {
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Size minimum_size = GetBasicMinimumUnselectedSize();
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  minimum_size.set_width(
6075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      kLeftPadding + gfx::kFaviconSize + kRightPadding);
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return minimum_size;
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Size Tab::GetStandardSize() {
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Size standard_size = GetBasicMinimumUnselectedSize();
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  standard_size.set_width(
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      standard_size.width() + kFaviconTitleSpacing + kStandardTitleWidth);
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return standard_size;
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int Tab::GetTouchWidth() {
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return kTouchWidth;
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int Tab::GetMiniWidth() {
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return browser_defaults::kMiniTabWidth;
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
6302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int Tab::GetImmersiveHeight() {
6312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return kImmersiveTabHeight;
6322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
6352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Tab, AnimationDelegate overrides:
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
637d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void Tab::AnimationProgressed(const gfx::Animation* animation) {
6382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Ignore if the pulse animation is being performed on active tab because
6392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // it repaints the same image. See |Tab::PaintTabBackground()|.
640116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (animation == pulse_animation_.get() && IsActive())
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SchedulePaint();
6432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void Tab::AnimationCanceled(const gfx::Animation* animation) {
6462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SchedulePaint();
6472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
649d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void Tab::AnimationEnded(const gfx::Animation* animation) {
6502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SchedulePaint();
6512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
6542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Tab, views::ButtonListener overrides:
6552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Tab::ButtonPressed(views::Button* sender, const ui::Event& event) {
6571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (media_indicator_button_ && media_indicator_button_->visible()) {
6581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (media_indicator_button_->enabled())
6591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      content::RecordAction(UserMetricsAction("CloseTab_MuteToggleAvailable"));
6601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    else if (data_.media_state == TAB_MEDIA_STATE_AUDIO_PLAYING)
6611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      content::RecordAction(UserMetricsAction("CloseTab_AudioIndicator"));
6621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    else
6631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      content::RecordAction(UserMetricsAction("CloseTab_RecordingIndicator"));
6641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  } else {
6651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    content::RecordAction(UserMetricsAction("CloseTab_NoMediaIndicator"));
6661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
6671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
6682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const CloseTabSource source =
6692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (event.type() == ui::ET_MOUSE_RELEASED &&
6702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       (event.flags() & ui::EF_FROM_TOUCH) == 0) ? CLOSE_TAB_FROM_MOUSE :
6712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      CLOSE_TAB_FROM_TOUCH;
6722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(close_button_, sender);
6735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  controller_->CloseTab(this, source);
674eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (event.type() == ui::ET_GESTURE_TAP)
675eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    TouchUMA::RecordGestureAction(TouchUMA::GESTURE_TABCLOSE_TAP);
6762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
6792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Tab, views::ContextMenuController overrides:
6802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Tab::ShowContextMenuForView(views::View* source,
6827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                 const gfx::Point& point,
6837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                 ui::MenuSourceType source_type) {
6845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!closing())
6855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    controller_->ShowContextMenuForTab(this, point, source_type);
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
689116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Tab, views::MaskedTargeterDelegate overrides:
690116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
691116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool Tab::GetHitTestMask(gfx::Path* mask) const {
692116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(mask);
693116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
694116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // When the window is maximized we don't want to shave off the edges or top
695116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // shadow of the tab, such that the user can click anywhere along the top
696116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // edge of the screen to select a tab. Ditto for immersive fullscreen.
697116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const views::Widget* widget = GetWidget();
698116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  bool include_top_shadow =
699116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      widget && (widget->IsMaximized() || widget->IsFullscreen());
700116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  TabResources::GetHitTestMask(width(), height(), include_top_shadow, mask);
701116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
702116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // It is possible for a portion of the tab to be occluded if tabs are
703116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // stacked, so modify the hit test mask to only include the visible
704116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // region of the tab.
705116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  gfx::Rect clip;
706116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  controller_->ShouldPaintTab(this, &clip);
707116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (clip.size().GetArea()) {
708116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    SkRect intersection(mask->getBounds());
709116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    intersection.intersect(RectToSkRect(clip));
710116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    mask->reset();
711116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    mask->addRect(intersection);
712116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
713116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
714116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return true;
715116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
716116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
717116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch////////////////////////////////////////////////////////////////////////////////
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Tab, views::View overrides:
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Tab::OnPaint(gfx::Canvas* canvas) {
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Don't paint if we're narrower than we can render correctly. (This should
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // only happen during animations).
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (width() < GetMinimumUnselectedSize().width() && !data().mini)
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect clip;
7275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!controller_->ShouldPaintTab(this, &clip))
7285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
7295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!clip.IsEmpty()) {
7305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    canvas->Save();
7315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    canvas->ClipRect(clip);
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (controller_->IsImmersiveStyle())
7352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    PaintImmersiveTab(canvas);
7362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else
7372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    PaintTab(canvas);
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!clip.IsEmpty())
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    canvas->Restore();
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Tab::Layout() {
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect lb = GetContentsBounds();
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (lb.IsEmpty())
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7481675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch  lb.Inset(kLeftPadding, kTopPadding, kRightPadding, kBottomPadding);
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  showing_icon_ = ShouldShowIcon();
7505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  favicon_bounds_.SetRect(lb.x(), lb.y(), 0, 0);
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (showing_icon_) {
7525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    favicon_bounds_.set_size(gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize));
7535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    favicon_bounds_.set_y(lb.y() + (lb.height() - gfx::kFaviconSize + 1) / 2);
75468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    MaybeAdjustLeftForMiniTab(&favicon_bounds_);
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  showing_close_button_ = ShouldShowCloseBox();
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (showing_close_button_) {
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the ratio of the close button size to tab width exceeds the maximum.
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The close button should be as large as possible so that there is a larger
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // hit-target for touch events. So the close button bounds extends to the
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // edges of the tab. However, the larger hit-target should be active only
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // for mouse events, and the close-image should show up in the right place.
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // So a border is added to the button with necessary padding. The close
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // button (BaseTab::TabCloseButton) makes sure the padding is a hit-target
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // only for touch events.
7675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    close_button_->SetBorder(views::Border::NullBorder());
7685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const gfx::Size close_button_size(close_button_->GetPreferredSize());
7695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const int top = lb.y() + (lb.height() - close_button_size.height() + 1) / 2;
7705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const int bottom = height() - (close_button_size.height() + top);
7715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const int left = kViewSpacing;
7725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const int right = width() - (lb.width() + close_button_size.width() + left);
7735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    close_button_->SetBorder(
7745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        views::Border::CreateEmptyBorder(top, left, bottom, right));
775c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    close_button_->SetPosition(gfx::Point(lb.width(), 0));
776c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    close_button_->SizeToPreferredSize();
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  close_button_->SetVisible(showing_close_button_);
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  showing_media_indicator_ = ShouldShowMediaIndicator();
7814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (showing_media_indicator_) {
7821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    views::ImageButton* const button = GetMediaIndicatorButton();
7831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const gfx::Size image_size(button->GetPreferredSize());
78468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const int right = showing_close_button_ ?
78568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        close_button_->x() + close_button_->GetInsets().left() : lb.right();
7861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    gfx::Rect bounds(
7871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        std::max(lb.x(), right - image_size.width()),
7881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        lb.y() + (lb.height() - image_size.height() + 1) / 2,
7891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        image_size.width(),
7901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        image_size.height());
7911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    MaybeAdjustLeftForMiniTab(&bounds);
7921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    button->SetBoundsRect(bounds);
7931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    button->SetVisible(true);
7941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  } else if (media_indicator_button_) {
7951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    media_indicator_button_->SetVisible(false);
79668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
79768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
7985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Size the title to fill the remaining width and use all available height.
7995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  bool show_title = !data().mini || width() >= kMiniTabRendererAsNormalTabWidth;
8005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (show_title) {
8015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    int title_left = favicon_bounds_.right() + kFaviconTitleSpacing;
8025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    int title_width = lb.width() - title_left;
8034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (showing_media_indicator_) {
8041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      title_width = media_indicator_button_->x() - kViewSpacing - title_left;
80568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    } else if (close_button_->visible()) {
8065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // Allow the title to overlay the close button's empty border padding.
80768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      title_width = close_button_->x() + close_button_->GetInsets().left() -
8085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          kViewSpacing - title_left;
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    gfx::Rect rect(title_left, lb.y(), std::max(title_width, 0), lb.height());
8116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    const int title_height = title_->GetPreferredSize().height();
8126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (title_height > rect.height()) {
8136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      rect.set_y(lb.y() - (title_height - rect.height()) / 2);
8146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      rect.set_height(title_height);
8156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
8165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    title_->SetBoundsRect(rect);
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  title_->SetVisible(show_title);
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Tab::OnThemeChanged() {
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LoadTabImages();
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)const char* Tab::GetClassName() const {
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return kViewClassName;
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
829a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool Tab::GetTooltipText(const gfx::Point& p, base::string16* tooltip) const {
8305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Note: Anything that affects the tooltip text should be accounted for when
8315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // calling TooltipTextChanged() from Tab::DataChanged().
8325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  *tooltip = chrome::AssembleTabTooltipText(data_.title, data_.media_state);
8335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return !tooltip->empty();
8342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Tab::GetTooltipTextOrigin(const gfx::Point& p, gfx::Point* origin) const {
837f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  origin->set_x(title_->x() + 10);
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  origin->set_y(-views::TooltipManager::GetTooltipHeight() - 4);
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Tab::OnMousePressed(const ui::MouseEvent& event) {
8435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  controller_->OnMouseEventInTab(this, event);
8442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Allow a right click from touch to drag, which corresponds to a long click.
8462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (event.IsOnlyLeftMouseButton() ||
8472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (event.IsOnlyRightMouseButton() && event.flags() & ui::EF_FROM_TOUCH)) {
8482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ui::ListSelectionModel original_selection;
8495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    original_selection.Copy(controller_->GetSelectionModel());
8502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Changing the selection may cause our bounds to change. If that happens
8512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // the location of the event may no longer be valid. Create a copy of the
8522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // event in the parents coordinate, which won't change, and recreate an
8532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // event after changing so the coordinates are correct.
8542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ui::MouseEvent event_in_parent(event, static_cast<View*>(this), parent());
8555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (controller_->SupportsMultipleSelection()) {
8562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (event.IsShiftDown() && event.IsControlDown()) {
8575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        controller_->AddSelectionFromAnchorTo(this);
8582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else if (event.IsShiftDown()) {
8595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        controller_->ExtendSelectionTo(this);
8602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else if (event.IsControlDown()) {
8615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        controller_->ToggleSelected(this);
8622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (!IsSelected()) {
8632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          // Don't allow dragging non-selected tabs.
8642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          return false;
8652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
8662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else if (!IsSelected()) {
8675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        controller_->SelectTab(this);
8682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
8692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else if (!IsSelected()) {
8705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      controller_->SelectTab(this);
8712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
8722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ui::MouseEvent cloned_event(event_in_parent, parent(),
8732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                static_cast<View*>(this));
8745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    controller_->MaybeStartDrag(this, cloned_event, original_selection);
8752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
8772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Tab::OnMouseDragged(const ui::MouseEvent& event) {
8805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  controller_->ContinueDrag(this, event);
8812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
8822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Tab::OnMouseReleased(const ui::MouseEvent& event) {
8855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  controller_->OnMouseEventInTab(this, event);
8862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Notify the drag helper that we're done with any potential drag operations.
8882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Clean up the drag helper, which is re-created on the next mouse press.
8892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // In some cases, ending the drag will schedule the tab for destruction; if
8902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // so, bail immediately, since our members are already dead and we shouldn't
8912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // do anything else except drop the tab where it is.
8925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (controller_->EndDrag(END_DRAG_COMPLETE))
8932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
8942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Close tab on middle click, but only if the button is released over the tab
8962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // (normal windows behavior is to discard presses of a UI element where the
8972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // releases happen off the element).
8982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (event.IsMiddleMouseButton()) {
8992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (HitTestPoint(event.location())) {
9005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      controller_->CloseTab(this, CLOSE_TAB_FROM_MOUSE);
9012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else if (closing_) {
9022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // We're animating closed and a middle mouse button was pushed on us but
9032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // we don't contain the mouse anymore. We assume the user is clicking
9042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // quicker than the animation and we should close the tab that falls under
9052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // the mouse.
9065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      Tab* closest_tab = controller_->GetTabAt(this, event.location());
9072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (closest_tab)
9085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        controller_->CloseTab(closest_tab, CLOSE_TAB_FROM_MOUSE);
9092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
9102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (event.IsOnlyLeftMouseButton() && !event.IsShiftDown() &&
9112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             !event.IsControlDown()) {
9122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // If the tab was already selected mouse pressed doesn't change the
9132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // selection. Reset it now to handle the case where multiple tabs were
9142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // selected.
9155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    controller_->SelectTab(this);
9161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
9171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (media_indicator_button_ && media_indicator_button_->visible() &&
9181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        media_indicator_button_->bounds().Contains(event.location())) {
9191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      content::RecordAction(UserMetricsAction("TabMediaIndicator_Clicked"));
9201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
9212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Tab::OnMouseCaptureLost() {
9255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  controller_->EndDrag(END_DRAG_CAPTURE_LOST);
9262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Tab::OnMouseEntered(const ui::MouseEvent& event) {
9292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  hover_controller_.Show(views::GlowHoverController::SUBTLE);
9302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Tab::OnMouseMoved(const ui::MouseEvent& event) {
9332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  hover_controller_.SetLocation(event.location());
9345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  controller_->OnMouseEventInTab(this, event);
9352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Tab::OnMouseExited(const ui::MouseEvent& event) {
9382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  hover_controller_.Hide();
9392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Tab::OnGestureEvent(ui::GestureEvent* event) {
9422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (event->type()) {
9435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case ui::ET_GESTURE_TAP_DOWN: {
9445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // TAP_DOWN is only dispatched for the first touch point.
9455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      DCHECK_EQ(1, event->details().touch_points());
9462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // See comment in OnMousePressed() as to why we copy the event.
9482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ui::GestureEvent event_in_parent(*event, static_cast<View*>(this),
9492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       parent());
9502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ui::ListSelectionModel original_selection;
9515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      original_selection.Copy(controller_->GetSelectionModel());
9525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      tab_activated_with_last_tap_down_ = !IsActive();
9532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (!IsSelected())
9545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        controller_->SelectTab(this);
9552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      gfx::Point loc(event->location());
9562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      views::View::ConvertPointToScreen(this, &loc);
9572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ui::GestureEvent cloned_event(event_in_parent, parent(),
9582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    static_cast<View*>(this));
9595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      controller_->MaybeStartDrag(this, cloned_event, original_selection);
9602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
9612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
9622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case ui::ET_GESTURE_END:
9645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      controller_->EndDrag(END_DRAG_COMPLETE);
9652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
9662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case ui::ET_GESTURE_SCROLL_UPDATE:
9685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      controller_->ContinueDrag(this, *event);
9692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
9702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    default:
9722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
9732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  event->SetHandled();
9752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
977a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void Tab::GetAccessibleState(ui::AXViewState* state) {
978a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  state->role = ui::AX_ROLE_TAB;
9792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  state->name = data_.title;
980116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  state->AddStateFlag(ui::AX_STATE_MULTISELECTABLE);
981116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  state->AddStateFlag(ui::AX_STATE_SELECTABLE);
9825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  controller_->UpdateTabAccessibilityState(this, state);
983116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (IsSelected())
984116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    state->AddStateFlag(ui::AX_STATE_SELECTED);
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Tab, private
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
99068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void Tab::MaybeAdjustLeftForMiniTab(gfx::Rect* bounds) const {
99168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!data().mini || width() >= kMiniTabRendererAsNormalTabWidth)
99268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return;
99368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const int mini_delta = kMiniTabRendererAsNormalTabWidth - GetMiniWidth();
99468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const int ideal_delta = width() - GetMiniWidth();
99568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const int ideal_x = (GetMiniWidth() - bounds->width()) / 2;
99668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  bounds->set_x(bounds->x() + static_cast<int>(
99768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      (1 - static_cast<float>(ideal_delta) / static_cast<float>(mini_delta)) *
99868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      (ideal_x - bounds->x())));
99968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
100068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
10012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Tab::DataChanged(const TabRendererData& old) {
10025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (data().media_state != old.media_state || data().title != old.title)
10035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    TooltipTextChanged();
10045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
10052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (data().blocked == old.blocked)
10062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
10072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (data().blocked)
10092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    StartPulse();
10102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else
10112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    StopPulse();
10122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
10132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Tab::PaintTab(gfx::Canvas* canvas) {
10152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // See if the model changes whether the icons should be painted.
10162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const bool show_icon = ShouldShowIcon();
10174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const bool show_media_indicator = ShouldShowMediaIndicator();
10182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const bool show_close_button = ShouldShowCloseBox();
101968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (show_icon != showing_icon_ ||
10204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      show_media_indicator != showing_media_indicator_ ||
102168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      show_close_button != showing_close_button_) {
10222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Layout();
102368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
10242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PaintTabBackground(canvas);
10262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1027f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const SkColor title_color = GetThemeProvider()->GetColor(IsSelected() ?
1028f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      ThemeProperties::COLOR_TAB_TEXT :
1029f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      ThemeProperties::COLOR_BACKGROUND_TAB_TEXT);
1030f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  title_->SetVisible(!data().mini ||
1031f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     width() > kMiniTabRendererAsNormalTabWidth);
1032f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  title_->SetEnabledColor(title_color);
10332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (show_icon)
10352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    PaintIcon(canvas);
10362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If the close button color has changed, generate a new one.
10382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!close_button_color_ || title_color != close_button_color_) {
10392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    close_button_color_ = title_color;
10402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
10412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    close_button_->SetBackground(close_button_color_,
1042c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        rb.GetImageSkiaNamed(IDR_CLOSE_1),
1043c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        rb.GetImageSkiaNamed(IDR_CLOSE_1_MASK));
10442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
10452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
10462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Tab::PaintImmersiveTab(gfx::Canvas* canvas) {
104890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Use transparency for the draw-attention animation.
1049ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  int alpha = 255;
1050116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (pulse_animation_ && pulse_animation_->is_animating() && !data().mini) {
1051116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    alpha = pulse_animation_->CurrentValueBetween(
1052ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        255, static_cast<int>(255 * kImmersiveTabMinThrobOpacity));
1053ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
105490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
10552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Draw a gray rectangle to represent the tab. This works for mini-tabs as
10562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // well as regular ones. The active tab has a brigher bar.
10572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SkColor color =
10582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      IsActive() ? kImmersiveActiveTabColor : kImmersiveInactiveTabColor;
10592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::Rect bar_rect = GetImmersiveBarRect();
106090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  canvas->FillRect(bar_rect, SkColorSetA(color, alpha));
10612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Paint network activity indicator.
10632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(jamescook): Replace this placeholder animation with a real one.
10642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // For now, let's go with a Cylon eye effect, but in blue.
10652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (data().network_state != TabRendererData::NETWORK_STATE_NONE) {
106690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const SkColor kEyeColor = SkColorSetARGB(alpha, 71, 138, 217);
10672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int eye_width = bar_rect.width() / 3;
10682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int eye_offset = bar_rect.width() * immersive_loading_step_ /
10692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        kImmersiveLoadingStepCount;
10702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (eye_offset + eye_width < bar_rect.width()) {
10712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Draw a single indicator strip because it fits inside |bar_rect|.
10722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      gfx::Rect eye_rect(
10732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          bar_rect.x() + eye_offset, 0, eye_width, kImmersiveBarHeight);
10742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      canvas->FillRect(eye_rect, kEyeColor);
10752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
10762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Draw two indicators to simulate the eye "wrapping around" to the left
10772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // side. The first part fills the remainder of the bar.
10782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      int right_eye_width = bar_rect.width() - eye_offset;
10792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      gfx::Rect right_eye_rect(
10802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          bar_rect.x() + eye_offset, 0, right_eye_width, kImmersiveBarHeight);
10812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      canvas->FillRect(right_eye_rect, kEyeColor);
10822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // The second part parts the remaining |eye_width| on the left.
10832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      int left_eye_width = eye_offset + eye_width - bar_rect.width();
10842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      gfx::Rect left_eye_rect(
10852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          bar_rect.x(), 0, left_eye_width, kImmersiveBarHeight);
10862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      canvas->FillRect(left_eye_rect, kEyeColor);
10872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
10882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
10892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
10902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Tab::PaintTabBackground(gfx::Canvas* canvas) {
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsActive()) {
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PaintActiveTabBackground(canvas);
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1095116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (mini_title_change_animation_ &&
1096116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        mini_title_change_animation_->is_animating()) {
1097116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      PaintInactiveTabBackgroundWithTitleChange(canvas);
10982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PaintInactiveTabBackground(canvas);
11002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    double throb_value = GetThrobValue();
11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (throb_value > 0) {
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      canvas->SaveLayerAlpha(static_cast<int>(throb_value * 0xff),
11052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             GetLocalBounds());
11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PaintActiveTabBackground(canvas);
11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      canvas->Restore();
11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1112116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid Tab::PaintInactiveTabBackgroundWithTitleChange(gfx::Canvas* canvas) {
11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Render the inactive tab background. We'll use this for clipping.
111468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  gfx::Canvas background_canvas(size(), canvas->image_scale(), false);
11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PaintInactiveTabBackground(&background_canvas);
11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::ImageSkia background_image(background_canvas.ExtractImageRep());
11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Draw a radial gradient to hover_canvas.
112068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  gfx::Canvas hover_canvas(size(), canvas->image_scale(), false);
11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int radius = kMiniTitleChangeGradientRadius;
11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int x0 = width() + radius - kMiniTitleChangeInitialXOffset;
11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int x1 = radius;
11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int x2 = -radius;
11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int x;
1126116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (mini_title_change_animation_->current_part_index() == 0) {
1127116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    x = mini_title_change_animation_->CurrentValueBetween(x0, x1);
1128116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  } else if (mini_title_change_animation_->current_part_index() == 1) {
11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    x = x1;
11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1131116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    x = mini_title_change_animation_->CurrentValueBetween(x1, x2);
11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SkPoint center_point;
11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  center_point.iset(x, 0);
11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SkColor colors[2] = { kMiniTitleChangeGradientColor1,
11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        kMiniTitleChangeGradientColor2 };
11372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  skia::RefPtr<SkShader> shader = skia::AdoptRef(
11382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SkGradientShader::CreateRadial(
11392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          center_point, SkIntToScalar(radius), colors, NULL, 2,
11402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          SkShader::kClamp_TileMode));
11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SkPaint paint;
11422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  paint.setShader(shader.get());
11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hover_canvas.DrawRect(gfx::Rect(x - radius, -radius, radius * 2, radius * 2),
11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        paint);
11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Draw the radial gradient clipped to the background into hover_image.
11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::ImageSkia hover_image = gfx::ImageSkiaOperations::CreateMaskedImage(
11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gfx::ImageSkia(hover_canvas.ExtractImageRep()), background_image);
11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Draw the tab background to the canvas.
11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  canvas->DrawImageInt(background_image, 0, 0);
11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // And then the gradient on top of that.
1154116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (mini_title_change_animation_->current_part_index() == 2) {
1155116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    uint8 alpha = mini_title_change_animation_->CurrentValueBetween(255, 0);
11565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    canvas->DrawImageInt(hover_image, 0, 0, alpha);
11575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
11585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    canvas->DrawImageInt(hover_image, 0, 0);
11595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Tab::PaintInactiveTabBackground(gfx::Canvas* canvas) {
11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int tab_id;
11642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int frame_id;
11652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  views::Widget* widget = GetWidget();
11662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GetTabIdAndFrameId(widget, &tab_id, &frame_id);
11672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Explicitly map the id so we cache correctly.
11692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const chrome::HostDesktopType host_desktop_type = GetHostDesktopType(this);
11702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  tab_id = chrome::MapThemeImage(host_desktop_type, tab_id);
11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // HasCustomImage() is only true if the theme provides the image. However,
11732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // even if the theme does not provide a tab background, the theme machinery
11742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // will make one if given a frame image.
11752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ui::ThemeProvider* theme_provider = GetThemeProvider();
11762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const bool theme_provided_image = theme_provider->HasCustomImage(tab_id) ||
11772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (frame_id != 0 && theme_provider->HasCustomImage(frame_id));
11782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const bool can_cache = !theme_provided_image &&
11802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !hover_controller_.ShouldDraw();
11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (can_cache) {
118368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    ui::ScaleFactor scale_factor =
118468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        ui::GetSupportedScaleFactor(canvas->image_scale());
118568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    gfx::ImageSkia cached_image(GetCachedImage(tab_id, size(), scale_factor));
11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (cached_image.width() == 0) {
118768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      gfx::Canvas tmp_canvas(size(), canvas->image_scale(), false);
11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PaintInactiveTabBackgroundUsingResourceId(&tmp_canvas, tab_id);
11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cached_image = gfx::ImageSkia(tmp_canvas.ExtractImageRep());
119068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      SetCachedImage(tab_id, scale_factor, cached_image);
11915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    canvas->DrawImageInt(cached_image, 0, 0);
11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PaintInactiveTabBackgroundUsingResourceId(canvas, tab_id);
11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Tab::PaintInactiveTabBackgroundUsingResourceId(gfx::Canvas* canvas,
11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                    int tab_id) {
12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // WARNING: the inactive tab background may be cached. If you change what it
12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // is drawn from you may need to update whether it can be cached.
12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The tab image needs to be lined up with the background image
12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // so that it feels partially transparent.  These offsets represent the tab
12055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // position within the frame background image.
12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int offset = GetMirroredX() + background_offset_.x();
12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::ImageSkia* tab_bg = GetThemeProvider()->GetImageSkiaNamed(tab_id);
12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TabImage* tab_image = &tab_active_;
12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TabImage* tab_inactive_image = &tab_inactive_;
12125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TabImage* alpha = &tab_alpha_;
12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the theme is providing a custom background image, then its top edge
12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // should be at the top of the tab. Otherwise, we assume that the background
12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // image is a composited foreground + frame image.
12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int bg_offset_y = GetThemeProvider()->HasCustomImage(tab_id) ?
12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      0 : background_offset_.y();
12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We need a gfx::Canvas object to be able to extract the image from.
12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We draw everything to this canvas and then output it to the canvas
12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // parameter in addition to using it to mask the hover glow if needed.
122368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  gfx::Canvas background_canvas(size(), canvas->image_scale(), false);
12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Draw left edge.  Don't draw over the toolbar, as we're not the foreground
12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // tab.
12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::ImageSkia tab_l = gfx::ImageSkiaOperations::CreateTiledImage(
12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *tab_bg, offset, bg_offset_y, tab_image->l_width, height());
12295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::ImageSkia theme_l =
12305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gfx::ImageSkiaOperations::CreateMaskedImage(tab_l, *alpha->image_l);
12315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  background_canvas.DrawImageInt(theme_l,
12325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      0, 0, theme_l.width(), theme_l.height() - kToolbarOverlap,
12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      0, 0, theme_l.width(), theme_l.height() - kToolbarOverlap,
12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      false);
12355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Draw right edge.  Again, don't draw over the toolbar.
12375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::ImageSkia tab_r = gfx::ImageSkiaOperations::CreateTiledImage(*tab_bg,
12385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      offset + width() - tab_image->r_width, bg_offset_y,
12395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_image->r_width, height());
12405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::ImageSkia theme_r =
12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gfx::ImageSkiaOperations::CreateMaskedImage(tab_r, *alpha->image_r);
12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  background_canvas.DrawImageInt(theme_r,
12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      0, 0, theme_r.width(), theme_r.height() - kToolbarOverlap,
12445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      width() - theme_r.width(), 0, theme_r.width(),
12455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      theme_r.height() - kToolbarOverlap, false);
12465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Draw center.  Instead of masking out the top portion we simply skip over
12485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // it by incrementing by GetDropShadowHeight(), since it's a simple
12495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // rectangle. And again, don't draw over the toolbar.
12505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  background_canvas.TileImageInt(*tab_bg,
12515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     offset + tab_image->l_width,
12525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu     bg_offset_y + kDropShadowHeight,
12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     tab_image->l_width,
12545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu     kDropShadowHeight,
12555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     width() - tab_image->l_width - tab_image->r_width,
12565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu     height() - kDropShadowHeight - kToolbarOverlap);
12575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  canvas->DrawImageInt(
12595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gfx::ImageSkia(background_canvas.ExtractImageRep()), 0, 0);
12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetThemeProvider()->HasCustomImage(tab_id) &&
12622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      hover_controller_.ShouldDraw()) {
12632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    hover_controller_.Draw(canvas, gfx::ImageSkia(
12645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        background_canvas.ExtractImageRep()));
12655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now draw the highlights/shadows around the tab edge.
12685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  canvas->DrawImageInt(*tab_inactive_image->image_l, 0, 0);
12695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  canvas->TileImageInt(*tab_inactive_image->image_c,
12705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       tab_inactive_image->l_width, 0,
12715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       width() - tab_inactive_image->l_width -
12725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           tab_inactive_image->r_width,
12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       height());
12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  canvas->DrawImageInt(*tab_inactive_image->image_r,
12755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       width() - tab_inactive_image->r_width, 0);
12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Tab::PaintActiveTabBackground(gfx::Canvas* canvas) {
12795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::ImageSkia* tab_background =
12805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetThemeProvider()->GetImageSkiaNamed(IDR_THEME_TOOLBAR);
12815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int offset = GetMirroredX() + background_offset_.x();
12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TabImage* tab_image = &tab_active_;
12845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TabImage* alpha = &tab_alpha_;
12855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Draw left edge.
12875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::ImageSkia tab_l = gfx::ImageSkiaOperations::CreateTiledImage(
12885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *tab_background, offset, 0, tab_image->l_width, height());
12895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::ImageSkia theme_l =
12905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gfx::ImageSkiaOperations::CreateMaskedImage(tab_l, *alpha->image_l);
12915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  canvas->DrawImageInt(theme_l, 0, 0);
12925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Draw right edge.
12945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::ImageSkia tab_r = gfx::ImageSkiaOperations::CreateTiledImage(
12955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *tab_background,
12965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      offset + width() - tab_image->r_width, 0, tab_image->r_width, height());
12975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::ImageSkia theme_r =
12985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gfx::ImageSkiaOperations::CreateMaskedImage(tab_r, *alpha->image_r);
12995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  canvas->DrawImageInt(theme_r, width() - tab_image->r_width, 0);
13005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Draw center.  Instead of masking out the top portion we simply skip over it
13025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // by incrementing by GetDropShadowHeight(), since it's a simple rectangle.
13035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  canvas->TileImageInt(*tab_background,
13045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     offset + tab_image->l_width,
13055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu     kDropShadowHeight,
13065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     tab_image->l_width,
13075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu     kDropShadowHeight,
13085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     width() - tab_image->l_width - tab_image->r_width,
13095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu     height() - kDropShadowHeight);
13105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now draw the highlights/shadows around the tab edge.
13125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  canvas->DrawImageInt(*tab_image->image_l, 0, 0);
13135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  canvas->TileImageInt(*tab_image->image_c, tab_image->l_width, 0,
13145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      width() - tab_image->l_width - tab_image->r_width, height());
13155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  canvas->DrawImageInt(*tab_image->image_r, width() - tab_image->r_width, 0);
13165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Tab::PaintIcon(gfx::Canvas* canvas) {
1319f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  gfx::Rect bounds = favicon_bounds_;
13202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (bounds.IsEmpty())
13212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
13222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bounds.set_x(GetMirroredXForRect(bounds));
13242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (data().network_state != TabRendererData::NETWORK_STATE_NONE) {
13264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Paint network activity (aka throbber) animation frame.
13272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ui::ThemeProvider* tp = GetThemeProvider();
13282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    gfx::ImageSkia frames(*tp->GetImageSkiaNamed(
13292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        (data().network_state == TabRendererData::NETWORK_STATE_WAITING) ?
13302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        IDR_THROBBER_WAITING : IDR_THROBBER));
13312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int icon_size = frames.height();
13332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int image_offset = loading_animation_frame_ * icon_size;
13342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DrawIconCenter(canvas, frames, image_offset,
13352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   icon_size, icon_size,
13362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   bounds, false, SkPaint());
13374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  } else if (should_display_crashed_favicon_) {
13384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Paint crash favicon.
13392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
13402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    gfx::ImageSkia crashed_favicon(*rb.GetImageSkiaNamed(IDR_SAD_FAVICON));
13412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bounds.set_y(bounds.y() + favicon_hiding_offset_);
13422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DrawIconCenter(canvas, crashed_favicon, 0,
1343f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                   crashed_favicon.width(),
1344f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                   crashed_favicon.height(),
1345f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                   bounds, true, SkPaint());
13464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  } else if (!data().favicon.isNull()) {
13474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Paint the normal favicon.
13484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    DrawIconCenter(canvas, data().favicon, 0,
13494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                   data().favicon.width(),
13504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                   data().favicon.height(),
13514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                   bounds, true, SkPaint());
13522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
13532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
13542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Tab::AdvanceLoadingAnimation(TabRendererData::NetworkState old_state,
13562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  TabRendererData::NetworkState state) {
13572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static bool initialized = false;
13582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static int loading_animation_frame_count = 0;
13592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static int waiting_animation_frame_count = 0;
13602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static int waiting_to_loading_frame_count_ratio = 0;
13612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!initialized) {
13622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    initialized = true;
13632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
13642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    gfx::ImageSkia loading_animation(*rb.GetImageSkiaNamed(IDR_THROBBER));
13652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    loading_animation_frame_count =
13662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        loading_animation.width() / loading_animation.height();
13672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    gfx::ImageSkia waiting_animation(*rb.GetImageSkiaNamed(
13682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        IDR_THROBBER_WAITING));
13692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    waiting_animation_frame_count =
13702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        waiting_animation.width() / waiting_animation.height();
13712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    waiting_to_loading_frame_count_ratio =
13722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        waiting_animation_frame_count / loading_animation_frame_count;
13732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::debug::Alias(&loading_animation_frame_count);
13752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::debug::Alias(&waiting_animation_frame_count);
13762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CHECK_NE(0, waiting_to_loading_frame_count_ratio) <<
13772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        "Number of frames in IDR_THROBBER must be equal to or greater " <<
13782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        "than the number of frames in IDR_THROBBER_WAITING. Please " <<
13792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        "investigate how this happened and update http://crbug.com/132590, " <<
13802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        "this is causing crashes in the wild.";
13812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
13822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The waiting animation is the reverse of the loading animation, but at a
13842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // different rate - the following reverses and scales the animation_frame_
13852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // so that the frame is at an equivalent position when going from one
13862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // animation to the other.
13872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (state != old_state) {
13882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    loading_animation_frame_ = loading_animation_frame_count -
13892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        (loading_animation_frame_ / waiting_to_loading_frame_count_ratio);
13902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
13912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (state == TabRendererData::NETWORK_STATE_WAITING) {
13932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    loading_animation_frame_ = (loading_animation_frame_ + 1) %
13942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        waiting_animation_frame_count;
13952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Waiting steps backwards.
13962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    immersive_loading_step_ =
13972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        (immersive_loading_step_ - 1 + kImmersiveLoadingStepCount) %
13982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            kImmersiveLoadingStepCount;
13992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (state == TabRendererData::NETWORK_STATE_LOADING) {
14002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    loading_animation_frame_ = (loading_animation_frame_ + 1) %
14012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        loading_animation_frame_count;
14022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    immersive_loading_step_ = (immersive_loading_step_ + 1) %
14032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        kImmersiveLoadingStepCount;
14042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
14052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    loading_animation_frame_ = 0;
14062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    immersive_loading_step_ = 0;
14072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
14085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (controller_->IsImmersiveStyle())
14092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SchedulePaintInRect(GetImmersiveBarRect());
14102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else
14112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ScheduleIconPaint();
14122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
14132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int Tab::IconCapacity() const {
14155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (height() < GetMinimumUnselectedSize().height())
14165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
14174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const int available_width =
14185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      std::max(0, width() - kLeftPadding - kRightPadding);
14195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  const int width_per_icon = gfx::kFaviconSize;
142068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const int kPaddingBetweenIcons = 2;
14214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (available_width >= width_per_icon &&
14224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      available_width < (width_per_icon + kPaddingBetweenIcons)) {
14234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return 1;
14244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
14254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return available_width / (width_per_icon + kPaddingBetweenIcons);
14265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Tab::ShouldShowIcon() const {
14294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return chrome::ShouldTabShowFavicon(
14304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      IconCapacity(), data().mini, IsActive(), data().show_icon,
14311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      media_indicator_button_ ? media_indicator_button_->showing_media_state() :
14321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                data_.media_state);
143368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
143468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
14354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool Tab::ShouldShowMediaIndicator() const {
14364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return chrome::ShouldTabShowMediaIndicator(
14374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      IconCapacity(), data().mini, IsActive(), data().show_icon,
14381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      media_indicator_button_ ? media_indicator_button_->showing_media_state() :
14391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                data_.media_state);
14405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Tab::ShouldShowCloseBox() const {
14434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return chrome::ShouldTabShowCloseButton(
14444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      IconCapacity(), data().mini, IsActive());
14455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)double Tab::GetThrobValue() {
1448116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const bool is_selected = IsSelected();
1449116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const double min = is_selected ? kSelectedTabOpacity : 0;
1450116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const double scale = is_selected ? kSelectedTabThrobScale : 1;
1451116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1452116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Showing both the pulse and title change animation at the same time is too
1453116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // much.
1454116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (pulse_animation_ && pulse_animation_->is_animating() &&
1455116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      (!mini_title_change_animation_ ||
1456116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       !mini_title_change_animation_->is_animating())) {
1457116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return pulse_animation_->GetCurrentValue() * kHoverOpacity * scale + min;
14582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
14595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (hover_controller_.ShouldDraw()) {
14612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return kHoverOpacity * hover_controller_.GetAnimationValue() * scale +
14625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        min;
14635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return is_selected ? kSelectedTabOpacity : 0;
14665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Tab::SetFaviconHidingOffset(int offset) {
14692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  favicon_hiding_offset_ = offset;
14702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ScheduleIconPaint();
14712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
14722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Tab::DisplayCrashedFavicon() {
14742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  should_display_crashed_favicon_ = true;
14752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
14762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Tab::ResetCrashedFavicon() {
14782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  should_display_crashed_favicon_ = false;
14792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
14802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void Tab::StopCrashAnimation() {
148268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  crash_icon_animation_.reset();
14832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
14842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Tab::StartCrashAnimation() {
148668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  crash_icon_animation_.reset(new FaviconCrashAnimation(this));
148768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  crash_icon_animation_->Start();
14882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
14892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Tab::IsPerformingCrashAnimation() const {
149168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return crash_icon_animation_.get() && data_.IsCrashed();
14922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
14932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Tab::ScheduleIconPaint() {
1495f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  gfx::Rect bounds = favicon_bounds_;
14962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (bounds.IsEmpty())
14972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
14982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1499f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Extends the area to the bottom when sad_favicon is animating.
15002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (IsPerformingCrashAnimation())
15012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bounds.set_height(height() - bounds.y());
15022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bounds.set_x(GetMirroredXForRect(bounds));
15032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SchedulePaintInRect(bounds);
15042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
15052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
15062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gfx::Rect Tab::GetImmersiveBarRect() const {
15072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The main bar is as wide as the normal tab's horizontal top line.
15082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This top line of the tab extends a few pixels left and right of the
15092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // center image due to pixels in the rounded corner images.
15102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const int kBarPadding = 1;
15112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int main_bar_left = tab_active_.l_width - kBarPadding;
15122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int main_bar_right = width() - tab_active_.r_width + kBarPadding;
15132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return gfx::Rect(
15142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      main_bar_left, 0, main_bar_right - main_bar_left, kImmersiveBarHeight);
15152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
15162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
15172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Tab::GetTabIdAndFrameId(views::Widget* widget,
15182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             int* tab_id,
15192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             int* frame_id) const {
15205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (widget &&
15215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      widget->GetTopLevelWidget()->ShouldWindowContentsBeTransparent()) {
15222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *tab_id = IDR_THEME_TAB_BACKGROUND_V;
15232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *frame_id = 0;
15242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (data().incognito) {
15252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *tab_id = IDR_THEME_TAB_BACKGROUND_INCOGNITO;
15262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *frame_id = IDR_THEME_FRAME_INCOGNITO;
15272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
15282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *tab_id = IDR_THEME_TAB_BACKGROUND;
15292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *frame_id = IDR_THEME_FRAME;
15302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
15312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
15322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
15331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciMediaIndicatorButton* Tab::GetMediaIndicatorButton() {
15341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!media_indicator_button_) {
15351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    media_indicator_button_ = new MediaIndicatorButton();
15361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    AddChildView(media_indicator_button_);  // Takes ownership.
15371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
15381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return media_indicator_button_;
15391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
15401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
15415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
15422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Tab, private static:
15435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
15455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Tab::InitTabResources() {
15465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool initialized = false;
15475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (initialized)
15485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
15495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  initialized = true;
15515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  image_cache_ = new ImageCache();
15525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Load the tab images once now, and maybe again later if the theme changes.
15545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LoadTabImages();
15555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
15585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Tab::LoadTabImages() {
15595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We're not letting people override tab images just yet.
15605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
15615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tab_alpha_.image_l = rb.GetImageSkiaNamed(IDR_TAB_ALPHA_LEFT);
15635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tab_alpha_.image_r = rb.GetImageSkiaNamed(IDR_TAB_ALPHA_RIGHT);
15645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tab_active_.image_l = rb.GetImageSkiaNamed(IDR_TAB_ACTIVE_LEFT);
15665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tab_active_.image_c = rb.GetImageSkiaNamed(IDR_TAB_ACTIVE_CENTER);
15675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tab_active_.image_r = rb.GetImageSkiaNamed(IDR_TAB_ACTIVE_RIGHT);
15685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tab_active_.l_width = tab_active_.image_l->width();
15695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tab_active_.r_width = tab_active_.image_r->width();
15705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tab_inactive_.image_l = rb.GetImageSkiaNamed(IDR_TAB_INACTIVE_LEFT);
15725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tab_inactive_.image_c = rb.GetImageSkiaNamed(IDR_TAB_INACTIVE_CENTER);
15735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tab_inactive_.image_r = rb.GetImageSkiaNamed(IDR_TAB_INACTIVE_RIGHT);
15745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tab_inactive_.l_width = tab_inactive_.image_l->width();
15755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tab_inactive_.r_width = tab_inactive_.image_r->width();
15765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
15795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::ImageSkia Tab::GetCachedImage(int resource_id,
15805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   const gfx::Size& size,
15815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   ui::ScaleFactor scale_factor) {
15825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (ImageCache::const_iterator i = image_cache_->begin();
15835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != image_cache_->end(); ++i) {
15845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (i->resource_id == resource_id && i->scale_factor == scale_factor &&
15855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        i->image.size() == size) {
15865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return i->image;
15875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
15885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return gfx::ImageSkia();
15905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
15935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Tab::SetCachedImage(int resource_id,
15945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         ui::ScaleFactor scale_factor,
15955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const gfx::ImageSkia& image) {
15962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_NE(scale_factor, ui::SCALE_FACTOR_NONE);
15975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ImageCacheEntry entry;
15985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entry.resource_id = resource_id;
15995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entry.scale_factor = scale_factor;
16005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entry.image = image;
16015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  image_cache_->push_front(entry);
16025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (image_cache_->size() > kMaxImageCacheSize)
16035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    image_cache_->pop_back();
16045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1605