- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / views / location_bar / location_bar_view.cc
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/location_bar/location_bar_view.h"
6
7 #include <algorithm>
8 #include <map>
9
10 #include "base/command_line.h"
11 #include "base/i18n/rtl.h"
12 #include "base/prefs/pref_service.h"
13 #include "base/stl_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "chrome/app/chrome_command_ids.h"
16 #include "chrome/browser/chrome_notification_types.h"
17 #include "chrome/browser/command_updater.h"
18 #include "chrome/browser/defaults.h"
19 #include "chrome/browser/extensions/api/omnibox/omnibox_api.h"
20 #include "chrome/browser/extensions/location_bar_controller.h"
21 #include "chrome/browser/extensions/script_bubble_controller.h"
22 #include "chrome/browser/extensions/tab_helper.h"
23 #include "chrome/browser/favicon/favicon_tab_helper.h"
24 #include "chrome/browser/profiles/profile.h"
25 #include "chrome/browser/search_engines/template_url.h"
26 #include "chrome/browser/search_engines/template_url_service.h"
27 #include "chrome/browser/search_engines/template_url_service_factory.h"
28 #include "chrome/browser/translate/translate_tab_helper.h"
29 #include "chrome/browser/ui/browser.h"
30 #include "chrome/browser/ui/browser_finder.h"
31 #include "chrome/browser/ui/browser_instant_controller.h"
32 #include "chrome/browser/ui/browser_window.h"
33 #include "chrome/browser/ui/omnibox/location_bar_util.h"
34 #include "chrome/browser/ui/omnibox/omnibox_popup_model.h"
35 #include "chrome/browser/ui/omnibox/omnibox_popup_view.h"
36 #include "chrome/browser/ui/tabs/tab_strip_model.h"
37 #include "chrome/browser/ui/view_ids.h"
38 #include "chrome/browser/ui/views/bookmarks/bookmark_prompt_view.h"
39 #include "chrome/browser/ui/views/browser_dialogs.h"
40 #include "chrome/browser/ui/views/extensions/extension_popup.h"
41 #include "chrome/browser/ui/views/location_bar/content_setting_image_view.h"
42 #include "chrome/browser/ui/views/location_bar/ev_bubble_view.h"
43 #include "chrome/browser/ui/views/location_bar/generated_credit_card_view.h"
44 #include "chrome/browser/ui/views/location_bar/keyword_hint_view.h"
45 #include "chrome/browser/ui/views/location_bar/location_bar_layout.h"
46 #include "chrome/browser/ui/views/location_bar/location_icon_view.h"
47 #include "chrome/browser/ui/views/location_bar/open_pdf_in_reader_view.h"
48 #include "chrome/browser/ui/views/location_bar/page_action_image_view.h"
49 #include "chrome/browser/ui/views/location_bar/page_action_with_badge_view.h"
50 #include "chrome/browser/ui/views/location_bar/script_bubble_icon_view.h"
51 #include "chrome/browser/ui/views/location_bar/selected_keyword_view.h"
52 #include "chrome/browser/ui/views/location_bar/star_view.h"
53 #include "chrome/browser/ui/views/location_bar/translate_icon_view.h"
54 #include "chrome/browser/ui/views/location_bar/zoom_bubble_view.h"
55 #include "chrome/browser/ui/views/location_bar/zoom_view.h"
56 #include "chrome/browser/ui/views/omnibox/omnibox_view_views.h"
57 #include "chrome/browser/ui/views/omnibox/omnibox_views.h"
58 #include "chrome/browser/ui/zoom/zoom_controller.h"
59 #include "chrome/common/chrome_switches.h"
60 #include "chrome/common/extensions/feature_switch.h"
61 #include "chrome/common/pref_names.h"
62 #include "content/public/browser/notification_service.h"
63 #include "content/public/browser/render_widget_host_view.h"
64 #include "content/public/browser/web_contents.h"
65 #include "grit/generated_resources.h"
66 #include "grit/theme_resources.h"
67 #include "ui/base/accessibility/accessible_view_state.h"
68 #include "ui/base/dragdrop/drag_drop_types.h"
69 #include "ui/base/l10n/l10n_util.h"
70 #include "ui/base/layout.h"
71 #include "ui/base/resource/resource_bundle.h"
72 #include "ui/base/theme_provider.h"
73 #include "ui/events/event.h"
74 #include "ui/gfx/canvas.h"
75 #include "ui/gfx/color_utils.h"
76 #include "ui/gfx/image/image.h"
77 #include "ui/gfx/image/image_skia_operations.h"
78 #include "ui/gfx/skia_util.h"
79 #include "ui/native_theme/native_theme.h"
80 #include "ui/views/background.h"
81 #include "ui/views/border.h"
82 #include "ui/views/button_drag_utils.h"
83 #include "ui/views/controls/button/image_button.h"
84 #include "ui/views/controls/label.h"
85 #include "ui/views/controls/textfield/textfield.h"
86 #include "ui/views/widget/widget.h"
87 #include "ui/views/window/non_client_view.h"
88
89 #if defined(OS_WIN)
90 #include "base/win/scoped_hdc.h"
91 #include "base/win/scoped_select_object.h"
92 #include "ui/native_theme/native_theme_win.h"
93 #endif
94
95 #if defined(OS_WIN) && !defined(USE_AURA)
96 #include "chrome/browser/ui/views/omnibox/omnibox_view_win.h"
97 #endif
98
99 #if !defined(OS_CHROMEOS)
100 #include "chrome/browser/ui/views/first_run_bubble.h"
101 #endif
102
103 #if defined(USE_AURA)
104 #include "ui/compositor/layer.h"
105 #include "ui/compositor/scoped_layer_animation_settings.h"
106 #endif
107
108 using content::WebContents;
109 using views::View;
110
111
112 namespace {
113
114 Browser* GetBrowserFromDelegate(LocationBarView::Delegate* delegate) {
115   WebContents* contents = delegate->GetWebContents();
116   return contents ? chrome::FindBrowserWithWebContents(contents) : NULL;
117 }
118
119 // Given a containing |height| and a |base_font_list|, shrinks the font size
120 // until the font list will fit within |height| while having its cap height
121 // vertically centered.  Returns the correctly-sized font list.
122 //
123 // The expected layout:
124 //   +--------+-----------------------------------------------+------------+
125 //   |        | y offset                                      | space      |
126 //   |        +--------+-------------------+------------------+ above      |
127 //   |        |        |                   | internal leading | cap height |
128 //   | box    | font   | ascent (baseline) +------------------+------------+
129 //   | height | height |                   | cap height                    |
130 //   |        |        |-------------------+------------------+------------+
131 //   |        |        | descent (height - baseline)          | space      |
132 //   |        +--------+--------------------------------------+ below      |
133 //   |        | space at bottom                               | cap height |
134 //   +--------+-----------------------------------------------+------------+
135 // Goal:
136 //     center of box height == center of cap height
137 //     (i.e. space above cap height == space below cap height)
138 // Restrictions:
139 //     y offset >= 0
140 //     space at bottom >= 0
141 //     (i.e. Entire font must be visible inside the box.)
142 gfx::FontList GetLargestFontListWithHeightBound(
143     const gfx::FontList& base_font_list,
144     int height) {
145   gfx::FontList font_list = base_font_list;
146   for (int font_size = font_list.GetFontSize(); font_size > 1; --font_size) {
147     const int internal_leading =
148         font_list.GetBaseline() - font_list.GetCapHeight();
149     // Some platforms don't support getting the cap height, and simply return
150     // the entire font ascent from GetCapHeight().  Centering the ascent makes
151     // the font look too low, so if GetCapHeight() returns the ascent, center
152     // the entire font height instead.
153     const int space =
154         height - ((internal_leading != 0) ?
155                   font_list.GetCapHeight() : font_list.GetHeight());
156     const int y_offset = space / 2 - internal_leading;
157     const int space_at_bottom = height - (y_offset + font_list.GetHeight());
158     if ((y_offset >= 0) && (space_at_bottom >= 0))
159       break;
160     font_list = font_list.DeriveFontListWithSizeDelta(-1);
161   }
162   return font_list;
163 }
164
165 }  // namespace
166
167
168 // LocationBarView -----------------------------------------------------------
169
170 // static
171 const int LocationBarView::kNormalEdgeThickness = 2;
172 const int LocationBarView::kPopupEdgeThickness = 1;
173 const int LocationBarView::kIconInternalPadding = 2;
174 const int LocationBarView::kBubblePadding = 1;
175 const char LocationBarView::kViewClassName[] = "LocationBarView";
176
177 LocationBarView::LocationBarView(Browser* browser,
178                                  Profile* profile,
179                                  CommandUpdater* command_updater,
180                                  Delegate* delegate,
181                                  bool is_popup_mode)
182     : OmniboxEditController(command_updater),
183       browser_(browser),
184       profile_(profile),
185       delegate_(delegate),
186       location_icon_view_(NULL),
187       ev_bubble_view_(NULL),
188       location_entry_view_(NULL),
189       ime_inline_autocomplete_view_(NULL),
190       selected_keyword_view_(NULL),
191       suggested_text_view_(NULL),
192       keyword_hint_view_(NULL),
193       mic_search_view_(NULL),
194       zoom_view_(NULL),
195       generated_credit_card_view_(NULL),
196       open_pdf_in_reader_view_(NULL),
197       script_bubble_icon_view_(NULL),
198       star_view_(NULL),
199       translate_icon_view_(NULL),
200       is_popup_mode_(is_popup_mode),
201       show_focus_rect_(false),
202       template_url_service_(NULL),
203       animation_offset_(0),
204       weak_ptr_factory_(this) {
205   if (!views::Textfield::IsViewsTextfieldEnabled())
206     set_id(VIEW_ID_OMNIBOX);
207
208   const int kOmniboxBorderImages[] = IMAGE_GRID(IDR_OMNIBOX_BORDER);
209   const int kOmniboxPopupImages[] = IMAGE_GRID(IDR_OMNIBOX_POPUP_BORDER);
210   background_border_painter_.reset(
211       views::Painter::CreateImageGridPainter(
212           is_popup_mode_ ? kOmniboxPopupImages : kOmniboxBorderImages));
213 #if defined(OS_CHROMEOS)
214   if (!is_popup_mode_) {
215     const int kOmniboxFillingImages[] = IMAGE_GRID(IDR_OMNIBOX_FILLING);
216     background_filling_painter_.reset(
217         views::Painter::CreateImageGridPainter(kOmniboxFillingImages));
218   }
219 #endif
220
221   edit_bookmarks_enabled_.Init(
222       prefs::kEditBookmarksEnabled,
223       profile_->GetPrefs(),
224       base::Bind(&LocationBarView::Update,
225                  base::Unretained(this),
226                  static_cast<content::WebContents*>(NULL)));
227
228   if (browser_)
229     browser_->search_model()->AddObserver(this);
230 }
231
232 LocationBarView::~LocationBarView() {
233   if (template_url_service_)
234     template_url_service_->RemoveObserver(this);
235   if (browser_)
236     browser_->search_model()->RemoveObserver(this);
237 }
238
239 // static
240 void LocationBarView::InitTouchableLocationBarChildView(views::View* view) {
241   int horizontal_padding = GetBuiltInHorizontalPaddingForChildViews();
242   if (horizontal_padding != 0) {
243     view->set_border(views::Border::CreateEmptyBorder(
244         3, horizontal_padding, 3, horizontal_padding));
245   }
246 }
247
248 void LocationBarView::Init() {
249   // We need to be in a Widget, otherwise GetNativeTheme() may change and we're
250   // not prepared for that.
251   DCHECK(GetWidget());
252
253   location_icon_view_ = new LocationIconView(this);
254   location_icon_view_->set_drag_controller(this);
255   AddChildView(location_icon_view_);
256
257   // Determine the main font.
258   gfx::FontList font_list = ResourceBundle::GetSharedInstance().GetFontList(
259       ResourceBundle::BaseFont);
260   const int current_font_size = font_list.GetFontSize();
261   const int desired_font_size = browser_defaults::kOmniboxFontPixelSize;
262   if (current_font_size < desired_font_size)
263     font_list = font_list.DeriveFontListWithSize(desired_font_size);
264   // Shrink large fonts to make them fit.
265   // TODO(pkasting): Stretch the location bar instead in this case.
266   const int location_height = GetInternalHeight(true);
267   font_list = GetLargestFontListWithHeightBound(font_list, location_height);
268
269   // Determine the font for use inside the bubbles.  The bubble background
270   // images have 1 px thick edges, which we don't want to overlap.
271   const int kBubbleInteriorVerticalPadding = 1;
272   const int bubble_vertical_padding =
273       (kBubblePadding + kBubbleInteriorVerticalPadding) * 2;
274   const gfx::FontList bubble_font_list(
275       GetLargestFontListWithHeightBound(
276           font_list, location_height - bubble_vertical_padding));
277
278   const SkColor background_color =
279       GetColor(ToolbarModel::NONE, LocationBarView::BACKGROUND);
280   ev_bubble_view_ = new EVBubbleView(
281       bubble_font_list, GetColor(ToolbarModel::EV_SECURE, SECURITY_TEXT),
282       background_color, this);
283   ev_bubble_view_->set_drag_controller(this);
284   AddChildView(ev_bubble_view_);
285
286   // Initialize the Omnibox view.
287   location_entry_.reset(CreateOmniboxView(this, profile_, command_updater(),
288                                           is_popup_mode_, this, font_list));
289   SetLocationEntryFocusable(true);
290   location_entry_view_ = location_entry_->AddToView(this);
291
292   // Initialize the inline autocomplete view which is visible only when IME is
293   // turned on.  Use the same font with the omnibox and highlighted background.
294   ime_inline_autocomplete_view_ = new views::Label(string16(), font_list);
295   ime_inline_autocomplete_view_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
296   ime_inline_autocomplete_view_->SetAutoColorReadabilityEnabled(false);
297   ime_inline_autocomplete_view_->set_background(
298       views::Background::CreateSolidBackground(GetNativeTheme()->GetSystemColor(
299           ui::NativeTheme::kColorId_TextfieldSelectionBackgroundFocused)));
300   ime_inline_autocomplete_view_->SetEnabledColor(
301       GetNativeTheme()->GetSystemColor(
302           ui::NativeTheme::kColorId_TextfieldSelectionColor));
303   ime_inline_autocomplete_view_->SetVisible(false);
304   AddChildView(ime_inline_autocomplete_view_);
305
306   const SkColor text_color = GetColor(ToolbarModel::NONE, TEXT);
307   selected_keyword_view_ = new SelectedKeywordView(
308       bubble_font_list, text_color, background_color, profile_);
309   AddChildView(selected_keyword_view_);
310
311   suggested_text_view_ = new views::Label(string16(), font_list);
312   suggested_text_view_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
313   suggested_text_view_->SetAutoColorReadabilityEnabled(false);
314   suggested_text_view_->SetEnabledColor(GetColor(
315       ToolbarModel::NONE, LocationBarView::DEEMPHASIZED_TEXT));
316   suggested_text_view_->SetVisible(false);
317   AddChildView(suggested_text_view_);
318
319   keyword_hint_view_ = new KeywordHintView(
320       profile_, font_list,
321       GetColor(ToolbarModel::NONE, LocationBarView::DEEMPHASIZED_TEXT),
322       background_color);
323   AddChildView(keyword_hint_view_);
324
325   mic_search_view_ = new views::ImageButton(this);
326   mic_search_view_->set_id(VIEW_ID_MIC_SEARCH_BUTTON);
327   mic_search_view_->set_accessibility_focusable(true);
328   mic_search_view_->SetTooltipText(
329       l10n_util::GetStringUTF16(IDS_TOOLTIP_MIC_SEARCH));
330   mic_search_view_->SetImage(
331       views::Button::STATE_NORMAL,
332       ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
333           IDR_OMNIBOX_MIC_SEARCH));
334   mic_search_view_->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
335                                       views::ImageButton::ALIGN_MIDDLE);
336   mic_search_view_->SetVisible(false);
337   InitTouchableLocationBarChildView(mic_search_view_);
338   AddChildView(mic_search_view_);
339
340   for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) {
341     ContentSettingImageView* content_blocked_view =
342         new ContentSettingImageView(static_cast<ContentSettingsType>(i), this,
343                                     bubble_font_list, text_color,
344                                     background_color);
345     content_setting_views_.push_back(content_blocked_view);
346     content_blocked_view->SetVisible(false);
347     AddChildView(content_blocked_view);
348   }
349
350   generated_credit_card_view_ = new GeneratedCreditCardView(delegate_);
351   AddChildView(generated_credit_card_view_);
352
353   zoom_view_ = new ZoomView(delegate_);
354   zoom_view_->set_id(VIEW_ID_ZOOM_BUTTON);
355   AddChildView(zoom_view_);
356
357   open_pdf_in_reader_view_ = new OpenPDFInReaderView(this);
358   AddChildView(open_pdf_in_reader_view_);
359
360   script_bubble_icon_view_ = new ScriptBubbleIconView(delegate());
361   script_bubble_icon_view_->SetVisible(false);
362   AddChildView(script_bubble_icon_view_);
363
364   star_view_ = new StarView(command_updater());
365   star_view_->SetVisible(false);
366   AddChildView(star_view_);
367
368   if (CommandLine::ForCurrentProcess()->HasSwitch(
369           switches::kEnableTranslateNewUX)) {
370     translate_icon_view_ = new TranslateIconView(command_updater());
371     translate_icon_view_->SetVisible(false);
372     AddChildView(translate_icon_view_);
373   }
374
375   registrar_.Add(this,
376                  chrome::NOTIFICATION_EXTENSION_LOCATION_BAR_UPDATED,
377                  content::Source<Profile>(profile_));
378
379   // Initialize the location entry. We do this to avoid a black flash which is
380   // visible when the location entry has just been initialized.
381   Update(NULL);
382 }
383
384 bool LocationBarView::IsInitialized() const {
385   return location_entry_view_ != NULL;
386 }
387
388 SkColor LocationBarView::GetColor(ToolbarModel::SecurityLevel security_level,
389                                   ColorKind kind) const {
390   const ui::NativeTheme* native_theme = GetNativeTheme();
391   switch (kind) {
392     case BACKGROUND:
393 #if defined(OS_CHROMEOS)
394       // Chrome OS requires a transparent omnibox background color.
395       return SkColorSetARGB(0, 255, 255, 255);
396 #else
397       return native_theme->GetSystemColor(
398           ui::NativeTheme::kColorId_TextfieldDefaultBackground);
399 #endif
400
401     case TEXT:
402       return native_theme->GetSystemColor(
403           ui::NativeTheme::kColorId_TextfieldDefaultColor);
404
405     case SELECTED_TEXT:
406       return native_theme->GetSystemColor(
407           ui::NativeTheme::kColorId_TextfieldSelectionColor);
408
409     case DEEMPHASIZED_TEXT:
410       return color_utils::AlphaBlend(
411           GetColor(security_level, TEXT),
412           GetColor(security_level, BACKGROUND),
413           128);
414
415     case SECURITY_TEXT: {
416       SkColor color;
417       switch (security_level) {
418         case ToolbarModel::EV_SECURE:
419         case ToolbarModel::SECURE:
420           color = SkColorSetRGB(7, 149, 0);
421           break;
422
423         case ToolbarModel::SECURITY_WARNING:
424         case ToolbarModel::SECURITY_POLICY_WARNING:
425           return GetColor(security_level, DEEMPHASIZED_TEXT);
426           break;
427
428         case ToolbarModel::SECURITY_ERROR:
429           color = SkColorSetRGB(162, 0, 0);
430           break;
431
432         default:
433           NOTREACHED();
434           return GetColor(security_level, TEXT);
435       }
436       return color_utils::GetReadableColor(
437           color, GetColor(security_level, BACKGROUND));
438     }
439
440     default:
441       NOTREACHED();
442       return GetColor(security_level, TEXT);
443   }
444 }
445
446 void LocationBarView::GetOmniboxPopupPositioningInfo(
447     gfx::Point* top_left_screen_coord,
448     int* popup_width,
449     int* left_margin,
450     int* right_margin) {
451   // Because the popup might appear atop the attached bookmark bar, there won't
452   // necessarily be a client edge separating it from the rest of the toolbar.
453   // Therefore we position the popup high enough so it can draw its own client
454   // edge at the top, in the same place the toolbar would normally draw the
455   // client edge.
456   *top_left_screen_coord = gfx::Point(
457       0,
458       parent()->height() - views::NonClientFrameView::kClientEdgeThickness);
459   views::View::ConvertPointToScreen(parent(), top_left_screen_coord);
460   *popup_width = parent()->width();
461
462   gfx::Rect location_bar_bounds(bounds());
463   location_bar_bounds.Inset(kNormalEdgeThickness, 0);
464   *left_margin = location_bar_bounds.x();
465   *right_margin = *popup_width - location_bar_bounds.right();
466 }
467
468 // static
469 int LocationBarView::GetItemPadding() {
470   const int kTouchItemPadding = 8;
471   if (ui::GetDisplayLayout() == ui::LAYOUT_TOUCH)
472     return kTouchItemPadding;
473
474   const int kDesktopScriptBadgeItemPadding = 9;
475   const int kDesktopItemPadding = 3;
476   return extensions::FeatureSwitch::script_badges()->IsEnabled() ?
477       kDesktopScriptBadgeItemPadding : kDesktopItemPadding;
478 }
479
480 // DropdownBarHostDelegate
481 void LocationBarView::SetFocusAndSelection(bool select_all) {
482   FocusLocation(select_all);
483 }
484
485 void LocationBarView::SetAnimationOffset(int offset) {
486   animation_offset_ = offset;
487 }
488
489 void LocationBarView::UpdateContentSettingsIcons() {
490   UpdateContentSettingViewsPreLayout();
491   Layout();
492   UpdateContentSettingViewsPostLayout();
493   SchedulePaint();
494 }
495
496 void LocationBarView::UpdatePageActions() {
497   size_t count_before = page_action_views_.size();
498   RefreshPageActionViews();
499   RefreshScriptBubble();
500   if (page_action_views_.size() != count_before) {
501     content::NotificationService::current()->Notify(
502         chrome::NOTIFICATION_EXTENSION_PAGE_ACTION_COUNT_CHANGED,
503         content::Source<LocationBar>(this),
504         content::NotificationService::NoDetails());
505   }
506
507   Layout();
508   SchedulePaint();
509 }
510
511 void LocationBarView::InvalidatePageActions() {
512   size_t count_before = page_action_views_.size();
513   DeletePageActionViews();
514   if (page_action_views_.size() != count_before) {
515     content::NotificationService::current()->Notify(
516         chrome::NOTIFICATION_EXTENSION_PAGE_ACTION_COUNT_CHANGED,
517         content::Source<LocationBar>(this),
518         content::NotificationService::NoDetails());
519   }
520 }
521
522 void LocationBarView::UpdateOpenPDFInReaderPrompt() {
523   open_pdf_in_reader_view_->Update(
524       GetToolbarModel()->input_in_progress() ? NULL : GetWebContents());
525   Layout();
526   SchedulePaint();
527 }
528
529 void LocationBarView::UpdateGeneratedCreditCardView() {
530   generated_credit_card_view_->Update();
531   Layout();
532   SchedulePaint();
533 }
534
535 void LocationBarView::OnFocus() {
536   // Focus the view widget first which implements accessibility for
537   // Chrome OS.  It is noop on Win. This should be removed once
538   // Chrome OS migrates to aura, which uses Views' textfield that receives
539   // focus. See crbug.com/106428.
540   NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_FOCUS, false);
541
542   // Then focus the native location view which implements accessibility for
543   // Windows.
544   location_entry_->SetFocus();
545 }
546
547 void LocationBarView::SetPreviewEnabledPageAction(ExtensionAction* page_action,
548                                                   bool preview_enabled) {
549   if (is_popup_mode_)
550     return;
551
552   DCHECK(page_action);
553   WebContents* contents = delegate_->GetWebContents();
554
555   RefreshPageActionViews();
556   PageActionWithBadgeView* page_action_view =
557       static_cast<PageActionWithBadgeView*>(GetPageActionView(page_action));
558   DCHECK(page_action_view);
559   if (!page_action_view)
560     return;
561
562   page_action_view->image_view()->set_preview_enabled(preview_enabled);
563   page_action_view->UpdateVisibility(contents, GetToolbarModel()->GetURL());
564   Layout();
565   SchedulePaint();
566 }
567
568 views::View* LocationBarView::GetPageActionView(ExtensionAction *page_action) {
569   DCHECK(page_action);
570   for (PageActionViews::const_iterator i(page_action_views_.begin());
571        i != page_action_views_.end(); ++i) {
572     if ((*i)->image_view()->page_action() == page_action)
573       return *i;
574   }
575   return NULL;
576 }
577
578 void LocationBarView::SetStarToggled(bool on) {
579   if (star_view_)
580     star_view_->SetToggled(on);
581 }
582
583 void LocationBarView::ShowBookmarkPrompt() {
584   if (star_view_ && star_view_->visible())
585     BookmarkPromptView::ShowPrompt(star_view_, profile_->GetPrefs());
586 }
587
588 void LocationBarView::ZoomChangedForActiveTab(bool can_show_bubble) {
589   DCHECK(zoom_view_);
590   RefreshZoomView();
591
592   Layout();
593   SchedulePaint();
594
595   if (can_show_bubble && zoom_view_->visible() && delegate_->GetWebContents())
596     ZoomBubbleView::ShowBubble(delegate_->GetWebContents(), true);
597 }
598
599 gfx::Point LocationBarView::GetLocationEntryOrigin() const {
600   gfx::Point origin(location_entry_view_->bounds().origin());
601   // If the UI layout is RTL, the coordinate system is not transformed and
602   // therefore we need to adjust the X coordinate so that bubble appears on the
603   // right hand side of the location bar.
604   if (base::i18n::IsRTL())
605     origin.set_x(width() - origin.x());
606   views::View::ConvertPointToScreen(this, &origin);
607   return origin;
608 }
609
610 void LocationBarView::SetImeInlineAutocompletion(const string16& text) {
611   ime_inline_autocomplete_view_->SetText(text);
612   ime_inline_autocomplete_view_->SetVisible(!text.empty());
613 }
614
615 void LocationBarView::SetGrayTextAutocompletion(const string16& text) {
616   if (suggested_text_view_->text() != text) {
617     suggested_text_view_->SetText(text);
618     suggested_text_view_->SetVisible(!text.empty());
619     Layout();
620     SchedulePaint();
621   }
622 }
623
624 string16 LocationBarView::GetGrayTextAutocompletion() const {
625   return HasValidSuggestText() ? suggested_text_view_->text() : string16();
626 }
627
628 void LocationBarView::SetLocationEntryFocusable(bool focusable) {
629   OmniboxViewViews* omnibox_views = GetOmniboxViewViews(location_entry_.get());
630   if (omnibox_views)
631     omnibox_views->set_focusable(focusable);
632   else
633     set_focusable(focusable);
634 }
635
636 bool LocationBarView::IsLocationEntryFocusableInRootView() const {
637   OmniboxViewViews* omnibox_views = GetOmniboxViewViews(location_entry_.get());
638   return omnibox_views ? omnibox_views->IsFocusable() : View::IsFocusable();
639 }
640
641 gfx::Size LocationBarView::GetPreferredSize() {
642   return background_border_painter_->GetMinimumSize();
643 }
644
645 void LocationBarView::Layout() {
646   if (!location_entry_.get())
647     return;
648
649   selected_keyword_view_->SetVisible(false);
650   location_icon_view_->SetVisible(false);
651   ev_bubble_view_->SetVisible(false);
652   keyword_hint_view_->SetVisible(false);
653
654   const int item_padding = GetItemPadding();
655   // The native edit has 1 px of whitespace inside it before the text when the
656   // text is not scrolled off the leading edge.  The views textfield has 1 px of
657   // whitespace before the text in the RTL case only.
658   const int kEditLeadingInternalSpace =
659       (base::i18n::IsRTL() || GetOmniboxViewWin(location_entry_.get())) ? 1 : 0;
660   LocationBarLayout leading_decorations(
661       LocationBarLayout::LEFT_EDGE, item_padding - kEditLeadingInternalSpace);
662   LocationBarLayout trailing_decorations(LocationBarLayout::RIGHT_EDGE,
663                                          item_padding);
664
665   const string16 keyword(location_entry_->model()->keyword());
666   const bool is_keyword_hint(location_entry_->model()->is_keyword_hint());
667   const int bubble_location_y = vertical_edge_thickness() + kBubblePadding;
668   // In some cases (e.g. fullscreen mode) we may have 0 height.  We still want
669   // to position our child views in this case, because other things may be
670   // positioned relative to them (e.g. the "bookmark added" bubble if the user
671   // hits ctrl-d).
672   const int location_height = GetInternalHeight(false);
673   const int bubble_height = std::max(location_height - (kBubblePadding * 2), 0);
674   if (!keyword.empty() && !is_keyword_hint) {
675     leading_decorations.AddDecoration(bubble_location_y, bubble_height, true, 0,
676                                       kBubblePadding, item_padding, 0,
677                                       selected_keyword_view_);
678     if (selected_keyword_view_->keyword() != keyword) {
679       selected_keyword_view_->SetKeyword(keyword);
680       const TemplateURL* template_url =
681           TemplateURLServiceFactory::GetForProfile(profile_)->
682           GetTemplateURLForKeyword(keyword);
683       if (template_url &&
684           (template_url->GetType() == TemplateURL::OMNIBOX_API_EXTENSION)) {
685         gfx::Image image = extensions::OmniboxAPI::Get(profile_)->
686             GetOmniboxIcon(template_url->GetExtensionId());
687         selected_keyword_view_->SetImage(image.AsImageSkia());
688         selected_keyword_view_->set_is_extension_icon(true);
689       } else {
690         selected_keyword_view_->SetImage(
691             *(GetThemeProvider()->GetImageSkiaNamed(IDR_OMNIBOX_SEARCH)));
692         selected_keyword_view_->set_is_extension_icon(false);
693       }
694     }
695   } else if (GetToolbarModel()->GetSecurityLevel(false) ==
696       ToolbarModel::EV_SECURE) {
697     ev_bubble_view_->SetLabel(GetToolbarModel()->GetEVCertName());
698     // The largest fraction of the omnibox that can be taken by the EV bubble.
699     const double kMaxBubbleFraction = 0.5;
700     leading_decorations.AddDecoration(bubble_location_y, bubble_height, false,
701                                       kMaxBubbleFraction, kBubblePadding,
702                                       item_padding, 0, ev_bubble_view_);
703   } else {
704     leading_decorations.AddDecoration(
705         vertical_edge_thickness(), location_height,
706         GetBuiltInHorizontalPaddingForChildViews(),
707         location_icon_view_);
708   }
709
710   if (star_view_ && star_view_->visible()) {
711     trailing_decorations.AddDecoration(
712         vertical_edge_thickness(), location_height,
713         GetBuiltInHorizontalPaddingForChildViews(), star_view_);
714   }
715   if (translate_icon_view_ && translate_icon_view_->visible()) {
716     trailing_decorations.AddDecoration(
717         vertical_edge_thickness(), location_height,
718         GetBuiltInHorizontalPaddingForChildViews(),
719         translate_icon_view_);
720   }
721   if (script_bubble_icon_view_ && script_bubble_icon_view_->visible()) {
722     trailing_decorations.AddDecoration(
723         vertical_edge_thickness(), location_height,
724         GetBuiltInHorizontalPaddingForChildViews(),
725         script_bubble_icon_view_);
726   }
727   if (open_pdf_in_reader_view_ && open_pdf_in_reader_view_->visible()) {
728     trailing_decorations.AddDecoration(
729         vertical_edge_thickness(), location_height,
730         GetBuiltInHorizontalPaddingForChildViews(),
731         open_pdf_in_reader_view_);
732   }
733   for (PageActionViews::const_iterator i(page_action_views_.begin());
734        i != page_action_views_.end(); ++i) {
735     if ((*i)->visible()) {
736       trailing_decorations.AddDecoration(
737           vertical_edge_thickness(), location_height,
738           GetBuiltInHorizontalPaddingForChildViews(), (*i));
739     }
740   }
741   if (zoom_view_->visible()) {
742     trailing_decorations.AddDecoration(vertical_edge_thickness(),
743                                        location_height, 0, zoom_view_);
744   }
745   for (ContentSettingViews::const_reverse_iterator i(
746            content_setting_views_.rbegin()); i != content_setting_views_.rend();
747        ++i) {
748     if ((*i)->visible()) {
749       trailing_decorations.AddDecoration(
750           bubble_location_y, bubble_height, false, 0, item_padding,
751           item_padding, GetBuiltInHorizontalPaddingForChildViews(), (*i));
752     }
753   }
754   if (generated_credit_card_view_->visible()) {
755     trailing_decorations.AddDecoration(vertical_edge_thickness(),
756                                        location_height, 0,
757                                        generated_credit_card_view_);
758   }
759   if (mic_search_view_->visible()) {
760     trailing_decorations.AddDecoration(vertical_edge_thickness(),
761                                        location_height, 0, mic_search_view_);
762   }
763   // Because IMEs may eat the tab key, we don't show "press tab to search" while
764   // IME composition is in progress.
765   if (!keyword.empty() && is_keyword_hint &&
766       !location_entry_->IsImeComposing()) {
767     trailing_decorations.AddDecoration(vertical_edge_thickness(),
768                                        location_height, true, 0, item_padding,
769                                        item_padding, 0, keyword_hint_view_);
770     if (keyword_hint_view_->keyword() != keyword)
771       keyword_hint_view_->SetKeyword(keyword);
772   }
773
774   // Perform layout.
775   const int horizontal_edge_thickness = GetHorizontalEdgeThickness();
776   int full_width = width() - 2 * horizontal_edge_thickness;
777   int entry_width = full_width;
778   leading_decorations.LayoutPass1(&entry_width);
779   trailing_decorations.LayoutPass1(&entry_width);
780   leading_decorations.LayoutPass2(&entry_width);
781   trailing_decorations.LayoutPass2(&entry_width);
782
783   int location_needed_width = location_entry_->TextWidth();
784   int available_width = entry_width - location_needed_width;
785   // The bounds must be wide enough for all the decorations to fit.
786   gfx::Rect location_bounds(
787       horizontal_edge_thickness, vertical_edge_thickness(),
788       std::max(full_width, full_width - entry_width), location_height);
789   leading_decorations.LayoutPass3(&location_bounds, &available_width);
790   trailing_decorations.LayoutPass3(&location_bounds, &available_width);
791
792   // Layout out the suggested text view right aligned to the location
793   // entry. Only show the suggested text if we can fit the text from one
794   // character before the end of the selection to the end of the text and the
795   // suggested text. If we can't it means either the suggested text is too big,
796   // or the user has scrolled.
797
798   // TODO(sky): We could potentially adjust this to take into account suggested
799   // text to force using minimum size if necessary, but currently the chance of
800   // showing keyword hints and suggested text is minimal and we're not confident
801   // this is the right approach for suggested text.
802
803   OmniboxViewViews* omnibox_views =
804       GetOmniboxViewViews(location_entry_.get());
805   int omnibox_views_margin = 0;
806   if (suggested_text_view_->visible()) {
807     // We do not display the suggested text when it contains a mix of RTL and
808     // LTR characters since this could mean the suggestion should be displayed
809     // in the middle of the string.
810     base::i18n::TextDirection text_direction =
811         base::i18n::GetStringDirection(location_entry_->GetText());
812     if (text_direction !=
813         base::i18n::GetStringDirection(suggested_text_view_->text()))
814       text_direction = base::i18n::UNKNOWN_DIRECTION;
815
816     // TODO(sky): need to layout when the user changes caret position.
817     gfx::Size suggested_text_size(suggested_text_view_->GetPreferredSize());
818     if (suggested_text_size.width() > available_width ||
819         text_direction == base::i18n::UNKNOWN_DIRECTION) {
820       // Hide the suggested text if the user has scrolled or we can't fit all
821       // the suggested text, or we have a mix of RTL and LTR characters.
822       suggested_text_view_->SetBounds(0, 0, 0, 0);
823     } else {
824       location_needed_width =
825           std::min(location_needed_width,
826                    location_bounds.width() - suggested_text_size.width());
827       gfx::Rect suggested_text_bounds(location_bounds.x(), location_bounds.y(),
828                                       suggested_text_size.width(),
829                                       location_bounds.height());
830       // TODO(sky): figure out why this needs the -1.
831       suggested_text_bounds.Offset(location_needed_width - 1, 0);
832       // For non-views the omnibox needs to be shrunk so that the suggest text
833       // is visible.
834       if (!omnibox_views)
835         location_bounds.set_width(location_needed_width);
836
837       // We reverse the order of the location entry and suggested text if:
838       // - Chrome is RTL but the text is fully LTR, or
839       // - Chrome is LTR but the text is fully RTL.
840       // This ensures the suggested text is correctly displayed to the right
841       // (or left) of the user text.
842       if (text_direction == (base::i18n::IsRTL() ?
843           base::i18n::LEFT_TO_RIGHT : base::i18n::RIGHT_TO_LEFT)) {
844         // TODO(sky): Figure out why we need the +1.
845         suggested_text_bounds.set_x(location_bounds.x() + 1);
846         if (omnibox_views) {
847           // Use a margin to prevent the omnibox text from overlapping the
848           // suggest text.
849           omnibox_views_margin = suggested_text_bounds.width();
850         } else {
851           // Non-views doesn't support margins so move the omnibox over.
852           location_bounds.set_x(
853               location_bounds.x() + suggested_text_bounds.width());
854         }
855       }
856       suggested_text_view_->SetBoundsRect(suggested_text_bounds);
857     }
858   }
859
860   if (omnibox_views)
861     omnibox_views->SetHorizontalMargins(0, omnibox_views_margin);
862
863   // Layout |ime_inline_autocomplete_view_| next to the user input.
864   if (ime_inline_autocomplete_view_->visible()) {
865     int width =
866         ime_inline_autocomplete_view_->font().GetStringWidth(
867             ime_inline_autocomplete_view_->text()) +
868         ime_inline_autocomplete_view_->GetInsets().width();
869     // All the target languages (IMEs) are LTR, and we do not need to support
870     // RTL so far.  In other words, no testable RTL environment so far.
871     int x = location_needed_width;
872     if (width > entry_width)
873       x = 0;
874     else if (location_needed_width + width > entry_width)
875       x = entry_width - width;
876     location_bounds.set_width(x);
877     ime_inline_autocomplete_view_->SetBounds(
878         location_bounds.right(), location_bounds.y(),
879         std::min(width, entry_width), location_bounds.height());
880   }
881
882   location_entry_view_->SetBoundsRect(location_bounds);
883 }
884
885 void LocationBarView::OnPaint(gfx::Canvas* canvas) {
886   View::OnPaint(canvas);
887
888   // Fill the location bar background color behind the border.  Parts of the
889   // border images are meant to rest atop the toolbar background and parts atop
890   // the omnibox background, so we can't just blindly fill our entire bounds.
891   const int horizontal_edge_thickness = GetHorizontalEdgeThickness();
892   if (!background_filling_painter_) {
893     gfx::Rect bounds(GetContentsBounds());
894     bounds.Inset(horizontal_edge_thickness, vertical_edge_thickness());
895     SkColor color(GetColor(ToolbarModel::NONE, BACKGROUND));
896     if (is_popup_mode_) {
897       canvas->FillRect(bounds, color);
898     } else {
899       SkPaint paint;
900       paint.setStyle(SkPaint::kFill_Style);
901       paint.setColor(color);
902       const int kBorderCornerRadius = 2;
903       canvas->DrawRoundRect(bounds, kBorderCornerRadius, paint);
904     }
905   }
906
907   // Maximized popup windows don't draw the horizontal edges.  We implement this
908   // by simply expanding the paint area outside the view by the edge thickness.
909   gfx::Rect background_rect(GetContentsBounds());
910   if (is_popup_mode_ && (horizontal_edge_thickness == 0))
911     background_rect.Inset(-kPopupEdgeThickness, 0);
912   views::Painter::PaintPainterAt(canvas, background_border_painter_.get(),
913                                  background_rect);
914   if (background_filling_painter_)
915     background_filling_painter_->Paint(canvas, size());
916
917   if (!is_popup_mode_)
918     PaintPageActionBackgrounds(canvas);
919
920   // For non-InstantExtendedAPI cases, if necessary, show focus rect.
921   // Note: |Canvas::DrawFocusRect| paints a dashed rect with gray color.
922   if (show_focus_rect_ && HasFocus()) {
923     gfx::Rect r = location_entry_view_->bounds();
924     // TODO(jamescook): Is this still needed?
925     r.Inset(-1, 0);
926 #if defined(OS_WIN)
927     r.Inset(0, -1);
928 #endif
929     canvas->DrawFocusRect(r);
930   }
931 }
932
933 void LocationBarView::SetShowFocusRect(bool show) {
934   show_focus_rect_ = show;
935   SchedulePaint();
936 }
937
938 void LocationBarView::SelectAll() {
939   location_entry_->SelectAll(true);
940 }
941
942 #if defined(OS_WIN) && !defined(USE_AURA)
943 bool LocationBarView::OnMousePressed(const ui::MouseEvent& event) {
944   UINT msg;
945   if (event.IsLeftMouseButton()) {
946     msg = (event.flags() & ui::EF_IS_DOUBLE_CLICK) ?
947         WM_LBUTTONDBLCLK : WM_LBUTTONDOWN;
948   } else if (event.IsMiddleMouseButton()) {
949     msg = (event.flags() & ui::EF_IS_DOUBLE_CLICK) ?
950         WM_MBUTTONDBLCLK : WM_MBUTTONDOWN;
951   } else if (event.IsRightMouseButton()) {
952     msg = (event.flags() & ui::EF_IS_DOUBLE_CLICK) ?
953         WM_RBUTTONDBLCLK : WM_RBUTTONDOWN;
954   } else {
955     NOTREACHED();
956     return false;
957   }
958   OnMouseEvent(event, msg);
959   return true;
960 }
961
962 bool LocationBarView::OnMouseDragged(const ui::MouseEvent& event) {
963   OnMouseEvent(event, WM_MOUSEMOVE);
964   return true;
965 }
966
967 void LocationBarView::OnMouseReleased(const ui::MouseEvent& event) {
968   UINT msg;
969   if (event.IsLeftMouseButton()) {
970     msg = WM_LBUTTONUP;
971   } else if (event.IsMiddleMouseButton()) {
972     msg = WM_MBUTTONUP;
973   } else if (event.IsRightMouseButton()) {
974     msg = WM_RBUTTONUP;
975   } else {
976     NOTREACHED();
977     return;
978   }
979   OnMouseEvent(event, msg);
980 }
981
982 void LocationBarView::OnMouseCaptureLost() {
983   OmniboxViewWin* omnibox_win = GetOmniboxViewWin(location_entry_.get());
984   if (omnibox_win)
985     omnibox_win->HandleExternalMsg(WM_CAPTURECHANGED, 0, CPoint());
986 }
987 #endif
988
989 views::View* LocationBarView::generated_credit_card_view() {
990   return generated_credit_card_view_;
991 }
992
993 void LocationBarView::Update(const WebContents* contents) {
994   mic_search_view_->SetVisible(
995       !GetToolbarModel()->input_in_progress() && browser_ &&
996       browser_->search_model()->voice_search_supported());
997   UpdateContentSettingViewsPreLayout();
998   generated_credit_card_view_->Update();
999   ZoomBubbleView::CloseBubble();
1000   RefreshZoomView();
1001   RefreshPageActionViews();
1002   RefreshScriptBubble();
1003   RefreshTranslateIcon();
1004   open_pdf_in_reader_view_->Update(
1005       GetToolbarModel()->input_in_progress() ? NULL : GetWebContents());
1006
1007   bool star_enabled = browser_defaults::bookmarks_enabled && !is_popup_mode_ &&
1008       star_view_ && !GetToolbarModel()->input_in_progress() &&
1009       edit_bookmarks_enabled_.GetValue();
1010
1011   command_updater()->UpdateCommandEnabled(IDC_BOOKMARK_PAGE, star_enabled);
1012   command_updater()->UpdateCommandEnabled(IDC_BOOKMARK_PAGE_FROM_STAR,
1013                                           star_enabled);
1014   if (star_view_)
1015     star_view_->SetVisible(star_enabled);
1016
1017   if (contents)
1018     location_entry_->OnTabChanged(contents);
1019   else
1020     location_entry_->Update();
1021
1022   OnChanged();  // NOTE: Calls Layout().
1023   UpdateContentSettingViewsPostLayout();
1024 }
1025
1026 void LocationBarView::OnChanged() {
1027   location_icon_view_->SetImage(
1028       GetThemeProvider()->GetImageSkiaNamed(location_entry_->GetIcon()));
1029   location_icon_view_->ShowTooltip(!GetLocationEntry()->IsEditingOrEmpty());
1030
1031   Layout();
1032   SchedulePaint();
1033 }
1034
1035 void LocationBarView::OnSetFocus() {
1036   GetFocusManager()->SetFocusedView(this);
1037 }
1038
1039 InstantController* LocationBarView::GetInstant() {
1040   return delegate_->GetInstant();
1041 }
1042
1043 WebContents* LocationBarView::GetWebContents() {
1044   return delegate_->GetWebContents();
1045 }
1046
1047 ToolbarModel* LocationBarView::GetToolbarModel() {
1048   return delegate_->GetToolbarModel();
1049 }
1050
1051 const ToolbarModel* LocationBarView::GetToolbarModel() const {
1052   return delegate_->GetToolbarModel();
1053 }
1054
1055 const char* LocationBarView::GetClassName() const {
1056   return kViewClassName;
1057 }
1058
1059 bool LocationBarView::SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) {
1060 #if defined(OS_WIN)
1061   if (views::FocusManager::IsTabTraversalKeyEvent(event)) {
1062     if (location_entry_->model()->popup_model()->IsOpen()) {
1063       // Return true so that the edit sees the tab and moves the selection.
1064       return true;
1065     }
1066     if (keyword_hint_view_->visible() && !event.IsShiftDown()) {
1067       // Return true so the edit gets the tab event and enters keyword mode.
1068       return true;
1069     }
1070   }
1071
1072 #if defined(USE_AURA)
1073   NOTIMPLEMENTED();
1074 #else
1075   OmniboxViewWin* omnibox_win = GetOmniboxViewWin(location_entry_.get());
1076   if (omnibox_win)
1077     return omnibox_win->SkipDefaultKeyEventProcessing(event);
1078 #endif  // USE_AURA
1079 #endif  // OS_WIN
1080
1081   // This method is not used for Linux ports. See FocusManager::OnKeyEvent() in
1082   // src/ui/views/focus/focus_manager.cc for details.
1083   return false;
1084 }
1085
1086 void LocationBarView::GetAccessibleState(ui::AccessibleViewState* state) {
1087   if (!location_entry_)
1088     return;
1089
1090   state->role = ui::AccessibilityTypes::ROLE_LOCATION_BAR;
1091   state->name = l10n_util::GetStringUTF16(IDS_ACCNAME_LOCATION);
1092   state->value = location_entry_->GetText();
1093
1094   string16::size_type entry_start;
1095   string16::size_type entry_end;
1096   location_entry_->GetSelectionBounds(&entry_start, &entry_end);
1097   state->selection_start = entry_start;
1098   state->selection_end = entry_end;
1099
1100   if (is_popup_mode_) {
1101     state->state |= ui::AccessibilityTypes::STATE_READONLY;
1102   } else {
1103     state->set_value_callback =
1104         base::Bind(&LocationBarView::AccessibilitySetValue,
1105                    weak_ptr_factory_.GetWeakPtr());
1106   }
1107 }
1108
1109 bool LocationBarView::HasFocus() const {
1110   return location_entry_->model()->has_focus();
1111 }
1112
1113 void LocationBarView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
1114   if (browser_ && browser_->instant_controller() && parent())
1115     browser_->instant_controller()->SetOmniboxBounds(bounds());
1116   OmniboxPopupView* popup = location_entry_->model()->popup_model()->view();
1117   if (popup->IsOpen())
1118     popup->UpdatePopupAppearance();
1119 }
1120
1121 void LocationBarView::ButtonPressed(views::Button* sender,
1122                                     const ui::Event& event) {
1123   DCHECK_EQ(mic_search_view_, sender);
1124   command_updater()->ExecuteCommand(IDC_TOGGLE_SPEECH_INPUT);
1125 }
1126
1127 void LocationBarView::WriteDragDataForView(views::View* sender,
1128                                            const gfx::Point& press_pt,
1129                                            OSExchangeData* data) {
1130   DCHECK_NE(GetDragOperationsForView(sender, press_pt),
1131             ui::DragDropTypes::DRAG_NONE);
1132
1133   WebContents* web_contents = GetWebContents();
1134   FaviconTabHelper* favicon_tab_helper =
1135       FaviconTabHelper::FromWebContents(web_contents);
1136   gfx::ImageSkia favicon = favicon_tab_helper->GetFavicon().AsImageSkia();
1137   button_drag_utils::SetURLAndDragImage(web_contents->GetURL(),
1138                                         web_contents->GetTitle(),
1139                                         favicon,
1140                                         data,
1141                                         sender->GetWidget());
1142 }
1143
1144 int LocationBarView::GetDragOperationsForView(views::View* sender,
1145                                               const gfx::Point& p) {
1146   DCHECK((sender == location_icon_view_) || (sender == ev_bubble_view_));
1147   WebContents* web_contents = delegate_->GetWebContents();
1148   return (web_contents && web_contents->GetURL().is_valid() &&
1149           !GetLocationEntry()->IsEditingOrEmpty()) ?
1150       (ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_LINK) :
1151       ui::DragDropTypes::DRAG_NONE;
1152 }
1153
1154 bool LocationBarView::CanStartDragForView(View* sender,
1155                                           const gfx::Point& press_pt,
1156                                           const gfx::Point& p) {
1157   return true;
1158 }
1159
1160 ////////////////////////////////////////////////////////////////////////////////
1161 // LocationBarView, LocationBar implementation:
1162
1163 void LocationBarView::ShowFirstRunBubble() {
1164   // Wait until search engines have loaded to show the first run bubble.
1165   TemplateURLService* url_service =
1166       TemplateURLServiceFactory::GetForProfile(profile_);
1167   if (!url_service->loaded()) {
1168     template_url_service_ = url_service;
1169     template_url_service_->AddObserver(this);
1170     template_url_service_->Load();
1171     return;
1172   }
1173   ShowFirstRunBubbleInternal();
1174 }
1175
1176 GURL LocationBarView::GetDestinationURL() const {
1177   return destination_url();
1178 }
1179
1180 WindowOpenDisposition LocationBarView::GetWindowOpenDisposition() const {
1181   return disposition();
1182 }
1183
1184 content::PageTransition LocationBarView::GetPageTransition() const {
1185   return transition();
1186 }
1187
1188 void LocationBarView::AcceptInput() {
1189   location_entry_->model()->AcceptInput(CURRENT_TAB, false);
1190 }
1191
1192 void LocationBarView::FocusLocation(bool select_all) {
1193   location_entry_->SetFocus();
1194   if (select_all)
1195     location_entry_->SelectAll(true);
1196 }
1197
1198 void LocationBarView::FocusSearch() {
1199   location_entry_->SetFocus();
1200   location_entry_->SetForcedQuery();
1201 }
1202
1203 void LocationBarView::SaveStateToContents(WebContents* contents) {
1204   location_entry_->SaveStateToTab(contents);
1205 }
1206
1207 void LocationBarView::Revert() {
1208   location_entry_->RevertAll();
1209 }
1210
1211 const OmniboxView* LocationBarView::GetLocationEntry() const {
1212   return location_entry_.get();
1213 }
1214
1215 OmniboxView* LocationBarView::GetLocationEntry() {
1216   return location_entry_.get();
1217 }
1218
1219 LocationBarTesting* LocationBarView::GetLocationBarForTesting() {
1220   return this;
1221 }
1222
1223 int LocationBarView::PageActionCount() {
1224   return page_action_views_.size();
1225 }
1226
1227 int LocationBarView::PageActionVisibleCount() {
1228   int result = 0;
1229   for (size_t i = 0; i < page_action_views_.size(); i++) {
1230     if (page_action_views_[i]->visible())
1231       ++result;
1232   }
1233   return result;
1234 }
1235
1236 ExtensionAction* LocationBarView::GetPageAction(size_t index) {
1237   if (index < page_action_views_.size())
1238     return page_action_views_[index]->image_view()->page_action();
1239
1240   NOTREACHED();
1241   return NULL;
1242 }
1243
1244 ExtensionAction* LocationBarView::GetVisiblePageAction(size_t index) {
1245   size_t current = 0;
1246   for (size_t i = 0; i < page_action_views_.size(); ++i) {
1247     if (page_action_views_[i]->visible()) {
1248       if (current == index)
1249         return page_action_views_[i]->image_view()->page_action();
1250
1251       ++current;
1252     }
1253   }
1254
1255   NOTREACHED();
1256   return NULL;
1257 }
1258
1259 void LocationBarView::TestPageActionPressed(size_t index) {
1260   size_t current = 0;
1261   for (size_t i = 0; i < page_action_views_.size(); ++i) {
1262     if (page_action_views_[i]->visible()) {
1263       if (current == index) {
1264         page_action_views_[i]->image_view()->ExecuteAction(
1265             ExtensionPopup::SHOW);
1266         return;
1267       }
1268       ++current;
1269     }
1270   }
1271
1272   NOTREACHED();
1273 }
1274
1275 bool LocationBarView::GetBookmarkStarVisibility() {
1276   DCHECK(star_view_);
1277   return star_view_->visible();
1278 }
1279
1280 void LocationBarView::OnTemplateURLServiceChanged() {
1281   template_url_service_->RemoveObserver(this);
1282   template_url_service_ = NULL;
1283   // If the browser is no longer active, let's not show the info bubble, as this
1284   // would make the browser the active window again.
1285   if (location_entry_view_ && location_entry_view_->GetWidget()->IsActive())
1286     ShowFirstRunBubble();
1287 }
1288
1289 void LocationBarView::Observe(int type,
1290                               const content::NotificationSource& source,
1291                               const content::NotificationDetails& details) {
1292   switch (type) {
1293     case chrome::NOTIFICATION_EXTENSION_LOCATION_BAR_UPDATED: {
1294       // Only update if the updated action box was for the active tab contents.
1295       WebContents* target_tab = content::Details<WebContents>(details).ptr();
1296       if (target_tab == GetWebContents())
1297         UpdatePageActions();
1298       break;
1299     }
1300
1301     default:
1302       NOTREACHED() << "Unexpected notification.";
1303   }
1304 }
1305
1306 void LocationBarView::ModelChanged(const SearchModel::State& old_state,
1307                                    const SearchModel::State& new_state) {
1308   const bool visible = !GetToolbarModel()->input_in_progress() &&
1309       new_state.voice_search_supported;
1310   if (mic_search_view_->visible() != visible) {
1311     mic_search_view_->SetVisible(visible);
1312     Layout();
1313   }
1314 }
1315
1316 int LocationBarView::GetInternalHeight(bool use_preferred_size) {
1317   int total_height =
1318       use_preferred_size ? GetPreferredSize().height() : height();
1319   return std::max(total_height - (vertical_edge_thickness() * 2), 0);
1320 }
1321
1322 ////////////////////////////////////////////////////////////////////////////////
1323 // LocationBarView, private:
1324
1325 // static
1326 int LocationBarView::GetBuiltInHorizontalPaddingForChildViews() {
1327   return (ui::GetDisplayLayout() == ui::LAYOUT_TOUCH) ?
1328       GetItemPadding() / 2 : 0;
1329 }
1330
1331 int LocationBarView::GetHorizontalEdgeThickness() const {
1332   // In maximized popup mode, there isn't any edge.
1333   return (is_popup_mode_ && browser_ && browser_->window() &&
1334       browser_->window()->IsMaximized()) ? 0 : vertical_edge_thickness();
1335 }
1336
1337 void LocationBarView::UpdateContentSettingViewsPreLayout() {
1338   for (ContentSettingViews::const_iterator i(content_setting_views_.begin());
1339        i != content_setting_views_.end(); ++i) {
1340     (*i)->UpdatePreLayout(GetToolbarModel()->input_in_progress() ?
1341         NULL : GetWebContents());
1342   }
1343 }
1344
1345 void LocationBarView::UpdateContentSettingViewsPostLayout() {
1346   for (ContentSettingViews::const_iterator i(content_setting_views_.begin());
1347        i != content_setting_views_.end(); ++i) {
1348     (*i)->UpdatePostLayout(GetToolbarModel()->input_in_progress() ?
1349         NULL : GetWebContents());
1350   }
1351 }
1352
1353 void LocationBarView::DeletePageActionViews() {
1354   for (PageActionViews::const_iterator i(page_action_views_.begin());
1355        i != page_action_views_.end(); ++i)
1356     RemoveChildView(*i);
1357   STLDeleteElements(&page_action_views_);
1358 }
1359
1360 void LocationBarView::RefreshPageActionViews() {
1361   if (is_popup_mode_)
1362     return;
1363
1364   // Remember the previous visibility of the page actions so that we can
1365   // notify when this changes.
1366   std::map<ExtensionAction*, bool> old_visibility;
1367   for (PageActionViews::const_iterator i(page_action_views_.begin());
1368        i != page_action_views_.end(); ++i) {
1369     old_visibility[(*i)->image_view()->page_action()] = (*i)->visible();
1370   }
1371
1372   std::vector<ExtensionAction*> new_page_actions;
1373
1374   WebContents* contents = delegate_->GetWebContents();
1375   if (contents) {
1376     extensions::TabHelper* extensions_tab_helper =
1377         extensions::TabHelper::FromWebContents(contents);
1378     extensions::LocationBarController* controller =
1379         extensions_tab_helper->location_bar_controller();
1380     new_page_actions = controller->GetCurrentActions();
1381   }
1382
1383   // On startup we sometimes haven't loaded any extensions. This makes sure
1384   // we catch up when the extensions (and any page actions) load.
1385   if (page_actions_ != new_page_actions) {
1386     page_actions_.swap(new_page_actions);
1387     DeletePageActionViews();  // Delete the old views (if any).
1388
1389     page_action_views_.resize(page_actions_.size());
1390     View* right_anchor = open_pdf_in_reader_view_;
1391     if (!right_anchor)
1392       right_anchor = star_view_;
1393     if (!right_anchor)
1394       right_anchor = script_bubble_icon_view_;
1395     DCHECK(right_anchor);
1396
1397     // Add the page actions in reverse order, so that the child views are
1398     // inserted in left-to-right order for accessibility.
1399     for (int i = page_actions_.size() - 1; i >= 0; --i) {
1400       page_action_views_[i] = new PageActionWithBadgeView(
1401           delegate_->CreatePageActionImageView(this, page_actions_[i]));
1402       page_action_views_[i]->SetVisible(false);
1403       AddChildViewAt(page_action_views_[i], GetIndexOf(right_anchor));
1404     }
1405   }
1406
1407   if (!page_action_views_.empty() && contents) {
1408     Browser* browser = chrome::FindBrowserWithWebContents(contents);
1409     GURL url = browser->tab_strip_model()->GetActiveWebContents()->GetURL();
1410
1411     for (PageActionViews::const_iterator i(page_action_views_.begin());
1412          i != page_action_views_.end(); ++i) {
1413       (*i)->UpdateVisibility(
1414           GetToolbarModel()->input_in_progress() ? NULL : contents, url);
1415
1416       // Check if the visibility of the action changed and notify if it did.
1417       ExtensionAction* action = (*i)->image_view()->page_action();
1418       if (old_visibility.find(action) == old_visibility.end() ||
1419           old_visibility[action] != (*i)->visible()) {
1420         content::NotificationService::current()->Notify(
1421             chrome::NOTIFICATION_EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED,
1422             content::Source<ExtensionAction>(action),
1423             content::Details<WebContents>(contents));
1424       }
1425     }
1426   }
1427 }
1428
1429 size_t LocationBarView::ScriptBubbleScriptsRunning() {
1430   WebContents* contents = delegate_->GetWebContents();
1431   if (!contents)
1432     return false;
1433   extensions::TabHelper* extensions_tab_helper =
1434       extensions::TabHelper::FromWebContents(contents);
1435   if (!extensions_tab_helper)
1436     return false;
1437   extensions::ScriptBubbleController* script_bubble_controller =
1438       extensions_tab_helper->script_bubble_controller();
1439   if (!script_bubble_controller)
1440     return false;
1441   size_t script_count =
1442       script_bubble_controller->extensions_running_scripts().size();
1443   return script_count;
1444 }
1445
1446 void LocationBarView::RefreshScriptBubble() {
1447   if (!script_bubble_icon_view_)
1448     return;
1449   size_t script_count = ScriptBubbleScriptsRunning();
1450   script_bubble_icon_view_->SetVisible(script_count > 0);
1451   if (script_count > 0)
1452     script_bubble_icon_view_->SetScriptCount(script_count);
1453 }
1454
1455 void LocationBarView::RefreshZoomView() {
1456   DCHECK(zoom_view_);
1457   WebContents* web_contents = GetWebContents();
1458   if (!web_contents)
1459     return;
1460
1461   ZoomController* zoom_controller =
1462       ZoomController::FromWebContents(web_contents);
1463   zoom_view_->Update(zoom_controller);
1464 }
1465
1466 void LocationBarView::RefreshTranslateIcon() {
1467   if (!translate_icon_view_)
1468     return;
1469
1470   WebContents* web_contents = GetWebContents();
1471   if (!web_contents)
1472     return;
1473
1474   TranslateTabHelper* translate_tab_helper =
1475       TranslateTabHelper::FromWebContents(web_contents);
1476   bool enabled =
1477       translate_tab_helper->language_state().translate_enabled();
1478
1479   command_updater()->UpdateCommandEnabled(IDC_TRANSLATE_PAGE, enabled);
1480   translate_icon_view_->SetVisible(enabled);
1481 }
1482
1483 #if defined(OS_WIN) && !defined(USE_AURA)
1484 void LocationBarView::OnMouseEvent(const ui::MouseEvent& event, UINT msg) {
1485   OmniboxViewWin* omnibox_win = GetOmniboxViewWin(location_entry_.get());
1486   if (omnibox_win) {
1487     UINT flags = event.native_event().wParam;
1488     gfx::Point screen_point(event.location());
1489     ConvertPointToScreen(this, &screen_point);
1490     omnibox_win->HandleExternalMsg(msg, flags, screen_point.ToPOINT());
1491   }
1492 }
1493 #endif
1494
1495 bool LocationBarView::HasValidSuggestText() const {
1496   return suggested_text_view_->visible() &&
1497       !suggested_text_view_->size().IsEmpty();
1498 }
1499
1500 void LocationBarView::ShowFirstRunBubbleInternal() {
1501 #if !defined(OS_CHROMEOS)
1502   // First run bubble doesn't make sense for Chrome OS.
1503   Browser* browser = GetBrowserFromDelegate(delegate_);
1504   if (!browser)
1505     return; // Possible when browser is shutting down.
1506
1507   FirstRunBubble::ShowBubble(browser, location_icon_view_);
1508 #endif
1509 }
1510
1511 void LocationBarView::PaintPageActionBackgrounds(gfx::Canvas* canvas) {
1512   WebContents* web_contents = GetWebContents();
1513   // web_contents may be NULL while the browser is shutting down.
1514   if (!web_contents)
1515     return;
1516
1517   const int32 tab_id = SessionID::IdForTab(web_contents);
1518   const ToolbarModel::SecurityLevel security_level =
1519       GetToolbarModel()->GetSecurityLevel(false);
1520   const SkColor text_color = GetColor(security_level, TEXT);
1521   const SkColor background_color = GetColor(security_level, BACKGROUND);
1522
1523   for (PageActionViews::const_iterator
1524            page_action_view = page_action_views_.begin();
1525        page_action_view != page_action_views_.end();
1526        ++page_action_view) {
1527     gfx::Rect bounds = (*page_action_view)->bounds();
1528     int horizontal_padding =
1529         GetItemPadding() - GetBuiltInHorizontalPaddingForChildViews();
1530     // Make the bounding rectangle include the whole vertical range of the
1531     // location bar, and the mid-point pixels between adjacent page actions.
1532     //
1533     // For odd horizontal_paddings, "horizontal_padding + 1" includes the
1534     // mid-point between two page actions in the bounding rectangle.  For even
1535     // paddings, the +1 is dropped, which is right since there is no pixel at
1536     // the mid-point.
1537     bounds.Inset(-(horizontal_padding + 1) / 2, 0);
1538     location_bar_util::PaintExtensionActionBackground(
1539         *(*page_action_view)->image_view()->page_action(),
1540         tab_id, canvas, bounds, text_color, background_color);
1541   }
1542 }
1543
1544 void LocationBarView::AccessibilitySetValue(const string16& new_value) {
1545   location_entry_->SetUserText(new_value);
1546 }