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