Home | History | Annotate | Download | only in tabs
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/ui/views/tabs/tab.h"
      6 #include "chrome/browser/ui/views/tabs/tab_controller.h"
      7 
      8 #include "base/strings/utf_string_conversions.h"
      9 #include "testing/gtest/include/gtest/gtest.h"
     10 #include "ui/base/models/list_selection_model.h"
     11 #include "ui/views/controls/button/image_button.h"
     12 #include "ui/views/test/views_test_base.h"
     13 #include "ui/views/widget/widget.h"
     14 
     15 using views::Widget;
     16 
     17 class FakeTabController : public TabController {
     18  public:
     19   FakeTabController() : immersive_style_(false) {
     20   }
     21   virtual ~FakeTabController() {}
     22 
     23   void set_immersive_style(bool value) { immersive_style_ = value; }
     24 
     25   virtual const ui::ListSelectionModel& GetSelectionModel() OVERRIDE {
     26     return selection_model_;
     27   }
     28   virtual bool SupportsMultipleSelection() OVERRIDE { return false; }
     29   virtual void SelectTab(Tab* tab) OVERRIDE {}
     30   virtual void ExtendSelectionTo(Tab* tab) OVERRIDE {}
     31   virtual void ToggleSelected(Tab* tab) OVERRIDE {}
     32   virtual void AddSelectionFromAnchorTo(Tab* tab) OVERRIDE {}
     33   virtual void CloseTab(Tab* tab, CloseTabSource source) OVERRIDE {}
     34   virtual void ShowContextMenuForTab(Tab* tab,
     35                                      const gfx::Point& p,
     36                                      ui::MenuSourceType source_type) OVERRIDE {}
     37   virtual bool IsActiveTab(const Tab* tab) const OVERRIDE { return false; }
     38   virtual bool IsTabSelected(const Tab* tab) const OVERRIDE {
     39     return false;
     40   }
     41   virtual bool IsTabPinned(const Tab* tab) const OVERRIDE { return false; }
     42   virtual void MaybeStartDrag(
     43       Tab* tab,
     44       const ui::LocatedEvent& event,
     45       const ui::ListSelectionModel& original_selection) OVERRIDE {}
     46   virtual void ContinueDrag(views::View* view,
     47                             const ui::LocatedEvent& event) OVERRIDE {}
     48   virtual bool EndDrag(EndDragReason reason) OVERRIDE { return false; }
     49   virtual Tab* GetTabAt(Tab* tab,
     50                         const gfx::Point& tab_in_tab_coordinates) OVERRIDE {
     51     return NULL;
     52   }
     53   virtual void OnMouseEventInTab(views::View* source,
     54                                  const ui::MouseEvent& event) OVERRIDE {}
     55   virtual bool ShouldPaintTab(const Tab* tab, gfx::Rect* clip) OVERRIDE {
     56     return true;
     57   }
     58   virtual bool IsImmersiveStyle() const OVERRIDE { return immersive_style_; }
     59 
     60  private:
     61   ui::ListSelectionModel selection_model_;
     62   bool immersive_style_;
     63 
     64   DISALLOW_COPY_AND_ASSIGN(FakeTabController);
     65 };
     66 
     67 class TabTest : public views::ViewsTestBase {
     68  public:
     69   TabTest() {}
     70   virtual ~TabTest() {}
     71 
     72   static bool IconAnimationInvariant(const Tab& tab) {
     73     bool capture_invariant =
     74         tab.data().CaptureActive() == (tab.icon_animation_.get() != NULL);
     75     bool audio_invariant =
     76         !tab.data().AudioActive() || tab.tab_audio_indicator_->IsAnimating();
     77     return capture_invariant && audio_invariant;
     78   }
     79 };
     80 
     81 TEST_F(TabTest, HitTestTopPixel) {
     82   Widget widget;
     83   Widget::InitParams params(CreateParams(Widget::InitParams::TYPE_WINDOW));
     84   params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
     85   params.bounds.SetRect(10, 20, 300, 400);
     86   widget.Init(params);
     87 
     88   FakeTabController tab_controller;
     89   Tab tab(&tab_controller);
     90   widget.GetContentsView()->AddChildView(&tab);
     91   tab.SetBoundsRect(gfx::Rect(gfx::Point(0, 0), Tab::GetStandardSize()));
     92 
     93   // Tabs have some shadow in the top, so by default we don't hit the tab there.
     94   int middle_x = tab.width() / 2;
     95   EXPECT_FALSE(tab.HitTestPoint(gfx::Point(middle_x, 0)));
     96 
     97   // Tabs are slanted, so a click halfway down the left edge won't hit it.
     98   int middle_y = tab.height() / 2;
     99   EXPECT_FALSE(tab.HitTestPoint(gfx::Point(0, middle_y)));
    100 
    101   // If the window is maximized, however, we want clicks in the top edge to
    102   // select the tab.
    103   widget.Maximize();
    104   EXPECT_TRUE(tab.HitTestPoint(gfx::Point(middle_x, 0)));
    105 
    106   // But clicks in the area above the slanted sides should still miss.
    107   EXPECT_FALSE(tab.HitTestPoint(gfx::Point(0, 0)));
    108   EXPECT_FALSE(tab.HitTestPoint(gfx::Point(tab.width() - 1, 0)));
    109 }
    110 
    111 // Regression test for http://crbug.com/226253. Calling Layout() more than once
    112 // shouldn't change the insets of the close button.
    113 TEST_F(TabTest, CloseButtonLayout) {
    114   FakeTabController tab_controller;
    115   Tab tab(&tab_controller);
    116   tab.SetBounds(0, 0, 100, 50);
    117   tab.Layout();
    118   gfx::Insets close_button_insets = tab.close_button_->GetInsets();
    119   tab.Layout();
    120   gfx::Insets close_button_insets_2 = tab.close_button_->GetInsets();
    121   EXPECT_EQ(close_button_insets.top(), close_button_insets_2.top());
    122   EXPECT_EQ(close_button_insets.left(), close_button_insets_2.left());
    123   EXPECT_EQ(close_button_insets.bottom(), close_button_insets_2.bottom());
    124   EXPECT_EQ(close_button_insets.right(), close_button_insets_2.right());
    125 
    126   // Also make sure the close button is sized as large as the tab.
    127   EXPECT_EQ(50, tab.close_button_->bounds().height());
    128 }
    129 
    130 TEST_F(TabTest, ActivityIndicators) {
    131   FakeTabController controller;
    132   Tab tab(&controller);
    133 
    134   SkBitmap bitmap;
    135   bitmap.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
    136   bitmap.allocPixels();
    137 
    138   TabRendererData data;
    139   data.favicon = gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
    140   tab.SetData(data);
    141 
    142   // Audio starts and stops.
    143   data.audio_state = TabRendererData::AUDIO_STATE_PLAYING;
    144   tab.SetData(data);
    145   EXPECT_TRUE(IconAnimationInvariant(tab));
    146   EXPECT_EQ(TabRendererData::AUDIO_STATE_PLAYING, tab.data().audio_state);
    147   EXPECT_EQ(TabRendererData::CAPTURE_STATE_NONE, tab.data().capture_state);
    148   data.audio_state = TabRendererData::AUDIO_STATE_NONE;
    149   tab.SetData(data);
    150   EXPECT_TRUE(IconAnimationInvariant(tab));
    151   EXPECT_EQ(TabRendererData::AUDIO_STATE_NONE, tab.data().audio_state);
    152   EXPECT_EQ(TabRendererData::CAPTURE_STATE_NONE, tab.data().capture_state);
    153   EXPECT_TRUE(IconAnimationInvariant(tab));
    154 
    155   // Capture starts and stops.
    156   data.capture_state = TabRendererData::CAPTURE_STATE_RECORDING;
    157   tab.SetData(data);
    158   EXPECT_TRUE(IconAnimationInvariant(tab));
    159   EXPECT_EQ(TabRendererData::AUDIO_STATE_NONE, tab.data().audio_state);
    160   EXPECT_EQ(TabRendererData::CAPTURE_STATE_RECORDING, tab.data().capture_state);
    161   data.capture_state = TabRendererData::CAPTURE_STATE_NONE;
    162   tab.SetData(data);
    163   EXPECT_TRUE(IconAnimationInvariant(tab));
    164   EXPECT_EQ(TabRendererData::AUDIO_STATE_NONE, tab.data().audio_state);
    165   EXPECT_EQ(TabRendererData::CAPTURE_STATE_NONE, tab.data().capture_state);
    166   EXPECT_TRUE(IconAnimationInvariant(tab));
    167 
    168   // Audio starts then capture starts, then audio stops then capture stops.
    169   data.audio_state = TabRendererData::AUDIO_STATE_PLAYING;
    170   tab.SetData(data);
    171   data.capture_state = TabRendererData::CAPTURE_STATE_RECORDING;
    172   tab.SetData(data);
    173   EXPECT_TRUE(IconAnimationInvariant(tab));
    174   EXPECT_EQ(TabRendererData::AUDIO_STATE_PLAYING, tab.data().audio_state);
    175   EXPECT_EQ(TabRendererData::CAPTURE_STATE_RECORDING, tab.data().capture_state);
    176 
    177   data.title = ASCIIToUTF16("test X");
    178   tab.SetData(data);
    179   EXPECT_TRUE(IconAnimationInvariant(tab));
    180 
    181   data.audio_state = TabRendererData::AUDIO_STATE_NONE;
    182   tab.SetData(data);
    183   EXPECT_TRUE(IconAnimationInvariant(tab));
    184   EXPECT_EQ(TabRendererData::CAPTURE_STATE_RECORDING, tab.data().capture_state);
    185   data.capture_state = TabRendererData::CAPTURE_STATE_NONE;
    186   tab.SetData(data);
    187   EXPECT_TRUE(IconAnimationInvariant(tab));
    188   EXPECT_EQ(TabRendererData::AUDIO_STATE_NONE, tab.data().audio_state);
    189   EXPECT_EQ(TabRendererData::CAPTURE_STATE_NONE, tab.data().capture_state);
    190 
    191   // Audio starts then capture starts, then capture stops then audio stops.
    192   data.audio_state = TabRendererData::AUDIO_STATE_PLAYING;
    193   tab.SetData(data);
    194   data.capture_state = TabRendererData::CAPTURE_STATE_RECORDING;
    195   tab.SetData(data);
    196   EXPECT_TRUE(IconAnimationInvariant(tab));
    197   EXPECT_EQ(TabRendererData::AUDIO_STATE_PLAYING, tab.data().audio_state);
    198   EXPECT_EQ(TabRendererData::CAPTURE_STATE_RECORDING, tab.data().capture_state);
    199 
    200   data.title = ASCIIToUTF16("test Y");
    201   tab.SetData(data);
    202   EXPECT_TRUE(IconAnimationInvariant(tab));
    203 
    204   data.capture_state = TabRendererData::CAPTURE_STATE_NONE;
    205   tab.SetData(data);
    206   EXPECT_TRUE(IconAnimationInvariant(tab));
    207   EXPECT_EQ(TabRendererData::CAPTURE_STATE_NONE, tab.data().capture_state);
    208 
    209   data.audio_state = TabRendererData::AUDIO_STATE_NONE;
    210   tab.SetData(data);
    211   EXPECT_TRUE(IconAnimationInvariant(tab));
    212   EXPECT_EQ(TabRendererData::AUDIO_STATE_NONE, tab.data().audio_state);
    213   EXPECT_EQ(TabRendererData::CAPTURE_STATE_NONE, tab.data().capture_state);
    214   EXPECT_TRUE(IconAnimationInvariant(tab));
    215 }
    216