| Index: chrome/browser/ui/views/tabs/tab_unittest.cc
 | 
| diff --git a/chrome/browser/ui/views/tabs/tab_unittest.cc b/chrome/browser/ui/views/tabs/tab_unittest.cc
 | 
| index 6a175fa09506154477ab7ab90e4d6d60ae2e4b70..da4a1a7b08ca7483cdc1c94d4edc8d3c4e48e2e6 100644
 | 
| --- a/chrome/browser/ui/views/tabs/tab_unittest.cc
 | 
| +++ b/chrome/browser/ui/views/tabs/tab_unittest.cc
 | 
| @@ -16,11 +16,12 @@ using views::Widget;
 | 
|  
 | 
|  class FakeTabController : public TabController {
 | 
|   public:
 | 
| -  FakeTabController() : immersive_style_(false) {
 | 
| +  FakeTabController() : immersive_style_(false), active_tab_(false) {
 | 
|    }
 | 
|    virtual ~FakeTabController() {}
 | 
|  
 | 
|    void set_immersive_style(bool value) { immersive_style_ = value; }
 | 
| +  void set_active_tab(bool value) { active_tab_ = value; }
 | 
|  
 | 
|    virtual const ui::ListSelectionModel& GetSelectionModel() OVERRIDE {
 | 
|      return selection_model_;
 | 
| @@ -34,7 +35,9 @@ class FakeTabController : public TabController {
 | 
|    virtual void ShowContextMenuForTab(Tab* tab,
 | 
|                                       const gfx::Point& p,
 | 
|                                       ui::MenuSourceType source_type) OVERRIDE {}
 | 
| -  virtual bool IsActiveTab(const Tab* tab) const OVERRIDE { return false; }
 | 
| +  virtual bool IsActiveTab(const Tab* tab) const OVERRIDE {
 | 
| +    return active_tab_;
 | 
| +  }
 | 
|    virtual bool IsTabSelected(const Tab* tab) const OVERRIDE {
 | 
|      return false;
 | 
|    }
 | 
| @@ -60,6 +63,7 @@ class FakeTabController : public TabController {
 | 
|   private:
 | 
|    ui::ListSelectionModel selection_model_;
 | 
|    bool immersive_style_;
 | 
| +  bool active_tab_;
 | 
|  
 | 
|    DISALLOW_COPY_AND_ASSIGN(FakeTabController);
 | 
|  };
 | 
| @@ -70,11 +74,108 @@ class TabTest : public views::ViewsTestBase {
 | 
|    virtual ~TabTest() {}
 | 
|  
 | 
|    static bool IconAnimationInvariant(const Tab& tab) {
 | 
| -    bool capture_invariant =
 | 
| -        tab.data().CaptureActive() == (tab.icon_animation_.get() != NULL);
 | 
| -    bool audio_invariant =
 | 
| -        !tab.data().AudioActive() || tab.tab_audio_indicator_->IsAnimating();
 | 
| -    return capture_invariant && audio_invariant;
 | 
| +    return tab.data().CaptureActive() == (tab.icon_animation_.get() != NULL);
 | 
| +  }
 | 
| +
 | 
| +  static void CheckForExpectedLayoutAndVisibilityOfElements(const Tab& tab) {
 | 
| +    // Check whether elements are visible when they are supposed to be, given
 | 
| +    // Tab size and TabRendererData state.
 | 
| +    if (tab.data_.mini) {
 | 
| +      if (tab.data_.CaptureActive())
 | 
| +        EXPECT_TRUE(tab.ShouldShowIcon());
 | 
| +      else
 | 
| +        EXPECT_TRUE(tab.ShouldShowIcon() != tab.ShouldShowAudioIndicator());
 | 
| +      EXPECT_FALSE(tab.ShouldShowCloseBox());
 | 
| +    } else if (tab.IsActive()) {
 | 
| +      EXPECT_TRUE(tab.ShouldShowCloseBox());
 | 
| +      switch (tab.IconCapacity()) {
 | 
| +        case 0:
 | 
| +        case 1:
 | 
| +          EXPECT_FALSE(tab.ShouldShowIcon());
 | 
| +          EXPECT_FALSE(tab.ShouldShowAudioIndicator());
 | 
| +          break;
 | 
| +        case 2:
 | 
| +          if (tab.data_.CaptureActive())
 | 
| +            EXPECT_TRUE(tab.ShouldShowIcon());
 | 
| +          else
 | 
| +            EXPECT_TRUE(tab.ShouldShowIcon() != tab.ShouldShowAudioIndicator());
 | 
| +          break;
 | 
| +        default:
 | 
| +          EXPECT_LE(3, tab.IconCapacity());
 | 
| +          EXPECT_TRUE(tab.ShouldShowIcon());
 | 
| +          if (tab.data_.CaptureActive()) {
 | 
| +            EXPECT_FALSE(tab.ShouldShowAudioIndicator());
 | 
| +          } else {
 | 
| +            EXPECT_TRUE(tab.data_.AudioActive() ==
 | 
| +                            tab.ShouldShowAudioIndicator());
 | 
| +          }
 | 
| +          break;
 | 
| +      }
 | 
| +    } else {  // Tab not active and not mini tab.
 | 
| +      switch (tab.IconCapacity()) {
 | 
| +        case 0:
 | 
| +          EXPECT_FALSE(tab.ShouldShowCloseBox());
 | 
| +          EXPECT_FALSE(tab.ShouldShowIcon());
 | 
| +          EXPECT_FALSE(tab.ShouldShowAudioIndicator());
 | 
| +          break;
 | 
| +        case 1:
 | 
| +          EXPECT_FALSE(tab.ShouldShowCloseBox());
 | 
| +          if (tab.data_.CaptureActive())
 | 
| +            EXPECT_TRUE(tab.ShouldShowIcon());
 | 
| +          else
 | 
| +            EXPECT_TRUE(tab.ShouldShowIcon() != tab.ShouldShowAudioIndicator());
 | 
| +          break;
 | 
| +        default:
 | 
| +          EXPECT_LE(2, tab.IconCapacity());
 | 
| +          EXPECT_TRUE(tab.ShouldShowIcon());
 | 
| +          if (tab.data_.CaptureActive()) {
 | 
| +            EXPECT_FALSE(tab.ShouldShowAudioIndicator());
 | 
| +          } else {
 | 
| +            EXPECT_TRUE(tab.data_.AudioActive() ==
 | 
| +                            tab.ShouldShowAudioIndicator());
 | 
| +          }
 | 
| +          break;
 | 
| +      }
 | 
| +    }
 | 
| +
 | 
| +    // Check positioning of elements with respect to each other, and that they
 | 
| +    // are fully within the contents bounds.
 | 
| +    const gfx::Rect contents_bounds = tab.GetContentsBounds();
 | 
| +    if (tab.ShouldShowIcon()) {
 | 
| +      EXPECT_LE(contents_bounds.x(), tab.favicon_bounds_.x());
 | 
| +      if (tab.title_bounds_.width() > 0)
 | 
| +        EXPECT_LE(tab.favicon_bounds_.right(), tab.title_bounds_.x());
 | 
| +      EXPECT_LE(contents_bounds.y(), tab.favicon_bounds_.y());
 | 
| +      EXPECT_LE(tab.favicon_bounds_.bottom(), contents_bounds.bottom());
 | 
| +    }
 | 
| +    if (tab.ShouldShowIcon() && tab.ShouldShowAudioIndicator())
 | 
| +      EXPECT_LE(tab.favicon_bounds_.right(), tab.audio_indicator_bounds_.x());
 | 
| +    if (tab.ShouldShowAudioIndicator()) {
 | 
| +      if (tab.title_bounds_.width() > 0)
 | 
| +        EXPECT_LE(tab.title_bounds_.right(), tab.audio_indicator_bounds_.x());
 | 
| +      EXPECT_LE(tab.audio_indicator_bounds_.right(), contents_bounds.right());
 | 
| +      EXPECT_LE(contents_bounds.y(), tab.audio_indicator_bounds_.y());
 | 
| +      EXPECT_LE(tab.audio_indicator_bounds_.bottom(), contents_bounds.bottom());
 | 
| +    }
 | 
| +    if (tab.ShouldShowAudioIndicator() && tab.ShouldShowCloseBox()) {
 | 
| +      // Note: The audio indicator can overlap the left-insets of the close box,
 | 
| +      // but should otherwise be to the left of the close button.
 | 
| +      EXPECT_LE(tab.audio_indicator_bounds_.right(),
 | 
| +                tab.close_button_->bounds().x() +
 | 
| +                    tab.close_button_->GetInsets().left());
 | 
| +    }
 | 
| +    if (tab.ShouldShowCloseBox()) {
 | 
| +      // Note: The title bounds can overlap the left-insets of the close box,
 | 
| +      // but should otherwise be to the left of the close button.
 | 
| +      if (tab.title_bounds_.width() > 0) {
 | 
| +        EXPECT_LE(tab.title_bounds_.right(),
 | 
| +                  tab.close_button_->bounds().x() +
 | 
| +                      tab.close_button_->GetInsets().left());
 | 
| +      }
 | 
| +      EXPECT_LE(tab.close_button_->bounds().right(), contents_bounds.right());
 | 
| +      EXPECT_LE(contents_bounds.y(), tab.close_button_->bounds().y());
 | 
| +      EXPECT_LE(tab.close_button_->bounds().bottom(), contents_bounds.bottom());
 | 
| +    }
 | 
|    }
 | 
|  };
 | 
|  
 | 
| @@ -108,6 +209,61 @@ TEST_F(TabTest, HitTestTopPixel) {
 | 
|    EXPECT_FALSE(tab.HitTestPoint(gfx::Point(tab.width() - 1, 0)));
 | 
|  }
 | 
|  
 | 
| +TEST_F(TabTest, LayoutAndVisibilityOfElements) {
 | 
| +  FakeTabController controller;
 | 
| +  Tab tab(&controller);
 | 
| +
 | 
| +  SkBitmap bitmap;
 | 
| +  bitmap.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
 | 
| +  bitmap.allocPixels();
 | 
| +  TabRendererData data;
 | 
| +  data.favicon = gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
 | 
| +
 | 
| +  // Perform layout over all possible combinations, checking for correct
 | 
| +  // results.
 | 
| +  for (int is_mini_tab = 0; is_mini_tab < 2; ++is_mini_tab) {
 | 
| +    for (int is_active_tab = 0; is_active_tab < 2; ++is_active_tab) {
 | 
| +      for (int audio_state = TabRendererData::AUDIO_STATE_NONE;
 | 
| +           audio_state <= TabRendererData::AUDIO_STATE_PLAYING; ++audio_state) {
 | 
| +        for (int capture_state = TabRendererData::CAPTURE_STATE_NONE;
 | 
| +             capture_state <= TabRendererData::CAPTURE_STATE_PROJECTING;
 | 
| +             ++capture_state) {
 | 
| +          SCOPED_TRACE(::testing::Message()
 | 
| +                       << (is_active_tab ? "Active" : "Inactive") << ' '
 | 
| +                       << (is_mini_tab ? "Mini " : "")
 | 
| +                       << "Tab with audio_state=" << audio_state
 | 
| +                       << " and capture_state=" << capture_state);
 | 
| +          data.mini = !!is_mini_tab;
 | 
| +          controller.set_active_tab(!!is_active_tab);
 | 
| +          data.audio_state =
 | 
| +              static_cast<TabRendererData::AudioState>(audio_state);
 | 
| +          data.capture_state =
 | 
| +              static_cast<TabRendererData::CaptureState>(capture_state);
 | 
| +          tab.SetData(data);
 | 
| +
 | 
| +          // Test layout for every width from standard to minimum.
 | 
| +          gfx::Rect bounds(gfx::Point(0, 0), Tab::GetStandardSize());
 | 
| +          int min_width;
 | 
| +          if (is_mini_tab) {
 | 
| +            bounds.set_width(Tab::GetMiniWidth());
 | 
| +            min_width = Tab::GetMiniWidth();
 | 
| +          } else {
 | 
| +            min_width = is_active_tab ? Tab::GetMinimumSelectedSize().width() :
 | 
| +                Tab::GetMinimumUnselectedSize().width();
 | 
| +          }
 | 
| +          while (bounds.width() >= min_width) {
 | 
| +            SCOPED_TRACE(::testing::Message()
 | 
| +                         << "bounds=" << bounds.ToString());
 | 
| +            tab.SetBoundsRect(bounds);  // Invokes Tab::Layout().
 | 
| +            CheckForExpectedLayoutAndVisibilityOfElements(tab);
 | 
| +            bounds.set_width(bounds.width() - 1);
 | 
| +          }
 | 
| +        }
 | 
| +      }
 | 
| +    }
 | 
| +  }
 | 
| +}
 | 
| +
 | 
|  // Regression test for http://crbug.com/226253. Calling Layout() more than once
 | 
|  // shouldn't change the insets of the close button.
 | 
|  TEST_F(TabTest, CloseButtonLayout) {
 | 
| @@ -127,9 +283,10 @@ TEST_F(TabTest, CloseButtonLayout) {
 | 
|    EXPECT_EQ(50, tab.close_button_->bounds().height());
 | 
|  }
 | 
|  
 | 
| -TEST_F(TabTest, ActivityIndicators) {
 | 
| +TEST_F(TabTest, RecordingAndProjectingActivityIndicators) {
 | 
|    FakeTabController controller;
 | 
|    Tab tab(&controller);
 | 
| +  tab.SetBoundsRect(gfx::Rect(gfx::Point(0, 0), Tab::GetStandardSize()));
 | 
|  
 | 
|    SkBitmap bitmap;
 | 
|    bitmap.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
 | 
| @@ -139,77 +296,45 @@ TEST_F(TabTest, ActivityIndicators) {
 | 
|    data.favicon = gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
 | 
|    tab.SetData(data);
 | 
|  
 | 
| -  // Audio starts and stops.
 | 
| -  data.audio_state = TabRendererData::AUDIO_STATE_PLAYING;
 | 
| -  tab.SetData(data);
 | 
| -  EXPECT_TRUE(IconAnimationInvariant(tab));
 | 
| -  EXPECT_EQ(TabRendererData::AUDIO_STATE_PLAYING, tab.data().audio_state);
 | 
| -  EXPECT_EQ(TabRendererData::CAPTURE_STATE_NONE, tab.data().capture_state);
 | 
| -  data.audio_state = TabRendererData::AUDIO_STATE_NONE;
 | 
| -  tab.SetData(data);
 | 
| -  EXPECT_TRUE(IconAnimationInvariant(tab));
 | 
| -  EXPECT_EQ(TabRendererData::AUDIO_STATE_NONE, tab.data().audio_state);
 | 
| -  EXPECT_EQ(TabRendererData::CAPTURE_STATE_NONE, tab.data().capture_state);
 | 
| -  EXPECT_TRUE(IconAnimationInvariant(tab));
 | 
| -
 | 
| -  // Capture starts and stops.
 | 
| +  // Recording starts and stops.
 | 
|    data.capture_state = TabRendererData::CAPTURE_STATE_RECORDING;
 | 
|    tab.SetData(data);
 | 
|    EXPECT_TRUE(IconAnimationInvariant(tab));
 | 
| -  EXPECT_EQ(TabRendererData::AUDIO_STATE_NONE, tab.data().audio_state);
 | 
|    EXPECT_EQ(TabRendererData::CAPTURE_STATE_RECORDING, tab.data().capture_state);
 | 
|    data.capture_state = TabRendererData::CAPTURE_STATE_NONE;
 | 
|    tab.SetData(data);
 | 
|    EXPECT_TRUE(IconAnimationInvariant(tab));
 | 
| -  EXPECT_EQ(TabRendererData::AUDIO_STATE_NONE, tab.data().audio_state);
 | 
|    EXPECT_EQ(TabRendererData::CAPTURE_STATE_NONE, tab.data().capture_state);
 | 
|    EXPECT_TRUE(IconAnimationInvariant(tab));
 | 
|  
 | 
| -  // Audio starts then capture starts, then audio stops then capture stops.
 | 
| -  data.audio_state = TabRendererData::AUDIO_STATE_PLAYING;
 | 
| -  tab.SetData(data);
 | 
| +  // Recording starts then tab capture starts, then back to just recording, then
 | 
| +  // recording stops.
 | 
|    data.capture_state = TabRendererData::CAPTURE_STATE_RECORDING;
 | 
|    tab.SetData(data);
 | 
|    EXPECT_TRUE(IconAnimationInvariant(tab));
 | 
| -  EXPECT_EQ(TabRendererData::AUDIO_STATE_PLAYING, tab.data().audio_state);
 | 
|    EXPECT_EQ(TabRendererData::CAPTURE_STATE_RECORDING, tab.data().capture_state);
 | 
|  
 | 
|    data.title = ASCIIToUTF16("test X");
 | 
|    tab.SetData(data);
 | 
|    EXPECT_TRUE(IconAnimationInvariant(tab));
 | 
|  
 | 
| -  data.audio_state = TabRendererData::AUDIO_STATE_NONE;
 | 
| +  data.capture_state = TabRendererData::CAPTURE_STATE_PROJECTING;
 | 
|    tab.SetData(data);
 | 
|    EXPECT_TRUE(IconAnimationInvariant(tab));
 | 
| -  EXPECT_EQ(TabRendererData::CAPTURE_STATE_RECORDING, tab.data().capture_state);
 | 
| -  data.capture_state = TabRendererData::CAPTURE_STATE_NONE;
 | 
| +  EXPECT_EQ(TabRendererData::CAPTURE_STATE_PROJECTING,
 | 
| +            tab.data().capture_state);
 | 
| +
 | 
| +  data.title = ASCIIToUTF16("test Y");
 | 
|    tab.SetData(data);
 | 
|    EXPECT_TRUE(IconAnimationInvariant(tab));
 | 
| -  EXPECT_EQ(TabRendererData::AUDIO_STATE_NONE, tab.data().audio_state);
 | 
| -  EXPECT_EQ(TabRendererData::CAPTURE_STATE_NONE, tab.data().capture_state);
 | 
|  
 | 
| -  // Audio starts then capture starts, then capture stops then audio stops.
 | 
| -  data.audio_state = TabRendererData::AUDIO_STATE_PLAYING;
 | 
| -  tab.SetData(data);
 | 
|    data.capture_state = TabRendererData::CAPTURE_STATE_RECORDING;
 | 
|    tab.SetData(data);
 | 
|    EXPECT_TRUE(IconAnimationInvariant(tab));
 | 
| -  EXPECT_EQ(TabRendererData::AUDIO_STATE_PLAYING, tab.data().audio_state);
 | 
|    EXPECT_EQ(TabRendererData::CAPTURE_STATE_RECORDING, tab.data().capture_state);
 | 
|  
 | 
| -  data.title = ASCIIToUTF16("test Y");
 | 
| -  tab.SetData(data);
 | 
| -  EXPECT_TRUE(IconAnimationInvariant(tab));
 | 
| -
 | 
|    data.capture_state = TabRendererData::CAPTURE_STATE_NONE;
 | 
|    tab.SetData(data);
 | 
|    EXPECT_TRUE(IconAnimationInvariant(tab));
 | 
|    EXPECT_EQ(TabRendererData::CAPTURE_STATE_NONE, tab.data().capture_state);
 | 
| -
 | 
| -  data.audio_state = TabRendererData::AUDIO_STATE_NONE;
 | 
| -  tab.SetData(data);
 | 
| -  EXPECT_TRUE(IconAnimationInvariant(tab));
 | 
| -  EXPECT_EQ(TabRendererData::AUDIO_STATE_NONE, tab.data().audio_state);
 | 
| -  EXPECT_EQ(TabRendererData::CAPTURE_STATE_NONE, tab.data().capture_state);
 | 
| -  EXPECT_TRUE(IconAnimationInvariant(tab));
 | 
|  }
 | 
| 
 |