Home | History | Annotate | Download | only in tabs
      1 // Copyright (c) 2011 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/touch/tabs/touch_tab.h"
      6 
      7 #include "base/logging.h"
      8 #include "chrome/browser/themes/theme_service.h"
      9 #include "grit/app_resources.h"
     10 #include "grit/theme_resources.h"
     11 #include "ui/base/resource/resource_bundle.h"
     12 #include "ui/gfx/canvas_skia.h"
     13 #include "ui/gfx/favicon_size.h"
     14 #include "ui/gfx/path.h"
     15 #include "ui/gfx/skbitmap_operations.h"
     16 
     17 static const int kLeftPadding = 16;
     18 static const int kRightPadding = 15;
     19 static const int kDropShadowHeight = 2;
     20 
     21 // The size of the favicon touch area. This generally would be the same as
     22 // kFaviconSize in ui/gfx/favicon_size.h
     23 static const int kTouchTabIconSize = 32;
     24 
     25 TouchTab::TouchTabImage TouchTab::tab_alpha = {0};
     26 TouchTab::TouchTabImage TouchTab::tab_active = {0};
     27 TouchTab::TouchTabImage TouchTab::tab_inactive = {0};
     28 
     29 ////////////////////////////////////////////////////////////////////////////////
     30 // TouchTab, public:
     31 
     32 TouchTab::TouchTab(TabController* controller)
     33     : BaseTab(controller) {
     34   InitTabResources();
     35 }
     36 
     37 TouchTab::~TouchTab() {
     38 }
     39 
     40 // static
     41 gfx::Size TouchTab::GetMinimumUnselectedSize() {
     42   InitTabResources();
     43 
     44   gfx::Size minimum_size;
     45   minimum_size.set_width(kLeftPadding + kRightPadding);
     46   minimum_size.set_height(32);
     47   return minimum_size;
     48 }
     49 
     50 ////////////////////////////////////////////////////////////////////////////////
     51 // TouchTab, protected:
     52 const gfx::Rect& TouchTab::GetTitleBounds() const {
     53   return title_bounds_;
     54 }
     55 
     56 const gfx::Rect& TouchTab::GetIconBounds() const {
     57   return favicon_bounds_;
     58 }
     59 
     60 ////////////////////////////////////////////////////////////////////////////////
     61 // TouchTab, views::View overrides:
     62 
     63 // We'll get selected via the mouse interactions with the TouchTabStrip.  There
     64 // is no need to directly handle the mouse movements in the TouchTab.
     65 
     66 bool TouchTab::OnMousePressed(const views::MouseEvent& event) {
     67   return false;
     68 }
     69 
     70 bool TouchTab::OnMouseDragged(const views::MouseEvent& event) {
     71   return false;
     72 }
     73 
     74 void TouchTab::OnMouseReleased(const views::MouseEvent& event) {
     75 }
     76 
     77 void TouchTab::OnPaint(gfx::Canvas* canvas) {
     78   // Don't paint if we're narrower than we can render correctly. (This should
     79   // only happen during animations).
     80   if (width() < GetMinimumUnselectedSize().width() && !data().mini)
     81     return;
     82 
     83   PaintTabBackground(canvas);
     84 
     85   SkColor title_color = GetThemeProvider()->
     86       GetColor(IsSelected() ?
     87           ThemeService::COLOR_TAB_TEXT :
     88           ThemeService::COLOR_BACKGROUND_TAB_TEXT);
     89 
     90   PaintTitle(canvas, title_color);
     91   PaintIcon(canvas);
     92 }
     93 
     94 void TouchTab::Layout() {
     95   gfx::Rect local_bounds = GetContentsBounds();
     96   TouchTabImage* tab_image = &tab_active;
     97   TouchTabImage* alpha = &tab_alpha;
     98   int image_height = alpha->image_l->height();
     99   int x_base = tab_image->image_l->width();
    100   int y_base = height() - image_height;
    101   int center_width = width() - tab_image->l_width - tab_image->r_width;
    102   if (center_width < 0)
    103     center_width = 0;
    104   title_bounds_ = gfx::Rect(x_base, y_base, center_width, image_height);
    105   favicon_bounds_ = local_bounds;
    106 }
    107 
    108 bool TouchTab::HasHitTestMask() const {
    109   return true;
    110 }
    111 
    112 void TouchTab::GetHitTestMask(gfx::Path* path) const {
    113   DCHECK(path);
    114 
    115   SkScalar h = SkIntToScalar(height());
    116   SkScalar w = SkIntToScalar(width());
    117 
    118   path->moveTo(0, h);
    119   path->lineTo(0, 0);
    120   path->lineTo(w, 0);
    121   path->lineTo(w, h);
    122   path->lineTo(0, h);
    123   path->close();
    124 }
    125 
    126 ////////////////////////////////////////////////////////////////////////////////
    127 // TouchTab, private:
    128 
    129 void TouchTab::PaintTabBackground(gfx::Canvas* canvas) {
    130   if (IsSelected()) {
    131     PaintActiveTabBackground(canvas);
    132   }
    133 }
    134 
    135 void TouchTab::PaintActiveTabBackground(gfx::Canvas* canvas) {
    136   int offset = GetMirroredX() + background_offset_.x();
    137   ThemeProvider* tp = GetThemeProvider();
    138   if (!tp)
    139     NOTREACHED() << "Unable to get theme provider";
    140 
    141   SkBitmap* tab_bg = GetThemeProvider()->GetBitmapNamed(IDR_THEME_TOOLBAR);
    142 
    143   TouchTabImage* tab_image = &tab_active;
    144   TouchTabImage* alpha = &tab_alpha;
    145 
    146   // Draw left edge.
    147   int image_height = alpha->image_l->height();
    148   int y_base = height() - image_height;
    149   SkBitmap tab_l = SkBitmapOperations::CreateTiledBitmap(
    150       *tab_bg, offset, 0, tab_image->l_width, image_height);
    151   SkBitmap theme_l =
    152       SkBitmapOperations::CreateMaskedBitmap(tab_l, *alpha->image_l);
    153   canvas->DrawBitmapInt(theme_l, 0, y_base);
    154 
    155   // Draw right edge.
    156   SkBitmap tab_r = SkBitmapOperations::CreateTiledBitmap(*tab_bg,
    157       offset + width() - tab_image->r_width, 0,
    158       tab_image->r_width, image_height);
    159   SkBitmap theme_r =
    160       SkBitmapOperations::CreateMaskedBitmap(tab_r, *alpha->image_r);
    161   canvas->DrawBitmapInt(theme_r, width() - tab_image->r_width, y_base);
    162 
    163   // Draw center.  Instead of masking out the top portion we simply skip over it
    164   // by incrementing by kDropShadowHeight, since it's a simple rectangle.
    165   canvas->TileImageInt(*tab_bg,
    166      offset + tab_image->l_width,
    167      kDropShadowHeight + tab_image->y_offset,
    168      tab_image->l_width,
    169      y_base + kDropShadowHeight + tab_image->y_offset,
    170      width() - tab_image->l_width - tab_image->r_width,
    171      height() - kDropShadowHeight - tab_image->y_offset);
    172 
    173   // Now draw the highlights/shadows around the tab edge.
    174   canvas->DrawBitmapInt(*tab_image->image_l, 0, y_base);
    175   canvas->TileImageInt(*tab_image->image_c, tab_image->l_width, y_base,
    176       width() - tab_image->l_width - tab_image->r_width, image_height);
    177   canvas->DrawBitmapInt(*tab_image->image_r, width() - tab_image->r_width,
    178                         y_base);
    179 }
    180 
    181 void TouchTab::PaintIcon(gfx::Canvas* canvas) {
    182   // TODO(wyck): use thumbnailer to get better page images
    183   int x = favicon_bounds_.x();
    184   int y = favicon_bounds_.y();
    185 
    186   TouchTabImage* tab_image = &tab_active;
    187   int x_base = tab_image->image_l->width();
    188 
    189   x += x_base;
    190 
    191   if (base::i18n::IsRTL()) {
    192     x = width() - x -
    193         (data().favicon.isNull() ? kFaviconSize : data().favicon.width());
    194   }
    195 
    196   int favicon_x = x;
    197   if (!data().favicon.isNull() && data().favicon.width() != kFaviconSize)
    198     favicon_x += (data().favicon.width() - kFaviconSize) / 2;
    199 
    200   if (data().network_state != TabRendererData::NETWORK_STATE_NONE) {
    201     ThemeProvider* tp = GetThemeProvider();
    202     SkBitmap frames(*tp->GetBitmapNamed(
    203         (data().network_state == TabRendererData::NETWORK_STATE_WAITING) ?
    204         IDR_THROBBER_WAITING : IDR_THROBBER));
    205     int image_size = frames.height();
    206     int image_offset = loading_animation_frame() * image_size;
    207     canvas->DrawBitmapInt(frames, image_offset, 0, image_size, image_size, x, y,
    208                           kTouchTabIconSize, kTouchTabIconSize, false);
    209   } else {
    210     canvas->Save();
    211     canvas->ClipRectInt(0, 0, width(), height());
    212     if (should_display_crashed_favicon()) {
    213       ResourceBundle& rb = ResourceBundle::GetSharedInstance();
    214       SkBitmap crashed_favicon(*rb.GetBitmapNamed(IDR_SAD_FAVICON));
    215       canvas->DrawBitmapInt(crashed_favicon, 0, 0, crashed_favicon.width(),
    216           crashed_favicon.height(), x, y + favicon_hiding_offset(),
    217           kTouchTabIconSize, kTouchTabIconSize, true);
    218     } else {
    219       if (!data().favicon.isNull()) {
    220 
    221         if ((data().favicon.width() == kTouchTabIconSize) &&
    222             (data().favicon.height() == kTouchTabIconSize)) {
    223           canvas->DrawBitmapInt(data().favicon, 0, 0,
    224                                 data().favicon.width(), data().favicon.height(),
    225                                 x, y + favicon_hiding_offset(),
    226                                 kTouchTabIconSize, kTouchTabIconSize, true);
    227         } else {
    228           // Draw a background around target touch area in case the favicon
    229           // is smaller than touch area (e.g www.google.com is 16x16 now)
    230           canvas->DrawRectInt(
    231               GetThemeProvider()->GetColor(
    232                   ThemeService::COLOR_BUTTON_BACKGROUND),
    233               x, y, kTouchTabIconSize, kTouchTabIconSize);
    234 
    235           // We center the image
    236           // TODO(saintlou): later request larger image from HistoryService
    237           canvas->DrawBitmapInt(data().favicon, 0, 0, data().favicon.width(),
    238               data().favicon.height(),
    239               x + ((kTouchTabIconSize - data().favicon.width()) / 2),
    240               y + ((kTouchTabIconSize - data().favicon.height()) / 2) +
    241                                                      favicon_hiding_offset(),
    242               data().favicon.width(), data().favicon.height(), true);
    243         }
    244       }
    245     }
    246     canvas->Restore();
    247   }
    248 }
    249 
    250 // static
    251 void TouchTab::InitTabResources() {
    252   static bool initialized = false;
    253   if (initialized)
    254     return;
    255 
    256   initialized = true;
    257 
    258   // Load the tab images once now, and maybe again later if the theme changes.
    259   LoadTabImages();
    260 }
    261 
    262 
    263 // static
    264 void TouchTab::LoadTabImages() {
    265   // We're not letting people override tab images just yet.
    266   ResourceBundle& rb = ResourceBundle::GetSharedInstance();
    267 
    268   tab_alpha.image_l = rb.GetBitmapNamed(IDR_TAB_ALPHA_LEFT);
    269   tab_alpha.image_r = rb.GetBitmapNamed(IDR_TAB_ALPHA_RIGHT);
    270 
    271   tab_active.image_l = rb.GetBitmapNamed(IDR_TAB_ACTIVE_LEFT);
    272   tab_active.image_c = rb.GetBitmapNamed(IDR_TAB_ACTIVE_CENTER);
    273   tab_active.image_r = rb.GetBitmapNamed(IDR_TAB_ACTIVE_RIGHT);
    274   tab_active.l_width = tab_active.image_l->width();
    275   tab_active.r_width = tab_active.image_r->width();
    276 
    277   tab_inactive.image_l = rb.GetBitmapNamed(IDR_TAB_INACTIVE_LEFT);
    278   tab_inactive.image_c = rb.GetBitmapNamed(IDR_TAB_INACTIVE_CENTER);
    279   tab_inactive.image_r = rb.GetBitmapNamed(IDR_TAB_INACTIVE_RIGHT);
    280   tab_inactive.l_width = tab_inactive.image_l->width();
    281   tab_inactive.r_width = tab_inactive.image_r->width();
    282 }
    283